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