b113c50209e3913123288ccfa61708d663e6cb18
[linux-2.6.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 void conf(struct menu *menu);
282 static void conf_choice(struct menu *menu);
283 static void conf_string(struct menu *menu);
284 static void conf_load(void);
285 static void conf_save(void);
286 static void show_help(struct menu *menu);
287 static int do_exit(void);
288 static void setup_windows(void);
289 static void search_conf(void);
290
291 typedef void (*function_key_handler_t)(int *key, struct menu *menu);
292 static void handle_f1(int *key, struct menu *current_item);
293 static void handle_f2(int *key, struct menu *current_item);
294 static void handle_f3(int *key, struct menu *current_item);
295 static void handle_f4(int *key, struct menu *current_item);
296 static void handle_f5(int *key, struct menu *current_item);
297 static void handle_f6(int *key, struct menu *current_item);
298 static void handle_f7(int *key, struct menu *current_item);
299 static void handle_f8(int *key, struct menu *current_item);
300 static void handle_f9(int *key, struct menu *current_item);
301
302 struct function_keys {
303         const char *key_str;
304         const char *func;
305         function_key key;
306         function_key_handler_t handler;
307 };
308
309 static const int function_keys_num = 9;
310 struct function_keys function_keys[] = {
311         {
312                 .key_str = "F1",
313                 .func = "Help",
314                 .key = F_HELP,
315                 .handler = handle_f1,
316         },
317         {
318                 .key_str = "F2",
319                 .func = "Sym Info",
320                 .key = F_SYMBOL,
321                 .handler = handle_f2,
322         },
323         {
324                 .key_str = "F3",
325                 .func = "Insts",
326                 .key = F_INSTS,
327                 .handler = handle_f3,
328         },
329         {
330                 .key_str = "F4",
331                 .func = "Config",
332                 .key = F_CONF,
333                 .handler = handle_f4,
334         },
335         {
336                 .key_str = "F5",
337                 .func = "Back",
338                 .key = F_BACK,
339                 .handler = handle_f5,
340         },
341         {
342                 .key_str = "F6",
343                 .func = "Save",
344                 .key = F_SAVE,
345                 .handler = handle_f6,
346         },
347         {
348                 .key_str = "F7",
349                 .func = "Load",
350                 .key = F_LOAD,
351                 .handler = handle_f7,
352         },
353         {
354                 .key_str = "F8",
355                 .func = "Sym Search",
356                 .key = F_SEARCH,
357                 .handler = handle_f8,
358         },
359         {
360                 .key_str = "F9",
361                 .func = "Exit",
362                 .key = F_EXIT,
363                 .handler = handle_f9,
364         },
365 };
366
367 static void print_function_line(void)
368 {
369         int i;
370         int offset = 1;
371         const int skip = 1;
372
373         for (i = 0; i < function_keys_num; i++) {
374                 (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
375                 mvwprintw(main_window, LINES-3, offset,
376                                 "%s",
377                                 function_keys[i].key_str);
378                 (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
379                 offset += strlen(function_keys[i].key_str);
380                 mvwprintw(main_window, LINES-3,
381                                 offset, "%s",
382                                 function_keys[i].func);
383                 offset += strlen(function_keys[i].func) + skip;
384         }
385         (void) wattrset(main_window, attributes[NORMAL]);
386 }
387
388 /* help */
389 static void handle_f1(int *key, struct menu *current_item)
390 {
391         show_scroll_win(main_window,
392                         _("README"), _(nconf_readme));
393         return;
394 }
395
396 /* symbole help */
397 static void handle_f2(int *key, struct menu *current_item)
398 {
399         show_help(current_item);
400         return;
401 }
402
403 /* instructions */
404 static void handle_f3(int *key, struct menu *current_item)
405 {
406         show_scroll_win(main_window,
407                         _("Instructions"),
408                         _(current_instructions));
409         return;
410 }
411
412 /* config */
413 static void handle_f4(int *key, struct menu *current_item)
414 {
415         int res = btn_dialog(main_window,
416                         _("Show all symbols?"),
417                         2,
418                         "   <Show All>   ",
419                         "<Don't show all>");
420         if (res == 0)
421                 show_all_items = 1;
422         else if (res == 1)
423                 show_all_items = 0;
424
425         return;
426 }
427
428 /* back */
429 static void handle_f5(int *key, struct menu *current_item)
430 {
431         *key = KEY_LEFT;
432         return;
433 }
434
435 /* save */
436 static void handle_f6(int *key, struct menu *current_item)
437 {
438         conf_save();
439         return;
440 }
441
442 /* load */
443 static void handle_f7(int *key, struct menu *current_item)
444 {
445         conf_load();
446         return;
447 }
448
449 /* search */
450 static void handle_f8(int *key, struct menu *current_item)
451 {
452         search_conf();
453         return;
454 }
455
456 /* exit */
457 static void handle_f9(int *key, struct menu *current_item)
458 {
459         do_exit();
460         return;
461 }
462
463 /* return != 0 to indicate the key was handles */
464 static int process_special_keys(int *key, struct menu *menu)
465 {
466         int i;
467
468         if (*key == KEY_RESIZE) {
469                 setup_windows();
470                 return 1;
471         }
472
473         for (i = 0; i < function_keys_num; i++) {
474                 if (*key == KEY_F(function_keys[i].key) ||
475                     *key == '0' + function_keys[i].key){
476                         function_keys[i].handler(key, menu);
477                         return 1;
478                 }
479         }
480
481         return 0;
482 }
483
484 static void clean_items(void)
485 {
486         int i;
487         for (i = 0; curses_menu_items[i]; i++)
488                 free_item(curses_menu_items[i]);
489         bzero(curses_menu_items, sizeof(curses_menu_items));
490         bzero(k_menu_items, sizeof(k_menu_items));
491         items_num = 0;
492 }
493
494 typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
495         FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
496
497 /* return the index of the matched item, or -1 if no such item exists */
498 static int get_mext_match(const char *match_str, match_f flag)
499 {
500         int match_start = item_index(current_item(curses_menu));
501         int index;
502
503         if (flag == FIND_NEXT_MATCH_DOWN)
504                 ++match_start;
505         else if (flag == FIND_NEXT_MATCH_UP)
506                 --match_start;
507
508         index = match_start;
509         index = (index + items_num) % items_num;
510         while (true) {
511                 char *str = k_menu_items[index].str;
512                 if (strcasestr(str, match_str) != 0)
513                         return index;
514                 if (flag == FIND_NEXT_MATCH_UP ||
515                     flag == MATCH_TINKER_PATTERN_UP)
516                         --index;
517                 else
518                         ++index;
519                 index = (index + items_num) % items_num;
520                 if (index == match_start)
521                         return -1;
522         }
523 }
524
525 /* Make a new item. */
526 static void item_make(struct menu *menu, char tag, const char *fmt, ...)
527 {
528         va_list ap;
529
530         if (items_num > MAX_MENU_ITEMS-1)
531                 return;
532
533         bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
534         k_menu_items[items_num].tag = tag;
535         k_menu_items[items_num].usrptr = menu;
536         if (menu != NULL)
537                 k_menu_items[items_num].is_visible =
538                         menu_is_visible(menu);
539         else
540                 k_menu_items[items_num].is_visible = 1;
541
542         va_start(ap, fmt);
543         vsnprintf(k_menu_items[items_num].str,
544                   sizeof(k_menu_items[items_num].str),
545                   fmt, ap);
546         va_end(ap);
547
548         if (!k_menu_items[items_num].is_visible)
549                 memcpy(k_menu_items[items_num].str, "XXX", 3);
550
551         curses_menu_items[items_num] = new_item(
552                         k_menu_items[items_num].str,
553                         k_menu_items[items_num].str);
554         set_item_userptr(curses_menu_items[items_num],
555                         &k_menu_items[items_num]);
556         /*
557         if (!k_menu_items[items_num].is_visible)
558                 item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
559         */
560
561         items_num++;
562         curses_menu_items[items_num] = NULL;
563 }
564
565 /* very hackish. adds a string to the last item added */
566 static void item_add_str(const char *fmt, ...)
567 {
568         va_list ap;
569         int index = items_num-1;
570         char new_str[256];
571         char tmp_str[256];
572
573         if (index < 0)
574                 return;
575
576         va_start(ap, fmt);
577         vsnprintf(new_str, sizeof(new_str), fmt, ap);
578         va_end(ap);
579         snprintf(tmp_str, sizeof(tmp_str), "%s%s",
580                         k_menu_items[index].str, new_str);
581         strncpy(k_menu_items[index].str,
582                 tmp_str,
583                 sizeof(k_menu_items[index].str));
584
585         free_item(curses_menu_items[index]);
586         curses_menu_items[index] = new_item(
587                         k_menu_items[index].str,
588                         k_menu_items[index].str);
589         set_item_userptr(curses_menu_items[index],
590                         &k_menu_items[index]);
591 }
592
593 /* get the tag of the currently selected item */
594 static char item_tag(void)
595 {
596         ITEM *cur;
597         struct mitem *mcur;
598
599         cur = current_item(curses_menu);
600         if (cur == NULL)
601                 return 0;
602         mcur = (struct mitem *) item_userptr(cur);
603         return mcur->tag;
604 }
605
606 static int curses_item_index(void)
607 {
608         return  item_index(current_item(curses_menu));
609 }
610
611 static void *item_data(void)
612 {
613         ITEM *cur;
614         struct mitem *mcur;
615
616         cur = current_item(curses_menu);
617         if (!cur)
618                 return NULL;
619         mcur = (struct mitem *) item_userptr(cur);
620         return mcur->usrptr;
621
622 }
623
624 static int item_is_tag(char tag)
625 {
626         return item_tag() == tag;
627 }
628
629 static char filename[PATH_MAX+1];
630 static char menu_backtitle[PATH_MAX+128];
631 static const char *set_config_filename(const char *config_filename)
632 {
633         int size;
634
635         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
636                         "%s - %s", config_filename, rootmenu.prompt->text);
637         if (size >= sizeof(menu_backtitle))
638                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
639
640         size = snprintf(filename, sizeof(filename), "%s", config_filename);
641         if (size >= sizeof(filename))
642                 filename[sizeof(filename)-1] = '\0';
643         return menu_backtitle;
644 }
645
646 /* return = 0 means we are successful.
647  * -1 means go on doing what you were doing
648  */
649 static int do_exit(void)
650 {
651         int res;
652         if (!conf_get_changed()) {
653                 global_exit = 1;
654                 return 0;
655         }
656         res = btn_dialog(main_window,
657                         _("Do you wish to save your new configuration?\n"
658                                 "<ESC> to cancel and resume nconfig."),
659                         2,
660                         "   <save>   ",
661                         "<don't save>");
662         if (res == KEY_EXIT) {
663                 global_exit = 0;
664                 return -1;
665         }
666
667         /* if we got here, the user really wants to exit */
668         switch (res) {
669         case 0:
670                 res = conf_write(filename);
671                 if (res)
672                         btn_dialog(
673                                 main_window,
674                                 _("Error during writing of configuration.\n"
675                                   "Your configuration changes were NOT saved."),
676                                   1,
677                                   "<OK>");
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         char dialog_input_result[100];
697         char *dialog_input;
698         int dres;
699 again:
700         dres = dialog_inputbox(main_window,
701                         _("Search Configuration Parameter"),
702                         _("Enter " CONFIG_ " (sub)string to search for "
703                                 "(with or without \"" CONFIG_ "\")"),
704                         "", dialog_input_result, 99);
705         switch (dres) {
706         case 0:
707                 break;
708         case 1:
709                 show_scroll_win(main_window,
710                                 _("Search Configuration"), search_help);
711                 goto again;
712         default:
713                 return;
714         }
715
716         /* strip the prefix if necessary */
717         dialog_input = dialog_input_result;
718         if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
719                 dialog_input += strlen(CONFIG_);
720
721         sym_arr = sym_re_search(dialog_input);
722         res = get_relations_str(sym_arr);
723         free(sym_arr);
724         show_scroll_win(main_window,
725                         _("Search Results"), str_get(&res));
726         str_free(&res);
727 }
728
729
730 static void build_conf(struct menu *menu)
731 {
732         struct symbol *sym;
733         struct property *prop;
734         struct menu *child;
735         int type, tmp, doint = 2;
736         tristate val;
737         char ch;
738
739         if (!menu || (!show_all_items && !menu_is_visible(menu)))
740                 return;
741
742         sym = menu->sym;
743         prop = menu->prompt;
744         if (!sym) {
745                 if (prop && menu != current_menu) {
746                         const char *prompt = menu_get_prompt(menu);
747                         enum prop_type ptype;
748                         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
749                         switch (ptype) {
750                         case P_MENU:
751                                 child_count++;
752                                 prompt = _(prompt);
753                                 if (single_menu_mode) {
754                                         item_make(menu, 'm',
755                                                 "%s%*c%s",
756                                                 menu->data ? "-->" : "++>",
757                                                 indent + 1, ' ', prompt);
758                                 } else
759                                         item_make(menu, 'm',
760                                                 "   %*c%s  --->",
761                                                 indent + 1,
762                                                 ' ', prompt);
763
764                                 if (single_menu_mode && menu->data)
765                                         goto conf_childs;
766                                 return;
767                         case P_COMMENT:
768                                 if (prompt) {
769                                         child_count++;
770                                         item_make(menu, ':',
771                                                 "   %*c*** %s ***",
772                                                 indent + 1, ' ',
773                                                 _(prompt));
774                                 }
775                                 break;
776                         default:
777                                 if (prompt) {
778                                         child_count++;
779                                         item_make(menu, ':', "---%*c%s",
780                                                 indent + 1, ' ',
781                                                 _(prompt));
782                                 }
783                         }
784                 } else
785                         doint = 0;
786                 goto conf_childs;
787         }
788
789         type = sym_get_type(sym);
790         if (sym_is_choice(sym)) {
791                 struct symbol *def_sym = sym_get_choice_value(sym);
792                 struct menu *def_menu = NULL;
793
794                 child_count++;
795                 for (child = menu->list; child; child = child->next) {
796                         if (menu_is_visible(child) && child->sym == def_sym)
797                                 def_menu = child;
798                 }
799
800                 val = sym_get_tristate_value(sym);
801                 if (sym_is_changable(sym)) {
802                         switch (type) {
803                         case S_BOOLEAN:
804                                 item_make(menu, 't', "[%c]",
805                                                 val == no ? ' ' : '*');
806                                 break;
807                         case S_TRISTATE:
808                                 switch (val) {
809                                 case yes:
810                                         ch = '*';
811                                         break;
812                                 case mod:
813                                         ch = 'M';
814                                         break;
815                                 default:
816                                         ch = ' ';
817                                         break;
818                                 }
819                                 item_make(menu, 't', "<%c>", ch);
820                                 break;
821                         }
822                 } else {
823                         item_make(menu, def_menu ? 't' : ':', "   ");
824                 }
825
826                 item_add_str("%*c%s", indent + 1,
827                                 ' ', _(menu_get_prompt(menu)));
828                 if (val == yes) {
829                         if (def_menu) {
830                                 item_add_str(" (%s)",
831                                         _(menu_get_prompt(def_menu)));
832                                 item_add_str("  --->");
833                                 if (def_menu->list) {
834                                         indent += 2;
835                                         build_conf(def_menu);
836                                         indent -= 2;
837                                 }
838                         }
839                         return;
840                 }
841         } else {
842                 if (menu == current_menu) {
843                         item_make(menu, ':',
844                                 "---%*c%s", indent + 1,
845                                 ' ', _(menu_get_prompt(menu)));
846                         goto conf_childs;
847                 }
848                 child_count++;
849                 val = sym_get_tristate_value(sym);
850                 if (sym_is_choice_value(sym) && val == yes) {
851                         item_make(menu, ':', "   ");
852                 } else {
853                         switch (type) {
854                         case S_BOOLEAN:
855                                 if (sym_is_changable(sym))
856                                         item_make(menu, 't', "[%c]",
857                                                 val == no ? ' ' : '*');
858                                 else
859                                         item_make(menu, 't', "-%c-",
860                                                 val == no ? ' ' : '*');
861                                 break;
862                         case S_TRISTATE:
863                                 switch (val) {
864                                 case yes:
865                                         ch = '*';
866                                         break;
867                                 case mod:
868                                         ch = 'M';
869                                         break;
870                                 default:
871                                         ch = ' ';
872                                         break;
873                                 }
874                                 if (sym_is_changable(sym)) {
875                                         if (sym->rev_dep.tri == mod)
876                                                 item_make(menu,
877                                                         't', "{%c}", ch);
878                                         else
879                                                 item_make(menu,
880                                                         't', "<%c>", ch);
881                                 } else
882                                         item_make(menu, 't', "-%c-", ch);
883                                 break;
884                         default:
885                                 tmp = 2 + strlen(sym_get_string_value(sym));
886                                 item_make(menu, 's', "    (%s)",
887                                                 sym_get_string_value(sym));
888                                 tmp = indent - tmp + 4;
889                                 if (tmp < 0)
890                                         tmp = 0;
891                                 item_add_str("%*c%s%s", tmp, ' ',
892                                                 _(menu_get_prompt(menu)),
893                                                 (sym_has_value(sym) ||
894                                                  !sym_is_changable(sym)) ? "" :
895                                                 _(" (NEW)"));
896                                 goto conf_childs;
897                         }
898                 }
899                 item_add_str("%*c%s%s", indent + 1, ' ',
900                                 _(menu_get_prompt(menu)),
901                                 (sym_has_value(sym) || !sym_is_changable(sym)) ?
902                                 "" : _(" (NEW)"));
903                 if (menu->prompt && menu->prompt->type == P_MENU) {
904                         item_add_str("  --->");
905                         return;
906                 }
907         }
908
909 conf_childs:
910         indent += doint;
911         for (child = menu->list; child; child = child->next)
912                 build_conf(child);
913         indent -= doint;
914 }
915
916 static void reset_menu(void)
917 {
918         unpost_menu(curses_menu);
919         clean_items();
920 }
921
922 /* adjust the menu to show this item.
923  * prefer not to scroll the menu if possible*/
924 static void center_item(int selected_index, int *last_top_row)
925 {
926         int toprow;
927
928         set_top_row(curses_menu, *last_top_row);
929         toprow = top_row(curses_menu);
930         if (selected_index < toprow ||
931             selected_index >= toprow+mwin_max_lines) {
932                 toprow = max(selected_index-mwin_max_lines/2, 0);
933                 if (toprow >= item_count(curses_menu)-mwin_max_lines)
934                         toprow = item_count(curses_menu)-mwin_max_lines;
935                 set_top_row(curses_menu, toprow);
936         }
937         set_current_item(curses_menu,
938                         curses_menu_items[selected_index]);
939         *last_top_row = toprow;
940         post_menu(curses_menu);
941         refresh_all_windows(main_window);
942 }
943
944 /* this function assumes reset_menu has been called before */
945 static void show_menu(const char *prompt, const char *instructions,
946                 int selected_index, int *last_top_row)
947 {
948         int maxx, maxy;
949         WINDOW *menu_window;
950
951         current_instructions = instructions;
952
953         clear();
954         (void) wattrset(main_window, attributes[NORMAL]);
955         print_in_middle(stdscr, 1, 0, COLS,
956                         menu_backtitle,
957                         attributes[MAIN_HEADING]);
958
959         (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
960         box(main_window, 0, 0);
961         (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
962         mvwprintw(main_window, 0, 3, " %s ", prompt);
963         (void) wattrset(main_window, attributes[NORMAL]);
964
965         set_menu_items(curses_menu, curses_menu_items);
966
967         /* position the menu at the middle of the screen */
968         scale_menu(curses_menu, &maxy, &maxx);
969         maxx = min(maxx, mwin_max_cols-2);
970         maxy = mwin_max_lines;
971         menu_window = derwin(main_window,
972                         maxy,
973                         maxx,
974                         2,
975                         (mwin_max_cols-maxx)/2);
976         keypad(menu_window, TRUE);
977         set_menu_win(curses_menu, menu_window);
978         set_menu_sub(curses_menu, menu_window);
979
980         /* must reassert this after changing items, otherwise returns to a
981          * default of 16
982          */
983         set_menu_format(curses_menu, maxy, 1);
984         center_item(selected_index, last_top_row);
985         set_menu_format(curses_menu, maxy, 1);
986
987         print_function_line();
988
989         /* Post the menu */
990         post_menu(curses_menu);
991         refresh_all_windows(main_window);
992 }
993
994 static void adj_match_dir(match_f *match_direction)
995 {
996         if (*match_direction == FIND_NEXT_MATCH_DOWN)
997                 *match_direction =
998                         MATCH_TINKER_PATTERN_DOWN;
999         else if (*match_direction == FIND_NEXT_MATCH_UP)
1000                 *match_direction =
1001                         MATCH_TINKER_PATTERN_UP;
1002         /* else, do no change.. */
1003 }
1004
1005 struct match_state
1006 {
1007         int in_search;
1008         match_f match_direction;
1009         char pattern[256];
1010 };
1011
1012 /* Return 0 means I have handled the key. In such a case, ans should hold the
1013  * item to center, or -1 otherwise.
1014  * Else return -1 .
1015  */
1016 static int do_match(int key, struct match_state *state, int *ans)
1017 {
1018         char c = (char) key;
1019         int terminate_search = 0;
1020         *ans = -1;
1021         if (key == '/' || (state->in_search && key == 27)) {
1022                 move(0, 0);
1023                 refresh();
1024                 clrtoeol();
1025                 state->in_search = 1-state->in_search;
1026                 bzero(state->pattern, sizeof(state->pattern));
1027                 state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1028                 return 0;
1029         } else if (!state->in_search)
1030                 return 1;
1031
1032         if (isalnum(c) || isgraph(c) || c == ' ') {
1033                 state->pattern[strlen(state->pattern)] = c;
1034                 state->pattern[strlen(state->pattern)] = '\0';
1035                 adj_match_dir(&state->match_direction);
1036                 *ans = get_mext_match(state->pattern,
1037                                 state->match_direction);
1038         } else if (key == KEY_DOWN) {
1039                 state->match_direction = FIND_NEXT_MATCH_DOWN;
1040                 *ans = get_mext_match(state->pattern,
1041                                 state->match_direction);
1042         } else if (key == KEY_UP) {
1043                 state->match_direction = FIND_NEXT_MATCH_UP;
1044                 *ans = get_mext_match(state->pattern,
1045                                 state->match_direction);
1046         } else if (key == KEY_BACKSPACE || key == 127) {
1047                 state->pattern[strlen(state->pattern)-1] = '\0';
1048                 adj_match_dir(&state->match_direction);
1049         } else
1050                 terminate_search = 1;
1051
1052         if (terminate_search) {
1053                 state->in_search = 0;
1054                 bzero(state->pattern, sizeof(state->pattern));
1055                 move(0, 0);
1056                 refresh();
1057                 clrtoeol();
1058                 return -1;
1059         }
1060         return 0;
1061 }
1062
1063 static void conf(struct menu *menu)
1064 {
1065         struct menu *submenu = 0;
1066         const char *prompt = menu_get_prompt(menu);
1067         struct symbol *sym;
1068         int res;
1069         int current_index = 0;
1070         int last_top_row = 0;
1071         struct match_state match_state = {
1072                 .in_search = 0,
1073                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1074                 .pattern = "",
1075         };
1076
1077         while (!global_exit) {
1078                 reset_menu();
1079                 current_menu = menu;
1080                 build_conf(menu);
1081                 if (!child_count)
1082                         break;
1083
1084                 show_menu(prompt ? _(prompt) : _("Main Menu"),
1085                                 _(menu_instructions),
1086                                 current_index, &last_top_row);
1087                 keypad((menu_win(curses_menu)), TRUE);
1088                 while (!global_exit) {
1089                         if (match_state.in_search) {
1090                                 mvprintw(0, 0,
1091                                         "searching: %s", match_state.pattern);
1092                                 clrtoeol();
1093                         }
1094                         refresh_all_windows(main_window);
1095                         res = wgetch(menu_win(curses_menu));
1096                         if (!res)
1097                                 break;
1098                         if (do_match(res, &match_state, &current_index) == 0) {
1099                                 if (current_index != -1)
1100                                         center_item(current_index,
1101                                                     &last_top_row);
1102                                 continue;
1103                         }
1104                         if (process_special_keys(&res,
1105                                                 (struct menu *) item_data()))
1106                                 break;
1107                         switch (res) {
1108                         case KEY_DOWN:
1109                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1110                                 break;
1111                         case KEY_UP:
1112                                 menu_driver(curses_menu, REQ_UP_ITEM);
1113                                 break;
1114                         case KEY_NPAGE:
1115                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1116                                 break;
1117                         case KEY_PPAGE:
1118                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1119                                 break;
1120                         case KEY_HOME:
1121                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1122                                 break;
1123                         case KEY_END:
1124                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1125                                 break;
1126                         case 'h':
1127                         case '?':
1128                                 show_help((struct menu *) item_data());
1129                                 break;
1130                         }
1131                         if (res == 10 || res == 27 ||
1132                                 res == 32 || res == 'n' || res == 'y' ||
1133                                 res == KEY_LEFT || res == KEY_RIGHT ||
1134                                 res == 'm')
1135                                 break;
1136                         refresh_all_windows(main_window);
1137                 }
1138
1139                 refresh_all_windows(main_window);
1140                 /* if ESC or left*/
1141                 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1142                         break;
1143
1144                 /* remember location in the menu */
1145                 last_top_row = top_row(curses_menu);
1146                 current_index = curses_item_index();
1147
1148                 if (!item_tag())
1149                         continue;
1150
1151                 submenu = (struct menu *) item_data();
1152                 if (!submenu || !menu_is_visible(submenu))
1153                         continue;
1154                 sym = submenu->sym;
1155
1156                 switch (res) {
1157                 case ' ':
1158                         if (item_is_tag('t'))
1159                                 sym_toggle_tristate_value(sym);
1160                         else if (item_is_tag('m'))
1161                                 conf(submenu);
1162                         break;
1163                 case KEY_RIGHT:
1164                 case 10: /* ENTER WAS PRESSED */
1165                         switch (item_tag()) {
1166                         case 'm':
1167                                 if (single_menu_mode)
1168                                         submenu->data =
1169                                                 (void *) (long) !submenu->data;
1170                                 else
1171                                         conf(submenu);
1172                                 break;
1173                         case 't':
1174                                 if (sym_is_choice(sym) &&
1175                                     sym_get_tristate_value(sym) == yes)
1176                                         conf_choice(submenu);
1177                                 else if (submenu->prompt &&
1178                                          submenu->prompt->type == P_MENU)
1179                                         conf(submenu);
1180                                 else if (res == 10)
1181                                         sym_toggle_tristate_value(sym);
1182                                 break;
1183                         case 's':
1184                                 conf_string(submenu);
1185                                 break;
1186                         }
1187                         break;
1188                 case 'y':
1189                         if (item_is_tag('t')) {
1190                                 if (sym_set_tristate_value(sym, yes))
1191                                         break;
1192                                 if (sym_set_tristate_value(sym, mod))
1193                                         btn_dialog(main_window, setmod_text, 0);
1194                         }
1195                         break;
1196                 case 'n':
1197                         if (item_is_tag('t'))
1198                                 sym_set_tristate_value(sym, no);
1199                         break;
1200                 case 'm':
1201                         if (item_is_tag('t'))
1202                                 sym_set_tristate_value(sym, mod);
1203                         break;
1204                 }
1205         }
1206 }
1207
1208 static void conf_message_callback(const char *fmt, va_list ap)
1209 {
1210         char buf[1024];
1211
1212         vsnprintf(buf, sizeof(buf), fmt, ap);
1213         btn_dialog(main_window, buf, 1, "<OK>");
1214 }
1215
1216 static void show_help(struct menu *menu)
1217 {
1218         struct gstr help;
1219
1220         if (!menu)
1221                 return;
1222
1223         help = str_new();
1224         menu_get_ext_help(menu, &help);
1225         show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1226         str_free(&help);
1227 }
1228
1229 static void conf_choice(struct menu *menu)
1230 {
1231         const char *prompt = _(menu_get_prompt(menu));
1232         struct menu *child = 0;
1233         struct symbol *active;
1234         int selected_index = 0;
1235         int last_top_row = 0;
1236         int res, i = 0;
1237         struct match_state match_state = {
1238                 .in_search = 0,
1239                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1240                 .pattern = "",
1241         };
1242
1243         active = sym_get_choice_value(menu->sym);
1244         /* this is mostly duplicated from the conf() function. */
1245         while (!global_exit) {
1246                 reset_menu();
1247
1248                 for (i = 0, child = menu->list; child; child = child->next) {
1249                         if (!show_all_items && !menu_is_visible(child))
1250                                 continue;
1251
1252                         if (child->sym == sym_get_choice_value(menu->sym))
1253                                 item_make(child, ':', "<X> %s",
1254                                                 _(menu_get_prompt(child)));
1255                         else if (child->sym)
1256                                 item_make(child, ':', "    %s",
1257                                                 _(menu_get_prompt(child)));
1258                         else
1259                                 item_make(child, ':', "*** %s ***",
1260                                                 _(menu_get_prompt(child)));
1261
1262                         if (child->sym == active){
1263                                 last_top_row = top_row(curses_menu);
1264                                 selected_index = i;
1265                         }
1266                         i++;
1267                 }
1268                 show_menu(prompt ? _(prompt) : _("Choice Menu"),
1269                                 _(radiolist_instructions),
1270                                 selected_index,
1271                                 &last_top_row);
1272                 while (!global_exit) {
1273                         if (match_state.in_search) {
1274                                 mvprintw(0, 0, "searching: %s",
1275                                          match_state.pattern);
1276                                 clrtoeol();
1277                         }
1278                         refresh_all_windows(main_window);
1279                         res = wgetch(menu_win(curses_menu));
1280                         if (!res)
1281                                 break;
1282                         if (do_match(res, &match_state, &selected_index) == 0) {
1283                                 if (selected_index != -1)
1284                                         center_item(selected_index,
1285                                                     &last_top_row);
1286                                 continue;
1287                         }
1288                         if (process_special_keys(
1289                                                 &res,
1290                                                 (struct menu *) item_data()))
1291                                 break;
1292                         switch (res) {
1293                         case KEY_DOWN:
1294                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1295                                 break;
1296                         case KEY_UP:
1297                                 menu_driver(curses_menu, REQ_UP_ITEM);
1298                                 break;
1299                         case KEY_NPAGE:
1300                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1301                                 break;
1302                         case KEY_PPAGE:
1303                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1304                                 break;
1305                         case KEY_HOME:
1306                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1307                                 break;
1308                         case KEY_END:
1309                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1310                                 break;
1311                         case 'h':
1312                         case '?':
1313                                 show_help((struct menu *) item_data());
1314                                 break;
1315                         }
1316                         if (res == 10 || res == 27 || res == ' ' ||
1317                                         res == KEY_LEFT){
1318                                 break;
1319                         }
1320                         refresh_all_windows(main_window);
1321                 }
1322                 /* if ESC or left */
1323                 if (res == 27 || res == KEY_LEFT)
1324                         break;
1325
1326                 child = item_data();
1327                 if (!child || !menu_is_visible(child) || !child->sym)
1328                         continue;
1329                 switch (res) {
1330                 case ' ':
1331                 case  10:
1332                 case KEY_RIGHT:
1333                         sym_set_tristate_value(child->sym, yes);
1334                         return;
1335                 case 'h':
1336                 case '?':
1337                         show_help(child);
1338                         active = child->sym;
1339                         break;
1340                 case KEY_EXIT:
1341                         return;
1342                 }
1343         }
1344 }
1345
1346 static void conf_string(struct menu *menu)
1347 {
1348         const char *prompt = menu_get_prompt(menu);
1349         char dialog_input_result[256];
1350
1351         while (1) {
1352                 int res;
1353                 const char *heading;
1354
1355                 switch (sym_get_type(menu->sym)) {
1356                 case S_INT:
1357                         heading = _(inputbox_instructions_int);
1358                         break;
1359                 case S_HEX:
1360                         heading = _(inputbox_instructions_hex);
1361                         break;
1362                 case S_STRING:
1363                         heading = _(inputbox_instructions_string);
1364                         break;
1365                 default:
1366                         heading = _("Internal nconf error!");
1367                 }
1368                 res = dialog_inputbox(main_window,
1369                                 prompt ? _(prompt) : _("Main Menu"),
1370                                 heading,
1371                                 sym_get_string_value(menu->sym),
1372                                 dialog_input_result,
1373                                 sizeof(dialog_input_result));
1374                 switch (res) {
1375                 case 0:
1376                         if (sym_set_string_value(menu->sym,
1377                                                 dialog_input_result))
1378                                 return;
1379                         btn_dialog(main_window,
1380                                 _("You have made an invalid entry."), 0);
1381                         break;
1382                 case 1:
1383                         show_help(menu);
1384                         break;
1385                 case KEY_EXIT:
1386                         return;
1387                 }
1388         }
1389 }
1390
1391 static void conf_load(void)
1392 {
1393         char dialog_input_result[256];
1394         while (1) {
1395                 int res;
1396                 res = dialog_inputbox(main_window,
1397                                 NULL, load_config_text,
1398                                 filename,
1399                                 dialog_input_result,
1400                                 sizeof(dialog_input_result));
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         char dialog_input_result[256];
1426         while (1) {
1427                 int res;
1428                 res = dialog_inputbox(main_window,
1429                                 NULL, save_config_text,
1430                                 filename,
1431                                 dialog_input_result,
1432                                 sizeof(dialog_input_result));
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 void setup_windows(void)
1458 {
1459         if (main_window != NULL)
1460                 delwin(main_window);
1461
1462         /* set up the menu and menu window */
1463         main_window = newwin(LINES-2, COLS-2, 2, 1);
1464         keypad(main_window, TRUE);
1465         mwin_max_lines = LINES-7;
1466         mwin_max_cols = COLS-6;
1467
1468         /* panels order is from bottom to top */
1469         new_panel(main_window);
1470 }
1471
1472 int main(int ac, char **av)
1473 {
1474         char *mode;
1475
1476         setlocale(LC_ALL, "");
1477         bindtextdomain(PACKAGE, LOCALEDIR);
1478         textdomain(PACKAGE);
1479
1480         conf_parse(av[1]);
1481         conf_read(NULL);
1482
1483         mode = getenv("NCONFIG_MODE");
1484         if (mode) {
1485                 if (!strcasecmp(mode, "single_menu"))
1486                         single_menu_mode = 1;
1487         }
1488
1489         /* Initialize curses */
1490         initscr();
1491         /* set color theme */
1492         set_colors();
1493
1494         cbreak();
1495         noecho();
1496         keypad(stdscr, TRUE);
1497         curs_set(0);
1498
1499         if (COLS < 75 || LINES < 20) {
1500                 endwin();
1501                 printf("Your terminal should have at "
1502                         "least 20 lines and 75 columns\n");
1503                 return 1;
1504         }
1505
1506         notimeout(stdscr, FALSE);
1507         ESCDELAY = 1;
1508
1509         /* set btns menu */
1510         curses_menu = new_menu(curses_menu_items);
1511         menu_opts_off(curses_menu, O_SHOWDESC);
1512         menu_opts_on(curses_menu, O_SHOWMATCH);
1513         menu_opts_on(curses_menu, O_ONEVALUE);
1514         menu_opts_on(curses_menu, O_NONCYCLIC);
1515         menu_opts_on(curses_menu, O_IGNORECASE);
1516         set_menu_mark(curses_menu, " ");
1517         set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1518         set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1519         set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1520
1521         set_config_filename(conf_get_configname());
1522         setup_windows();
1523
1524         /* check for KEY_FUNC(1) */
1525         if (has_key(KEY_F(1)) == FALSE) {
1526                 show_scroll_win(main_window,
1527                                 _("Instructions"),
1528                                 _(menu_no_f_instructions));
1529         }
1530
1531         conf_set_message_callback(conf_message_callback);
1532         /* do the work */
1533         while (!global_exit) {
1534                 conf(&rootmenu);
1535                 if (!global_exit && do_exit() == 0)
1536                         break;
1537         }
1538         /* ok, we are done */
1539         unpost_menu(curses_menu);
1540         free_menu(curses_menu);
1541         delwin(main_window);
1542         clear();
1543         refresh();
1544         endwin();
1545         return 0;
1546 }
1547