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