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