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