Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
0004  *
0005  * Derived from menuconfig.
0006  */
0007 #ifndef _GNU_SOURCE
0008 #define _GNU_SOURCE
0009 #endif
0010 #include <string.h>
0011 #include <strings.h>
0012 #include <stdlib.h>
0013 
0014 #include "lkc.h"
0015 #include "nconf.h"
0016 #include <ctype.h>
0017 
0018 static const char nconf_global_help[] =
0019 "Help windows\n"
0020 "------------\n"
0021 "o  Global help:  Unless in a data entry window, pressing <F1> will give \n"
0022 "   you the global help window, which you are just reading.\n"
0023 "\n"
0024 "o  A short version of the global help is available by pressing <F3>.\n"
0025 "\n"
0026 "o  Local help:  To get help related to the current menu entry, use any\n"
0027 "   of <?> <h>, or if in a data entry window then press <F1>.\n"
0028 "\n"
0029 "\n"
0030 "Menu entries\n"
0031 "------------\n"
0032 "This interface lets you select features and parameters for the kernel\n"
0033 "build.  Kernel features can either be built-in, modularized, or removed.\n"
0034 "Parameters must be entered as text or decimal or hexadecimal numbers.\n"
0035 "\n"
0036 "Menu entries beginning with following braces represent features that\n"
0037 "  [ ]  can be built in or removed\n"
0038 "  < >  can be built in, modularized or removed\n"
0039 "  { }  can be built in or modularized, are selected by another feature\n"
0040 "  - -  are selected by another feature\n"
0041 "  XXX  cannot be selected.  Symbol Info <F2> tells you why.\n"
0042 "*, M or whitespace inside braces means to build in, build as a module\n"
0043 "or to exclude the feature respectively.\n"
0044 "\n"
0045 "To change any of these features, highlight it with the movement keys\n"
0046 "listed below and press <y> to build it in, <m> to make it a module or\n"
0047 "<n> to remove it.  You may press the <Space> key to cycle through the\n"
0048 "available options.\n"
0049 "\n"
0050 "A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
0051 "empty submenu.\n"
0052 "\n"
0053 "Menu navigation keys\n"
0054 "----------------------------------------------------------------------\n"
0055 "Linewise up                 <Up>    <k>\n"
0056 "Linewise down               <Down>  <j>\n"
0057 "Pagewise up                 <Page Up>\n"
0058 "Pagewise down               <Page Down>\n"
0059 "First entry                 <Home>\n"
0060 "Last entry                  <End>\n"
0061 "Enter a submenu             <Right>  <Enter>\n"
0062 "Go back to parent menu      <Left>   <Esc>  <F5>\n"
0063 "Close a help window         <Enter>  <Esc>  <F5>\n"
0064 "Close entry window, apply   <Enter>\n"
0065 "Close entry window, forget  <Esc>  <F5>\n"
0066 "Start incremental, case-insensitive search for STRING in menu entries,\n"
0067 "    no regex support, STRING is displayed in upper left corner\n"
0068 "                            </>STRING\n"
0069 "    Remove last character   <Backspace>\n"
0070 "    Jump to next hit        <Down>\n"
0071 "    Jump to previous hit    <Up>\n"
0072 "Exit menu search mode       </>  <Esc>\n"
0073 "Search for configuration variables with or without leading CONFIG_\n"
0074 "                            <F8>RegExpr<Enter>\n"
0075 "Verbose search help         <F8><F1>\n"
0076 "----------------------------------------------------------------------\n"
0077 "\n"
0078 "Unless in a data entry window, key <1> may be used instead of <F1>,\n"
0079 "<2> instead of <F2>, etc.\n"
0080 "\n"
0081 "\n"
0082 "Radiolist (Choice list)\n"
0083 "-----------------------\n"
0084 "Use the movement keys listed above to select the option you wish to set\n"
0085 "and press <Space>.\n"
0086 "\n"
0087 "\n"
0088 "Data entry\n"
0089 "----------\n"
0090 "Enter the requested information and press <Enter>.  Hexadecimal values\n"
0091 "may be entered without the \"0x\" prefix.\n"
0092 "\n"
0093 "\n"
0094 "Text Box (Help Window)\n"
0095 "----------------------\n"
0096 "Use movement keys as listed in table above.\n"
0097 "\n"
0098 "Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
0099 "\n"
0100 "\n"
0101 "Alternate configuration files\n"
0102 "-----------------------------\n"
0103 "nconfig supports switching between different configurations.\n"
0104 "Press <F6> to save your current configuration.  Press <F7> and enter\n"
0105 "a file name to load a previously saved configuration.\n"
0106 "\n"
0107 "\n"
0108 "Terminal configuration\n"
0109 "----------------------\n"
0110 "If you use nconfig in a xterm window, make sure your TERM environment\n"
0111 "variable specifies a terminal configuration which supports at least\n"
0112 "16 colors.  Otherwise nconfig will look rather bad.\n"
0113 "\n"
0114 "If the \"stty size\" command reports the current terminalsize correctly,\n"
0115 "nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n"
0116 "and display longer menus properly.\n"
0117 "\n"
0118 "\n"
0119 "Single menu mode\n"
0120 "----------------\n"
0121 "If you prefer to have all of the menu entries listed in a single menu,\n"
0122 "rather than the default multimenu hierarchy, run nconfig with\n"
0123 "NCONFIG_MODE environment variable set to single_menu.  Example:\n"
0124 "\n"
0125 "make NCONFIG_MODE=single_menu nconfig\n"
0126 "\n"
0127 "<Enter> will then unfold the appropriate category, or fold it if it\n"
0128 "is already unfolded.  Folded menu entries will be designated by a\n"
0129 "leading \"++>\" and unfolded entries by a leading \"-->\".\n"
0130 "\n"
0131 "Note that this mode can eventually be a little more CPU expensive than\n"
0132 "the default mode, especially with a larger number of unfolded submenus.\n"
0133 "\n",
0134 menu_no_f_instructions[] =
0135 "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
0136 "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
0137 "\n"
0138 "Use the following keys to navigate the menus:\n"
0139 "Move up or down with <Up> and <Down>.\n"
0140 "Enter a submenu with <Enter> or <Right>.\n"
0141 "Exit a submenu to its parent menu with <Esc> or <Left>.\n"
0142 "Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
0143 "Pressing <Space> cycles through the available options.\n"
0144 "To search for menu entries press </>.\n"
0145 "<Esc> always leaves the current window.\n"
0146 "\n"
0147 "You do not have function keys support.\n"
0148 "Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
0149 "For verbose global help use key <1>.\n"
0150 "For help related to the current menu entry press <?> or <h>.\n",
0151 menu_instructions[] =
0152 "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
0153 "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
0154 "\n"
0155 "Use the following keys to navigate the menus:\n"
0156 "Move up or down with <Up> or <Down>.\n"
0157 "Enter a submenu with <Enter> or <Right>.\n"
0158 "Exit a submenu to its parent menu with <Esc> or <Left>.\n"
0159 "Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
0160 "Pressing <Space> cycles through the available options.\n"
0161 "To search for menu entries press </>.\n"
0162 "<Esc> always leaves the current window.\n"
0163 "\n"
0164 "Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
0165 "For verbose global help press <F1>.\n"
0166 "For help related to the current menu entry press <?> or <h>.\n",
0167 radiolist_instructions[] =
0168 "Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
0169 "with <Space>.\n"
0170 "For help related to the current entry press <?> or <h>.\n"
0171 "For global help press <F1>.\n",
0172 inputbox_instructions_int[] =
0173 "Please enter a decimal value.\n"
0174 "Fractions will not be accepted.\n"
0175 "Press <Enter> to apply, <Esc> to cancel.",
0176 inputbox_instructions_hex[] =
0177 "Please enter a hexadecimal value.\n"
0178 "Press <Enter> to apply, <Esc> to cancel.",
0179 inputbox_instructions_string[] =
0180 "Please enter a string value.\n"
0181 "Press <Enter> to apply, <Esc> to cancel.",
0182 setmod_text[] =
0183 "This feature depends on another feature which has been configured as a\n"
0184 "module.  As a result, the current feature will be built as a module too.",
0185 load_config_text[] =
0186 "Enter the name of the configuration file you wish to load.\n"
0187 "Accept the name shown to restore the configuration you last\n"
0188 "retrieved.  Leave empty to abort.",
0189 load_config_help[] =
0190 "For various reasons, one may wish to keep several different\n"
0191 "configurations available on a single machine.\n"
0192 "\n"
0193 "If you have saved a previous configuration in a file other than the\n"
0194 "default one, entering its name here will allow you to load and modify\n"
0195 "that configuration.\n"
0196 "\n"
0197 "Leave empty to abort.\n",
0198 save_config_text[] =
0199 "Enter a filename to which this configuration should be saved\n"
0200 "as an alternate.  Leave empty to abort.",
0201 save_config_help[] =
0202 "For various reasons, one may wish to keep several different\n"
0203 "configurations available on a single machine.\n"
0204 "\n"
0205 "Entering a file name here will allow you to later retrieve, modify\n"
0206 "and use the current configuration as an alternate to whatever\n"
0207 "configuration options you have selected at that time.\n"
0208 "\n"
0209 "Leave empty to abort.\n",
0210 search_help[] =
0211 "Search for symbols (configuration variable names CONFIG_*) and display\n"
0212 "their relations.  Regular expressions are supported.\n"
0213 "Example:  Search for \"^FOO\".\n"
0214 "Result:\n"
0215 "-----------------------------------------------------------------\n"
0216 "Symbol: FOO [ = m]\n"
0217 "Prompt: Foo bus is used to drive the bar HW\n"
0218 "Defined at drivers/pci/Kconfig:47\n"
0219 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
0220 "Location:\n"
0221 "  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
0222 "    -> PCI support (PCI [ = y])\n"
0223 "      -> PCI access mode (<choice> [ = y])\n"
0224 "Selects: LIBCRC32\n"
0225 "Selected by: BAR\n"
0226 "-----------------------------------------------------------------\n"
0227 "o  The line 'Prompt:' shows the text displayed for this symbol in\n"
0228 "   the menu hierarchy.\n"
0229 "o  The 'Defined at' line tells at what file / line number the symbol is\n"
0230 "   defined.\n"
0231 "o  The 'Depends on:' line lists symbols that need to be defined for\n"
0232 "   this symbol to be visible and selectable in the menu.\n"
0233 "o  The 'Location:' lines tell, where in the menu structure this symbol\n"
0234 "   is located.  A location followed by a [ = y] indicates that this is\n"
0235 "   a selectable menu item, and the current value is displayed inside\n"
0236 "   brackets.\n"
0237 "o  The 'Selects:' line tells, what symbol will be automatically selected\n"
0238 "   if this symbol is selected (y or m).\n"
0239 "o  The 'Selected by' line tells what symbol has selected this symbol.\n"
0240 "\n"
0241 "Only relevant lines are shown.\n"
0242 "\n\n"
0243 "Search examples:\n"
0244 "USB  => find all symbols containing USB\n"
0245 "^USB => find all symbols starting with USB\n"
0246 "USB$ => find all symbols ending with USB\n"
0247 "\n";
0248 
0249 struct mitem {
0250     char str[256];
0251     char tag;
0252     void *usrptr;
0253     int is_visible;
0254 };
0255 
0256 #define MAX_MENU_ITEMS 4096
0257 static int show_all_items;
0258 static int indent;
0259 static struct menu *current_menu;
0260 static int child_count;
0261 static int single_menu_mode;
0262 /* the window in which all information appears */
0263 static WINDOW *main_window;
0264 /* the largest size of the menu window */
0265 static int mwin_max_lines;
0266 static int mwin_max_cols;
0267 /* the window in which we show option buttons */
0268 static MENU *curses_menu;
0269 static ITEM *curses_menu_items[MAX_MENU_ITEMS];
0270 static struct mitem k_menu_items[MAX_MENU_ITEMS];
0271 static unsigned int items_num;
0272 static int global_exit;
0273 /* the currently selected button */
0274 static const char *current_instructions = menu_instructions;
0275 
0276 static char *dialog_input_result;
0277 static int dialog_input_result_len;
0278 
0279 static void conf(struct menu *menu);
0280 static void conf_choice(struct menu *menu);
0281 static void conf_string(struct menu *menu);
0282 static void conf_load(void);
0283 static void conf_save(void);
0284 static void show_help(struct menu *menu);
0285 static int do_exit(void);
0286 static void setup_windows(void);
0287 static void search_conf(void);
0288 
0289 typedef void (*function_key_handler_t)(int *key, struct menu *menu);
0290 static void handle_f1(int *key, struct menu *current_item);
0291 static void handle_f2(int *key, struct menu *current_item);
0292 static void handle_f3(int *key, struct menu *current_item);
0293 static void handle_f4(int *key, struct menu *current_item);
0294 static void handle_f5(int *key, struct menu *current_item);
0295 static void handle_f6(int *key, struct menu *current_item);
0296 static void handle_f7(int *key, struct menu *current_item);
0297 static void handle_f8(int *key, struct menu *current_item);
0298 static void handle_f9(int *key, struct menu *current_item);
0299 
0300 struct function_keys {
0301     const char *key_str;
0302     const char *func;
0303     function_key key;
0304     function_key_handler_t handler;
0305 };
0306 
0307 static const int function_keys_num = 9;
0308 static struct function_keys function_keys[] = {
0309     {
0310         .key_str = "F1",
0311         .func = "Help",
0312         .key = F_HELP,
0313         .handler = handle_f1,
0314     },
0315     {
0316         .key_str = "F2",
0317         .func = "SymInfo",
0318         .key = F_SYMBOL,
0319         .handler = handle_f2,
0320     },
0321     {
0322         .key_str = "F3",
0323         .func = "Help 2",
0324         .key = F_INSTS,
0325         .handler = handle_f3,
0326     },
0327     {
0328         .key_str = "F4",
0329         .func = "ShowAll",
0330         .key = F_CONF,
0331         .handler = handle_f4,
0332     },
0333     {
0334         .key_str = "F5",
0335         .func = "Back",
0336         .key = F_BACK,
0337         .handler = handle_f5,
0338     },
0339     {
0340         .key_str = "F6",
0341         .func = "Save",
0342         .key = F_SAVE,
0343         .handler = handle_f6,
0344     },
0345     {
0346         .key_str = "F7",
0347         .func = "Load",
0348         .key = F_LOAD,
0349         .handler = handle_f7,
0350     },
0351     {
0352         .key_str = "F8",
0353         .func = "SymSearch",
0354         .key = F_SEARCH,
0355         .handler = handle_f8,
0356     },
0357     {
0358         .key_str = "F9",
0359         .func = "Exit",
0360         .key = F_EXIT,
0361         .handler = handle_f9,
0362     },
0363 };
0364 
0365 static void print_function_line(void)
0366 {
0367     int i;
0368     int offset = 1;
0369     const int skip = 1;
0370     int lines = getmaxy(stdscr);
0371 
0372     for (i = 0; i < function_keys_num; i++) {
0373         wattrset(main_window, attr_function_highlight);
0374         mvwprintw(main_window, lines-3, offset,
0375                 "%s",
0376                 function_keys[i].key_str);
0377         wattrset(main_window, attr_function_text);
0378         offset += strlen(function_keys[i].key_str);
0379         mvwprintw(main_window, lines-3,
0380                 offset, "%s",
0381                 function_keys[i].func);
0382         offset += strlen(function_keys[i].func) + skip;
0383     }
0384     wattrset(main_window, attr_normal);
0385 }
0386 
0387 /* help */
0388 static void handle_f1(int *key, struct menu *current_item)
0389 {
0390     show_scroll_win(main_window,
0391             "Global help", nconf_global_help);
0392     return;
0393 }
0394 
0395 /* symbole help */
0396 static void handle_f2(int *key, struct menu *current_item)
0397 {
0398     show_help(current_item);
0399     return;
0400 }
0401 
0402 /* instructions */
0403 static void handle_f3(int *key, struct menu *current_item)
0404 {
0405     show_scroll_win(main_window,
0406             "Short help",
0407             current_instructions);
0408     return;
0409 }
0410 
0411 /* config */
0412 static void handle_f4(int *key, struct menu *current_item)
0413 {
0414     int res = btn_dialog(main_window,
0415             "Show all symbols?",
0416             2,
0417             "   <Show All>   ",
0418             "<Don't show all>");
0419     if (res == 0)
0420         show_all_items = 1;
0421     else if (res == 1)
0422         show_all_items = 0;
0423 
0424     return;
0425 }
0426 
0427 /* back */
0428 static void handle_f5(int *key, struct menu *current_item)
0429 {
0430     *key = KEY_LEFT;
0431     return;
0432 }
0433 
0434 /* save */
0435 static void handle_f6(int *key, struct menu *current_item)
0436 {
0437     conf_save();
0438     return;
0439 }
0440 
0441 /* load */
0442 static void handle_f7(int *key, struct menu *current_item)
0443 {
0444     conf_load();
0445     return;
0446 }
0447 
0448 /* search */
0449 static void handle_f8(int *key, struct menu *current_item)
0450 {
0451     search_conf();
0452     return;
0453 }
0454 
0455 /* exit */
0456 static void handle_f9(int *key, struct menu *current_item)
0457 {
0458     do_exit();
0459     return;
0460 }
0461 
0462 /* return != 0 to indicate the key was handles */
0463 static int process_special_keys(int *key, struct menu *menu)
0464 {
0465     int i;
0466 
0467     if (*key == KEY_RESIZE) {
0468         setup_windows();
0469         return 1;
0470     }
0471 
0472     for (i = 0; i < function_keys_num; i++) {
0473         if (*key == KEY_F(function_keys[i].key) ||
0474             *key == '0' + function_keys[i].key){
0475             function_keys[i].handler(key, menu);
0476             return 1;
0477         }
0478     }
0479 
0480     return 0;
0481 }
0482 
0483 static void clean_items(void)
0484 {
0485     int i;
0486     for (i = 0; curses_menu_items[i]; i++)
0487         free_item(curses_menu_items[i]);
0488     bzero(curses_menu_items, sizeof(curses_menu_items));
0489     bzero(k_menu_items, sizeof(k_menu_items));
0490     items_num = 0;
0491 }
0492 
0493 typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
0494     FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
0495 
0496 /* return the index of the matched item, or -1 if no such item exists */
0497 static int get_mext_match(const char *match_str, match_f flag)
0498 {
0499     int match_start, index;
0500 
0501     /* Do not search if the menu is empty (i.e. items_num == 0) */
0502     match_start = item_index(current_item(curses_menu));
0503     if (match_start == ERR)
0504         return -1;
0505 
0506     if (flag == FIND_NEXT_MATCH_DOWN)
0507         ++match_start;
0508     else if (flag == FIND_NEXT_MATCH_UP)
0509         --match_start;
0510 
0511     match_start = (match_start + items_num) % items_num;
0512     index = match_start;
0513     while (true) {
0514         char *str = k_menu_items[index].str;
0515         if (strcasestr(str, match_str) != NULL)
0516             return index;
0517         if (flag == FIND_NEXT_MATCH_UP ||
0518             flag == MATCH_TINKER_PATTERN_UP)
0519             --index;
0520         else
0521             ++index;
0522         index = (index + items_num) % items_num;
0523         if (index == match_start)
0524             return -1;
0525     }
0526 }
0527 
0528 /* Make a new item. */
0529 static void item_make(struct menu *menu, char tag, const char *fmt, ...)
0530 {
0531     va_list ap;
0532 
0533     if (items_num > MAX_MENU_ITEMS-1)
0534         return;
0535 
0536     bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
0537     k_menu_items[items_num].tag = tag;
0538     k_menu_items[items_num].usrptr = menu;
0539     if (menu != NULL)
0540         k_menu_items[items_num].is_visible =
0541             menu_is_visible(menu);
0542     else
0543         k_menu_items[items_num].is_visible = 1;
0544 
0545     va_start(ap, fmt);
0546     vsnprintf(k_menu_items[items_num].str,
0547           sizeof(k_menu_items[items_num].str),
0548           fmt, ap);
0549     va_end(ap);
0550 
0551     if (!k_menu_items[items_num].is_visible)
0552         memcpy(k_menu_items[items_num].str, "XXX", 3);
0553 
0554     curses_menu_items[items_num] = new_item(
0555             k_menu_items[items_num].str,
0556             k_menu_items[items_num].str);
0557     set_item_userptr(curses_menu_items[items_num],
0558             &k_menu_items[items_num]);
0559     /*
0560     if (!k_menu_items[items_num].is_visible)
0561         item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
0562     */
0563 
0564     items_num++;
0565     curses_menu_items[items_num] = NULL;
0566 }
0567 
0568 /* very hackish. adds a string to the last item added */
0569 static void item_add_str(const char *fmt, ...)
0570 {
0571     va_list ap;
0572     int index = items_num-1;
0573     char new_str[256];
0574     char tmp_str[256];
0575 
0576     if (index < 0)
0577         return;
0578 
0579     va_start(ap, fmt);
0580     vsnprintf(new_str, sizeof(new_str), fmt, ap);
0581     va_end(ap);
0582     snprintf(tmp_str, sizeof(tmp_str), "%s%s",
0583             k_menu_items[index].str, new_str);
0584     strncpy(k_menu_items[index].str,
0585         tmp_str,
0586         sizeof(k_menu_items[index].str));
0587 
0588     free_item(curses_menu_items[index]);
0589     curses_menu_items[index] = new_item(
0590             k_menu_items[index].str,
0591             k_menu_items[index].str);
0592     set_item_userptr(curses_menu_items[index],
0593             &k_menu_items[index]);
0594 }
0595 
0596 /* get the tag of the currently selected item */
0597 static char item_tag(void)
0598 {
0599     ITEM *cur;
0600     struct mitem *mcur;
0601 
0602     cur = current_item(curses_menu);
0603     if (cur == NULL)
0604         return 0;
0605     mcur = (struct mitem *) item_userptr(cur);
0606     return mcur->tag;
0607 }
0608 
0609 static int curses_item_index(void)
0610 {
0611     return  item_index(current_item(curses_menu));
0612 }
0613 
0614 static void *item_data(void)
0615 {
0616     ITEM *cur;
0617     struct mitem *mcur;
0618 
0619     cur = current_item(curses_menu);
0620     if (!cur)
0621         return NULL;
0622     mcur = (struct mitem *) item_userptr(cur);
0623     return mcur->usrptr;
0624 
0625 }
0626 
0627 static int item_is_tag(char tag)
0628 {
0629     return item_tag() == tag;
0630 }
0631 
0632 static char filename[PATH_MAX+1];
0633 static char menu_backtitle[PATH_MAX+128];
0634 static void set_config_filename(const char *config_filename)
0635 {
0636     snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
0637          config_filename, rootmenu.prompt->text);
0638 
0639     snprintf(filename, sizeof(filename), "%s", config_filename);
0640 }
0641 
0642 /* return = 0 means we are successful.
0643  * -1 means go on doing what you were doing
0644  */
0645 static int do_exit(void)
0646 {
0647     int res;
0648     if (!conf_get_changed()) {
0649         global_exit = 1;
0650         return 0;
0651     }
0652     res = btn_dialog(main_window,
0653             "Do you wish to save your new configuration?\n"
0654                 "<ESC> to cancel and resume nconfig.",
0655             2,
0656             "   <save>   ",
0657             "<don't save>");
0658     if (res == KEY_EXIT) {
0659         global_exit = 0;
0660         return -1;
0661     }
0662 
0663     /* if we got here, the user really wants to exit */
0664     switch (res) {
0665     case 0:
0666         res = conf_write(filename);
0667         if (res)
0668             btn_dialog(
0669                 main_window,
0670                 "Error during writing of configuration.\n"
0671                   "Your configuration changes were NOT saved.",
0672                   1,
0673                   "<OK>");
0674         conf_write_autoconf(0);
0675         break;
0676     default:
0677         btn_dialog(
0678             main_window,
0679             "Your configuration changes were NOT saved.",
0680             1,
0681             "<OK>");
0682         break;
0683     }
0684     global_exit = 1;
0685     return 0;
0686 }
0687 
0688 
0689 static void search_conf(void)
0690 {
0691     struct symbol **sym_arr;
0692     struct gstr res;
0693     struct gstr title;
0694     char *dialog_input;
0695     int dres;
0696 
0697     title = str_new();
0698     str_printf( &title, "Enter (sub)string or regexp to search for "
0699                   "(with or without \"%s\")", CONFIG_);
0700 
0701 again:
0702     dres = dialog_inputbox(main_window,
0703             "Search Configuration Parameter",
0704             str_get(&title),
0705             "", &dialog_input_result, &dialog_input_result_len);
0706     switch (dres) {
0707     case 0:
0708         break;
0709     case 1:
0710         show_scroll_win(main_window,
0711                 "Search Configuration", search_help);
0712         goto again;
0713     default:
0714         str_free(&title);
0715         return;
0716     }
0717 
0718     /* strip the prefix if necessary */
0719     dialog_input = dialog_input_result;
0720     if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
0721         dialog_input += strlen(CONFIG_);
0722 
0723     sym_arr = sym_re_search(dialog_input);
0724     res = get_relations_str(sym_arr, NULL);
0725     free(sym_arr);
0726     show_scroll_win(main_window,
0727             "Search Results", str_get(&res));
0728     str_free(&res);
0729     str_free(&title);
0730 }
0731 
0732 
0733 static void build_conf(struct menu *menu)
0734 {
0735     struct symbol *sym;
0736     struct property *prop;
0737     struct menu *child;
0738     int type, tmp, doint = 2;
0739     tristate val;
0740     char ch;
0741 
0742     if (!menu || (!show_all_items && !menu_is_visible(menu)))
0743         return;
0744 
0745     sym = menu->sym;
0746     prop = menu->prompt;
0747     if (!sym) {
0748         if (prop && menu != current_menu) {
0749             const char *prompt = menu_get_prompt(menu);
0750             enum prop_type ptype;
0751             ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
0752             switch (ptype) {
0753             case P_MENU:
0754                 child_count++;
0755                 if (single_menu_mode) {
0756                     item_make(menu, 'm',
0757                         "%s%*c%s",
0758                         menu->data ? "-->" : "++>",
0759                         indent + 1, ' ', prompt);
0760                 } else
0761                     item_make(menu, 'm',
0762                           "   %*c%s  %s",
0763                           indent + 1, ' ', prompt,
0764                           menu_is_empty(menu) ? "----" : "--->");
0765 
0766                 if (single_menu_mode && menu->data)
0767                     goto conf_childs;
0768                 return;
0769             case P_COMMENT:
0770                 if (prompt) {
0771                     child_count++;
0772                     item_make(menu, ':',
0773                         "   %*c*** %s ***",
0774                         indent + 1, ' ',
0775                         prompt);
0776                 }
0777                 break;
0778             default:
0779                 if (prompt) {
0780                     child_count++;
0781                     item_make(menu, ':', "---%*c%s",
0782                         indent + 1, ' ',
0783                         prompt);
0784                 }
0785             }
0786         } else
0787             doint = 0;
0788         goto conf_childs;
0789     }
0790 
0791     type = sym_get_type(sym);
0792     if (sym_is_choice(sym)) {
0793         struct symbol *def_sym = sym_get_choice_value(sym);
0794         struct menu *def_menu = NULL;
0795 
0796         child_count++;
0797         for (child = menu->list; child; child = child->next) {
0798             if (menu_is_visible(child) && child->sym == def_sym)
0799                 def_menu = child;
0800         }
0801 
0802         val = sym_get_tristate_value(sym);
0803         if (sym_is_changeable(sym)) {
0804             switch (type) {
0805             case S_BOOLEAN:
0806                 item_make(menu, 't', "[%c]",
0807                         val == no ? ' ' : '*');
0808                 break;
0809             case S_TRISTATE:
0810                 switch (val) {
0811                 case yes:
0812                     ch = '*';
0813                     break;
0814                 case mod:
0815                     ch = 'M';
0816                     break;
0817                 default:
0818                     ch = ' ';
0819                     break;
0820                 }
0821                 item_make(menu, 't', "<%c>", ch);
0822                 break;
0823             }
0824         } else {
0825             item_make(menu, def_menu ? 't' : ':', "   ");
0826         }
0827 
0828         item_add_str("%*c%s", indent + 1,
0829                 ' ', menu_get_prompt(menu));
0830         if (val == yes) {
0831             if (def_menu) {
0832                 item_add_str(" (%s)",
0833                     menu_get_prompt(def_menu));
0834                 item_add_str("  --->");
0835                 if (def_menu->list) {
0836                     indent += 2;
0837                     build_conf(def_menu);
0838                     indent -= 2;
0839                 }
0840             }
0841             return;
0842         }
0843     } else {
0844         if (menu == current_menu) {
0845             item_make(menu, ':',
0846                 "---%*c%s", indent + 1,
0847                 ' ', menu_get_prompt(menu));
0848             goto conf_childs;
0849         }
0850         child_count++;
0851         val = sym_get_tristate_value(sym);
0852         if (sym_is_choice_value(sym) && val == yes) {
0853             item_make(menu, ':', "   ");
0854         } else {
0855             switch (type) {
0856             case S_BOOLEAN:
0857                 if (sym_is_changeable(sym))
0858                     item_make(menu, 't', "[%c]",
0859                         val == no ? ' ' : '*');
0860                 else
0861                     item_make(menu, 't', "-%c-",
0862                         val == no ? ' ' : '*');
0863                 break;
0864             case S_TRISTATE:
0865                 switch (val) {
0866                 case yes:
0867                     ch = '*';
0868                     break;
0869                 case mod:
0870                     ch = 'M';
0871                     break;
0872                 default:
0873                     ch = ' ';
0874                     break;
0875                 }
0876                 if (sym_is_changeable(sym)) {
0877                     if (sym->rev_dep.tri == mod)
0878                         item_make(menu,
0879                             't', "{%c}", ch);
0880                     else
0881                         item_make(menu,
0882                             't', "<%c>", ch);
0883                 } else
0884                     item_make(menu, 't', "-%c-", ch);
0885                 break;
0886             default:
0887                 tmp = 2 + strlen(sym_get_string_value(sym));
0888                 item_make(menu, 's', "    (%s)",
0889                         sym_get_string_value(sym));
0890                 tmp = indent - tmp + 4;
0891                 if (tmp < 0)
0892                     tmp = 0;
0893                 item_add_str("%*c%s%s", tmp, ' ',
0894                         menu_get_prompt(menu),
0895                         (sym_has_value(sym) ||
0896                          !sym_is_changeable(sym)) ? "" :
0897                         " (NEW)");
0898                 goto conf_childs;
0899             }
0900         }
0901         item_add_str("%*c%s%s", indent + 1, ' ',
0902                 menu_get_prompt(menu),
0903                 (sym_has_value(sym) || !sym_is_changeable(sym)) ?
0904                 "" : " (NEW)");
0905         if (menu->prompt && menu->prompt->type == P_MENU) {
0906             item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
0907             return;
0908         }
0909     }
0910 
0911 conf_childs:
0912     indent += doint;
0913     for (child = menu->list; child; child = child->next)
0914         build_conf(child);
0915     indent -= doint;
0916 }
0917 
0918 static void reset_menu(void)
0919 {
0920     unpost_menu(curses_menu);
0921     clean_items();
0922 }
0923 
0924 /* adjust the menu to show this item.
0925  * prefer not to scroll the menu if possible*/
0926 static void center_item(int selected_index, int *last_top_row)
0927 {
0928     int toprow;
0929 
0930     set_top_row(curses_menu, *last_top_row);
0931     toprow = top_row(curses_menu);
0932     if (selected_index < toprow ||
0933         selected_index >= toprow+mwin_max_lines) {
0934         toprow = max(selected_index-mwin_max_lines/2, 0);
0935         if (toprow >= item_count(curses_menu)-mwin_max_lines)
0936             toprow = item_count(curses_menu)-mwin_max_lines;
0937         set_top_row(curses_menu, toprow);
0938     }
0939     set_current_item(curses_menu,
0940             curses_menu_items[selected_index]);
0941     *last_top_row = toprow;
0942     post_menu(curses_menu);
0943     refresh_all_windows(main_window);
0944 }
0945 
0946 /* this function assumes reset_menu has been called before */
0947 static void show_menu(const char *prompt, const char *instructions,
0948         int selected_index, int *last_top_row)
0949 {
0950     int maxx, maxy;
0951     WINDOW *menu_window;
0952 
0953     current_instructions = instructions;
0954 
0955     clear();
0956     print_in_middle(stdscr, 1, getmaxx(stdscr),
0957             menu_backtitle,
0958             attr_main_heading);
0959 
0960     wattrset(main_window, attr_main_menu_box);
0961     box(main_window, 0, 0);
0962     wattrset(main_window, attr_main_menu_heading);
0963     mvwprintw(main_window, 0, 3, " %s ", prompt);
0964     wattrset(main_window, attr_normal);
0965 
0966     set_menu_items(curses_menu, curses_menu_items);
0967 
0968     /* position the menu at the middle of the screen */
0969     scale_menu(curses_menu, &maxy, &maxx);
0970     maxx = min(maxx, mwin_max_cols-2);
0971     maxy = mwin_max_lines;
0972     menu_window = derwin(main_window,
0973             maxy,
0974             maxx,
0975             2,
0976             (mwin_max_cols-maxx)/2);
0977     keypad(menu_window, TRUE);
0978     set_menu_win(curses_menu, menu_window);
0979     set_menu_sub(curses_menu, menu_window);
0980 
0981     /* must reassert this after changing items, otherwise returns to a
0982      * default of 16
0983      */
0984     set_menu_format(curses_menu, maxy, 1);
0985     center_item(selected_index, last_top_row);
0986     set_menu_format(curses_menu, maxy, 1);
0987 
0988     print_function_line();
0989 
0990     /* Post the menu */
0991     post_menu(curses_menu);
0992     refresh_all_windows(main_window);
0993 }
0994 
0995 static void adj_match_dir(match_f *match_direction)
0996 {
0997     if (*match_direction == FIND_NEXT_MATCH_DOWN)
0998         *match_direction =
0999             MATCH_TINKER_PATTERN_DOWN;
1000     else if (*match_direction == FIND_NEXT_MATCH_UP)
1001         *match_direction =
1002             MATCH_TINKER_PATTERN_UP;
1003     /* else, do no change.. */
1004 }
1005 
1006 struct match_state
1007 {
1008     int in_search;
1009     match_f match_direction;
1010     char pattern[256];
1011 };
1012 
1013 /* Return 0 means I have handled the key. In such a case, ans should hold the
1014  * item to center, or -1 otherwise.
1015  * Else return -1 .
1016  */
1017 static int do_match(int key, struct match_state *state, int *ans)
1018 {
1019     char c = (char) key;
1020     int terminate_search = 0;
1021     *ans = -1;
1022     if (key == '/' || (state->in_search && key == 27)) {
1023         move(0, 0);
1024         refresh();
1025         clrtoeol();
1026         state->in_search = 1-state->in_search;
1027         bzero(state->pattern, sizeof(state->pattern));
1028         state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1029         return 0;
1030     } else if (!state->in_search)
1031         return 1;
1032 
1033     if (isalnum(c) || isgraph(c) || c == ' ') {
1034         state->pattern[strlen(state->pattern)] = c;
1035         state->pattern[strlen(state->pattern)] = '\0';
1036         adj_match_dir(&state->match_direction);
1037         *ans = get_mext_match(state->pattern,
1038                 state->match_direction);
1039     } else if (key == KEY_DOWN) {
1040         state->match_direction = FIND_NEXT_MATCH_DOWN;
1041         *ans = get_mext_match(state->pattern,
1042                 state->match_direction);
1043     } else if (key == KEY_UP) {
1044         state->match_direction = FIND_NEXT_MATCH_UP;
1045         *ans = get_mext_match(state->pattern,
1046                 state->match_direction);
1047     } else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
1048         state->pattern[strlen(state->pattern)-1] = '\0';
1049         adj_match_dir(&state->match_direction);
1050     } else
1051         terminate_search = 1;
1052 
1053     if (terminate_search) {
1054         state->in_search = 0;
1055         bzero(state->pattern, sizeof(state->pattern));
1056         move(0, 0);
1057         refresh();
1058         clrtoeol();
1059         return -1;
1060     }
1061     return 0;
1062 }
1063 
1064 static void conf(struct menu *menu)
1065 {
1066     struct menu *submenu = NULL;
1067     struct symbol *sym;
1068     int res;
1069     int current_index = 0;
1070     int last_top_row = 0;
1071     struct match_state match_state = {
1072         .in_search = 0,
1073         .match_direction = MATCH_TINKER_PATTERN_DOWN,
1074         .pattern = "",
1075     };
1076 
1077     while (!global_exit) {
1078         reset_menu();
1079         current_menu = menu;
1080         build_conf(menu);
1081         if (!child_count)
1082             break;
1083 
1084         show_menu(menu_get_prompt(menu), menu_instructions,
1085               current_index, &last_top_row);
1086         keypad((menu_win(curses_menu)), TRUE);
1087         while (!global_exit) {
1088             if (match_state.in_search) {
1089                 mvprintw(0, 0,
1090                     "searching: %s", match_state.pattern);
1091                 clrtoeol();
1092             }
1093             refresh_all_windows(main_window);
1094             res = wgetch(menu_win(curses_menu));
1095             if (!res)
1096                 break;
1097             if (do_match(res, &match_state, &current_index) == 0) {
1098                 if (current_index != -1)
1099                     center_item(current_index,
1100                             &last_top_row);
1101                 continue;
1102             }
1103             if (process_special_keys(&res,
1104                         (struct menu *) item_data()))
1105                 break;
1106             switch (res) {
1107             case KEY_DOWN:
1108             case 'j':
1109                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1110                 break;
1111             case KEY_UP:
1112             case 'k':
1113                 menu_driver(curses_menu, REQ_UP_ITEM);
1114                 break;
1115             case KEY_NPAGE:
1116                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1117                 break;
1118             case KEY_PPAGE:
1119                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1120                 break;
1121             case KEY_HOME:
1122                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1123                 break;
1124             case KEY_END:
1125                 menu_driver(curses_menu, REQ_LAST_ITEM);
1126                 break;
1127             case 'h':
1128             case '?':
1129                 show_help((struct menu *) item_data());
1130                 break;
1131             }
1132             if (res == 10 || res == 27 ||
1133                 res == 32 || res == 'n' || res == 'y' ||
1134                 res == KEY_LEFT || res == KEY_RIGHT ||
1135                 res == 'm')
1136                 break;
1137             refresh_all_windows(main_window);
1138         }
1139 
1140         refresh_all_windows(main_window);
1141         /* if ESC or left*/
1142         if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1143             break;
1144 
1145         /* remember location in the menu */
1146         last_top_row = top_row(curses_menu);
1147         current_index = curses_item_index();
1148 
1149         if (!item_tag())
1150             continue;
1151 
1152         submenu = (struct menu *) item_data();
1153         if (!submenu || !menu_is_visible(submenu))
1154             continue;
1155         sym = submenu->sym;
1156 
1157         switch (res) {
1158         case ' ':
1159             if (item_is_tag('t'))
1160                 sym_toggle_tristate_value(sym);
1161             else if (item_is_tag('m'))
1162                 conf(submenu);
1163             break;
1164         case KEY_RIGHT:
1165         case 10: /* ENTER WAS PRESSED */
1166             switch (item_tag()) {
1167             case 'm':
1168                 if (single_menu_mode)
1169                     submenu->data =
1170                         (void *) (long) !submenu->data;
1171                 else
1172                     conf(submenu);
1173                 break;
1174             case 't':
1175                 if (sym_is_choice(sym) &&
1176                     sym_get_tristate_value(sym) == yes)
1177                     conf_choice(submenu);
1178                 else if (submenu->prompt &&
1179                      submenu->prompt->type == P_MENU)
1180                     conf(submenu);
1181                 else if (res == 10)
1182                     sym_toggle_tristate_value(sym);
1183                 break;
1184             case 's':
1185                 conf_string(submenu);
1186                 break;
1187             }
1188             break;
1189         case 'y':
1190             if (item_is_tag('t')) {
1191                 if (sym_set_tristate_value(sym, yes))
1192                     break;
1193                 if (sym_set_tristate_value(sym, mod))
1194                     btn_dialog(main_window, setmod_text, 0);
1195             }
1196             break;
1197         case 'n':
1198             if (item_is_tag('t'))
1199                 sym_set_tristate_value(sym, no);
1200             break;
1201         case 'm':
1202             if (item_is_tag('t'))
1203                 sym_set_tristate_value(sym, mod);
1204             break;
1205         }
1206     }
1207 }
1208 
1209 static void conf_message_callback(const char *s)
1210 {
1211     btn_dialog(main_window, s, 1, "<OK>");
1212 }
1213 
1214 static void show_help(struct menu *menu)
1215 {
1216     struct gstr help;
1217 
1218     if (!menu)
1219         return;
1220 
1221     help = str_new();
1222     menu_get_ext_help(menu, &help);
1223     show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help));
1224     str_free(&help);
1225 }
1226 
1227 static void conf_choice(struct menu *menu)
1228 {
1229     const char *prompt = menu_get_prompt(menu);
1230     struct menu *child = NULL;
1231     struct symbol *active;
1232     int selected_index = 0;
1233     int last_top_row = 0;
1234     int res, i = 0;
1235     struct match_state match_state = {
1236         .in_search = 0,
1237         .match_direction = MATCH_TINKER_PATTERN_DOWN,
1238         .pattern = "",
1239     };
1240 
1241     active = sym_get_choice_value(menu->sym);
1242     /* this is mostly duplicated from the conf() function. */
1243     while (!global_exit) {
1244         reset_menu();
1245 
1246         for (i = 0, child = menu->list; child; child = child->next) {
1247             if (!show_all_items && !menu_is_visible(child))
1248                 continue;
1249 
1250             if (child->sym == sym_get_choice_value(menu->sym))
1251                 item_make(child, ':', "<X> %s",
1252                         menu_get_prompt(child));
1253             else if (child->sym)
1254                 item_make(child, ':', "    %s",
1255                         menu_get_prompt(child));
1256             else
1257                 item_make(child, ':', "*** %s ***",
1258                         menu_get_prompt(child));
1259 
1260             if (child->sym == active){
1261                 last_top_row = top_row(curses_menu);
1262                 selected_index = i;
1263             }
1264             i++;
1265         }
1266         show_menu(prompt ? prompt : "Choice Menu",
1267                 radiolist_instructions,
1268                 selected_index,
1269                 &last_top_row);
1270         while (!global_exit) {
1271             if (match_state.in_search) {
1272                 mvprintw(0, 0, "searching: %s",
1273                      match_state.pattern);
1274                 clrtoeol();
1275             }
1276             refresh_all_windows(main_window);
1277             res = wgetch(menu_win(curses_menu));
1278             if (!res)
1279                 break;
1280             if (do_match(res, &match_state, &selected_index) == 0) {
1281                 if (selected_index != -1)
1282                     center_item(selected_index,
1283                             &last_top_row);
1284                 continue;
1285             }
1286             if (process_special_keys(
1287                         &res,
1288                         (struct menu *) item_data()))
1289                 break;
1290             switch (res) {
1291             case KEY_DOWN:
1292             case 'j':
1293                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1294                 break;
1295             case KEY_UP:
1296             case 'k':
1297                 menu_driver(curses_menu, REQ_UP_ITEM);
1298                 break;
1299             case KEY_NPAGE:
1300                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1301                 break;
1302             case KEY_PPAGE:
1303                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1304                 break;
1305             case KEY_HOME:
1306                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1307                 break;
1308             case KEY_END:
1309                 menu_driver(curses_menu, REQ_LAST_ITEM);
1310                 break;
1311             case 'h':
1312             case '?':
1313                 show_help((struct menu *) item_data());
1314                 break;
1315             }
1316             if (res == 10 || res == 27 || res == ' ' ||
1317                     res == KEY_LEFT){
1318                 break;
1319             }
1320             refresh_all_windows(main_window);
1321         }
1322         /* if ESC or left */
1323         if (res == 27 || res == KEY_LEFT)
1324             break;
1325 
1326         child = item_data();
1327         if (!child || !menu_is_visible(child) || !child->sym)
1328             continue;
1329         switch (res) {
1330         case ' ':
1331         case  10:
1332         case KEY_RIGHT:
1333             sym_set_tristate_value(child->sym, yes);
1334             return;
1335         case 'h':
1336         case '?':
1337             show_help(child);
1338             active = child->sym;
1339             break;
1340         case KEY_EXIT:
1341             return;
1342         }
1343     }
1344 }
1345 
1346 static void conf_string(struct menu *menu)
1347 {
1348     const char *prompt = menu_get_prompt(menu);
1349 
1350     while (1) {
1351         int res;
1352         const char *heading;
1353 
1354         switch (sym_get_type(menu->sym)) {
1355         case S_INT:
1356             heading = inputbox_instructions_int;
1357             break;
1358         case S_HEX:
1359             heading = inputbox_instructions_hex;
1360             break;
1361         case S_STRING:
1362             heading = inputbox_instructions_string;
1363             break;
1364         default:
1365             heading = "Internal nconf error!";
1366         }
1367         res = dialog_inputbox(main_window,
1368                 prompt ? prompt : "Main Menu",
1369                 heading,
1370                 sym_get_string_value(menu->sym),
1371                 &dialog_input_result,
1372                 &dialog_input_result_len);
1373         switch (res) {
1374         case 0:
1375             if (sym_set_string_value(menu->sym,
1376                         dialog_input_result))
1377                 return;
1378             btn_dialog(main_window,
1379                 "You have made an invalid entry.", 0);
1380             break;
1381         case 1:
1382             show_help(menu);
1383             break;
1384         case KEY_EXIT:
1385             return;
1386         }
1387     }
1388 }
1389 
1390 static void conf_load(void)
1391 {
1392     while (1) {
1393         int res;
1394         res = dialog_inputbox(main_window,
1395                 NULL, load_config_text,
1396                 filename,
1397                 &dialog_input_result,
1398                 &dialog_input_result_len);
1399         switch (res) {
1400         case 0:
1401             if (!dialog_input_result[0])
1402                 return;
1403             if (!conf_read(dialog_input_result)) {
1404                 set_config_filename(dialog_input_result);
1405                 conf_set_changed(true);
1406                 return;
1407             }
1408             btn_dialog(main_window, "File does not exist!", 0);
1409             break;
1410         case 1:
1411             show_scroll_win(main_window,
1412                     "Load Alternate Configuration",
1413                     load_config_help);
1414             break;
1415         case KEY_EXIT:
1416             return;
1417         }
1418     }
1419 }
1420 
1421 static void conf_save(void)
1422 {
1423     while (1) {
1424         int res;
1425         res = dialog_inputbox(main_window,
1426                 NULL, save_config_text,
1427                 filename,
1428                 &dialog_input_result,
1429                 &dialog_input_result_len);
1430         switch (res) {
1431         case 0:
1432             if (!dialog_input_result[0])
1433                 return;
1434             res = conf_write(dialog_input_result);
1435             if (!res) {
1436                 set_config_filename(dialog_input_result);
1437                 return;
1438             }
1439             btn_dialog(main_window, "Can't create file!",
1440                 1, "<OK>");
1441             break;
1442         case 1:
1443             show_scroll_win(main_window,
1444                 "Save Alternate Configuration",
1445                 save_config_help);
1446             break;
1447         case KEY_EXIT:
1448             return;
1449         }
1450     }
1451 }
1452 
1453 static void setup_windows(void)
1454 {
1455     int lines, columns;
1456 
1457     getmaxyx(stdscr, lines, columns);
1458 
1459     if (main_window != NULL)
1460         delwin(main_window);
1461 
1462     /* set up the menu and menu window */
1463     main_window = newwin(lines-2, columns-2, 2, 1);
1464     keypad(main_window, TRUE);
1465     mwin_max_lines = lines-7;
1466     mwin_max_cols = columns-6;
1467 
1468     /* panels order is from bottom to top */
1469     new_panel(main_window);
1470 }
1471 
1472 int main(int ac, char **av)
1473 {
1474     int lines, columns;
1475     char *mode;
1476 
1477     if (ac > 1 && strcmp(av[1], "-s") == 0) {
1478         /* Silence conf_read() until the real callback is set up */
1479         conf_set_message_callback(NULL);
1480         av++;
1481     }
1482     conf_parse(av[1]);
1483     conf_read(NULL);
1484 
1485     mode = getenv("NCONFIG_MODE");
1486     if (mode) {
1487         if (!strcasecmp(mode, "single_menu"))
1488             single_menu_mode = 1;
1489     }
1490 
1491     /* Initialize curses */
1492     initscr();
1493     /* set color theme */
1494     set_colors();
1495 
1496     cbreak();
1497     noecho();
1498     keypad(stdscr, TRUE);
1499     curs_set(0);
1500 
1501     getmaxyx(stdscr, lines, columns);
1502     if (columns < 75 || lines < 20) {
1503         endwin();
1504         printf("Your terminal should have at "
1505             "least 20 lines and 75 columns\n");
1506         return 1;
1507     }
1508 
1509     notimeout(stdscr, FALSE);
1510 #if NCURSES_REENTRANT
1511     set_escdelay(1);
1512 #else
1513     ESCDELAY = 1;
1514 #endif
1515 
1516     /* set btns menu */
1517     curses_menu = new_menu(curses_menu_items);
1518     menu_opts_off(curses_menu, O_SHOWDESC);
1519     menu_opts_on(curses_menu, O_SHOWMATCH);
1520     menu_opts_on(curses_menu, O_ONEVALUE);
1521     menu_opts_on(curses_menu, O_NONCYCLIC);
1522     menu_opts_on(curses_menu, O_IGNORECASE);
1523     set_menu_mark(curses_menu, " ");
1524     set_menu_fore(curses_menu, attr_main_menu_fore);
1525     set_menu_back(curses_menu, attr_main_menu_back);
1526     set_menu_grey(curses_menu, attr_main_menu_grey);
1527 
1528     set_config_filename(conf_get_configname());
1529     setup_windows();
1530 
1531     /* check for KEY_FUNC(1) */
1532     if (has_key(KEY_F(1)) == FALSE) {
1533         show_scroll_win(main_window,
1534                 "Instructions",
1535                 menu_no_f_instructions);
1536     }
1537 
1538     conf_set_message_callback(conf_message_callback);
1539     /* do the work */
1540     while (!global_exit) {
1541         conf(&rootmenu);
1542         if (!global_exit && do_exit() == 0)
1543             break;
1544     }
1545     /* ok, we are done */
1546     unpost_menu(curses_menu);
1547     free_menu(curses_menu);
1548     delwin(main_window);
1549     clear();
1550     refresh();
1551     endwin();
1552     return 0;
1553 }