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