Merge branch 'kconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/mmarek/kbuild-2.6
[pandora-kernel.git] / scripts / kconfig / nconf.c
1 /*
2  * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
3  * Released under the terms of the GNU GPL v2.0.
4  *
5  * Derived from menuconfig.
6  *
7  */
8 #define _GNU_SOURCE
9 #include <string.h>
10 #define LKC_DIRECT_LINK
11 #include "lkc.h"
12 #include "nconf.h"
13 #include <ctype.h>
14
15 static const char nconf_readme[] = N_(
16 "Overview\n"
17 "--------\n"
18 "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 <SPACE BAR> for those\n"
87 "   who are familiar with less and lynx.\n"
88 "\n"
89 "o  Press <Enter>, <F1>, <F5>, <F7> 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 nohelp_text[] = N_(
186 "There is no help available for this option.\n"),
187 load_config_text[] = N_(
188 "Enter the name of the configuration file you wish to load.\n"
189 "Accept the name shown to restore the configuration you\n"
190 "last retrieved.  Leave blank to abort."),
191 load_config_help[] = N_(
192 "\n"
193 "For various reasons, one may wish to keep several different\n"
194 "configurations available on a single machine.\n"
195 "\n"
196 "If you have saved a previous configuration in a file other than the\n"
197 "default one, entering its name here will allow you to modify that\n"
198 "configuration.\n"
199 "\n"
200 "If you are uncertain, then you have probably never used alternate\n"
201 "configuration files.  You should therefor leave this blank to abort.\n"),
202 save_config_text[] = N_(
203 "Enter a filename to which this configuration should be saved\n"
204 "as an alternate.  Leave blank to abort."),
205 save_config_help[] = N_(
206 "\n"
207 "For various reasons, one may wish to keep different configurations\n"
208 "available on a single machine.\n"
209 "\n"
210 "Entering a file name here will allow you to later retrieve, modify\n"
211 "and use the current configuration as an alternate to whatever\n"
212 "configuration options you have selected at that time.\n"
213 "\n"
214 "If you are uncertain what all this means then you should probably\n"
215 "leave this blank.\n"),
216 search_help[] = N_(
217 "\n"
218 "Search for symbols and display their relations. Regular expressions\n"
219 "are allowed.\n"
220 "Example: search for \"^FOO\"\n"
221 "Result:\n"
222 "-----------------------------------------------------------------\n"
223 "Symbol: FOO [ = m]\n"
224 "Prompt: Foo bus is used to drive the bar HW\n"
225 "Defined at drivers/pci/Kconfig:47\n"
226 "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
227 "Location:\n"
228 "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
229 "    -> PCI support (PCI [ = y])\n"
230 "      -> PCI access mode (<choice> [ = y])\n"
231 "Selects: LIBCRC32\n"
232 "Selected by: BAR\n"
233 "-----------------------------------------------------------------\n"
234 "o The line 'Prompt:' shows the text used in the menu structure for\n"
235 "  this symbol\n"
236 "o The 'Defined at' line tell at what file / line number the symbol\n"
237 "  is defined\n"
238 "o The 'Depends on:' line tell what symbols needs to be defined for\n"
239 "  this symbol to be visible in the menu (selectable)\n"
240 "o The 'Location:' lines tell where in the menu structure this symbol\n"
241 "  is located\n"
242 "    A location followed by a [ = y] indicate that this is a selectable\n"
243 "    menu item - and current value is displayed inside brackets.\n"
244 "o The 'Selects:' line tell what symbol will be automatically\n"
245 "  selected if this symbol is selected (y or m)\n"
246 "o The 'Selected by' line tell what symbol has selected this symbol\n"
247 "\n"
248 "Only relevant lines are shown.\n"
249 "\n\n"
250 "Search examples:\n"
251 "Examples: USB  => find all symbols containing USB\n"
252 "          ^USB => find all symbols starting with USB\n"
253 "          USB$ => find all symbols ending with USB\n"
254 "\n");
255
256 struct mitem {
257         char str[256];
258         char tag;
259         void *usrptr;
260         int is_visible;
261 };
262
263 #define MAX_MENU_ITEMS 4096
264 static int show_all_items;
265 static int indent;
266 static struct menu *current_menu;
267 static int child_count;
268 static int single_menu_mode;
269 /* the window in which all information appears */
270 static WINDOW *main_window;
271 /* the largest size of the menu window */
272 static int mwin_max_lines;
273 static int mwin_max_cols;
274 /* the window in which we show option buttons */
275 static MENU *curses_menu;
276 static ITEM *curses_menu_items[MAX_MENU_ITEMS];
277 static struct mitem k_menu_items[MAX_MENU_ITEMS];
278 static int items_num;
279 static int global_exit;
280 /* the currently selected button */
281 const char *current_instructions = menu_instructions;
282
283 static void conf(struct menu *menu);
284 static void conf_choice(struct menu *menu);
285 static void conf_string(struct menu *menu);
286 static void conf_load(void);
287 static void conf_save(void);
288 static void show_help(struct menu *menu);
289 static int do_exit(void);
290 static void setup_windows(void);
291 static void search_conf(void);
292
293 typedef void (*function_key_handler_t)(int *key, struct menu *menu);
294 static void handle_f1(int *key, struct menu *current_item);
295 static void handle_f2(int *key, struct menu *current_item);
296 static void handle_f3(int *key, struct menu *current_item);
297 static void handle_f4(int *key, struct menu *current_item);
298 static void handle_f5(int *key, struct menu *current_item);
299 static void handle_f6(int *key, struct menu *current_item);
300 static void handle_f7(int *key, struct menu *current_item);
301 static void handle_f8(int *key, struct menu *current_item);
302 static void handle_f9(int *key, struct menu *current_item);
303
304 struct function_keys {
305         const char *key_str;
306         const char *func;
307         function_key key;
308         function_key_handler_t handler;
309 };
310
311 static const int function_keys_num = 9;
312 struct function_keys function_keys[] = {
313         {
314                 .key_str = "F1",
315                 .func = "Help",
316                 .key = F_HELP,
317                 .handler = handle_f1,
318         },
319         {
320                 .key_str = "F2",
321                 .func = "Sym Info",
322                 .key = F_SYMBOL,
323                 .handler = handle_f2,
324         },
325         {
326                 .key_str = "F3",
327                 .func = "Insts",
328                 .key = F_INSTS,
329                 .handler = handle_f3,
330         },
331         {
332                 .key_str = "F4",
333                 .func = "Config",
334                 .key = F_CONF,
335                 .handler = handle_f4,
336         },
337         {
338                 .key_str = "F5",
339                 .func = "Back",
340                 .key = F_BACK,
341                 .handler = handle_f5,
342         },
343         {
344                 .key_str = "F6",
345                 .func = "Save",
346                 .key = F_SAVE,
347                 .handler = handle_f6,
348         },
349         {
350                 .key_str = "F7",
351                 .func = "Load",
352                 .key = F_LOAD,
353                 .handler = handle_f7,
354         },
355         {
356                 .key_str = "F8",
357                 .func = "Sym Search",
358                 .key = F_SEARCH,
359                 .handler = handle_f8,
360         },
361         {
362                 .key_str = "F9",
363                 .func = "Exit",
364                 .key = F_EXIT,
365                 .handler = handle_f9,
366         },
367 };
368
369 static void print_function_line(void)
370 {
371         int i;
372         int offset = 1;
373         const int skip = 1;
374
375         for (i = 0; i < function_keys_num; i++) {
376                 wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
377                 mvwprintw(main_window, LINES-3, offset,
378                                 "%s",
379                                 function_keys[i].key_str);
380                 wattrset(main_window, attributes[FUNCTION_TEXT]);
381                 offset += strlen(function_keys[i].key_str);
382                 mvwprintw(main_window, LINES-3,
383                                 offset, "%s",
384                                 function_keys[i].func);
385                 offset += strlen(function_keys[i].func) + skip;
386         }
387         wattrset(main_window, attributes[NORMAL]);
388 }
389
390 /* help */
391 static void handle_f1(int *key, struct menu *current_item)
392 {
393         show_scroll_win(main_window,
394                         _("README"), _(nconf_readme));
395         return;
396 }
397
398 /* symbole help */
399 static void handle_f2(int *key, struct menu *current_item)
400 {
401         show_help(current_item);
402         return;
403 }
404
405 /* instructions */
406 static void handle_f3(int *key, struct menu *current_item)
407 {
408         show_scroll_win(main_window,
409                         _("Instructions"),
410                         _(current_instructions));
411         return;
412 }
413
414 /* config */
415 static void handle_f4(int *key, struct menu *current_item)
416 {
417         int res = btn_dialog(main_window,
418                         _("Show all symbols?"),
419                         2,
420                         "   <Show All>   ",
421                         "<Don't show all>");
422         if (res == 0)
423                 show_all_items = 1;
424         else if (res == 1)
425                 show_all_items = 0;
426
427         return;
428 }
429
430 /* back */
431 static void handle_f5(int *key, struct menu *current_item)
432 {
433         *key = KEY_LEFT;
434         return;
435 }
436
437 /* save */
438 static void handle_f6(int *key, struct menu *current_item)
439 {
440         conf_save();
441         return;
442 }
443
444 /* load */
445 static void handle_f7(int *key, struct menu *current_item)
446 {
447         conf_load();
448         return;
449 }
450
451 /* search */
452 static void handle_f8(int *key, struct menu *current_item)
453 {
454         search_conf();
455         return;
456 }
457
458 /* exit */
459 static void handle_f9(int *key, struct menu *current_item)
460 {
461         do_exit();
462         return;
463 }
464
465 /* return != 0 to indicate the key was handles */
466 static int process_special_keys(int *key, struct menu *menu)
467 {
468         int i;
469
470         if (*key == KEY_RESIZE) {
471                 setup_windows();
472                 return 1;
473         }
474
475         for (i = 0; i < function_keys_num; i++) {
476                 if (*key == KEY_F(function_keys[i].key) ||
477                     *key == '0' + function_keys[i].key){
478                         function_keys[i].handler(key, menu);
479                         return 1;
480                 }
481         }
482
483         return 0;
484 }
485
486 static void clean_items(void)
487 {
488         int i;
489         for (i = 0; curses_menu_items[i]; i++)
490                 free_item(curses_menu_items[i]);
491         bzero(curses_menu_items, sizeof(curses_menu_items));
492         bzero(k_menu_items, sizeof(k_menu_items));
493         items_num = 0;
494 }
495
496 typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
497         FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
498
499 /* return the index of the matched item, or -1 if no such item exists */
500 static int get_mext_match(const char *match_str, match_f flag)
501 {
502         int match_start = item_index(current_item(curses_menu));
503         int index;
504
505         if (flag == FIND_NEXT_MATCH_DOWN)
506                 ++match_start;
507         else if (flag == FIND_NEXT_MATCH_UP)
508                 --match_start;
509
510         index = match_start;
511         index = (index + items_num) % items_num;
512         while (true) {
513                 char *str = k_menu_items[index].str;
514                 if (strcasestr(str, match_str) != 0)
515                         return index;
516                 if (flag == FIND_NEXT_MATCH_UP ||
517                     flag == MATCH_TINKER_PATTERN_UP)
518                         --index;
519                 else
520                         ++index;
521                 index = (index + items_num) % items_num;
522                 if (index == match_start)
523                         return -1;
524         }
525 }
526
527 /* Make a new item. */
528 static void item_make(struct menu *menu, char tag, const char *fmt, ...)
529 {
530         va_list ap;
531
532         if (items_num > MAX_MENU_ITEMS-1)
533                 return;
534
535         bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
536         k_menu_items[items_num].tag = tag;
537         k_menu_items[items_num].usrptr = menu;
538         if (menu != NULL)
539                 k_menu_items[items_num].is_visible =
540                         menu_is_visible(menu);
541         else
542                 k_menu_items[items_num].is_visible = 1;
543
544         va_start(ap, fmt);
545         vsnprintf(k_menu_items[items_num].str,
546                   sizeof(k_menu_items[items_num].str),
547                   fmt, ap);
548         va_end(ap);
549
550         if (!k_menu_items[items_num].is_visible)
551                 memcpy(k_menu_items[items_num].str, "XXX", 3);
552
553         curses_menu_items[items_num] = new_item(
554                         k_menu_items[items_num].str,
555                         k_menu_items[items_num].str);
556         set_item_userptr(curses_menu_items[items_num],
557                         &k_menu_items[items_num]);
558         /*
559         if (!k_menu_items[items_num].is_visible)
560                 item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
561         */
562
563         items_num++;
564         curses_menu_items[items_num] = NULL;
565 }
566
567 /* very hackish. adds a string to the last item added */
568 static void item_add_str(const char *fmt, ...)
569 {
570         va_list ap;
571         int index = items_num-1;
572         char new_str[256];
573         char tmp_str[256];
574
575         if (index < 0)
576                 return;
577
578         va_start(ap, fmt);
579         vsnprintf(new_str, sizeof(new_str), fmt, ap);
580         va_end(ap);
581         snprintf(tmp_str, sizeof(tmp_str), "%s%s",
582                         k_menu_items[index].str, new_str);
583         strncpy(k_menu_items[index].str,
584                 tmp_str,
585                 sizeof(k_menu_items[index].str));
586
587         free_item(curses_menu_items[index]);
588         curses_menu_items[index] = new_item(
589                         k_menu_items[index].str,
590                         k_menu_items[index].str);
591         set_item_userptr(curses_menu_items[index],
592                         &k_menu_items[index]);
593 }
594
595 /* get the tag of the currently selected item */
596 static char item_tag(void)
597 {
598         ITEM *cur;
599         struct mitem *mcur;
600
601         cur = current_item(curses_menu);
602         if (cur == NULL)
603                 return 0;
604         mcur = (struct mitem *) item_userptr(cur);
605         return mcur->tag;
606 }
607
608 static int curses_item_index(void)
609 {
610         return  item_index(current_item(curses_menu));
611 }
612
613 static void *item_data(void)
614 {
615         ITEM *cur;
616         struct mitem *mcur;
617
618         cur = current_item(curses_menu);
619         if (!cur)
620                 return NULL;
621         mcur = (struct mitem *) item_userptr(cur);
622         return mcur->usrptr;
623
624 }
625
626 static int item_is_tag(char tag)
627 {
628         return item_tag() == tag;
629 }
630
631 static char filename[PATH_MAX+1];
632 static char menu_backtitle[PATH_MAX+128];
633 static const char *set_config_filename(const char *config_filename)
634 {
635         int size;
636
637         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
638                         "%s - %s", config_filename, rootmenu.prompt->text);
639         if (size >= sizeof(menu_backtitle))
640                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
641
642         size = snprintf(filename, sizeof(filename), "%s", config_filename);
643         if (size >= sizeof(filename))
644                 filename[sizeof(filename)-1] = '\0';
645         return menu_backtitle;
646 }
647
648 /* return = 0 means we are successful.
649  * -1 means go on doing what you were doing
650  */
651 static int do_exit(void)
652 {
653         int res;
654         if (!conf_get_changed()) {
655                 global_exit = 1;
656                 return 0;
657         }
658         res = btn_dialog(main_window,
659                         _("Do you wish to save your new configuration?\n"
660                                 "<ESC> to cancel and resume nconfig."),
661                         2,
662                         "   <save>   ",
663                         "<don't save>");
664         if (res == KEY_EXIT) {
665                 global_exit = 0;
666                 return -1;
667         }
668
669         /* if we got here, the user really wants to exit */
670         switch (res) {
671         case 0:
672                 res = conf_write(filename);
673                 if (res)
674                         btn_dialog(
675                                 main_window,
676                                 _("Error during writing of configuration.\n"
677                                   "Your configuration changes were NOT saved."),
678                                   1,
679                                   "<OK>");
680                 break;
681         default:
682                 btn_dialog(
683                         main_window,
684                         _("Your configuration changes were NOT saved."),
685                         1,
686                         "<OK>");
687                 break;
688         }
689         global_exit = 1;
690         return 0;
691 }
692
693
694 static void search_conf(void)
695 {
696         struct symbol **sym_arr;
697         struct gstr res;
698         char dialog_input_result[100];
699         char *dialog_input;
700         int dres;
701 again:
702         dres = dialog_inputbox(main_window,
703                         _("Search Configuration Parameter"),
704                         _("Enter " CONFIG_ " (sub)string to search for "
705                                 "(with or without \"" CONFIG_ "\")"),
706                         "", dialog_input_result, 99);
707         switch (dres) {
708         case 0:
709                 break;
710         case 1:
711                 show_scroll_win(main_window,
712                                 _("Search Configuration"), search_help);
713                 goto again;
714         default:
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);
725         free(sym_arr);
726         show_scroll_win(main_window,
727                         _("Search Results"), str_get(&res));
728         str_free(&res);
729 }
730
731
732 static void build_conf(struct menu *menu)
733 {
734         struct symbol *sym;
735         struct property *prop;
736         struct menu *child;
737         int type, tmp, doint = 2;
738         tristate val;
739         char ch;
740
741         if (!menu || (!show_all_items && !menu_is_visible(menu)))
742                 return;
743
744         sym = menu->sym;
745         prop = menu->prompt;
746         if (!sym) {
747                 if (prop && menu != current_menu) {
748                         const char *prompt = menu_get_prompt(menu);
749                         enum prop_type ptype;
750                         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
751                         switch (ptype) {
752                         case P_MENU:
753                                 child_count++;
754                                 prompt = _(prompt);
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  --->",
763                                                 indent + 1,
764                                                 ' ', prompt);
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_changable(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_changable(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_changable(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_changable(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_changable(sym)) ?
904                                 "" : _(" (NEW)"));
905                 if (menu->prompt && menu->prompt->type == P_MENU) {
906                         item_add_str("  --->");
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         wattrset(main_window, attributes[NORMAL]);
957         print_in_middle(stdscr, 1, 0, COLS,
958                         menu_backtitle,
959                         attributes[MAIN_HEADING]);
960
961         wattrset(main_window, attributes[MAIN_MENU_BOX]);
962         box(main_window, 0, 0);
963         wattrset(main_window, attributes[MAIN_MENU_HEADING]);
964         mvwprintw(main_window, 0, 3, " %s ", prompt);
965         wattrset(main_window, attributes[NORMAL]);
966
967         set_menu_items(curses_menu, curses_menu_items);
968
969         /* position the menu at the middle of the screen */
970         scale_menu(curses_menu, &maxy, &maxx);
971         maxx = min(maxx, mwin_max_cols-2);
972         maxy = mwin_max_lines;
973         menu_window = derwin(main_window,
974                         maxy,
975                         maxx,
976                         2,
977                         (mwin_max_cols-maxx)/2);
978         keypad(menu_window, TRUE);
979         set_menu_win(curses_menu, menu_window);
980         set_menu_sub(curses_menu, menu_window);
981
982         /* must reassert this after changing items, otherwise returns to a
983          * default of 16
984          */
985         set_menu_format(curses_menu, maxy, 1);
986         center_item(selected_index, last_top_row);
987         set_menu_format(curses_menu, maxy, 1);
988
989         print_function_line();
990
991         /* Post the menu */
992         post_menu(curses_menu);
993         refresh_all_windows(main_window);
994 }
995
996 static void adj_match_dir(match_f *match_direction)
997 {
998         if (*match_direction == FIND_NEXT_MATCH_DOWN)
999                 *match_direction =
1000                         MATCH_TINKER_PATTERN_DOWN;
1001         else if (*match_direction == FIND_NEXT_MATCH_UP)
1002                 *match_direction =
1003                         MATCH_TINKER_PATTERN_UP;
1004         /* else, do no change.. */
1005 }
1006
1007 struct match_state
1008 {
1009         int in_search;
1010         match_f match_direction;
1011         char pattern[256];
1012 };
1013
1014 /* Return 0 means I have handled the key. In such a case, ans should hold the
1015  * item to center, or -1 otherwise.
1016  * Else return -1 .
1017  */
1018 static int do_match(int key, struct match_state *state, int *ans)
1019 {
1020         char c = (char) key;
1021         int terminate_search = 0;
1022         *ans = -1;
1023         if (key == '/' || (state->in_search && key == 27)) {
1024                 move(0, 0);
1025                 refresh();
1026                 clrtoeol();
1027                 state->in_search = 1-state->in_search;
1028                 bzero(state->pattern, sizeof(state->pattern));
1029                 state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1030                 return 0;
1031         } else if (!state->in_search)
1032                 return 1;
1033
1034         if (isalnum(c) || isgraph(c) || c == ' ') {
1035                 state->pattern[strlen(state->pattern)] = c;
1036                 state->pattern[strlen(state->pattern)] = '\0';
1037                 adj_match_dir(&state->match_direction);
1038                 *ans = get_mext_match(state->pattern,
1039                                 state->match_direction);
1040         } else if (key == KEY_DOWN) {
1041                 state->match_direction = FIND_NEXT_MATCH_DOWN;
1042                 *ans = get_mext_match(state->pattern,
1043                                 state->match_direction);
1044         } else if (key == KEY_UP) {
1045                 state->match_direction = FIND_NEXT_MATCH_UP;
1046                 *ans = get_mext_match(state->pattern,
1047                                 state->match_direction);
1048         } else if (key == KEY_BACKSPACE || key == 127) {
1049                 state->pattern[strlen(state->pattern)-1] = '\0';
1050                 adj_match_dir(&state->match_direction);
1051         } else
1052                 terminate_search = 1;
1053
1054         if (terminate_search) {
1055                 state->in_search = 0;
1056                 bzero(state->pattern, sizeof(state->pattern));
1057                 move(0, 0);
1058                 refresh();
1059                 clrtoeol();
1060                 return -1;
1061         }
1062         return 0;
1063 }
1064
1065 static void conf(struct menu *menu)
1066 {
1067         struct menu *submenu = 0;
1068         const char *prompt = menu_get_prompt(menu);
1069         struct symbol *sym;
1070         struct menu *active_menu = NULL;
1071         int res;
1072         int current_index = 0;
1073         int last_top_row = 0;
1074         struct match_state match_state = {
1075                 .in_search = 0,
1076                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1077                 .pattern = "",
1078         };
1079
1080         while (!global_exit) {
1081                 reset_menu();
1082                 current_menu = menu;
1083                 build_conf(menu);
1084                 if (!child_count)
1085                         break;
1086
1087                 show_menu(prompt ? _(prompt) : _("Main Menu"),
1088                                 _(menu_instructions),
1089                                 current_index, &last_top_row);
1090                 keypad((menu_win(curses_menu)), TRUE);
1091                 while (!global_exit) {
1092                         if (match_state.in_search) {
1093                                 mvprintw(0, 0,
1094                                         "searching: %s", match_state.pattern);
1095                                 clrtoeol();
1096                         }
1097                         refresh_all_windows(main_window);
1098                         res = wgetch(menu_win(curses_menu));
1099                         if (!res)
1100                                 break;
1101                         if (do_match(res, &match_state, &current_index) == 0) {
1102                                 if (current_index != -1)
1103                                         center_item(current_index,
1104                                                     &last_top_row);
1105                                 continue;
1106                         }
1107                         if (process_special_keys(&res,
1108                                                 (struct menu *) item_data()))
1109                                 break;
1110                         switch (res) {
1111                         case KEY_DOWN:
1112                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1113                                 break;
1114                         case KEY_UP:
1115                                 menu_driver(curses_menu, REQ_UP_ITEM);
1116                                 break;
1117                         case KEY_NPAGE:
1118                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1119                                 break;
1120                         case KEY_PPAGE:
1121                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1122                                 break;
1123                         case KEY_HOME:
1124                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1125                                 break;
1126                         case KEY_END:
1127                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1128                                 break;
1129                         case 'h':
1130                         case '?':
1131                                 show_help((struct menu *) item_data());
1132                                 break;
1133                         }
1134                         if (res == 10 || res == 27 ||
1135                                 res == 32 || res == 'n' || res == 'y' ||
1136                                 res == KEY_LEFT || res == KEY_RIGHT ||
1137                                 res == 'm')
1138                                 break;
1139                         refresh_all_windows(main_window);
1140                 }
1141
1142                 refresh_all_windows(main_window);
1143                 /* if ESC or left*/
1144                 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1145                         break;
1146
1147                 /* remember location in the menu */
1148                 last_top_row = top_row(curses_menu);
1149                 current_index = curses_item_index();
1150
1151                 if (!item_tag())
1152                         continue;
1153
1154                 submenu = (struct menu *) item_data();
1155                 active_menu = (struct menu *)item_data();
1156                 if (!submenu || !menu_is_visible(submenu))
1157                         continue;
1158                 if (submenu)
1159                         sym = submenu->sym;
1160                 else
1161                         sym = NULL;
1162
1163                 switch (res) {
1164                 case ' ':
1165                         if (item_is_tag('t'))
1166                                 sym_toggle_tristate_value(sym);
1167                         else if (item_is_tag('m'))
1168                                 conf(submenu);
1169                         break;
1170                 case KEY_RIGHT:
1171                 case 10: /* ENTER WAS PRESSED */
1172                         switch (item_tag()) {
1173                         case 'm':
1174                                 if (single_menu_mode)
1175                                         submenu->data =
1176                                                 (void *) (long) !submenu->data;
1177                                 else
1178                                         conf(submenu);
1179                                 break;
1180                         case 't':
1181                                 if (sym_is_choice(sym) &&
1182                                     sym_get_tristate_value(sym) == yes)
1183                                         conf_choice(submenu);
1184                                 else if (submenu->prompt &&
1185                                          submenu->prompt->type == P_MENU)
1186                                         conf(submenu);
1187                                 else if (res == 10)
1188                                         sym_toggle_tristate_value(sym);
1189                                 break;
1190                         case 's':
1191                                 conf_string(submenu);
1192                                 break;
1193                         }
1194                         break;
1195                 case 'y':
1196                         if (item_is_tag('t')) {
1197                                 if (sym_set_tristate_value(sym, yes))
1198                                         break;
1199                                 if (sym_set_tristate_value(sym, mod))
1200                                         btn_dialog(main_window, setmod_text, 0);
1201                         }
1202                         break;
1203                 case 'n':
1204                         if (item_is_tag('t'))
1205                                 sym_set_tristate_value(sym, no);
1206                         break;
1207                 case 'm':
1208                         if (item_is_tag('t'))
1209                                 sym_set_tristate_value(sym, mod);
1210                         break;
1211                 }
1212         }
1213 }
1214
1215 static void conf_message_callback(const char *fmt, va_list ap)
1216 {
1217         char buf[1024];
1218
1219         vsnprintf(buf, sizeof(buf), fmt, ap);
1220         btn_dialog(main_window, buf, 1, "<OK>");
1221 }
1222
1223 static void show_help(struct menu *menu)
1224 {
1225         struct gstr help = str_new();
1226
1227         if (menu && menu->sym && menu_has_help(menu)) {
1228                 if (menu->sym->name) {
1229                         str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name);
1230                         str_append(&help, _(menu_get_help(menu)));
1231                         str_append(&help, "\n");
1232                         get_symbol_str(&help, menu->sym);
1233                 } else {
1234                         str_append(&help, _(menu_get_help(menu)));
1235                 }
1236         } else {
1237                 str_append(&help, nohelp_text);
1238         }
1239         show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1240         str_free(&help);
1241 }
1242
1243 static void conf_choice(struct menu *menu)
1244 {
1245         const char *prompt = _(menu_get_prompt(menu));
1246         struct menu *child = 0;
1247         struct symbol *active;
1248         int selected_index = 0;
1249         int last_top_row = 0;
1250         int res, i = 0;
1251         struct match_state match_state = {
1252                 .in_search = 0,
1253                 .match_direction = MATCH_TINKER_PATTERN_DOWN,
1254                 .pattern = "",
1255         };
1256
1257         active = sym_get_choice_value(menu->sym);
1258         /* this is mostly duplicated from the conf() function. */
1259         while (!global_exit) {
1260                 reset_menu();
1261
1262                 for (i = 0, child = menu->list; child; child = child->next) {
1263                         if (!show_all_items && !menu_is_visible(child))
1264                                 continue;
1265
1266                         if (child->sym == sym_get_choice_value(menu->sym))
1267                                 item_make(child, ':', "<X> %s",
1268                                                 _(menu_get_prompt(child)));
1269                         else if (child->sym)
1270                                 item_make(child, ':', "    %s",
1271                                                 _(menu_get_prompt(child)));
1272                         else
1273                                 item_make(child, ':', "*** %s ***",
1274                                                 _(menu_get_prompt(child)));
1275
1276                         if (child->sym == active){
1277                                 last_top_row = top_row(curses_menu);
1278                                 selected_index = i;
1279                         }
1280                         i++;
1281                 }
1282                 show_menu(prompt ? _(prompt) : _("Choice Menu"),
1283                                 _(radiolist_instructions),
1284                                 selected_index,
1285                                 &last_top_row);
1286                 while (!global_exit) {
1287                         if (match_state.in_search) {
1288                                 mvprintw(0, 0, "searching: %s",
1289                                          match_state.pattern);
1290                                 clrtoeol();
1291                         }
1292                         refresh_all_windows(main_window);
1293                         res = wgetch(menu_win(curses_menu));
1294                         if (!res)
1295                                 break;
1296                         if (do_match(res, &match_state, &selected_index) == 0) {
1297                                 if (selected_index != -1)
1298                                         center_item(selected_index,
1299                                                     &last_top_row);
1300                                 continue;
1301                         }
1302                         if (process_special_keys(
1303                                                 &res,
1304                                                 (struct menu *) item_data()))
1305                                 break;
1306                         switch (res) {
1307                         case KEY_DOWN:
1308                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1309                                 break;
1310                         case KEY_UP:
1311                                 menu_driver(curses_menu, REQ_UP_ITEM);
1312                                 break;
1313                         case KEY_NPAGE:
1314                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1315                                 break;
1316                         case KEY_PPAGE:
1317                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1318                                 break;
1319                         case KEY_HOME:
1320                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1321                                 break;
1322                         case KEY_END:
1323                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1324                                 break;
1325                         case 'h':
1326                         case '?':
1327                                 show_help((struct menu *) item_data());
1328                                 break;
1329                         }
1330                         if (res == 10 || res == 27 || res == ' ' ||
1331                                         res == KEY_LEFT){
1332                                 break;
1333                         }
1334                         refresh_all_windows(main_window);
1335                 }
1336                 /* if ESC or left */
1337                 if (res == 27 || res == KEY_LEFT)
1338                         break;
1339
1340                 child = item_data();
1341                 if (!child || !menu_is_visible(child) || !child->sym)
1342                         continue;
1343                 switch (res) {
1344                 case ' ':
1345                 case  10:
1346                 case KEY_RIGHT:
1347                         sym_set_tristate_value(child->sym, yes);
1348                         return;
1349                 case 'h':
1350                 case '?':
1351                         show_help(child);
1352                         active = child->sym;
1353                         break;
1354                 case KEY_EXIT:
1355                         return;
1356                 }
1357         }
1358 }
1359
1360 static void conf_string(struct menu *menu)
1361 {
1362         const char *prompt = menu_get_prompt(menu);
1363         char dialog_input_result[256];
1364
1365         while (1) {
1366                 int res;
1367                 const char *heading;
1368
1369                 switch (sym_get_type(menu->sym)) {
1370                 case S_INT:
1371                         heading = _(inputbox_instructions_int);
1372                         break;
1373                 case S_HEX:
1374                         heading = _(inputbox_instructions_hex);
1375                         break;
1376                 case S_STRING:
1377                         heading = _(inputbox_instructions_string);
1378                         break;
1379                 default:
1380                         heading = _("Internal nconf error!");
1381                 }
1382                 res = dialog_inputbox(main_window,
1383                                 prompt ? _(prompt) : _("Main Menu"),
1384                                 heading,
1385                                 sym_get_string_value(menu->sym),
1386                                 dialog_input_result,
1387                                 sizeof(dialog_input_result));
1388                 switch (res) {
1389                 case 0:
1390                         if (sym_set_string_value(menu->sym,
1391                                                 dialog_input_result))
1392                                 return;
1393                         btn_dialog(main_window,
1394                                 _("You have made an invalid entry."), 0);
1395                         break;
1396                 case 1:
1397                         show_help(menu);
1398                         break;
1399                 case KEY_EXIT:
1400                         return;
1401                 }
1402         }
1403 }
1404
1405 static void conf_load(void)
1406 {
1407         char dialog_input_result[256];
1408         while (1) {
1409                 int res;
1410                 res = dialog_inputbox(main_window,
1411                                 NULL, load_config_text,
1412                                 filename,
1413                                 dialog_input_result,
1414                                 sizeof(dialog_input_result));
1415                 switch (res) {
1416                 case 0:
1417                         if (!dialog_input_result[0])
1418                                 return;
1419                         if (!conf_read(dialog_input_result)) {
1420                                 set_config_filename(dialog_input_result);
1421                                 sym_set_change_count(1);
1422                                 return;
1423                         }
1424                         btn_dialog(main_window, _("File does not exist!"), 0);
1425                         break;
1426                 case 1:
1427                         show_scroll_win(main_window,
1428                                         _("Load Alternate Configuration"),
1429                                         load_config_help);
1430                         break;
1431                 case KEY_EXIT:
1432                         return;
1433                 }
1434         }
1435 }
1436
1437 static void conf_save(void)
1438 {
1439         char dialog_input_result[256];
1440         while (1) {
1441                 int res;
1442                 res = dialog_inputbox(main_window,
1443                                 NULL, save_config_text,
1444                                 filename,
1445                                 dialog_input_result,
1446                                 sizeof(dialog_input_result));
1447                 switch (res) {
1448                 case 0:
1449                         if (!dialog_input_result[0])
1450                                 return;
1451                         res = conf_write(dialog_input_result);
1452                         if (!res) {
1453                                 set_config_filename(dialog_input_result);
1454                                 return;
1455                         }
1456                         btn_dialog(main_window, _("Can't create file! "
1457                                 "Probably a nonexistent directory."),
1458                                 1, "<OK>");
1459                         break;
1460                 case 1:
1461                         show_scroll_win(main_window,
1462                                 _("Save Alternate Configuration"),
1463                                 save_config_help);
1464                         break;
1465                 case KEY_EXIT:
1466                         return;
1467                 }
1468         }
1469 }
1470
1471 void setup_windows(void)
1472 {
1473         if (main_window != NULL)
1474                 delwin(main_window);
1475
1476         /* set up the menu and menu window */
1477         main_window = newwin(LINES-2, COLS-2, 2, 1);
1478         keypad(main_window, TRUE);
1479         mwin_max_lines = LINES-7;
1480         mwin_max_cols = COLS-6;
1481
1482         /* panels order is from bottom to top */
1483         new_panel(main_window);
1484 }
1485
1486 int main(int ac, char **av)
1487 {
1488         char *mode;
1489
1490         setlocale(LC_ALL, "");
1491         bindtextdomain(PACKAGE, LOCALEDIR);
1492         textdomain(PACKAGE);
1493
1494         conf_parse(av[1]);
1495         conf_read(NULL);
1496
1497         mode = getenv("NCONFIG_MODE");
1498         if (mode) {
1499                 if (!strcasecmp(mode, "single_menu"))
1500                         single_menu_mode = 1;
1501         }
1502
1503         /* Initialize curses */
1504         initscr();
1505         /* set color theme */
1506         set_colors();
1507
1508         cbreak();
1509         noecho();
1510         keypad(stdscr, TRUE);
1511         curs_set(0);
1512
1513         if (COLS < 75 || LINES < 20) {
1514                 endwin();
1515                 printf("Your terminal should have at "
1516                         "least 20 lines and 75 columns\n");
1517                 return 1;
1518         }
1519
1520         notimeout(stdscr, FALSE);
1521         ESCDELAY = 1;
1522
1523         /* set btns menu */
1524         curses_menu = new_menu(curses_menu_items);
1525         menu_opts_off(curses_menu, O_SHOWDESC);
1526         menu_opts_on(curses_menu, O_SHOWMATCH);
1527         menu_opts_on(curses_menu, O_ONEVALUE);
1528         menu_opts_on(curses_menu, O_NONCYCLIC);
1529         menu_opts_on(curses_menu, O_IGNORECASE);
1530         set_menu_mark(curses_menu, " ");
1531         set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1532         set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1533         set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1534
1535         set_config_filename(conf_get_configname());
1536         setup_windows();
1537
1538         /* check for KEY_FUNC(1) */
1539         if (has_key(KEY_F(1)) == FALSE) {
1540                 show_scroll_win(main_window,
1541                                 _("Instructions"),
1542                                 _(menu_no_f_instructions));
1543         }
1544
1545         conf_set_message_callback(conf_message_callback);
1546         /* do the work */
1547         while (!global_exit) {
1548                 conf(&rootmenu);
1549                 if (!global_exit && do_exit() == 0)
1550                         break;
1551         }
1552         /* ok, we are done */
1553         unpost_menu(curses_menu);
1554         free_menu(curses_menu);
1555         delwin(main_window);
1556         clear();
1557         refresh();
1558         endwin();
1559         return 0;
1560 }
1561