GNU Linux-libre 6.1.90-gnu
[releases.git] / scripts / kconfig / nconf.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
4  *
5  * Derived from menuconfig.
6  */
7 #ifndef _GNU_SOURCE
8 #define _GNU_SOURCE
9 #endif
10 #include <string.h>
11 #include <strings.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[] =
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>    <k>\n"
56 "Linewise down               <Down>  <j>\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[] =
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[] =
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[] =
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[] =
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[] =
177 "Please enter a hexadecimal value.\n"
178 "Press <Enter> to apply, <Esc> to cancel.",
179 inputbox_instructions_string[] =
180 "Please enter a string value.\n"
181 "Press <Enter> to apply, <Esc> to cancel.",
182 setmod_text[] =
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[] =
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[] =
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[] =
199 "Enter a filename to which this configuration should be saved\n"
200 "as an alternate.  Leave empty to abort.",
201 save_config_help[] =
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[] =
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 unsigned int items_num;
272 static int global_exit;
273 /* the currently selected button */
274 static 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 static 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                 wattrset(main_window, attr_function_highlight);
374                 mvwprintw(main_window, lines-3, offset,
375                                 "%s",
376                                 function_keys[i].key_str);
377                 wattrset(main_window, attr_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         wattrset(main_window, attr_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, index;
500
501         /* Do not search if the menu is empty (i.e. items_num == 0) */
502         match_start = item_index(current_item(curses_menu));
503         if (match_start == ERR)
504                 return -1;
505
506         if (flag == FIND_NEXT_MATCH_DOWN)
507                 ++match_start;
508         else if (flag == FIND_NEXT_MATCH_UP)
509                 --match_start;
510
511         match_start = (match_start + items_num) % items_num;
512         index = match_start;
513         while (true) {
514                 char *str = k_menu_items[index].str;
515                 if (strcasestr(str, match_str) != NULL)
516                         return index;
517                 if (flag == FIND_NEXT_MATCH_UP ||
518                     flag == MATCH_TINKER_PATTERN_UP)
519                         --index;
520                 else
521                         ++index;
522                 index = (index + items_num) % items_num;
523                 if (index == match_start)
524                         return -1;
525         }
526 }
527
528 /* Make a new item. */
529 static void item_make(struct menu *menu, char tag, const char *fmt, ...)
530 {
531         va_list ap;
532
533         if (items_num > MAX_MENU_ITEMS-1)
534                 return;
535
536         bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
537         k_menu_items[items_num].tag = tag;
538         k_menu_items[items_num].usrptr = menu;
539         if (menu != NULL)
540                 k_menu_items[items_num].is_visible =
541                         menu_is_visible(menu);
542         else
543                 k_menu_items[items_num].is_visible = 1;
544
545         va_start(ap, fmt);
546         vsnprintf(k_menu_items[items_num].str,
547                   sizeof(k_menu_items[items_num].str),
548                   fmt, ap);
549         va_end(ap);
550
551         if (!k_menu_items[items_num].is_visible)
552                 memcpy(k_menu_items[items_num].str, "XXX", 3);
553
554         curses_menu_items[items_num] = new_item(
555                         k_menu_items[items_num].str,
556                         k_menu_items[items_num].str);
557         set_item_userptr(curses_menu_items[items_num],
558                         &k_menu_items[items_num]);
559         /*
560         if (!k_menu_items[items_num].is_visible)
561                 item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
562         */
563
564         items_num++;
565         curses_menu_items[items_num] = NULL;
566 }
567
568 /* very hackish. adds a string to the last item added */
569 static void item_add_str(const char *fmt, ...)
570 {
571         va_list ap;
572         int index = items_num-1;
573         char new_str[256];
574         char tmp_str[256];
575
576         if (index < 0)
577                 return;
578
579         va_start(ap, fmt);
580         vsnprintf(new_str, sizeof(new_str), fmt, ap);
581         va_end(ap);
582         snprintf(tmp_str, sizeof(tmp_str), "%s%s",
583                         k_menu_items[index].str, new_str);
584         strncpy(k_menu_items[index].str,
585                 tmp_str,
586                 sizeof(k_menu_items[index].str));
587
588         free_item(curses_menu_items[index]);
589         curses_menu_items[index] = new_item(
590                         k_menu_items[index].str,
591                         k_menu_items[index].str);
592         set_item_userptr(curses_menu_items[index],
593                         &k_menu_items[index]);
594 }
595
596 /* get the tag of the currently selected item */
597 static char item_tag(void)
598 {
599         ITEM *cur;
600         struct mitem *mcur;
601
602         cur = current_item(curses_menu);
603         if (cur == NULL)
604                 return 0;
605         mcur = (struct mitem *) item_userptr(cur);
606         return mcur->tag;
607 }
608
609 static int curses_item_index(void)
610 {
611         return  item_index(current_item(curses_menu));
612 }
613
614 static void *item_data(void)
615 {
616         ITEM *cur;
617         struct mitem *mcur;
618
619         cur = current_item(curses_menu);
620         if (!cur)
621                 return NULL;
622         mcur = (struct mitem *) item_userptr(cur);
623         return mcur->usrptr;
624
625 }
626
627 static int item_is_tag(char tag)
628 {
629         return item_tag() == tag;
630 }
631
632 static char filename[PATH_MAX+1];
633 static char menu_backtitle[PATH_MAX+128];
634 static void set_config_filename(const char *config_filename)
635 {
636         snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
637                  config_filename, rootmenu.prompt->text);
638
639         snprintf(filename, sizeof(filename), "%s", config_filename);
640 }
641
642 /* return = 0 means we are successful.
643  * -1 means go on doing what you were doing
644  */
645 static int do_exit(void)
646 {
647         int res;
648         if (!conf_get_changed()) {
649                 global_exit = 1;
650                 return 0;
651         }
652         res = btn_dialog(main_window,
653                         "Do you wish to save your new configuration?\n"
654                                 "<ESC> to cancel and resume nconfig.",
655                         2,
656                         "   <save>   ",
657                         "<don't save>");
658         if (res == KEY_EXIT) {
659                 global_exit = 0;
660                 return -1;
661         }
662
663         /* if we got here, the user really wants to exit */
664         switch (res) {
665         case 0:
666                 res = conf_write(filename);
667                 if (res)
668                         btn_dialog(
669                                 main_window,
670                                 "Error during writing of configuration.\n"
671                                   "Your configuration changes were NOT saved.",
672                                   1,
673                                   "<OK>");
674                 conf_write_autoconf(0);
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                                 if (single_menu_mode) {
756                                         item_make(menu, 'm',
757                                                 "%s%*c%s",
758                                                 menu->data ? "-->" : "++>",
759                                                 indent + 1, ' ', prompt);
760                                 } else
761                                         item_make(menu, 'm',
762                                                   "   %*c%s  %s",
763                                                   indent + 1, ' ', prompt,
764                                                   menu_is_empty(menu) ? "----" : "--->");
765
766                                 if (single_menu_mode && menu->data)
767                                         goto conf_childs;
768                                 return;
769                         case P_COMMENT:
770                                 if (prompt) {
771                                         child_count++;
772                                         item_make(menu, ':',
773                                                 "   %*c*** %s ***",
774                                                 indent + 1, ' ',
775                                                 prompt);
776                                 }
777                                 break;
778                         default:
779                                 if (prompt) {
780                                         child_count++;
781                                         item_make(menu, ':', "---%*c%s",
782                                                 indent + 1, ' ',
783                                                 prompt);
784                                 }
785                         }
786                 } else
787                         doint = 0;
788                 goto conf_childs;
789         }
790
791         type = sym_get_type(sym);
792         if (sym_is_choice(sym)) {
793                 struct symbol *def_sym = sym_get_choice_value(sym);
794                 struct menu *def_menu = NULL;
795
796                 child_count++;
797                 for (child = menu->list; child; child = child->next) {
798                         if (menu_is_visible(child) && child->sym == def_sym)
799                                 def_menu = child;
800                 }
801
802                 val = sym_get_tristate_value(sym);
803                 if (sym_is_changeable(sym)) {
804                         switch (type) {
805                         case S_BOOLEAN:
806                                 item_make(menu, 't', "[%c]",
807                                                 val == no ? ' ' : '*');
808                                 break;
809                         case S_TRISTATE:
810                                 switch (val) {
811                                 case yes:
812                                         ch = '*';
813                                         break;
814                                 case mod:
815                                         ch = 'M';
816                                         break;
817                                 default:
818                                         ch = ' ';
819                                         break;
820                                 }
821                                 item_make(menu, 't', "<%c>", ch);
822                                 break;
823                         }
824                 } else {
825                         item_make(menu, def_menu ? 't' : ':', "   ");
826                 }
827
828                 item_add_str("%*c%s", indent + 1,
829                                 ' ', menu_get_prompt(menu));
830                 if (val == yes) {
831                         if (def_menu) {
832                                 item_add_str(" (%s)",
833                                         menu_get_prompt(def_menu));
834                                 item_add_str("  --->");
835                                 if (def_menu->list) {
836                                         indent += 2;
837                                         build_conf(def_menu);
838                                         indent -= 2;
839                                 }
840                         }
841                         return;
842                 }
843         } else {
844                 if (menu == current_menu) {
845                         item_make(menu, ':',
846                                 "---%*c%s", indent + 1,
847                                 ' ', menu_get_prompt(menu));
848                         goto conf_childs;
849                 }
850                 child_count++;
851                 val = sym_get_tristate_value(sym);
852                 if (sym_is_choice_value(sym) && val == yes) {
853                         item_make(menu, ':', "   ");
854                 } else {
855                         switch (type) {
856                         case S_BOOLEAN:
857                                 if (sym_is_changeable(sym))
858                                         item_make(menu, 't', "[%c]",
859                                                 val == no ? ' ' : '*');
860                                 else
861                                         item_make(menu, 't', "-%c-",
862                                                 val == no ? ' ' : '*');
863                                 break;
864                         case S_TRISTATE:
865                                 switch (val) {
866                                 case yes:
867                                         ch = '*';
868                                         break;
869                                 case mod:
870                                         ch = 'M';
871                                         break;
872                                 default:
873                                         ch = ' ';
874                                         break;
875                                 }
876                                 if (sym_is_changeable(sym)) {
877                                         if (sym->rev_dep.tri == mod)
878                                                 item_make(menu,
879                                                         't', "{%c}", ch);
880                                         else
881                                                 item_make(menu,
882                                                         't', "<%c>", ch);
883                                 } else
884                                         item_make(menu, 't', "-%c-", ch);
885                                 break;
886                         default:
887                                 tmp = 2 + strlen(sym_get_string_value(sym));
888                                 item_make(menu, 's', "    (%s)",
889                                                 sym_get_string_value(sym));
890                                 tmp = indent - tmp + 4;
891                                 if (tmp < 0)
892                                         tmp = 0;
893                                 item_add_str("%*c%s%s", tmp, ' ',
894                                                 menu_get_prompt(menu),
895                                                 (sym_has_value(sym) ||
896                                                  !sym_is_changeable(sym)) ? "" :
897                                                 " (NEW)");
898                                 goto conf_childs;
899                         }
900                 }
901                 item_add_str("%*c%s%s", indent + 1, ' ',
902                                 menu_get_prompt(menu),
903                                 (sym_has_value(sym) || !sym_is_changeable(sym)) ?
904                                 "" : " (NEW)");
905                 if (menu->prompt && menu->prompt->type == P_MENU) {
906                         item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
907                         return;
908                 }
909         }
910
911 conf_childs:
912         indent += doint;
913         for (child = menu->list; child; child = child->next)
914                 build_conf(child);
915         indent -= doint;
916 }
917
918 static void reset_menu(void)
919 {
920         unpost_menu(curses_menu);
921         clean_items();
922 }
923
924 /* adjust the menu to show this item.
925  * prefer not to scroll the menu if possible*/
926 static void center_item(int selected_index, int *last_top_row)
927 {
928         int toprow;
929
930         set_top_row(curses_menu, *last_top_row);
931         toprow = top_row(curses_menu);
932         if (selected_index < toprow ||
933             selected_index >= toprow+mwin_max_lines) {
934                 toprow = max(selected_index-mwin_max_lines/2, 0);
935                 if (toprow >= item_count(curses_menu)-mwin_max_lines)
936                         toprow = item_count(curses_menu)-mwin_max_lines;
937                 set_top_row(curses_menu, toprow);
938         }
939         set_current_item(curses_menu,
940                         curses_menu_items[selected_index]);
941         *last_top_row = toprow;
942         post_menu(curses_menu);
943         refresh_all_windows(main_window);
944 }
945
946 /* this function assumes reset_menu has been called before */
947 static void show_menu(const char *prompt, const char *instructions,
948                 int selected_index, int *last_top_row)
949 {
950         int maxx, maxy;
951         WINDOW *menu_window;
952
953         current_instructions = instructions;
954
955         clear();
956         print_in_middle(stdscr, 1, getmaxx(stdscr),
957                         menu_backtitle,
958                         attr_main_heading);
959
960         wattrset(main_window, attr_main_menu_box);
961         box(main_window, 0, 0);
962         wattrset(main_window, attr_main_menu_heading);
963         mvwprintw(main_window, 0, 3, " %s ", prompt);
964         wattrset(main_window, attr_normal);
965
966         set_menu_items(curses_menu, curses_menu_items);
967
968         /* position the menu at the middle of the screen */
969         scale_menu(curses_menu, &maxy, &maxx);
970         maxx = min(maxx, mwin_max_cols-2);
971         maxy = mwin_max_lines;
972         menu_window = derwin(main_window,
973                         maxy,
974                         maxx,
975                         2,
976                         (mwin_max_cols-maxx)/2);
977         keypad(menu_window, TRUE);
978         set_menu_win(curses_menu, menu_window);
979         set_menu_sub(curses_menu, menu_window);
980
981         /* must reassert this after changing items, otherwise returns to a
982          * default of 16
983          */
984         set_menu_format(curses_menu, maxy, 1);
985         center_item(selected_index, last_top_row);
986         set_menu_format(curses_menu, maxy, 1);
987
988         print_function_line();
989
990         /* Post the menu */
991         post_menu(curses_menu);
992         refresh_all_windows(main_window);
993 }
994
995 static void adj_match_dir(match_f *match_direction)
996 {
997         if (*match_direction == FIND_NEXT_MATCH_DOWN)
998                 *match_direction =
999                         MATCH_TINKER_PATTERN_DOWN;
1000         else if (*match_direction == FIND_NEXT_MATCH_UP)
1001                 *match_direction =
1002                         MATCH_TINKER_PATTERN_UP;
1003         /* else, do no change.. */
1004 }
1005
1006 struct match_state
1007 {
1008         int in_search;
1009         match_f match_direction;
1010         char pattern[256];
1011 };
1012
1013 /* Return 0 means I have handled the key. In such a case, ans should hold the
1014  * item to center, or -1 otherwise.
1015  * Else return -1 .
1016  */
1017 static int do_match(int key, struct match_state *state, int *ans)
1018 {
1019         char c = (char) key;
1020         int terminate_search = 0;
1021         *ans = -1;
1022         if (key == '/' || (state->in_search && key == 27)) {
1023                 move(0, 0);
1024                 refresh();
1025                 clrtoeol();
1026                 state->in_search = 1-state->in_search;
1027                 bzero(state->pattern, sizeof(state->pattern));
1028                 state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1029                 return 0;
1030         } else if (!state->in_search)
1031                 return 1;
1032
1033         if (isalnum(c) || isgraph(c) || c == ' ') {
1034                 state->pattern[strlen(state->pattern)] = c;
1035                 state->pattern[strlen(state->pattern)] = '\0';
1036                 adj_match_dir(&state->match_direction);
1037                 *ans = get_mext_match(state->pattern,
1038                                 state->match_direction);
1039         } else if (key == KEY_DOWN) {
1040                 state->match_direction = FIND_NEXT_MATCH_DOWN;
1041                 *ans = get_mext_match(state->pattern,
1042                                 state->match_direction);
1043         } else if (key == KEY_UP) {
1044                 state->match_direction = FIND_NEXT_MATCH_UP;
1045                 *ans = get_mext_match(state->pattern,
1046                                 state->match_direction);
1047         } else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
1048                 state->pattern[strlen(state->pattern)-1] = '\0';
1049                 adj_match_dir(&state->match_direction);
1050         } else
1051                 terminate_search = 1;
1052
1053         if (terminate_search) {
1054                 state->in_search = 0;
1055                 bzero(state->pattern, sizeof(state->pattern));
1056                 move(0, 0);
1057                 refresh();
1058                 clrtoeol();
1059                 return -1;
1060         }
1061         return 0;
1062 }
1063
1064 static void conf(struct menu *menu)
1065 {
1066         struct menu *submenu = NULL;
1067         struct symbol *sym;
1068         int res;
1069         int current_index = 0;
1070         int last_top_row = 0;
1071         struct match_state match_state = {
1072                 .in_search = 0,
1073                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1074                 .pattern = "",
1075         };
1076
1077         while (!global_exit) {
1078                 reset_menu();
1079                 current_menu = menu;
1080                 build_conf(menu);
1081                 if (!child_count)
1082                         break;
1083
1084                 show_menu(menu_get_prompt(menu), menu_instructions,
1085                           current_index, &last_top_row);
1086                 keypad((menu_win(curses_menu)), TRUE);
1087                 while (!global_exit) {
1088                         if (match_state.in_search) {
1089                                 mvprintw(0, 0,
1090                                         "searching: %s", match_state.pattern);
1091                                 clrtoeol();
1092                         }
1093                         refresh_all_windows(main_window);
1094                         res = wgetch(menu_win(curses_menu));
1095                         if (!res)
1096                                 break;
1097                         if (do_match(res, &match_state, &current_index) == 0) {
1098                                 if (current_index != -1)
1099                                         center_item(current_index,
1100                                                     &last_top_row);
1101                                 continue;
1102                         }
1103                         if (process_special_keys(&res,
1104                                                 (struct menu *) item_data()))
1105                                 break;
1106                         switch (res) {
1107                         case KEY_DOWN:
1108                         case 'j':
1109                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1110                                 break;
1111                         case KEY_UP:
1112                         case 'k':
1113                                 menu_driver(curses_menu, REQ_UP_ITEM);
1114                                 break;
1115                         case KEY_NPAGE:
1116                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1117                                 break;
1118                         case KEY_PPAGE:
1119                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1120                                 break;
1121                         case KEY_HOME:
1122                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1123                                 break;
1124                         case KEY_END:
1125                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1126                                 break;
1127                         case 'h':
1128                         case '?':
1129                                 show_help((struct menu *) item_data());
1130                                 break;
1131                         }
1132                         if (res == 10 || res == 27 ||
1133                                 res == 32 || res == 'n' || res == 'y' ||
1134                                 res == KEY_LEFT || res == KEY_RIGHT ||
1135                                 res == 'm')
1136                                 break;
1137                         refresh_all_windows(main_window);
1138                 }
1139
1140                 refresh_all_windows(main_window);
1141                 /* if ESC or left*/
1142                 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1143                         break;
1144
1145                 /* remember location in the menu */
1146                 last_top_row = top_row(curses_menu);
1147                 current_index = curses_item_index();
1148
1149                 if (!item_tag())
1150                         continue;
1151
1152                 submenu = (struct menu *) item_data();
1153                 if (!submenu || !menu_is_visible(submenu))
1154                         continue;
1155                 sym = submenu->sym;
1156
1157                 switch (res) {
1158                 case ' ':
1159                         if (item_is_tag('t'))
1160                                 sym_toggle_tristate_value(sym);
1161                         else if (item_is_tag('m'))
1162                                 conf(submenu);
1163                         break;
1164                 case KEY_RIGHT:
1165                 case 10: /* ENTER WAS PRESSED */
1166                         switch (item_tag()) {
1167                         case 'm':
1168                                 if (single_menu_mode)
1169                                         submenu->data =
1170                                                 (void *) (long) !submenu->data;
1171                                 else
1172                                         conf(submenu);
1173                                 break;
1174                         case 't':
1175                                 if (sym_is_choice(sym) &&
1176                                     sym_get_tristate_value(sym) == yes)
1177                                         conf_choice(submenu);
1178                                 else if (submenu->prompt &&
1179                                          submenu->prompt->type == P_MENU)
1180                                         conf(submenu);
1181                                 else if (res == 10)
1182                                         sym_toggle_tristate_value(sym);
1183                                 break;
1184                         case 's':
1185                                 conf_string(submenu);
1186                                 break;
1187                         }
1188                         break;
1189                 case 'y':
1190                         if (item_is_tag('t')) {
1191                                 if (sym_set_tristate_value(sym, yes))
1192                                         break;
1193                                 if (sym_set_tristate_value(sym, mod))
1194                                         btn_dialog(main_window, setmod_text, 0);
1195                         }
1196                         break;
1197                 case 'n':
1198                         if (item_is_tag('t'))
1199                                 sym_set_tristate_value(sym, no);
1200                         break;
1201                 case 'm':
1202                         if (item_is_tag('t'))
1203                                 sym_set_tristate_value(sym, mod);
1204                         break;
1205                 }
1206         }
1207 }
1208
1209 static void conf_message_callback(const char *s)
1210 {
1211         btn_dialog(main_window, s, 1, "<OK>");
1212 }
1213
1214 static void show_help(struct menu *menu)
1215 {
1216         struct gstr help;
1217
1218         if (!menu)
1219                 return;
1220
1221         help = str_new();
1222         menu_get_ext_help(menu, &help);
1223         show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help));
1224         str_free(&help);
1225 }
1226
1227 static void conf_choice(struct menu *menu)
1228 {
1229         const char *prompt = menu_get_prompt(menu);
1230         struct menu *child = NULL;
1231         struct symbol *active;
1232         int selected_index = 0;
1233         int last_top_row = 0;
1234         int res, i = 0;
1235         struct match_state match_state = {
1236                 .in_search = 0,
1237                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1238                 .pattern = "",
1239         };
1240
1241         active = sym_get_choice_value(menu->sym);
1242         /* this is mostly duplicated from the conf() function. */
1243         while (!global_exit) {
1244                 reset_menu();
1245
1246                 for (i = 0, child = menu->list; child; child = child->next) {
1247                         if (!show_all_items && !menu_is_visible(child))
1248                                 continue;
1249
1250                         if (child->sym == sym_get_choice_value(menu->sym))
1251                                 item_make(child, ':', "<X> %s",
1252                                                 menu_get_prompt(child));
1253                         else if (child->sym)
1254                                 item_make(child, ':', "    %s",
1255                                                 menu_get_prompt(child));
1256                         else
1257                                 item_make(child, ':', "*** %s ***",
1258                                                 menu_get_prompt(child));
1259
1260                         if (child->sym == active){
1261                                 last_top_row = top_row(curses_menu);
1262                                 selected_index = i;
1263                         }
1264                         i++;
1265                 }
1266                 show_menu(prompt ? prompt : "Choice Menu",
1267                                 radiolist_instructions,
1268                                 selected_index,
1269                                 &last_top_row);
1270                 while (!global_exit) {
1271                         if (match_state.in_search) {
1272                                 mvprintw(0, 0, "searching: %s",
1273                                          match_state.pattern);
1274                                 clrtoeol();
1275                         }
1276                         refresh_all_windows(main_window);
1277                         res = wgetch(menu_win(curses_menu));
1278                         if (!res)
1279                                 break;
1280                         if (do_match(res, &match_state, &selected_index) == 0) {
1281                                 if (selected_index != -1)
1282                                         center_item(selected_index,
1283                                                     &last_top_row);
1284                                 continue;
1285                         }
1286                         if (process_special_keys(
1287                                                 &res,
1288                                                 (struct menu *) item_data()))
1289                                 break;
1290                         switch (res) {
1291                         case KEY_DOWN:
1292                         case 'j':
1293                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1294                                 break;
1295                         case KEY_UP:
1296                         case 'k':
1297                                 menu_driver(curses_menu, REQ_UP_ITEM);
1298                                 break;
1299                         case KEY_NPAGE:
1300                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1301                                 break;
1302                         case KEY_PPAGE:
1303                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1304                                 break;
1305                         case KEY_HOME:
1306                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1307                                 break;
1308                         case KEY_END:
1309                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1310                                 break;
1311                         case 'h':
1312                         case '?':
1313                                 show_help((struct menu *) item_data());
1314                                 break;
1315                         }
1316                         if (res == 10 || res == 27 || res == ' ' ||
1317                                         res == KEY_LEFT){
1318                                 break;
1319                         }
1320                         refresh_all_windows(main_window);
1321                 }
1322                 /* if ESC or left */
1323                 if (res == 27 || res == KEY_LEFT)
1324                         break;
1325
1326                 child = item_data();
1327                 if (!child || !menu_is_visible(child) || !child->sym)
1328                         continue;
1329                 switch (res) {
1330                 case ' ':
1331                 case  10:
1332                 case KEY_RIGHT:
1333                         sym_set_tristate_value(child->sym, yes);
1334                         return;
1335                 case 'h':
1336                 case '?':
1337                         show_help(child);
1338                         active = child->sym;
1339                         break;
1340                 case KEY_EXIT:
1341                         return;
1342                 }
1343         }
1344 }
1345
1346 static void conf_string(struct menu *menu)
1347 {
1348         const char *prompt = menu_get_prompt(menu);
1349
1350         while (1) {
1351                 int res;
1352                 const char *heading;
1353
1354                 switch (sym_get_type(menu->sym)) {
1355                 case S_INT:
1356                         heading = inputbox_instructions_int;
1357                         break;
1358                 case S_HEX:
1359                         heading = inputbox_instructions_hex;
1360                         break;
1361                 case S_STRING:
1362                         heading = inputbox_instructions_string;
1363                         break;
1364                 default:
1365                         heading = "Internal nconf error!";
1366                 }
1367                 res = dialog_inputbox(main_window,
1368                                 prompt ? prompt : "Main Menu",
1369                                 heading,
1370                                 sym_get_string_value(menu->sym),
1371                                 &dialog_input_result,
1372                                 &dialog_input_result_len);
1373                 switch (res) {
1374                 case 0:
1375                         if (sym_set_string_value(menu->sym,
1376                                                 dialog_input_result))
1377                                 return;
1378                         btn_dialog(main_window,
1379                                 "You have made an invalid entry.", 0);
1380                         break;
1381                 case 1:
1382                         show_help(menu);
1383                         break;
1384                 case KEY_EXIT:
1385                         return;
1386                 }
1387         }
1388 }
1389
1390 static void conf_load(void)
1391 {
1392         while (1) {
1393                 int res;
1394                 res = dialog_inputbox(main_window,
1395                                 NULL, load_config_text,
1396                                 filename,
1397                                 &dialog_input_result,
1398                                 &dialog_input_result_len);
1399                 switch (res) {
1400                 case 0:
1401                         if (!dialog_input_result[0])
1402                                 return;
1403                         if (!conf_read(dialog_input_result)) {
1404                                 set_config_filename(dialog_input_result);
1405                                 conf_set_changed(true);
1406                                 return;
1407                         }
1408                         btn_dialog(main_window, "File does not exist!", 0);
1409                         break;
1410                 case 1:
1411                         show_scroll_win(main_window,
1412                                         "Load Alternate Configuration",
1413                                         load_config_help);
1414                         break;
1415                 case KEY_EXIT:
1416                         return;
1417                 }
1418         }
1419 }
1420
1421 static void conf_save(void)
1422 {
1423         while (1) {
1424                 int res;
1425                 res = dialog_inputbox(main_window,
1426                                 NULL, save_config_text,
1427                                 filename,
1428                                 &dialog_input_result,
1429                                 &dialog_input_result_len);
1430                 switch (res) {
1431                 case 0:
1432                         if (!dialog_input_result[0])
1433                                 return;
1434                         res = conf_write(dialog_input_result);
1435                         if (!res) {
1436                                 set_config_filename(dialog_input_result);
1437                                 return;
1438                         }
1439                         btn_dialog(main_window, "Can't create file!",
1440                                 1, "<OK>");
1441                         break;
1442                 case 1:
1443                         show_scroll_win(main_window,
1444                                 "Save Alternate Configuration",
1445                                 save_config_help);
1446                         break;
1447                 case KEY_EXIT:
1448                         return;
1449                 }
1450         }
1451 }
1452
1453 static void setup_windows(void)
1454 {
1455         int lines, columns;
1456
1457         getmaxyx(stdscr, lines, columns);
1458
1459         if (main_window != NULL)
1460                 delwin(main_window);
1461
1462         /* set up the menu and menu window */
1463         main_window = newwin(lines-2, columns-2, 2, 1);
1464         keypad(main_window, TRUE);
1465         mwin_max_lines = lines-7;
1466         mwin_max_cols = columns-6;
1467
1468         /* panels order is from bottom to top */
1469         new_panel(main_window);
1470 }
1471
1472 int main(int ac, char **av)
1473 {
1474         int lines, columns;
1475         char *mode;
1476
1477         if (ac > 1 && strcmp(av[1], "-s") == 0) {
1478                 /* Silence conf_read() until the real callback is set up */
1479                 conf_set_message_callback(NULL);
1480                 av++;
1481         }
1482         conf_parse(av[1]);
1483         conf_read(NULL);
1484
1485         mode = getenv("NCONFIG_MODE");
1486         if (mode) {
1487                 if (!strcasecmp(mode, "single_menu"))
1488                         single_menu_mode = 1;
1489         }
1490
1491         /* Initialize curses */
1492         initscr();
1493         /* set color theme */
1494         set_colors();
1495
1496         cbreak();
1497         noecho();
1498         keypad(stdscr, TRUE);
1499         curs_set(0);
1500
1501         getmaxyx(stdscr, lines, columns);
1502         if (columns < 75 || lines < 20) {
1503                 endwin();
1504                 printf("Your terminal should have at "
1505                         "least 20 lines and 75 columns\n");
1506                 return 1;
1507         }
1508
1509         notimeout(stdscr, FALSE);
1510 #if NCURSES_REENTRANT
1511         set_escdelay(1);
1512 #else
1513         ESCDELAY = 1;
1514 #endif
1515
1516         /* set btns menu */
1517         curses_menu = new_menu(curses_menu_items);
1518         menu_opts_off(curses_menu, O_SHOWDESC);
1519         menu_opts_on(curses_menu, O_SHOWMATCH);
1520         menu_opts_on(curses_menu, O_ONEVALUE);
1521         menu_opts_on(curses_menu, O_NONCYCLIC);
1522         menu_opts_on(curses_menu, O_IGNORECASE);
1523         set_menu_mark(curses_menu, " ");
1524         set_menu_fore(curses_menu, attr_main_menu_fore);
1525         set_menu_back(curses_menu, attr_main_menu_back);
1526         set_menu_grey(curses_menu, attr_main_menu_grey);
1527
1528         set_config_filename(conf_get_configname());
1529         setup_windows();
1530
1531         /* check for KEY_FUNC(1) */
1532         if (has_key(KEY_F(1)) == FALSE) {
1533                 show_scroll_win(main_window,
1534                                 "Instructions",
1535                                 menu_no_f_instructions);
1536         }
1537
1538         conf_set_message_callback(conf_message_callback);
1539         /* do the work */
1540         while (!global_exit) {
1541                 conf(&rootmenu);
1542                 if (!global_exit && do_exit() == 0)
1543                         break;
1544         }
1545         /* ok, we are done */
1546         unpost_menu(curses_menu);
1547         free_menu(curses_menu);
1548         delwin(main_window);
1549         clear();
1550         refresh();
1551         endwin();
1552         return 0;
1553 }