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