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