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