linux/scripts/kconfig/nconf.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
   3 * Released under the terms of the GNU GPL v2.0.
   4 *
   5 * Derived from menuconfig.
   6 *
   7 */
   8#define LKC_DIRECT_LINK
   9#include "lkc.h"
  10#include "nconf.h"
  11
  12static const char nconf_readme[] = N_(
  13"Overview\n"
  14"--------\n"
  15"Some kernel features may be built directly into the kernel.\n"
  16"Some may be made into loadable runtime modules.  Some features\n"
  17"may be completely removed altogether.  There are also certain\n"
  18"kernel parameters which are not really features, but must be\n"
  19"entered in as decimal or hexadecimal numbers or possibly text.\n"
  20"\n"
  21"Menu items beginning with following braces represent features that\n"
  22"  [ ] can be built in or removed\n"
  23"  < > can be built in, modularized or removed\n"
  24"  { } can be built in or modularized (selected by other feature)\n"
  25"  - - are selected by other feature,\n"
  26"  XXX cannot be selected. use Symbol Info to find out why,\n"
  27"while *, M or whitespace inside braces means to build in, build as\n"
  28"a module or to exclude the feature respectively.\n"
  29"\n"
  30"To change any of these features, highlight it with the cursor\n"
  31"keys and press <Y> to build it in, <M> to make it a module or\n"
  32"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
  33"through the available options (ie. Y->N->M->Y).\n"
  34"\n"
  35"Some additional keyboard hints:\n"
  36"\n"
  37"Menus\n"
  38"----------\n"
  39"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
  40"   you wish to change use <Enter> or <Space>. Goto submenu by \n"
  41"   pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
  42"   Submenus are designated by \"--->\".\n"
  43"\n"
  44"   Shortcut: Press the option's highlighted letter (hotkey).\n"
  45"             Pressing a hotkey more than once will sequence\n"
  46"             through all visible items which use that hotkey.\n"
  47"\n"
  48"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
  49"   unseen options into view.\n"
  50"\n"
  51"o  To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
  52"\n"
  53"o  To get help with an item, press <F1>\n"
  54"   Shortcut: Press <h> or <?>.\n"
  55"\n"
  56"\n"
  57"Radiolists  (Choice lists)\n"
  58"-----------\n"
  59"o  Use the cursor keys to select the option you wish to set and press\n"
  60"   <S> or the <SPACE BAR>.\n"
  61"\n"
  62"   Shortcut: Press the first letter of the option you wish to set then\n"
  63"             press <S> or <SPACE BAR>.\n"
  64"\n"
  65"o  To see available help for the item, press <F1>\n"
  66"   Shortcut: Press <H> or <?>.\n"
  67"\n"
  68"\n"
  69"Data Entry\n"
  70"-----------\n"
  71"o  Enter the requested information and press <ENTER>\n"
  72"   If you are entering hexadecimal values, it is not necessary to\n"
  73"   add the '0x' prefix to the entry.\n"
  74"\n"
  75"o  For help, press <F1>.\n"
  76"\n"
  77"\n"
  78"Text Box    (Help Window)\n"
  79"--------\n"
  80"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
  81"   keys h,j,k,l function here as do <SPACE BAR> for those\n"
  82"   who are familiar with less and lynx.\n"
  83"\n"
  84"o  Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
  85"\n"
  86"\n"
  87"Alternate Configuration Files\n"
  88"-----------------------------\n"
  89"nconfig supports the use of alternate configuration files for\n"
  90"those who, for various reasons, find it necessary to switch\n"
  91"between different kernel configurations.\n"
  92"\n"
  93"At the end of the main menu you will find two options.  One is\n"
  94"for saving the current configuration to a file of your choosing.\n"
  95"The other option is for loading a previously saved alternate\n"
  96"configuration.\n"
  97"\n"
  98"Even if you don't use alternate configuration files, but you\n"
  99"find during a nconfig session that you have completely messed\n"
 100"up your settings, you may use the \"Load Alternate...\" option to\n"
 101"restore your previously saved settings from \".config\" without\n"
 102"restarting nconfig.\n"
 103"\n"
 104"Other information\n"
 105"-----------------\n"
 106"If you use nconfig in an XTERM window make sure you have your\n"
 107"$TERM variable set to point to a xterm definition which supports color.\n"
 108"Otherwise, nconfig will look rather bad.  nconfig will not\n"
 109"display correctly in a RXVT window because rxvt displays only one\n"
 110"intensity of color, bright.\n"
 111"\n"
 112"nconfig will display larger menus on screens or xterms which are\n"
 113"set to display more than the standard 25 row by 80 column geometry.\n"
 114"In order for this to work, the \"stty size\" command must be able to\n"
 115"display the screen's current row and column geometry.  I STRONGLY\n"
 116"RECOMMEND that you make sure you do NOT have the shell variables\n"
 117"LINES and COLUMNS exported into your environment.  Some distributions\n"
 118"export those variables via /etc/profile.  Some ncurses programs can\n"
 119"become confused when those variables (LINES & COLUMNS) don't reflect\n"
 120"the true screen size.\n"
 121"\n"
 122"Optional personality available\n"
 123"------------------------------\n"
 124"If you prefer to have all of the kernel options listed in a single\n"
 125"menu, rather than the default multimenu hierarchy, run the nconfig\n"
 126"with NCONFIG_MODE environment variable set to single_menu. Example:\n"
 127"\n"
 128"make NCONFIG_MODE=single_menu nconfig\n"
 129"\n"
 130"<Enter> will then unroll the appropriate category, or enfold it if it\n"
 131"is already unrolled.\n"
 132"\n"
 133"Note that this mode can eventually be a little more CPU expensive\n"
 134"(especially with a larger number of unrolled categories) than the\n"
 135"default mode.\n"
 136"\n"),
 137menu_no_f_instructions[] = N_(
 138" You do not have function keys support. Please follow the\n"
 139" following instructions:\n"
 140" Arrow keys navigate the menu.\n"
 141" <Enter> or <right-arrow> selects submenus --->.\n"
 142" Capital Letters are hotkeys.\n"
 143" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
 144" Pressing SpaceBar toggles between the above options\n"
 145" Press <Esc> or <left-arrow> to go back one menu, \n"
 146" <?> or <h> for Help, </> for Search.\n"
 147" <1> is interchangable with <F1>, <2> with <F2>, etc.\n"
 148" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
 149" <Esc> always leaves the current window\n"),
 150menu_instructions[] = N_(
 151" Arrow keys navigate the menu.\n"
 152" <Enter> or <right-arrow> selects submenus --->.\n"
 153" Capital Letters are hotkeys.\n"
 154" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
 155" Pressing SpaceBar toggles between the above options\n"
 156" Press <Esc>, <F3> or <left-arrow> to go back one menu, \n"
 157" <?>, <F1> or <h> for Help, </> for Search.\n"
 158" <1> is interchangable with <F1>, <2> with <F2>, etc.\n"
 159" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
 160" <Esc> always leaves the current window\n"),
 161radiolist_instructions[] = N_(
 162" Use the arrow keys to navigate this window or\n"
 163" press the hotkey of the item you wish to select\n"
 164" followed by the <SPACE BAR>.\n"
 165" Press <?>, <F1> or <h> for additional information about this option.\n"),
 166inputbox_instructions_int[] = N_(
 167"Please enter a decimal value.\n"
 168"Fractions will not be accepted.\n"
 169"Press <RETURN> to accept, <ESC> to cancel."),
 170inputbox_instructions_hex[] = N_(
 171"Please enter a hexadecimal value.\n"
 172"Press <RETURN> to accept, <ESC> to cancel."),
 173inputbox_instructions_string[] = N_(
 174"Please enter a string value.\n"
 175"Press <RETURN> to accept, <ESC> to cancel."),
 176setmod_text[] = N_(
 177"This feature depends on another which\n"
 178"has been configured as a module.\n"
 179"As a result, this feature will be built as a module."),
 180nohelp_text[] = N_(
 181"There is no help available for this kernel option.\n"),
 182load_config_text[] = N_(
 183"Enter the name of the configuration file you wish to load.\n"
 184"Accept the name shown to restore the configuration you\n"
 185"last retrieved.  Leave blank to abort."),
 186load_config_help[] = N_(
 187"\n"
 188"For various reasons, one may wish to keep several different kernel\n"
 189"configurations available on a single machine.\n"
 190"\n"
 191"If you have saved a previous configuration in a file other than the\n"
 192"kernel's default, entering the name of the file here will allow you\n"
 193"to modify that configuration.\n"
 194"\n"
 195"If you are uncertain, then you have probably never used alternate\n"
 196"configuration files.  You should therefor leave this blank to abort.\n"),
 197save_config_text[] = N_(
 198"Enter a filename to which this configuration should be saved\n"
 199"as an alternate.  Leave blank to abort."),
 200save_config_help[] = N_(
 201"\n"
 202"For various reasons, one may wish to keep different kernel\n"
 203"configurations available on a single machine.\n"
 204"\n"
 205"Entering a file name here will allow you to later retrieve, modify\n"
 206"and use the current configuration as an alternate to whatever\n"
 207"configuration options you have selected at that time.\n"
 208"\n"
 209"If you are uncertain what all this means then you should probably\n"
 210"leave this blank.\n"),
 211search_help[] = N_(
 212"\n"
 213"Search for CONFIG_ symbols and display their relations.\n"
 214"Regular expressions are allowed.\n"
 215"Example: search for \"^FOO\"\n"
 216"Result:\n"
 217"-----------------------------------------------------------------\n"
 218"Symbol: FOO [ = m]\n"
 219"Prompt: Foo bus is used to drive the bar HW\n"
 220"Defined at drivers/pci/Kconfig:47\n"
 221"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
 222"Location:\n"
 223"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
 224"    -> PCI support (PCI [ = y])\n"
 225"      -> PCI access mode (<choice> [ = y])\n"
 226"Selects: LIBCRC32\n"
 227"Selected by: BAR\n"
 228"-----------------------------------------------------------------\n"
 229"o The line 'Prompt:' shows the text used in the menu structure for\n"
 230"  this CONFIG_ symbol\n"
 231"o The 'Defined at' line tell at what file / line number the symbol\n"
 232"  is defined\n"
 233"o The 'Depends on:' line tell what symbols needs to be defined for\n"
 234"  this symbol to be visible in the menu (selectable)\n"
 235"o The 'Location:' lines tell where in the menu structure this symbol\n"
 236"  is located\n"
 237"    A location followed by a [ = y] indicate that this is a selectable\n"
 238"    menu item - and current value is displayed inside brackets.\n"
 239"o The 'Selects:' line tell what symbol will be automatically\n"
 240"  selected if this symbol is selected (y or m)\n"
 241"o The 'Selected by' line tell what symbol has selected this symbol\n"
 242"\n"
 243"Only relevant lines are shown.\n"
 244"\n\n"
 245"Search examples:\n"
 246"Examples: USB   = > find all CONFIG_ symbols containing USB\n"
 247"          ^USB => find all CONFIG_ symbols starting with USB\n"
 248"          USB$ => find all CONFIG_ symbols ending with USB\n"
 249"\n");
 250
 251struct mitem {
 252        char str[256];
 253        char tag;
 254        void *usrptr;
 255        int is_hot;
 256        int is_visible;
 257};
 258
 259#define MAX_MENU_ITEMS 4096
 260static int show_all_items;
 261static int indent;
 262static struct menu *current_menu;
 263static int child_count;
 264static int single_menu_mode;
 265/* the window in which all information appears */
 266static WINDOW *main_window;
 267/* the largest size of the menu window */
 268static int mwin_max_lines;
 269static int mwin_max_cols;
 270/* the window in which we show option buttons */
 271static MENU *curses_menu;
 272static ITEM *curses_menu_items[MAX_MENU_ITEMS];
 273static struct mitem k_menu_items[MAX_MENU_ITEMS];
 274static int items_num;
 275static int global_exit;
 276/* the currently selected button */
 277const char *current_instructions = menu_instructions;
 278/* this array is used to implement hot keys. it is updated in item_make and
 279 * resetted in clean_items. It would be better to use a hash, but lets keep it
 280 * simple... */
 281#define MAX_SAME_KEY MAX_MENU_ITEMS
 282struct {
 283        int count;
 284        int ptrs[MAX_MENU_ITEMS];
 285} hotkeys[1<<(sizeof(char)*8)];
 286
 287static void conf(struct menu *menu);
 288static void conf_choice(struct menu *menu);
 289static void conf_string(struct menu *menu);
 290static void conf_load(void);
 291static void conf_save(void);
 292static void show_help(struct menu *menu);
 293static int do_exit(void);
 294static void setup_windows(void);
 295
 296typedef void (*function_key_handler_t)(int *key, struct menu *menu);
 297static void handle_f1(int *key, struct menu *current_item);
 298static void handle_f2(int *key, struct menu *current_item);
 299static void handle_f3(int *key, struct menu *current_item);
 300static void handle_f4(int *key, struct menu *current_item);
 301static void handle_f5(int *key, struct menu *current_item);
 302static void handle_f6(int *key, struct menu *current_item);
 303static void handle_f7(int *key, struct menu *current_item);
 304static void handle_f8(int *key, struct menu *current_item);
 305
 306struct function_keys {
 307        const char *key_str;
 308        const char *func;
 309        function_key key;
 310        function_key_handler_t handler;
 311};
 312
 313static const int function_keys_num = 8;
 314struct function_keys function_keys[] = {
 315        {
 316                .key_str = "F1",
 317                .func = "Help",
 318                .key = F_HELP,
 319                .handler = handle_f1,
 320        },
 321        {
 322                .key_str = "F2",
 323                .func = "Symbol Info",
 324                .key = F_SYMBOL,
 325                .handler = handle_f2,
 326        },
 327        {
 328                .key_str = "F3",
 329                .func = "Instructions",
 330                .key = F_INSTS,
 331                .handler = handle_f3,
 332        },
 333        {
 334                .key_str = "F4",
 335                .func = "Config",
 336                .key = F_CONF,
 337                .handler = handle_f4,
 338        },
 339        {
 340                .key_str = "F5",
 341                .func = "Back",
 342                .key = F_BACK,
 343                .handler = handle_f5,
 344        },
 345        {
 346                .key_str = "F6",
 347                .func = "Save",
 348                .key = F_SAVE,
 349                .handler = handle_f6,
 350        },
 351        {
 352                .key_str = "F7",
 353                .func = "Load",
 354                .key = F_LOAD,
 355                .handler = handle_f7,
 356        },
 357        {
 358                .key_str = "F8",
 359                .func = "Exit",
 360                .key = F_EXIT,
 361                .handler = handle_f8,
 362        },
 363};
 364
 365static void print_function_line(void)
 366{
 367        int i;
 368        int offset = 1;
 369        const int skip = 1;
 370
 371        for (i = 0; i < function_keys_num; i++) {
 372                wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
 373                mvwprintw(main_window, LINES-3, offset,
 374                                "%s",
 375                                function_keys[i].key_str);
 376                wattrset(main_window, attributes[FUNCTION_TEXT]);
 377                offset += strlen(function_keys[i].key_str);
 378                mvwprintw(main_window, LINES-3,
 379                                offset, "%s",
 380                                function_keys[i].func);
 381                offset += strlen(function_keys[i].func) + skip;
 382        }
 383        wattrset(main_window, attributes[NORMAL]);
 384}
 385
 386/* help */
 387static void handle_f1(int *key, struct menu *current_item)
 388{
 389        show_scroll_win(main_window,
 390                        _("README"), _(nconf_readme));
 391        return;
 392}
 393
 394/* symbole help */
 395static void handle_f2(int *key, struct menu *current_item)
 396{
 397        show_help(current_item);
 398        return;
 399}
 400
 401/* instructions */
 402static void handle_f3(int *key, struct menu *current_item)
 403{
 404        show_scroll_win(main_window,
 405                        _("Instructions"),
 406                        _(current_instructions));
 407        return;
 408}
 409
 410/* config */
 411static void handle_f4(int *key, struct menu *current_item)
 412{
 413        int res = btn_dialog(main_window,
 414                        _("Show all symbols?"),
 415                        2,
 416                        "   <Show All>   ",
 417                        "<Don't show all>");
 418        if (res == 0)
 419                show_all_items = 1;
 420        else if (res == 1)
 421                show_all_items = 0;
 422
 423        return;
 424}
 425
 426/* back */
 427static void handle_f5(int *key, struct menu *current_item)
 428{
 429        *key = KEY_LEFT;
 430        return;
 431}
 432
 433/* save */
 434static void handle_f6(int *key, struct menu *current_item)
 435{
 436        conf_save();
 437        return;
 438}
 439
 440/* load */
 441static void handle_f7(int *key, struct menu *current_item)
 442{
 443        conf_load();
 444        return;
 445}
 446
 447/* exit */
 448static void handle_f8(int *key, struct menu *current_item)
 449{
 450        do_exit();
 451        return;
 452}
 453
 454/* return != 0 to indicate the key was handles */
 455static int process_special_keys(int *key, struct menu *menu)
 456{
 457        int i;
 458
 459        if (*key == KEY_RESIZE) {
 460                setup_windows();
 461                return 1;
 462        }
 463
 464        for (i = 0; i < function_keys_num; i++) {
 465                if (*key == KEY_F(function_keys[i].key) ||
 466                    *key == '0' + function_keys[i].key){
 467                        function_keys[i].handler(key, menu);
 468                        return 1;
 469                }
 470        }
 471
 472        return 0;
 473}
 474
 475static void clean_items(void)
 476{
 477        int i;
 478        for (i = 0; curses_menu_items[i]; i++)
 479                free_item(curses_menu_items[i]);
 480        bzero(curses_menu_items, sizeof(curses_menu_items));
 481        bzero(k_menu_items, sizeof(k_menu_items));
 482        bzero(hotkeys, sizeof(hotkeys));
 483        items_num = 0;
 484}
 485
 486/* return the index of the next hot item, or -1 if no such item exists */
 487static int get_next_hot(int c)
 488{
 489        static int hot_index;
 490        static int hot_char;
 491
 492        if (c < 0 || c > 255 || hotkeys[c].count <= 0)
 493                return -1;
 494
 495        if (hot_char == c) {
 496                hot_index = (hot_index+1)%hotkeys[c].count;
 497                return hotkeys[c].ptrs[hot_index];
 498        } else {
 499                hot_char = c;
 500                hot_index = 0;
 501                return hotkeys[c].ptrs[0];
 502        }
 503}
 504
 505/* can the char c be a hot key? no, if c is a common shortcut used elsewhere */
 506static int canbhot(char c)
 507{
 508        c = tolower(c);
 509        return isalnum(c) && c != 'y' && c != 'm' && c != 'h' &&
 510                c != 'n' && c != '?';
 511}
 512
 513/* check if str already contains a hot key. */
 514static int is_hot(int index)
 515{
 516        return k_menu_items[index].is_hot;
 517}
 518
 519/* find the first possible hot key, and mark it.
 520 * index is the index of the item in the menu
 521 * return 0 on success*/
 522static int make_hot(char *dest, int len, const char *org, int index)
 523{
 524        int position = -1;
 525        int i;
 526        int tmp;
 527        int c;
 528        int org_len = strlen(org);
 529
 530        if (org == NULL || is_hot(index))
 531                return 1;
 532
 533        /* make sure not to make hot keys out of markers.
 534         * find where to start looking for a hot key
 535         */
 536        i = 0;
 537        /* skip white space */
 538        while (i < org_len && org[i] == ' ')
 539                i++;
 540        if (i == org_len)
 541                return -1;
 542        /* if encountering '(' or '<' or '[', find the match and look from there
 543         **/
 544        if (org[i] == '[' || org[i] == '<' || org[i] == '(') {
 545                i++;
 546                for (; i < org_len; i++)
 547                        if (org[i] == ']' || org[i] == '>' || org[i] == ')')
 548                                break;
 549        }
 550        if (i == org_len)
 551                return -1;
 552        for (; i < org_len; i++) {
 553                if (canbhot(org[i]) && org[i-1] != '<' && org[i-1] != '(') {
 554                        position = i;
 555                        break;
 556                }
 557        }
 558        if (position == -1)
 559                return 1;
 560
 561        /* ok, char at org[position] should be a hot key to this item */
 562        c = tolower(org[position]);
 563        tmp = hotkeys[c].count;
 564        hotkeys[c].ptrs[tmp] = index;
 565        hotkeys[c].count++;
 566        /*
 567           snprintf(dest, len, "%.*s(%c)%s", position, org, org[position],
 568           &org[position+1]);
 569           */
 570        /* make org[position] uppercase, and all leading letter small case */
 571        strncpy(dest, org, len);
 572        for (i = 0; i < position; i++)
 573                dest[i] = tolower(dest[i]);
 574        dest[position] = toupper(dest[position]);
 575        k_menu_items[index].is_hot = 1;
 576        return 0;
 577}
 578
 579/* Make a new item. Add a hotkey mark in the first possible letter.
 580 * As ncurses does not allow any attributes inside menue item, we mark the
 581 * hot key as the first capitalized letter in the string */
 582static void item_make(struct menu *menu, char tag, const char *fmt, ...)
 583{
 584        va_list ap;
 585        char tmp_str[256];
 586
 587        if (items_num > MAX_MENU_ITEMS-1)
 588                return;
 589
 590        bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
 591        k_menu_items[items_num].tag = tag;
 592        k_menu_items[items_num].usrptr = menu;
 593        if (menu != NULL)
 594                k_menu_items[items_num].is_visible =
 595                        menu_is_visible(menu);
 596        else
 597                k_menu_items[items_num].is_visible = 1;
 598
 599        va_start(ap, fmt);
 600        vsnprintf(tmp_str, sizeof(tmp_str), fmt, ap);
 601        if (!k_menu_items[items_num].is_visible)
 602                memcpy(tmp_str, "XXX", 3);
 603        va_end(ap);
 604        if (make_hot(
 605                k_menu_items[items_num].str,
 606                sizeof(k_menu_items[items_num].str), tmp_str, items_num) != 0)
 607                strncpy(k_menu_items[items_num].str,
 608                        tmp_str,
 609                        sizeof(k_menu_items[items_num].str));
 610
 611        curses_menu_items[items_num] = new_item(
 612                        k_menu_items[items_num].str,
 613                        k_menu_items[items_num].str);
 614        set_item_userptr(curses_menu_items[items_num],
 615                        &k_menu_items[items_num]);
 616        /*
 617        if (!k_menu_items[items_num].is_visible)
 618                item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
 619        */
 620
 621        items_num++;
 622        curses_menu_items[items_num] = NULL;
 623}
 624
 625/* very hackish. adds a string to the last item added */
 626static void item_add_str(const char *fmt, ...)
 627{
 628        va_list ap;
 629        int index = items_num-1;
 630        char new_str[256];
 631        char tmp_str[256];
 632
 633        if (index < 0)
 634                return;
 635
 636        va_start(ap, fmt);
 637        vsnprintf(new_str, sizeof(new_str), fmt, ap);
 638        va_end(ap);
 639        snprintf(tmp_str, sizeof(tmp_str), "%s%s",
 640                        k_menu_items[index].str, new_str);
 641        if (make_hot(k_menu_items[index].str,
 642                        sizeof(k_menu_items[index].str), tmp_str, index) != 0)
 643                strncpy(k_menu_items[index].str,
 644                        tmp_str,
 645                        sizeof(k_menu_items[index].str));
 646
 647        free_item(curses_menu_items[index]);
 648        curses_menu_items[index] = new_item(
 649                        k_menu_items[index].str,
 650                        k_menu_items[index].str);
 651        set_item_userptr(curses_menu_items[index],
 652                        &k_menu_items[index]);
 653}
 654
 655/* get the tag of the currently selected item */
 656static char item_tag(void)
 657{
 658        ITEM *cur;
 659        struct mitem *mcur;
 660
 661        cur = current_item(curses_menu);
 662        if (cur == NULL)
 663                return 0;
 664        mcur = (struct mitem *) item_userptr(cur);
 665        return mcur->tag;
 666}
 667
 668static int curses_item_index(void)
 669{
 670        return  item_index(current_item(curses_menu));
 671}
 672
 673static void *item_data(void)
 674{
 675        ITEM *cur;
 676        struct mitem *mcur;
 677
 678        cur = current_item(curses_menu);
 679        if (!cur)
 680                return NULL;
 681        mcur = (struct mitem *) item_userptr(cur);
 682        return mcur->usrptr;
 683
 684}
 685
 686static int item_is_tag(char tag)
 687{
 688        return item_tag() == tag;
 689}
 690
 691static char filename[PATH_MAX+1];
 692static char menu_backtitle[PATH_MAX+128];
 693static const char *set_config_filename(const char *config_filename)
 694{
 695        int size;
 696        struct symbol *sym;
 697
 698        sym = sym_lookup("KERNELVERSION", 0);
 699        sym_calc_value(sym);
 700        size = snprintf(menu_backtitle, sizeof(menu_backtitle),
 701                        _("%s - Linux Kernel v%s Configuration"),
 702                        config_filename, sym_get_string_value(sym));
 703        if (size >= sizeof(menu_backtitle))
 704                menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
 705
 706        size = snprintf(filename, sizeof(filename), "%s", config_filename);
 707        if (size >= sizeof(filename))
 708                filename[sizeof(filename)-1] = '\0';
 709        return menu_backtitle;
 710}
 711
 712/* command = 0 is supress, 1 is restore */
 713static void supress_stdout(int command)
 714{
 715        static FILE *org_stdout;
 716        static FILE *org_stderr;
 717
 718        if (command == 0) {
 719                org_stdout = stdout;
 720                org_stderr = stderr;
 721                stdout = fopen("/dev/null", "a");
 722                stderr = fopen("/dev/null", "a");
 723        } else {
 724                fclose(stdout);
 725                fclose(stderr);
 726                stdout = org_stdout;
 727                stderr = org_stderr;
 728        }
 729}
 730
 731/* return = 0 means we are successful.
 732 * -1 means go on doing what you were doing
 733 */
 734static int do_exit(void)
 735{
 736        int res;
 737        if (!conf_get_changed()) {
 738                global_exit = 1;
 739                return 0;
 740        }
 741        res = btn_dialog(main_window,
 742                        _("Do you wish to save your "
 743                                "new kernel configuration?\n"
 744                                "<ESC> to cancel and resume nconfig."),
 745                        2,
 746                        "   <save>   ",
 747                        "<don't save>");
 748        if (res == KEY_EXIT) {
 749                global_exit = 0;
 750                return -1;
 751        }
 752
 753        /* if we got here, the user really wants to exit */
 754        switch (res) {
 755        case 0:
 756                supress_stdout(0);
 757                res = conf_write(filename);
 758                supress_stdout(1);
 759                if (res)
 760                        btn_dialog(
 761                                main_window,
 762                                _("Error during writing of the kernel "
 763                                  "configuration.\n"
 764                                  "Your kernel configuration "
 765                                  "changes were NOT saved."),
 766                                  1,
 767                                  "<OK>");
 768                else {
 769                        char buf[1024];
 770                        snprintf(buf, 1024,
 771                                _("Configuration written to %s\n"
 772                                  "End of Linux kernel configuration.\n"
 773                                  "Execute 'make' to build the kernel or try"
 774                                  " 'make help'."), filename);
 775                        btn_dialog(
 776                                main_window,
 777                                buf,
 778                                1,
 779                                "<OK>");
 780                }
 781                break;
 782        default:
 783                btn_dialog(
 784                        main_window,
 785                        _("Your kernel configuration changes were NOT saved."),
 786                        1,
 787                        "<OK>");
 788                break;
 789        }
 790        global_exit = 1;
 791        return 0;
 792}
 793
 794
 795static void search_conf(void)
 796{
 797        struct symbol **sym_arr;
 798        struct gstr res;
 799        char dialog_input_result[100];
 800        char *dialog_input;
 801        int dres;
 802again:
 803        dres = dialog_inputbox(main_window,
 804                        _("Search Configuration Parameter"),
 805                        _("Enter CONFIG_ (sub)string to search for "
 806                                "(with or without \"CONFIG\")"),
 807                        "", dialog_input_result, 99);
 808        switch (dres) {
 809        case 0:
 810                break;
 811        case 1:
 812                show_scroll_win(main_window,
 813                                _("Search Configuration"), search_help);
 814                goto again;
 815        default:
 816                return;
 817        }
 818
 819        /* strip CONFIG_ if necessary */
 820        dialog_input = dialog_input_result;
 821        if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
 822                dialog_input += 7;
 823
 824        sym_arr = sym_re_search(dialog_input);
 825        res = get_relations_str(sym_arr);
 826        free(sym_arr);
 827        show_scroll_win(main_window,
 828                        _("Search Results"), str_get(&res));
 829        str_free(&res);
 830}
 831
 832
 833static void build_conf(struct menu *menu)
 834{
 835        struct symbol *sym;
 836        struct property *prop;
 837        struct menu *child;
 838        int type, tmp, doint = 2;
 839        tristate val;
 840        char ch;
 841
 842        if (!menu || (!show_all_items && !menu_is_visible(menu)))
 843                return;
 844
 845        sym = menu->sym;
 846        prop = menu->prompt;
 847        if (!sym) {
 848                if (prop && menu != current_menu) {
 849                        const char *prompt = menu_get_prompt(menu);
 850                        enum prop_type ptype;
 851                        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 852                        switch (ptype) {
 853                        case P_MENU:
 854                                child_count++;
 855                                prompt = _(prompt);
 856                                if (single_menu_mode) {
 857                                        item_make(menu, 'm',
 858                                                "%s%*c%s",
 859                                                menu->data ? "-->" : "++>",
 860                                                indent + 1, ' ', prompt);
 861                                } else
 862                                        item_make(menu, 'm',
 863                                                "   %*c%s  --->",
 864                                                indent + 1,
 865                                                ' ', prompt);
 866
 867                                if (single_menu_mode && menu->data)
 868                                        goto conf_childs;
 869                                return;
 870                        case P_COMMENT:
 871                                if (prompt) {
 872                                        child_count++;
 873                                        item_make(menu, ':',
 874                                                "   %*c*** %s ***",
 875                                                indent + 1, ' ',
 876                                                _(prompt));
 877                                }
 878                                break;
 879                        default:
 880                                if (prompt) {
 881                                        child_count++;
 882                                        item_make(menu, ':', "---%*c%s",
 883                                                indent + 1, ' ',
 884                                                _(prompt));
 885                                }
 886                        }
 887                } else
 888                        doint = 0;
 889                goto conf_childs;
 890        }
 891
 892        type = sym_get_type(sym);
 893        if (sym_is_choice(sym)) {
 894                struct symbol *def_sym = sym_get_choice_value(sym);
 895                struct menu *def_menu = NULL;
 896
 897                child_count++;
 898                for (child = menu->list; child; child = child->next) {
 899                        if (menu_is_visible(child) && child->sym == def_sym)
 900                                def_menu = child;
 901                }
 902
 903                val = sym_get_tristate_value(sym);
 904                if (sym_is_changable(sym)) {
 905                        switch (type) {
 906                        case S_BOOLEAN:
 907                                item_make(menu, 't', "[%c]",
 908                                                val == no ? ' ' : '*');
 909                                break;
 910                        case S_TRISTATE:
 911                                switch (val) {
 912                                case yes:
 913                                        ch = '*';
 914                                        break;
 915                                case mod:
 916                                        ch = 'M';
 917                                        break;
 918                                default:
 919                                        ch = ' ';
 920                                        break;
 921                                }
 922                                item_make(menu, 't', "<%c>", ch);
 923                                break;
 924                        }
 925                } else {
 926                        item_make(menu, def_menu ? 't' : ':', "   ");
 927                }
 928
 929                item_add_str("%*c%s", indent + 1,
 930                                ' ', _(menu_get_prompt(menu)));
 931                if (val == yes) {
 932                        if (def_menu) {
 933                                item_add_str(" (%s)",
 934                                        _(menu_get_prompt(def_menu)));
 935                                item_add_str("  --->");
 936                                if (def_menu->list) {
 937                                        indent += 2;
 938                                        build_conf(def_menu);
 939                                        indent -= 2;
 940                                }
 941                        }
 942                        return;
 943                }
 944        } else {
 945                if (menu == current_menu) {
 946                        item_make(menu, ':',
 947                                "---%*c%s", indent + 1,
 948                                ' ', _(menu_get_prompt(menu)));
 949                        goto conf_childs;
 950                }
 951                child_count++;
 952                val = sym_get_tristate_value(sym);
 953                if (sym_is_choice_value(sym) && val == yes) {
 954                        item_make(menu, ':', "   ");
 955                } else {
 956                        switch (type) {
 957                        case S_BOOLEAN:
 958                                if (sym_is_changable(sym))
 959                                        item_make(menu, 't', "[%c]",
 960                                                val == no ? ' ' : '*');
 961                                else
 962                                        item_make(menu, 't', "-%c-",
 963                                                val == no ? ' ' : '*');
 964                                break;
 965                        case S_TRISTATE:
 966                                switch (val) {
 967                                case yes:
 968                                        ch = '*';
 969                                        break;
 970                                case mod:
 971                                        ch = 'M';
 972                                        break;
 973                                default:
 974                                        ch = ' ';
 975                                        break;
 976                                }
 977                                if (sym_is_changable(sym)) {
 978                                        if (sym->rev_dep.tri == mod)
 979                                                item_make(menu,
 980                                                        't', "{%c}", ch);
 981                                        else
 982                                                item_make(menu,
 983                                                        't', "<%c>", ch);
 984                                } else
 985                                        item_make(menu, 't', "-%c-", ch);
 986                                break;
 987                        default:
 988                                tmp = 2 + strlen(sym_get_string_value(sym));
 989                                item_make(menu, 's', "    (%s)",
 990                                                sym_get_string_value(sym));
 991                                tmp = indent - tmp + 4;
 992                                if (tmp < 0)
 993                                        tmp = 0;
 994                                item_add_str("%*c%s%s", tmp, ' ',
 995                                                _(menu_get_prompt(menu)),
 996                                                (sym_has_value(sym) ||
 997                                                 !sym_is_changable(sym)) ? "" :
 998                                                _(" (NEW)"));
 999                                goto conf_childs;
1000                        }
1001                }
1002                item_add_str("%*c%s%s", indent + 1, ' ',
1003                                _(menu_get_prompt(menu)),
1004                                (sym_has_value(sym) || !sym_is_changable(sym)) ?
1005                                "" : _(" (NEW)"));
1006                if (menu->prompt && menu->prompt->type == P_MENU) {
1007                        item_add_str("  --->");
1008                        return;
1009                }
1010        }
1011
1012conf_childs:
1013        indent += doint;
1014        for (child = menu->list; child; child = child->next)
1015                build_conf(child);
1016        indent -= doint;
1017}
1018
1019static void reset_menu(void)
1020{
1021        unpost_menu(curses_menu);
1022        clean_items();
1023}
1024
1025/* adjust the menu to show this item.
1026 * prefer not to scroll the menu if possible*/
1027static void center_item(int selected_index, int *last_top_row)
1028{
1029        int toprow;
1030        int maxy, maxx;
1031
1032        scale_menu(curses_menu, &maxy, &maxx);
1033        set_top_row(curses_menu, *last_top_row);
1034        toprow = top_row(curses_menu);
1035        if (selected_index >= toprow && selected_index < toprow+maxy) {
1036                /* we can only move the selected item. no need to scroll */
1037                set_current_item(curses_menu,
1038                                curses_menu_items[selected_index]);
1039        } else {
1040                toprow = max(selected_index-maxy/2, 0);
1041                if (toprow >= item_count(curses_menu)-maxy)
1042                        toprow = item_count(curses_menu)-mwin_max_lines;
1043                set_top_row(curses_menu, toprow);
1044                set_current_item(curses_menu,
1045                                curses_menu_items[selected_index]);
1046        }
1047        *last_top_row = toprow;
1048        post_menu(curses_menu);
1049        refresh_all_windows(main_window);
1050}
1051
1052/* this function assumes reset_menu has been called before */
1053static void show_menu(const char *prompt, const char *instructions,
1054                int selected_index, int *last_top_row)
1055{
1056        int maxx, maxy;
1057        WINDOW *menu_window;
1058
1059        current_instructions = instructions;
1060
1061        clear();
1062        wattrset(main_window, attributes[NORMAL]);
1063        print_in_middle(stdscr, 1, 0, COLS,
1064                        menu_backtitle,
1065                        attributes[MAIN_HEADING]);
1066
1067        wattrset(main_window, attributes[MAIN_MENU_BOX]);
1068        box(main_window, 0, 0);
1069        wattrset(main_window, attributes[MAIN_MENU_HEADING]);
1070        mvwprintw(main_window, 0, 3, " %s ", prompt);
1071        wattrset(main_window, attributes[NORMAL]);
1072
1073        set_menu_items(curses_menu, curses_menu_items);
1074
1075        /* position the menu at the middle of the screen */
1076        scale_menu(curses_menu, &maxy, &maxx);
1077        maxx = min(maxx, mwin_max_cols-2);
1078        maxy = mwin_max_lines-2;
1079        menu_window = derwin(main_window,
1080                        maxy,
1081                        maxx,
1082                        2,
1083                        (mwin_max_cols-maxx)/2);
1084        keypad(menu_window, TRUE);
1085        set_menu_win(curses_menu, menu_window);
1086        set_menu_sub(curses_menu, menu_window);
1087
1088        /* must reassert this after changing items, otherwise returns to a
1089         * default of 16
1090         */
1091        set_menu_format(curses_menu, maxy, 1);
1092        center_item(selected_index, last_top_row);
1093        set_menu_format(curses_menu, maxy, 1);
1094
1095        print_function_line();
1096
1097        /* Post the menu */
1098        post_menu(curses_menu);
1099        refresh_all_windows(main_window);
1100}
1101
1102
1103static void conf(struct menu *menu)
1104{
1105        char pattern[256];
1106        struct menu *submenu = 0;
1107        const char *prompt = menu_get_prompt(menu);
1108        struct symbol *sym;
1109        struct menu *active_menu = NULL;
1110        int res;
1111        int current_index = 0;
1112        int last_top_row = 0;
1113
1114        bzero(pattern, sizeof(pattern));
1115
1116        while (!global_exit) {
1117                reset_menu();
1118                current_menu = menu;
1119                build_conf(menu);
1120                if (!child_count)
1121                        break;
1122
1123                show_menu(prompt ? _(prompt) : _("Main Menu"),
1124                                _(menu_instructions),
1125                                current_index, &last_top_row);
1126                keypad((menu_win(curses_menu)), TRUE);
1127                while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
1128                        if (process_special_keys(&res,
1129                                                (struct menu *) item_data()))
1130                                break;
1131                        switch (res) {
1132                        case KEY_DOWN:
1133                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1134                                break;
1135                        case KEY_UP:
1136                                menu_driver(curses_menu, REQ_UP_ITEM);
1137                                break;
1138                        case KEY_NPAGE:
1139                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1140                                break;
1141                        case KEY_PPAGE:
1142                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1143                                break;
1144                        case KEY_HOME:
1145                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1146                                break;
1147                        case KEY_END:
1148                                menu_driver(curses_menu, REQ_LAST_ITEM);
1149                                break;
1150                        case 'h':
1151                        case '?':
1152                                show_help((struct menu *) item_data());
1153                                break;
1154                        }
1155                        if (res == 10 || res == 27 ||
1156                                res == 32 || res == 'n' || res == 'y' ||
1157                                res == KEY_LEFT || res == KEY_RIGHT ||
1158                                res == 'm' || res == '/')
1159                                break;
1160                        else if (canbhot(res)) {
1161                                /* check for hot keys: */
1162                                int tmp = get_next_hot(res);
1163                                if (tmp != -1)
1164                                        center_item(tmp, &last_top_row);
1165                        }
1166                        refresh_all_windows(main_window);
1167                }
1168
1169                refresh_all_windows(main_window);
1170                /* if ESC  or left*/
1171                if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1172                        break;
1173
1174                /* remember location in the menu */
1175                last_top_row = top_row(curses_menu);
1176                current_index = curses_item_index();
1177
1178                if (!item_tag())
1179                        continue;
1180
1181                submenu = (struct menu *) item_data();
1182                active_menu = (struct menu *)item_data();
1183                if (!submenu || !menu_is_visible(submenu))
1184                        continue;
1185                if (submenu)
1186                        sym = submenu->sym;
1187                else
1188                        sym = NULL;
1189
1190                switch (res) {
1191                case ' ':
1192                        if (item_is_tag('t'))
1193                                sym_toggle_tristate_value(sym);
1194                        else if (item_is_tag('m'))
1195                                conf(submenu);
1196                        break;
1197                case KEY_RIGHT:
1198                case 10: /* ENTER WAS PRESSED */
1199                        switch (item_tag()) {
1200                        case 'm':
1201                                if (single_menu_mode)
1202                                        submenu->data =
1203                                                (void *) (long) !submenu->data;
1204                                else
1205                                        conf(submenu);
1206                                break;
1207                        case 't':
1208                                if (sym_is_choice(sym) &&
1209                                    sym_get_tristate_value(sym) == yes)
1210                                        conf_choice(submenu);
1211                                else if (submenu->prompt &&
1212                                         submenu->prompt->type == P_MENU)
1213                                        conf(submenu);
1214                                else if (res == 10)
1215                                        sym_toggle_tristate_value(sym);
1216                                break;
1217                        case 's':
1218                                conf_string(submenu);
1219                                break;
1220                        }
1221                        break;
1222                case 'y':
1223                        if (item_is_tag('t')) {
1224                                if (sym_set_tristate_value(sym, yes))
1225                                        break;
1226                                if (sym_set_tristate_value(sym, mod))
1227                                        btn_dialog(main_window, setmod_text, 0);
1228                        }
1229                        break;
1230                case 'n':
1231                        if (item_is_tag('t'))
1232                                sym_set_tristate_value(sym, no);
1233                        break;
1234                case 'm':
1235                        if (item_is_tag('t'))
1236                                sym_set_tristate_value(sym, mod);
1237                        break;
1238                case '/':
1239                        search_conf();
1240                        break;
1241                }
1242        }
1243}
1244
1245static void show_help(struct menu *menu)
1246{
1247        struct gstr help = str_new();
1248
1249        if (menu && menu->sym && menu_has_help(menu)) {
1250                if (menu->sym->name) {
1251                        str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name);
1252                        str_append(&help, _(menu_get_help(menu)));
1253                        str_append(&help, "\n");
1254                        get_symbol_str(&help, menu->sym);
1255                }
1256        } else {
1257                str_append(&help, nohelp_text);
1258        }
1259        show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1260        str_free(&help);
1261}
1262
1263static void conf_choice(struct menu *menu)
1264{
1265        const char *prompt = _(menu_get_prompt(menu));
1266        struct menu *child = 0;
1267        struct symbol *active;
1268        int selected_index = 0;
1269        int last_top_row = 0;
1270        int res, i = 0;
1271
1272        active = sym_get_choice_value(menu->sym);
1273        /* this is mostly duplicated from the conf() function. */
1274        while (!global_exit) {
1275                reset_menu();
1276
1277                for (i = 0, child = menu->list; child; child = child->next) {
1278                        if (!show_all_items && !menu_is_visible(child))
1279                                continue;
1280
1281                        if (child->sym == sym_get_choice_value(menu->sym))
1282                                item_make(child, ':', "<X> %s",
1283                                                _(menu_get_prompt(child)));
1284                        else
1285                                item_make(child, ':', "    %s",
1286                                                _(menu_get_prompt(child)));
1287                        if (child->sym == active){
1288                                last_top_row = top_row(curses_menu);
1289                                selected_index = i;
1290                        }
1291                        i++;
1292                }
1293                show_menu(prompt ? _(prompt) : _("Choice Menu"),
1294                                _(radiolist_instructions),
1295                                selected_index,
1296                                &last_top_row);
1297                while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
1298                        if (process_special_keys(
1299                                                &res,
1300                                                (struct menu *) item_data()))
1301                                break;
1302                        switch (res) {
1303                        case KEY_DOWN:
1304                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1305                                break;
1306                        case KEY_UP:
1307                                menu_driver(curses_menu, REQ_UP_ITEM);
1308                                break;
1309                        case KEY_NPAGE:
1310                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1311                                break;
1312                        case KEY_PPAGE:
1313                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1314                                break;
1315                        case KEY_HOME:
1316                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1317                                break;
1318                        case KEY_END:
1319                                menu_driver(curses_menu, REQ_LAST_ITEM);
1320                                break;
1321                        case 'h':
1322                        case '?':
1323                                show_help((struct menu *) item_data());
1324                                break;
1325                        }
1326                        if (res == 10 || res == 27 || res == ' ' ||
1327                                res == KEY_LEFT)
1328                                break;
1329                        else if (canbhot(res)) {
1330                                /* check for hot keys: */
1331                                int tmp = get_next_hot(res);
1332                                if (tmp != -1)
1333                                        center_item(tmp, &last_top_row);
1334                        }
1335                        refresh_all_windows(main_window);
1336                }
1337                /* if ESC or left */
1338                if (res == 27 || res == KEY_LEFT)
1339                        break;
1340
1341                child = item_data();
1342                if (!child || !menu_is_visible(child))
1343                        continue;
1344                switch (res) {
1345                case ' ':
1346                case  10:
1347                case KEY_RIGHT:
1348                        sym_set_tristate_value(child->sym, yes);
1349                        return;
1350                case 'h':
1351                case '?':
1352                        show_help(child);
1353                        active = child->sym;
1354                        break;
1355                case KEY_EXIT:
1356                        return;
1357                }
1358        }
1359}
1360
1361static void conf_string(struct menu *menu)
1362{
1363        const char *prompt = menu_get_prompt(menu);
1364        char dialog_input_result[256];
1365
1366        while (1) {
1367                int res;
1368                const char *heading;
1369
1370                switch (sym_get_type(menu->sym)) {
1371                case S_INT:
1372                        heading = _(inputbox_instructions_int);
1373                        break;
1374                case S_HEX:
1375                        heading = _(inputbox_instructions_hex);
1376                        break;
1377                case S_STRING:
1378                        heading = _(inputbox_instructions_string);
1379                        break;
1380                default:
1381                        heading = _("Internal nconf error!");
1382                }
1383                res = dialog_inputbox(main_window,
1384                                prompt ? _(prompt) : _("Main Menu"),
1385                                heading,
1386                                sym_get_string_value(menu->sym),
1387                                dialog_input_result,
1388                                sizeof(dialog_input_result));
1389                switch (res) {
1390                case 0:
1391                        if (sym_set_string_value(menu->sym,
1392                                                dialog_input_result))
1393                                return;
1394                        btn_dialog(main_window,
1395                                _("You have made an invalid entry."), 0);
1396                        break;
1397                case 1:
1398                        show_help(menu);
1399                        break;
1400                case KEY_EXIT:
1401                        return;
1402                }
1403        }
1404}
1405
1406static void conf_load(void)
1407{
1408        char dialog_input_result[256];
1409        while (1) {
1410                int res;
1411                res = dialog_inputbox(main_window,
1412                                NULL, load_config_text,
1413                                filename,
1414                                dialog_input_result,
1415                                sizeof(dialog_input_result));
1416                switch (res) {
1417                case 0:
1418                        if (!dialog_input_result[0])
1419                                return;
1420                        if (!conf_read(dialog_input_result)) {
1421                                set_config_filename(dialog_input_result);
1422                                sym_set_change_count(1);
1423                                return;
1424                        }
1425                        btn_dialog(main_window, _("File does not exist!"), 0);
1426                        break;
1427                case 1:
1428                        show_scroll_win(main_window,
1429                                        _("Load Alternate Configuration"),
1430                                        load_config_help);
1431                        break;
1432                case KEY_EXIT:
1433                        return;
1434                }
1435        }
1436}
1437
1438static void conf_save(void)
1439{
1440        char dialog_input_result[256];
1441        while (1) {
1442                int res;
1443                res = dialog_inputbox(main_window,
1444                                NULL, save_config_text,
1445                                filename,
1446                                dialog_input_result,
1447                                sizeof(dialog_input_result));
1448                switch (res) {
1449                case 0:
1450                        if (!dialog_input_result[0])
1451                                return;
1452                        supress_stdout(0);
1453                        res = conf_write(dialog_input_result);
1454                        supress_stdout(1);
1455                        if (!res) {
1456                                char buf[1024];
1457                                sprintf(buf, "%s %s",
1458                                        _("configuration file saved to: "),
1459                                        dialog_input_result);
1460                                btn_dialog(main_window,
1461                                           buf, 1, "<OK>");
1462                                set_config_filename(dialog_input_result);
1463                                return;
1464                        }
1465                        btn_dialog(main_window, _("Can't create file! "
1466                                "Probably a nonexistent directory."),
1467                                1, "<OK>");
1468                        break;
1469                case 1:
1470                        show_scroll_win(main_window,
1471                                _("Save Alternate Configuration"),
1472                                save_config_help);
1473                        break;
1474                case KEY_EXIT:
1475                        return;
1476                }
1477        }
1478}
1479
1480void setup_windows(void)
1481{
1482        if (main_window != NULL)
1483                delwin(main_window);
1484
1485        /* set up the menu and menu window */
1486        main_window = newwin(LINES-2, COLS-2, 2, 1);
1487        keypad(main_window, TRUE);
1488        mwin_max_lines = LINES-6;
1489        mwin_max_cols = COLS-6;
1490
1491        /* panels order is from bottom to top */
1492        new_panel(main_window);
1493}
1494
1495int main(int ac, char **av)
1496{
1497        char *mode;
1498
1499        setlocale(LC_ALL, "");
1500        bindtextdomain(PACKAGE, LOCALEDIR);
1501        textdomain(PACKAGE);
1502
1503        conf_parse(av[1]);
1504        conf_read(NULL);
1505
1506        mode = getenv("NCONFIG_MODE");
1507        if (mode) {
1508                if (!strcasecmp(mode, "single_menu"))
1509                        single_menu_mode = 1;
1510        }
1511
1512        /* Initialize curses */
1513        initscr();
1514        /* set color theme */
1515        set_colors();
1516
1517        cbreak();
1518        noecho();
1519        keypad(stdscr, TRUE);
1520        curs_set(0);
1521
1522        if (COLS < 75 || LINES < 20) {
1523                endwin();
1524                printf("Your terminal should have at "
1525                        "least 20 lines and 75 columns\n");
1526                return 1;
1527        }
1528
1529        notimeout(stdscr, FALSE);
1530        ESCDELAY = 1;
1531
1532        /* set btns menu */
1533        curses_menu = new_menu(curses_menu_items);
1534        menu_opts_off(curses_menu, O_SHOWDESC);
1535        menu_opts_off(curses_menu, O_SHOWMATCH);
1536        menu_opts_on(curses_menu, O_ONEVALUE);
1537        menu_opts_on(curses_menu, O_NONCYCLIC);
1538        set_menu_mark(curses_menu, " ");
1539        set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1540        set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1541        set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1542
1543        set_config_filename(conf_get_configname());
1544        setup_windows();
1545
1546        /* check for KEY_FUNC(1) */
1547        if (has_key(KEY_F(1)) == FALSE) {
1548                show_scroll_win(main_window,
1549                                _("Instructions"),
1550                                _(menu_no_f_instructions));
1551        }
1552
1553
1554
1555        /* do the work */
1556        while (!global_exit) {
1557                conf(&rootmenu);
1558                if (!global_exit && do_exit() == 0)
1559                        break;
1560        }
1561        /* ok, we are done */
1562        unpost_menu(curses_menu);
1563        free_menu(curses_menu);
1564        delwin(main_window);
1565        clear();
1566        refresh();
1567        endwin();
1568        return 0;
1569}
1570
1571