kconfig: Allow frontends to display messages themselves
[pandora-kernel.git] / scripts / kconfig / nconf.c
1 /*
2  * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
3  * Released under the terms of the GNU GPL v2.0.
4  *
5  * Derived from menuconfig.
6  *
7  */
8 #define _GNU_SOURCE
9 #include <string.h>
10 #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 /* return = 0 means we are successful.
655  * -1 means go on doing what you were doing
656  */
657 static int do_exit(void)
658 {
659         int res;
660         if (!conf_get_changed()) {
661                 global_exit = 1;
662                 return 0;
663         }
664         res = btn_dialog(main_window,
665                         _("Do you wish to save your "
666                                 "new kernel configuration?\n"
667                                 "<ESC> to cancel and resume nconfig."),
668                         2,
669                         "   <save>   ",
670                         "<don't save>");
671         if (res == KEY_EXIT) {
672                 global_exit = 0;
673                 return -1;
674         }
675
676         /* if we got here, the user really wants to exit */
677         switch (res) {
678         case 0:
679                 res = conf_write(filename);
680                 if (res)
681                         btn_dialog(
682                                 main_window,
683                                 _("Error during writing of the kernel "
684                                   "configuration.\n"
685                                   "Your kernel configuration "
686                                   "changes were NOT saved."),
687                                   1,
688                                   "<OK>");
689                 break;
690         default:
691                 btn_dialog(
692                         main_window,
693                         _("Your kernel configuration changes were NOT saved."),
694                         1,
695                         "<OK>");
696                 break;
697         }
698         global_exit = 1;
699         return 0;
700 }
701
702
703 static void search_conf(void)
704 {
705         struct symbol **sym_arr;
706         struct gstr res;
707         char dialog_input_result[100];
708         char *dialog_input;
709         int dres;
710 again:
711         dres = dialog_inputbox(main_window,
712                         _("Search Configuration Parameter"),
713                         _("Enter CONFIG_ (sub)string to search for "
714                                 "(with or without \"CONFIG\")"),
715                         "", dialog_input_result, 99);
716         switch (dres) {
717         case 0:
718                 break;
719         case 1:
720                 show_scroll_win(main_window,
721                                 _("Search Configuration"), search_help);
722                 goto again;
723         default:
724                 return;
725         }
726
727         /* strip CONFIG_ if necessary */
728         dialog_input = dialog_input_result;
729         if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
730                 dialog_input += 7;
731
732         sym_arr = sym_re_search(dialog_input);
733         res = get_relations_str(sym_arr);
734         free(sym_arr);
735         show_scroll_win(main_window,
736                         _("Search Results"), str_get(&res));
737         str_free(&res);
738 }
739
740
741 static void build_conf(struct menu *menu)
742 {
743         struct symbol *sym;
744         struct property *prop;
745         struct menu *child;
746         int type, tmp, doint = 2;
747         tristate val;
748         char ch;
749
750         if (!menu || (!show_all_items && !menu_is_visible(menu)))
751                 return;
752
753         sym = menu->sym;
754         prop = menu->prompt;
755         if (!sym) {
756                 if (prop && menu != current_menu) {
757                         const char *prompt = menu_get_prompt(menu);
758                         enum prop_type ptype;
759                         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
760                         switch (ptype) {
761                         case P_MENU:
762                                 child_count++;
763                                 prompt = _(prompt);
764                                 if (single_menu_mode) {
765                                         item_make(menu, 'm',
766                                                 "%s%*c%s",
767                                                 menu->data ? "-->" : "++>",
768                                                 indent + 1, ' ', prompt);
769                                 } else
770                                         item_make(menu, 'm',
771                                                 "   %*c%s  --->",
772                                                 indent + 1,
773                                                 ' ', prompt);
774
775                                 if (single_menu_mode && menu->data)
776                                         goto conf_childs;
777                                 return;
778                         case P_COMMENT:
779                                 if (prompt) {
780                                         child_count++;
781                                         item_make(menu, ':',
782                                                 "   %*c*** %s ***",
783                                                 indent + 1, ' ',
784                                                 _(prompt));
785                                 }
786                                 break;
787                         default:
788                                 if (prompt) {
789                                         child_count++;
790                                         item_make(menu, ':', "---%*c%s",
791                                                 indent + 1, ' ',
792                                                 _(prompt));
793                                 }
794                         }
795                 } else
796                         doint = 0;
797                 goto conf_childs;
798         }
799
800         type = sym_get_type(sym);
801         if (sym_is_choice(sym)) {
802                 struct symbol *def_sym = sym_get_choice_value(sym);
803                 struct menu *def_menu = NULL;
804
805                 child_count++;
806                 for (child = menu->list; child; child = child->next) {
807                         if (menu_is_visible(child) && child->sym == def_sym)
808                                 def_menu = child;
809                 }
810
811                 val = sym_get_tristate_value(sym);
812                 if (sym_is_changable(sym)) {
813                         switch (type) {
814                         case S_BOOLEAN:
815                                 item_make(menu, 't', "[%c]",
816                                                 val == no ? ' ' : '*');
817                                 break;
818                         case S_TRISTATE:
819                                 switch (val) {
820                                 case yes:
821                                         ch = '*';
822                                         break;
823                                 case mod:
824                                         ch = 'M';
825                                         break;
826                                 default:
827                                         ch = ' ';
828                                         break;
829                                 }
830                                 item_make(menu, 't', "<%c>", ch);
831                                 break;
832                         }
833                 } else {
834                         item_make(menu, def_menu ? 't' : ':', "   ");
835                 }
836
837                 item_add_str("%*c%s", indent + 1,
838                                 ' ', _(menu_get_prompt(menu)));
839                 if (val == yes) {
840                         if (def_menu) {
841                                 item_add_str(" (%s)",
842                                         _(menu_get_prompt(def_menu)));
843                                 item_add_str("  --->");
844                                 if (def_menu->list) {
845                                         indent += 2;
846                                         build_conf(def_menu);
847                                         indent -= 2;
848                                 }
849                         }
850                         return;
851                 }
852         } else {
853                 if (menu == current_menu) {
854                         item_make(menu, ':',
855                                 "---%*c%s", indent + 1,
856                                 ' ', _(menu_get_prompt(menu)));
857                         goto conf_childs;
858                 }
859                 child_count++;
860                 val = sym_get_tristate_value(sym);
861                 if (sym_is_choice_value(sym) && val == yes) {
862                         item_make(menu, ':', "   ");
863                 } else {
864                         switch (type) {
865                         case S_BOOLEAN:
866                                 if (sym_is_changable(sym))
867                                         item_make(menu, 't', "[%c]",
868                                                 val == no ? ' ' : '*');
869                                 else
870                                         item_make(menu, 't', "-%c-",
871                                                 val == no ? ' ' : '*');
872                                 break;
873                         case S_TRISTATE:
874                                 switch (val) {
875                                 case yes:
876                                         ch = '*';
877                                         break;
878                                 case mod:
879                                         ch = 'M';
880                                         break;
881                                 default:
882                                         ch = ' ';
883                                         break;
884                                 }
885                                 if (sym_is_changable(sym)) {
886                                         if (sym->rev_dep.tri == mod)
887                                                 item_make(menu,
888                                                         't', "{%c}", ch);
889                                         else
890                                                 item_make(menu,
891                                                         't', "<%c>", ch);
892                                 } else
893                                         item_make(menu, 't', "-%c-", ch);
894                                 break;
895                         default:
896                                 tmp = 2 + strlen(sym_get_string_value(sym));
897                                 item_make(menu, 's', "    (%s)",
898                                                 sym_get_string_value(sym));
899                                 tmp = indent - tmp + 4;
900                                 if (tmp < 0)
901                                         tmp = 0;
902                                 item_add_str("%*c%s%s", tmp, ' ',
903                                                 _(menu_get_prompt(menu)),
904                                                 (sym_has_value(sym) ||
905                                                  !sym_is_changable(sym)) ? "" :
906                                                 _(" (NEW)"));
907                                 goto conf_childs;
908                         }
909                 }
910                 item_add_str("%*c%s%s", indent + 1, ' ',
911                                 _(menu_get_prompt(menu)),
912                                 (sym_has_value(sym) || !sym_is_changable(sym)) ?
913                                 "" : _(" (NEW)"));
914                 if (menu->prompt && menu->prompt->type == P_MENU) {
915                         item_add_str("  --->");
916                         return;
917                 }
918         }
919
920 conf_childs:
921         indent += doint;
922         for (child = menu->list; child; child = child->next)
923                 build_conf(child);
924         indent -= doint;
925 }
926
927 static void reset_menu(void)
928 {
929         unpost_menu(curses_menu);
930         clean_items();
931 }
932
933 /* adjust the menu to show this item.
934  * prefer not to scroll the menu if possible*/
935 static void center_item(int selected_index, int *last_top_row)
936 {
937         int toprow;
938
939         set_top_row(curses_menu, *last_top_row);
940         toprow = top_row(curses_menu);
941         if (selected_index < toprow ||
942             selected_index >= toprow+mwin_max_lines) {
943                 toprow = max(selected_index-mwin_max_lines/2, 0);
944                 if (toprow >= item_count(curses_menu)-mwin_max_lines)
945                         toprow = item_count(curses_menu)-mwin_max_lines;
946                 set_top_row(curses_menu, toprow);
947         }
948         set_current_item(curses_menu,
949                         curses_menu_items[selected_index]);
950         *last_top_row = toprow;
951         post_menu(curses_menu);
952         refresh_all_windows(main_window);
953 }
954
955 /* this function assumes reset_menu has been called before */
956 static void show_menu(const char *prompt, const char *instructions,
957                 int selected_index, int *last_top_row)
958 {
959         int maxx, maxy;
960         WINDOW *menu_window;
961
962         current_instructions = instructions;
963
964         clear();
965         wattrset(main_window, attributes[NORMAL]);
966         print_in_middle(stdscr, 1, 0, COLS,
967                         menu_backtitle,
968                         attributes[MAIN_HEADING]);
969
970         wattrset(main_window, attributes[MAIN_MENU_BOX]);
971         box(main_window, 0, 0);
972         wattrset(main_window, attributes[MAIN_MENU_HEADING]);
973         mvwprintw(main_window, 0, 3, " %s ", prompt);
974         wattrset(main_window, attributes[NORMAL]);
975
976         set_menu_items(curses_menu, curses_menu_items);
977
978         /* position the menu at the middle of the screen */
979         scale_menu(curses_menu, &maxy, &maxx);
980         maxx = min(maxx, mwin_max_cols-2);
981         maxy = mwin_max_lines;
982         menu_window = derwin(main_window,
983                         maxy,
984                         maxx,
985                         2,
986                         (mwin_max_cols-maxx)/2);
987         keypad(menu_window, TRUE);
988         set_menu_win(curses_menu, menu_window);
989         set_menu_sub(curses_menu, menu_window);
990
991         /* must reassert this after changing items, otherwise returns to a
992          * default of 16
993          */
994         set_menu_format(curses_menu, maxy, 1);
995         center_item(selected_index, last_top_row);
996         set_menu_format(curses_menu, maxy, 1);
997
998         print_function_line();
999
1000         /* Post the menu */
1001         post_menu(curses_menu);
1002         refresh_all_windows(main_window);
1003 }
1004
1005 static void adj_match_dir(match_f *match_direction)
1006 {
1007         if (*match_direction == FIND_NEXT_MATCH_DOWN)
1008                 *match_direction =
1009                         MATCH_TINKER_PATTERN_DOWN;
1010         else if (*match_direction == FIND_NEXT_MATCH_UP)
1011                 *match_direction =
1012                         MATCH_TINKER_PATTERN_UP;
1013         /* else, do no change.. */
1014 }
1015
1016 struct match_state
1017 {
1018         int in_search;
1019         match_f match_direction;
1020         char pattern[256];
1021 };
1022
1023 /* Return 0 means I have handled the key. In such a case, ans should hold the
1024  * item to center, or -1 otherwise.
1025  * Else return -1 .
1026  */
1027 static int do_match(int key, struct match_state *state, int *ans)
1028 {
1029         char c = (char) key;
1030         int terminate_search = 0;
1031         *ans = -1;
1032         if (key == '/' || (state->in_search && key == 27)) {
1033                 move(0, 0);
1034                 refresh();
1035                 clrtoeol();
1036                 state->in_search = 1-state->in_search;
1037                 bzero(state->pattern, sizeof(state->pattern));
1038                 state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1039                 return 0;
1040         } else if (!state->in_search)
1041                 return 1;
1042
1043         if (isalnum(c) || isgraph(c) || c == ' ') {
1044                 state->pattern[strlen(state->pattern)] = c;
1045                 state->pattern[strlen(state->pattern)] = '\0';
1046                 adj_match_dir(&state->match_direction);
1047                 *ans = get_mext_match(state->pattern,
1048                                 state->match_direction);
1049         } else if (key == KEY_DOWN) {
1050                 state->match_direction = FIND_NEXT_MATCH_DOWN;
1051                 *ans = get_mext_match(state->pattern,
1052                                 state->match_direction);
1053         } else if (key == KEY_UP) {
1054                 state->match_direction = FIND_NEXT_MATCH_UP;
1055                 *ans = get_mext_match(state->pattern,
1056                                 state->match_direction);
1057         } else if (key == KEY_BACKSPACE || key == 127) {
1058                 state->pattern[strlen(state->pattern)-1] = '\0';
1059                 adj_match_dir(&state->match_direction);
1060         } else
1061                 terminate_search = 1;
1062
1063         if (terminate_search) {
1064                 state->in_search = 0;
1065                 bzero(state->pattern, sizeof(state->pattern));
1066                 move(0, 0);
1067                 refresh();
1068                 clrtoeol();
1069                 return -1;
1070         }
1071         return 0;
1072 }
1073
1074 static void conf(struct menu *menu)
1075 {
1076         struct menu *submenu = 0;
1077         const char *prompt = menu_get_prompt(menu);
1078         struct symbol *sym;
1079         struct menu *active_menu = NULL;
1080         int res;
1081         int current_index = 0;
1082         int last_top_row = 0;
1083         struct match_state match_state = {
1084                 .in_search = 0,
1085                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1086                 .pattern = "",
1087         };
1088
1089         while (!global_exit) {
1090                 reset_menu();
1091                 current_menu = menu;
1092                 build_conf(menu);
1093                 if (!child_count)
1094                         break;
1095
1096                 show_menu(prompt ? _(prompt) : _("Main Menu"),
1097                                 _(menu_instructions),
1098                                 current_index, &last_top_row);
1099                 keypad((menu_win(curses_menu)), TRUE);
1100                 while (!global_exit) {
1101                         if (match_state.in_search) {
1102                                 mvprintw(0, 0,
1103                                         "searching: %s", match_state.pattern);
1104                                 clrtoeol();
1105                         }
1106                         refresh_all_windows(main_window);
1107                         res = wgetch(menu_win(curses_menu));
1108                         if (!res)
1109                                 break;
1110                         if (do_match(res, &match_state, &current_index) == 0) {
1111                                 if (current_index != -1)
1112                                         center_item(current_index,
1113                                                     &last_top_row);
1114                                 continue;
1115                         }
1116                         if (process_special_keys(&res,
1117                                                 (struct menu *) item_data()))
1118                                 break;
1119                         switch (res) {
1120                         case KEY_DOWN:
1121                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1122                                 break;
1123                         case KEY_UP:
1124                                 menu_driver(curses_menu, REQ_UP_ITEM);
1125                                 break;
1126                         case KEY_NPAGE:
1127                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1128                                 break;
1129                         case KEY_PPAGE:
1130                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1131                                 break;
1132                         case KEY_HOME:
1133                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1134                                 break;
1135                         case KEY_END:
1136                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1137                                 break;
1138                         case 'h':
1139                         case '?':
1140                                 show_help((struct menu *) item_data());
1141                                 break;
1142                         }
1143                         if (res == 10 || res == 27 ||
1144                                 res == 32 || res == 'n' || res == 'y' ||
1145                                 res == KEY_LEFT || res == KEY_RIGHT ||
1146                                 res == 'm')
1147                                 break;
1148                         refresh_all_windows(main_window);
1149                 }
1150
1151                 refresh_all_windows(main_window);
1152                 /* if ESC or left*/
1153                 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1154                         break;
1155
1156                 /* remember location in the menu */
1157                 last_top_row = top_row(curses_menu);
1158                 current_index = curses_item_index();
1159
1160                 if (!item_tag())
1161                         continue;
1162
1163                 submenu = (struct menu *) item_data();
1164                 active_menu = (struct menu *)item_data();
1165                 if (!submenu || !menu_is_visible(submenu))
1166                         continue;
1167                 if (submenu)
1168                         sym = submenu->sym;
1169                 else
1170                         sym = NULL;
1171
1172                 switch (res) {
1173                 case ' ':
1174                         if (item_is_tag('t'))
1175                                 sym_toggle_tristate_value(sym);
1176                         else if (item_is_tag('m'))
1177                                 conf(submenu);
1178                         break;
1179                 case KEY_RIGHT:
1180                 case 10: /* ENTER WAS PRESSED */
1181                         switch (item_tag()) {
1182                         case 'm':
1183                                 if (single_menu_mode)
1184                                         submenu->data =
1185                                                 (void *) (long) !submenu->data;
1186                                 else
1187                                         conf(submenu);
1188                                 break;
1189                         case 't':
1190                                 if (sym_is_choice(sym) &&
1191                                     sym_get_tristate_value(sym) == yes)
1192                                         conf_choice(submenu);
1193                                 else if (submenu->prompt &&
1194                                          submenu->prompt->type == P_MENU)
1195                                         conf(submenu);
1196                                 else if (res == 10)
1197                                         sym_toggle_tristate_value(sym);
1198                                 break;
1199                         case 's':
1200                                 conf_string(submenu);
1201                                 break;
1202                         }
1203                         break;
1204                 case 'y':
1205                         if (item_is_tag('t')) {
1206                                 if (sym_set_tristate_value(sym, yes))
1207                                         break;
1208                                 if (sym_set_tristate_value(sym, mod))
1209                                         btn_dialog(main_window, setmod_text, 0);
1210                         }
1211                         break;
1212                 case 'n':
1213                         if (item_is_tag('t'))
1214                                 sym_set_tristate_value(sym, no);
1215                         break;
1216                 case 'm':
1217                         if (item_is_tag('t'))
1218                                 sym_set_tristate_value(sym, mod);
1219                         break;
1220                 }
1221         }
1222 }
1223
1224 static void conf_message_callback(const char *fmt, va_list ap)
1225 {
1226         char buf[1024];
1227
1228         vsnprintf(buf, sizeof(buf), fmt, ap);
1229         btn_dialog(main_window, buf, 1, "<OK>");
1230 }
1231
1232 static void show_help(struct menu *menu)
1233 {
1234         struct gstr help = str_new();
1235
1236         if (menu && menu->sym && menu_has_help(menu)) {
1237                 if (menu->sym->name) {
1238                         str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name);
1239                         str_append(&help, _(menu_get_help(menu)));
1240                         str_append(&help, "\n");
1241                         get_symbol_str(&help, menu->sym);
1242                 }
1243         } else {
1244                 str_append(&help, nohelp_text);
1245         }
1246         show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1247         str_free(&help);
1248 }
1249
1250 static void conf_choice(struct menu *menu)
1251 {
1252         const char *prompt = _(menu_get_prompt(menu));
1253         struct menu *child = 0;
1254         struct symbol *active;
1255         int selected_index = 0;
1256         int last_top_row = 0;
1257         int res, i = 0;
1258         struct match_state match_state = {
1259                 .in_search = 0,
1260                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1261                 .pattern = "",
1262         };
1263
1264         active = sym_get_choice_value(menu->sym);
1265         /* this is mostly duplicated from the conf() function. */
1266         while (!global_exit) {
1267                 reset_menu();
1268
1269                 for (i = 0, child = menu->list; child; child = child->next) {
1270                         if (!show_all_items && !menu_is_visible(child))
1271                                 continue;
1272
1273                         if (child->sym == sym_get_choice_value(menu->sym))
1274                                 item_make(child, ':', "<X> %s",
1275                                                 _(menu_get_prompt(child)));
1276                         else
1277                                 item_make(child, ':', "    %s",
1278                                                 _(menu_get_prompt(child)));
1279                         if (child->sym == active){
1280                                 last_top_row = top_row(curses_menu);
1281                                 selected_index = i;
1282                         }
1283                         i++;
1284                 }
1285                 show_menu(prompt ? _(prompt) : _("Choice Menu"),
1286                                 _(radiolist_instructions),
1287                                 selected_index,
1288                                 &last_top_row);
1289                 while (!global_exit) {
1290                         if (match_state.in_search) {
1291                                 mvprintw(0, 0, "searching: %s",
1292                                          match_state.pattern);
1293                                 clrtoeol();
1294                         }
1295                         refresh_all_windows(main_window);
1296                         res = wgetch(menu_win(curses_menu));
1297                         if (!res)
1298                                 break;
1299                         if (do_match(res, &match_state, &selected_index) == 0) {
1300                                 if (selected_index != -1)
1301                                         center_item(selected_index,
1302                                                     &last_top_row);
1303                                 continue;
1304                         }
1305                         if (process_special_keys(
1306                                                 &res,
1307                                                 (struct menu *) item_data()))
1308                                 break;
1309                         switch (res) {
1310                         case KEY_DOWN:
1311                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1312                                 break;
1313                         case KEY_UP:
1314                                 menu_driver(curses_menu, REQ_UP_ITEM);
1315                                 break;
1316                         case KEY_NPAGE:
1317                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1318                                 break;
1319                         case KEY_PPAGE:
1320                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1321                                 break;
1322                         case KEY_HOME:
1323                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1324                                 break;
1325                         case KEY_END:
1326                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1327                                 break;
1328                         case 'h':
1329                         case '?':
1330                                 show_help((struct menu *) item_data());
1331                                 break;
1332                         }
1333                         if (res == 10 || res == 27 || res == ' ' ||
1334                                         res == KEY_LEFT){
1335                                 break;
1336                         }
1337                         refresh_all_windows(main_window);
1338                 }
1339                 /* if ESC or left */
1340                 if (res == 27 || res == KEY_LEFT)
1341                         break;
1342
1343                 child = item_data();
1344                 if (!child || !menu_is_visible(child))
1345                         continue;
1346                 switch (res) {
1347                 case ' ':
1348                 case  10:
1349                 case KEY_RIGHT:
1350                         sym_set_tristate_value(child->sym, yes);
1351                         return;
1352                 case 'h':
1353                 case '?':
1354                         show_help(child);
1355                         active = child->sym;
1356                         break;
1357                 case KEY_EXIT:
1358                         return;
1359                 }
1360         }
1361 }
1362
1363 static void conf_string(struct menu *menu)
1364 {
1365         const char *prompt = menu_get_prompt(menu);
1366         char dialog_input_result[256];
1367
1368         while (1) {
1369                 int res;
1370                 const char *heading;
1371
1372                 switch (sym_get_type(menu->sym)) {
1373                 case S_INT:
1374                         heading = _(inputbox_instructions_int);
1375                         break;
1376                 case S_HEX:
1377                         heading = _(inputbox_instructions_hex);
1378                         break;
1379                 case S_STRING:
1380                         heading = _(inputbox_instructions_string);
1381                         break;
1382                 default:
1383                         heading = _("Internal nconf error!");
1384                 }
1385                 res = dialog_inputbox(main_window,
1386                                 prompt ? _(prompt) : _("Main Menu"),
1387                                 heading,
1388                                 sym_get_string_value(menu->sym),
1389                                 dialog_input_result,
1390                                 sizeof(dialog_input_result));
1391                 switch (res) {
1392                 case 0:
1393                         if (sym_set_string_value(menu->sym,
1394                                                 dialog_input_result))
1395                                 return;
1396                         btn_dialog(main_window,
1397                                 _("You have made an invalid entry."), 0);
1398                         break;
1399                 case 1:
1400                         show_help(menu);
1401                         break;
1402                 case KEY_EXIT:
1403                         return;
1404                 }
1405         }
1406 }
1407
1408 static void conf_load(void)
1409 {
1410         char dialog_input_result[256];
1411         while (1) {
1412                 int res;
1413                 res = dialog_inputbox(main_window,
1414                                 NULL, load_config_text,
1415                                 filename,
1416                                 dialog_input_result,
1417                                 sizeof(dialog_input_result));
1418                 switch (res) {
1419                 case 0:
1420                         if (!dialog_input_result[0])
1421                                 return;
1422                         if (!conf_read(dialog_input_result)) {
1423                                 set_config_filename(dialog_input_result);
1424                                 sym_set_change_count(1);
1425                                 return;
1426                         }
1427                         btn_dialog(main_window, _("File does not exist!"), 0);
1428                         break;
1429                 case 1:
1430                         show_scroll_win(main_window,
1431                                         _("Load Alternate Configuration"),
1432                                         load_config_help);
1433                         break;
1434                 case KEY_EXIT:
1435                         return;
1436                 }
1437         }
1438 }
1439
1440 static void conf_save(void)
1441 {
1442         char dialog_input_result[256];
1443         while (1) {
1444                 int res;
1445                 res = dialog_inputbox(main_window,
1446                                 NULL, save_config_text,
1447                                 filename,
1448                                 dialog_input_result,
1449                                 sizeof(dialog_input_result));
1450                 switch (res) {
1451                 case 0:
1452                         if (!dialog_input_result[0])
1453                                 return;
1454                         res = conf_write(dialog_input_result);
1455                         if (!res) {
1456                                 set_config_filename(dialog_input_result);
1457                                 return;
1458                         }
1459                         btn_dialog(main_window, _("Can't create file! "
1460                                 "Probably a nonexistent directory."),
1461                                 1, "<OK>");
1462                         break;
1463                 case 1:
1464                         show_scroll_win(main_window,
1465                                 _("Save Alternate Configuration"),
1466                                 save_config_help);
1467                         break;
1468                 case KEY_EXIT:
1469                         return;
1470                 }
1471         }
1472 }
1473
1474 void setup_windows(void)
1475 {
1476         if (main_window != NULL)
1477                 delwin(main_window);
1478
1479         /* set up the menu and menu window */
1480         main_window = newwin(LINES-2, COLS-2, 2, 1);
1481         keypad(main_window, TRUE);
1482         mwin_max_lines = LINES-7;
1483         mwin_max_cols = COLS-6;
1484
1485         /* panels order is from bottom to top */
1486         new_panel(main_window);
1487 }
1488
1489 int main(int ac, char **av)
1490 {
1491         char *mode;
1492
1493         setlocale(LC_ALL, "");
1494         bindtextdomain(PACKAGE, LOCALEDIR);
1495         textdomain(PACKAGE);
1496
1497         conf_parse(av[1]);
1498         conf_read(NULL);
1499
1500         mode = getenv("NCONFIG_MODE");
1501         if (mode) {
1502                 if (!strcasecmp(mode, "single_menu"))
1503                         single_menu_mode = 1;
1504         }
1505
1506         /* Initialize curses */
1507         initscr();
1508         /* set color theme */
1509         set_colors();
1510
1511         cbreak();
1512         noecho();
1513         keypad(stdscr, TRUE);
1514         curs_set(0);
1515
1516         if (COLS < 75 || LINES < 20) {
1517                 endwin();
1518                 printf("Your terminal should have at "
1519                         "least 20 lines and 75 columns\n");
1520                 return 1;
1521         }
1522
1523         notimeout(stdscr, FALSE);
1524         ESCDELAY = 1;
1525
1526         /* set btns menu */
1527         curses_menu = new_menu(curses_menu_items);
1528         menu_opts_off(curses_menu, O_SHOWDESC);
1529         menu_opts_on(curses_menu, O_SHOWMATCH);
1530         menu_opts_on(curses_menu, O_ONEVALUE);
1531         menu_opts_on(curses_menu, O_NONCYCLIC);
1532         menu_opts_on(curses_menu, O_IGNORECASE);
1533         set_menu_mark(curses_menu, " ");
1534         set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1535         set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1536         set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1537
1538         set_config_filename(conf_get_configname());
1539         setup_windows();
1540
1541         /* check for KEY_FUNC(1) */
1542         if (has_key(KEY_F(1)) == FALSE) {
1543                 show_scroll_win(main_window,
1544                                 _("Instructions"),
1545                                 _(menu_no_f_instructions));
1546         }
1547
1548         conf_set_message_callback(conf_message_callback);
1549         /* do the work */
1550         while (!global_exit) {
1551                 conf(&rootmenu);
1552                 if (!global_exit && do_exit() == 0)
1553                         break;
1554         }
1555         /* ok, we are done */
1556         unpost_menu(curses_menu);
1557         free_menu(curses_menu);
1558         delwin(main_window);
1559         clear();
1560         refresh();
1561         endwin();
1562         return 0;
1563 }
1564