]> rtime.felk.cvut.cz Git - l4.git/blob - l4/tool/kconfig/scripts/kconfig/nconf.c
update
[l4.git] / l4 / tool / kconfig / 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         if (!cur)
680                 return NULL;
681         mcur = (struct mitem *) item_userptr(cur);
682         return mcur->usrptr;
683
684 }
685
686 static int item_is_tag(char tag)
687 {
688         return item_tag() == tag;
689 }
690
691 static char filename[PATH_MAX+1];
692 static char menu_backtitle[PATH_MAX+128];
693 static const char *set_config_filename(const char *config_filename)
694 {
695         int size;
696         struct symbol *sym;
697
698         sym = sym_lookup("KERNELVERSION", 0);
699         sym_calc_value(sym);
700         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
701                         _("%s - Linux Kernel v%s Configuration"),
702                         config_filename, sym_get_string_value(sym));
703         if (size >= sizeof(menu_backtitle))
704                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
705
706         size = snprintf(filename, sizeof(filename), "%s", config_filename);
707         if (size >= sizeof(filename))
708                 filename[sizeof(filename)-1] = '\0';
709         return menu_backtitle;
710 }
711
712 /* command = 0 is supress, 1 is restore */
713 static void supress_stdout(int command)
714 {
715         static FILE *org_stdout;
716         static FILE *org_stderr;
717
718         if (command == 0) {
719                 org_stdout = stdout;
720                 org_stderr = stderr;
721                 stdout = fopen("/dev/null", "a");
722                 stderr = fopen("/dev/null", "a");
723         } else {
724                 fclose(stdout);
725                 fclose(stderr);
726                 stdout = org_stdout;
727                 stderr = org_stderr;
728         }
729 }
730
731 /* return = 0 means we are successful.
732  * -1 means go on doing what you were doing
733  */
734 static int do_exit(void)
735 {
736         int res;
737         if (!conf_get_changed()) {
738                 global_exit = 1;
739                 return 0;
740         }
741         res = btn_dialog(main_window,
742                         _("Do you wish to save your "
743                                 "new kernel configuration?\n"
744                                 "<ESC> to cancel and resume nconfig."),
745                         2,
746                         "   <save>   ",
747                         "<don't save>");
748         if (res == KEY_EXIT) {
749                 global_exit = 0;
750                 return -1;
751         }
752
753         /* if we got here, the user really wants to exit */
754         switch (res) {
755         case 0:
756                 supress_stdout(0);
757                 res = conf_write(filename);
758                 supress_stdout(1);
759                 if (res)
760                         btn_dialog(
761                                 main_window,
762                                 _("Error during writing of the kernel "
763                                   "configuration.\n"
764                                   "Your kernel configuration "
765                                   "changes were NOT saved."),
766                                   1,
767                                   "<OK>");
768                 else {
769                         char buf[1024];
770                         snprintf(buf, 1024,
771                                 _("Configuration written to %s\n"
772                                   "End of Linux kernel configuration.\n"
773                                   "Execute 'make' to build the kernel or try"
774                                   " 'make help'."), filename);
775                         btn_dialog(
776                                 main_window,
777                                 buf,
778                                 1,
779                                 "<OK>");
780                 }
781                 break;
782         default:
783                 btn_dialog(
784                         main_window,
785                         _("Your kernel configuration changes were NOT saved."),
786                         1,
787                         "<OK>");
788                 break;
789         }
790         global_exit = 1;
791         return 0;
792 }
793
794
795 static void search_conf(void)
796 {
797         struct symbol **sym_arr;
798         struct gstr res;
799         char dialog_input_result[100];
800         char *dialog_input;
801         int dres;
802 again:
803         dres = dialog_inputbox(main_window,
804                         _("Search Configuration Parameter"),
805                         _("Enter CONFIG_ (sub)string to search for "
806                                 "(with or without \"CONFIG\")"),
807                         "", dialog_input_result, 99);
808         switch (dres) {
809         case 0:
810                 break;
811         case 1:
812                 show_scroll_win(main_window,
813                                 _("Search Configuration"), search_help);
814                 goto again;
815         default:
816                 return;
817         }
818
819         /* strip CONFIG_ if necessary */
820         dialog_input = dialog_input_result;
821         if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
822                 dialog_input += 7;
823
824         sym_arr = sym_re_search(dialog_input);
825         res = get_relations_str(sym_arr);
826         free(sym_arr);
827         show_scroll_win(main_window,
828                         _("Search Results"), str_get(&res));
829         str_free(&res);
830 }
831
832
833 static void build_conf(struct menu *menu)
834 {
835         struct symbol *sym;
836         struct property *prop;
837         struct menu *child;
838         int type, tmp, doint = 2;
839         tristate val;
840         char ch;
841
842         if (!menu || (!show_all_items && !menu_is_visible(menu)))
843                 return;
844
845         sym = menu->sym;
846         prop = menu->prompt;
847         if (!sym) {
848                 if (prop && menu != current_menu) {
849                         const char *prompt = menu_get_prompt(menu);
850                         enum prop_type ptype;
851                         ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
852                         switch (ptype) {
853                         case P_MENU:
854                                 child_count++;
855                                 prompt = _(prompt);
856                                 if (single_menu_mode) {
857                                         item_make(menu, 'm',
858                                                 "%s%*c%s",
859                                                 menu->data ? "-->" : "++>",
860                                                 indent + 1, ' ', prompt);
861                                 } else
862                                         item_make(menu, 'm',
863                                                 "   %*c%s  --->",
864                                                 indent + 1,
865                                                 ' ', prompt);
866
867                                 if (single_menu_mode && menu->data)
868                                         goto conf_childs;
869                                 return;
870                         case P_COMMENT:
871                                 if (prompt) {
872                                         child_count++;
873                                         item_make(menu, ':',
874                                                 "   %*c*** %s ***",
875                                                 indent + 1, ' ',
876                                                 _(prompt));
877                                 }
878                                 break;
879                         default:
880                                 if (prompt) {
881                                         child_count++;
882                                         item_make(menu, ':', "---%*c%s",
883                                                 indent + 1, ' ',
884                                                 _(prompt));
885                                 }
886                         }
887                 } else
888                         doint = 0;
889                 goto conf_childs;
890         }
891
892         type = sym_get_type(sym);
893         if (sym_is_choice(sym)) {
894                 struct symbol *def_sym = sym_get_choice_value(sym);
895                 struct menu *def_menu = NULL;
896
897                 child_count++;
898                 for (child = menu->list; child; child = child->next) {
899                         if (menu_is_visible(child) && child->sym == def_sym)
900                                 def_menu = child;
901                 }
902
903                 val = sym_get_tristate_value(sym);
904                 if (sym_is_changable(sym)) {
905                         switch (type) {
906                         case S_BOOLEAN:
907                                 item_make(menu, 't', "[%c]",
908                                                 val == no ? ' ' : '*');
909                                 break;
910                         case S_TRISTATE:
911                                 switch (val) {
912                                 case yes:
913                                         ch = '*';
914                                         break;
915                                 case mod:
916                                         ch = 'M';
917                                         break;
918                                 default:
919                                         ch = ' ';
920                                         break;
921                                 }
922                                 item_make(menu, 't', "<%c>", ch);
923                                 break;
924                         }
925                 } else {
926                         item_make(menu, def_menu ? 't' : ':', "   ");
927                 }
928
929                 item_add_str("%*c%s", indent + 1,
930                                 ' ', _(menu_get_prompt(menu)));
931                 if (val == yes) {
932                         if (def_menu) {
933                                 item_add_str(" (%s)",
934                                         _(menu_get_prompt(def_menu)));
935                                 item_add_str("  --->");
936                                 if (def_menu->list) {
937                                         indent += 2;
938                                         build_conf(def_menu);
939                                         indent -= 2;
940                                 }
941                         }
942                         return;
943                 }
944         } else {
945                 if (menu == current_menu) {
946                         item_make(menu, ':',
947                                 "---%*c%s", indent + 1,
948                                 ' ', _(menu_get_prompt(menu)));
949                         goto conf_childs;
950                 }
951                 child_count++;
952                 val = sym_get_tristate_value(sym);
953                 if (sym_is_choice_value(sym) && val == yes) {
954                         item_make(menu, ':', "   ");
955                 } else {
956                         switch (type) {
957                         case S_BOOLEAN:
958                                 if (sym_is_changable(sym))
959                                         item_make(menu, 't', "[%c]",
960                                                 val == no ? ' ' : '*');
961                                 else
962                                         item_make(menu, 't', "-%c-",
963                                                 val == no ? ' ' : '*');
964                                 break;
965                         case S_TRISTATE:
966                                 switch (val) {
967                                 case yes:
968                                         ch = '*';
969                                         break;
970                                 case mod:
971                                         ch = 'M';
972                                         break;
973                                 default:
974                                         ch = ' ';
975                                         break;
976                                 }
977                                 if (sym_is_changable(sym)) {
978                                         if (sym->rev_dep.tri == mod)
979                                                 item_make(menu,
980                                                         't', "{%c}", ch);
981                                         else
982                                                 item_make(menu,
983                                                         't', "<%c>", ch);
984                                 } else
985                                         item_make(menu, 't', "-%c-", ch);
986                                 break;
987                         default:
988                                 tmp = 2 + strlen(sym_get_string_value(sym));
989                                 item_make(menu, 's', "    (%s)",
990                                                 sym_get_string_value(sym));
991                                 tmp = indent - tmp + 4;
992                                 if (tmp < 0)
993                                         tmp = 0;
994                                 item_add_str("%*c%s%s", tmp, ' ',
995                                                 _(menu_get_prompt(menu)),
996                                                 (sym_has_value(sym) ||
997                                                  !sym_is_changable(sym)) ? "" :
998                                                 _(" (NEW)"));
999                                 goto conf_childs;
1000                         }
1001                 }
1002                 item_add_str("%*c%s%s", indent + 1, ' ',
1003                                 _(menu_get_prompt(menu)),
1004                                 (sym_has_value(sym) || !sym_is_changable(sym)) ?
1005                                 "" : _(" (NEW)"));
1006                 if (menu->prompt && menu->prompt->type == P_MENU) {
1007                         item_add_str("  --->");
1008                         return;
1009                 }
1010         }
1011
1012 conf_childs:
1013         indent += doint;
1014         for (child = menu->list; child; child = child->next)
1015                 build_conf(child);
1016         indent -= doint;
1017 }
1018
1019 static void reset_menu(void)
1020 {
1021         unpost_menu(curses_menu);
1022         clean_items();
1023 }
1024
1025 /* adjust the menu to show this item.
1026  * prefer not to scroll the menu if possible*/
1027 static void center_item(int selected_index, int *last_top_row)
1028 {
1029         int toprow;
1030         int maxy, maxx;
1031
1032         scale_menu(curses_menu, &maxy, &maxx);
1033         set_top_row(curses_menu, *last_top_row);
1034         toprow = top_row(curses_menu);
1035         if (selected_index >= toprow && selected_index < toprow+maxy) {
1036                 /* we can only move the selected item. no need to scroll */
1037                 set_current_item(curses_menu,
1038                                 curses_menu_items[selected_index]);
1039         } else {
1040                 toprow = max(selected_index-maxy/2, 0);
1041                 if (toprow >= item_count(curses_menu)-maxy)
1042                         toprow = item_count(curses_menu)-mwin_max_lines;
1043                 set_top_row(curses_menu, toprow);
1044                 set_current_item(curses_menu,
1045                                 curses_menu_items[selected_index]);
1046         }
1047         *last_top_row = toprow;
1048         post_menu(curses_menu);
1049         refresh_all_windows(main_window);
1050 }
1051
1052 /* this function assumes reset_menu has been called before */
1053 static void show_menu(const char *prompt, const char *instructions,
1054                 int selected_index, int *last_top_row)
1055 {
1056         int maxx, maxy;
1057         WINDOW *menu_window;
1058
1059         current_instructions = instructions;
1060
1061         clear();
1062         wattrset(main_window, attributes[NORMAL]);
1063         print_in_middle(stdscr, 1, 0, COLS,
1064                         menu_backtitle,
1065                         attributes[MAIN_HEADING]);
1066
1067         wattrset(main_window, attributes[MAIN_MENU_BOX]);
1068         box(main_window, 0, 0);
1069         wattrset(main_window, attributes[MAIN_MENU_HEADING]);
1070         mvwprintw(main_window, 0, 3, " %s ", prompt);
1071         wattrset(main_window, attributes[NORMAL]);
1072
1073         set_menu_items(curses_menu, curses_menu_items);
1074
1075         /* position the menu at the middle of the screen */
1076         scale_menu(curses_menu, &maxy, &maxx);
1077         maxx = min(maxx, mwin_max_cols-2);
1078         maxy = mwin_max_lines-2;
1079         menu_window = derwin(main_window,
1080                         maxy,
1081                         maxx,
1082                         2,
1083                         (mwin_max_cols-maxx)/2);
1084         keypad(menu_window, TRUE);
1085         set_menu_win(curses_menu, menu_window);
1086         set_menu_sub(curses_menu, menu_window);
1087
1088         /* must reassert this after changing items, otherwise returns to a
1089          * default of 16
1090          */
1091         set_menu_format(curses_menu, maxy, 1);
1092         center_item(selected_index, last_top_row);
1093         set_menu_format(curses_menu, maxy, 1);
1094
1095         print_function_line();
1096
1097         /* Post the menu */
1098         post_menu(curses_menu);
1099         refresh_all_windows(main_window);
1100 }
1101
1102
1103 static void conf(struct menu *menu)
1104 {
1105         char pattern[256];
1106         struct menu *submenu = 0;
1107         const char *prompt = menu_get_prompt(menu);
1108         struct symbol *sym;
1109         struct menu *active_menu = NULL;
1110         int res;
1111         int current_index = 0;
1112         int last_top_row = 0;
1113
1114         bzero(pattern, sizeof(pattern));
1115
1116         while (!global_exit) {
1117                 reset_menu();
1118                 current_menu = menu;
1119                 build_conf(menu);
1120                 if (!child_count)
1121                         break;
1122
1123                 show_menu(prompt ? _(prompt) : _("Main Menu"),
1124                                 _(menu_instructions),
1125                                 current_index, &last_top_row);
1126                 keypad((menu_win(curses_menu)), TRUE);
1127                 while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
1128                         if (process_special_keys(&res,
1129                                                 (struct menu *) item_data()))
1130                                 break;
1131                         switch (res) {
1132                         case KEY_DOWN:
1133                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1134                                 break;
1135                         case KEY_UP:
1136                                 menu_driver(curses_menu, REQ_UP_ITEM);
1137                                 break;
1138                         case KEY_NPAGE:
1139                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1140                                 break;
1141                         case KEY_PPAGE:
1142                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1143                                 break;
1144                         case KEY_HOME:
1145                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1146                                 break;
1147                         case KEY_END:
1148                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1149                                 break;
1150                         case 'h':
1151                         case '?':
1152                                 show_help((struct menu *) item_data());
1153                                 break;
1154                         }
1155                         if (res == 10 || res == 27 ||
1156                                 res == 32 || res == 'n' || res == 'y' ||
1157                                 res == KEY_LEFT || res == KEY_RIGHT ||
1158                                 res == 'm' || res == '/')
1159                                 break;
1160                         else if (canbhot(res)) {
1161                                 /* check for hot keys: */
1162                                 int tmp = get_next_hot(res);
1163                                 if (tmp != -1)
1164                                         center_item(tmp, &last_top_row);
1165                         }
1166                         refresh_all_windows(main_window);
1167                 }
1168
1169                 refresh_all_windows(main_window);
1170                 /* if ESC  or left*/
1171                 if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1172                         break;
1173
1174                 /* remember location in the menu */
1175                 last_top_row = top_row(curses_menu);
1176                 current_index = curses_item_index();
1177
1178                 if (!item_tag())
1179                         continue;
1180
1181                 submenu = (struct menu *) item_data();
1182                 active_menu = (struct menu *)item_data();
1183                 if (!submenu || !menu_is_visible(submenu))
1184                         continue;
1185                 if (submenu)
1186                         sym = submenu->sym;
1187                 else
1188                         sym = NULL;
1189
1190                 switch (res) {
1191                 case ' ':
1192                         if (item_is_tag('t'))
1193                                 sym_toggle_tristate_value(sym);
1194                         else if (item_is_tag('m'))
1195                                 conf(submenu);
1196                         break;
1197                 case KEY_RIGHT:
1198                 case 10: /* ENTER WAS PRESSED */
1199                         switch (item_tag()) {
1200                         case 'm':
1201                                 if (single_menu_mode)
1202                                         submenu->data =
1203                                                 (void *) (long) !submenu->data;
1204                                 else
1205                                         conf(submenu);
1206                                 break;
1207                         case 't':
1208                                 if (sym_is_choice(sym) &&
1209                                     sym_get_tristate_value(sym) == yes)
1210                                         conf_choice(submenu);
1211                                 else if (submenu->prompt &&
1212                                          submenu->prompt->type == P_MENU)
1213                                         conf(submenu);
1214                                 else if (res == 10)
1215                                         sym_toggle_tristate_value(sym);
1216                                 break;
1217                         case 's':
1218                                 conf_string(submenu);
1219                                 break;
1220                         }
1221                         break;
1222                 case 'y':
1223                         if (item_is_tag('t')) {
1224                                 if (sym_set_tristate_value(sym, yes))
1225                                         break;
1226                                 if (sym_set_tristate_value(sym, mod))
1227                                         btn_dialog(main_window, setmod_text, 0);
1228                         }
1229                         break;
1230                 case 'n':
1231                         if (item_is_tag('t'))
1232                                 sym_set_tristate_value(sym, no);
1233                         break;
1234                 case 'm':
1235                         if (item_is_tag('t'))
1236                                 sym_set_tristate_value(sym, mod);
1237                         break;
1238                 case '/':
1239                         search_conf();
1240                         break;
1241                 }
1242         }
1243 }
1244
1245 static void show_help(struct menu *menu)
1246 {
1247         struct gstr help = str_new();
1248
1249         if (menu && menu->sym && menu_has_help(menu)) {
1250                 if (menu->sym->name) {
1251                         str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name);
1252                         str_append(&help, _(menu_get_help(menu)));
1253                         str_append(&help, "\n");
1254                         get_symbol_str(&help, menu->sym);
1255                 }
1256         } else {
1257                 str_append(&help, nohelp_text);
1258         }
1259         show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1260         str_free(&help);
1261 }
1262
1263 static void conf_choice(struct menu *menu)
1264 {
1265         const char *prompt = _(menu_get_prompt(menu));
1266         struct menu *child = 0;
1267         struct symbol *active;
1268         int selected_index = 0;
1269         int last_top_row = 0;
1270         int res, i = 0;
1271
1272         active = sym_get_choice_value(menu->sym);
1273         /* this is mostly duplicated from the conf() function. */
1274         while (!global_exit) {
1275                 reset_menu();
1276
1277                 for (i = 0, child = menu->list; child; child = child->next) {
1278                         if (!show_all_items && !menu_is_visible(child))
1279                                 continue;
1280
1281                         if (child->sym == sym_get_choice_value(menu->sym))
1282                                 item_make(child, ':', "<X> %s",
1283                                                 _(menu_get_prompt(child)));
1284                         else
1285                                 item_make(child, ':', "    %s",
1286                                                 _(menu_get_prompt(child)));
1287                         if (child->sym == active){
1288                                 last_top_row = top_row(curses_menu);
1289                                 selected_index = i;
1290                         }
1291                         i++;
1292                 }
1293                 show_menu(prompt ? _(prompt) : _("Choice Menu"),
1294                                 _(radiolist_instructions),
1295                                 selected_index,
1296                                 &last_top_row);
1297                 while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
1298                         if (process_special_keys(
1299                                                 &res,
1300                                                 (struct menu *) item_data()))
1301                                 break;
1302                         switch (res) {
1303                         case KEY_DOWN:
1304                                 menu_driver(curses_menu, REQ_DOWN_ITEM);
1305                                 break;
1306                         case KEY_UP:
1307                                 menu_driver(curses_menu, REQ_UP_ITEM);
1308                                 break;
1309                         case KEY_NPAGE:
1310                                 menu_driver(curses_menu, REQ_SCR_DPAGE);
1311                                 break;
1312                         case KEY_PPAGE:
1313                                 menu_driver(curses_menu, REQ_SCR_UPAGE);
1314                                 break;
1315                         case KEY_HOME:
1316                                 menu_driver(curses_menu, REQ_FIRST_ITEM);
1317                                 break;
1318                         case KEY_END:
1319                                 menu_driver(curses_menu, REQ_LAST_ITEM);
1320                                 break;
1321                         case 'h':
1322                         case '?':
1323                                 show_help((struct menu *) item_data());
1324                                 break;
1325                         }
1326                         if (res == 10 || res == 27 || res == ' ' ||
1327                                 res == KEY_LEFT)
1328                                 break;
1329                         else if (canbhot(res)) {
1330                                 /* check for hot keys: */
1331                                 int tmp = get_next_hot(res);
1332                                 if (tmp != -1)
1333                                         center_item(tmp, &last_top_row);
1334                         }
1335                         refresh_all_windows(main_window);
1336                 }
1337                 /* if ESC or left */
1338                 if (res == 27 || res == KEY_LEFT)
1339                         break;
1340
1341                 child = item_data();
1342                 if (!child || !menu_is_visible(child))
1343                         continue;
1344                 switch (res) {
1345                 case ' ':
1346                 case  10:
1347                 case KEY_RIGHT:
1348                         sym_set_tristate_value(child->sym, yes);
1349                         return;
1350                 case 'h':
1351                 case '?':
1352                         show_help(child);
1353                         active = child->sym;
1354                         break;
1355                 case KEY_EXIT:
1356                         return;
1357                 }
1358         }
1359 }
1360
1361 static void conf_string(struct menu *menu)
1362 {
1363         const char *prompt = menu_get_prompt(menu);
1364         char dialog_input_result[256];
1365
1366         while (1) {
1367                 int res;
1368                 const char *heading;
1369
1370                 switch (sym_get_type(menu->sym)) {
1371                 case S_INT:
1372                         heading = _(inputbox_instructions_int);
1373                         break;
1374                 case S_HEX:
1375                         heading = _(inputbox_instructions_hex);
1376                         break;
1377                 case S_STRING:
1378                         heading = _(inputbox_instructions_string);
1379                         break;
1380                 default:
1381                         heading = _("Internal nconf error!");
1382                 }
1383                 res = dialog_inputbox(main_window,
1384                                 prompt ? _(prompt) : _("Main Menu"),
1385                                 heading,
1386                                 sym_get_string_value(menu->sym),
1387                                 dialog_input_result,
1388                                 sizeof(dialog_input_result));
1389                 switch (res) {
1390                 case 0:
1391                         if (sym_set_string_value(menu->sym,
1392                                                 dialog_input_result))
1393                                 return;
1394                         btn_dialog(main_window,
1395                                 _("You have made an invalid entry."), 0);
1396                         break;
1397                 case 1:
1398                         show_help(menu);
1399                         break;
1400                 case KEY_EXIT:
1401                         return;
1402                 }
1403         }
1404 }
1405
1406 static void conf_load(void)
1407 {
1408         char dialog_input_result[256];
1409         while (1) {
1410                 int res;
1411                 res = dialog_inputbox(main_window,
1412                                 NULL, load_config_text,
1413                                 filename,
1414                                 dialog_input_result,
1415                                 sizeof(dialog_input_result));
1416                 switch (res) {
1417                 case 0:
1418                         if (!dialog_input_result[0])
1419                                 return;
1420                         if (!conf_read(dialog_input_result)) {
1421                                 set_config_filename(dialog_input_result);
1422                                 sym_set_change_count(1);
1423                                 return;
1424                         }
1425                         btn_dialog(main_window, _("File does not exist!"), 0);
1426                         break;
1427                 case 1:
1428                         show_scroll_win(main_window,
1429                                         _("Load Alternate Configuration"),
1430                                         load_config_help);
1431                         break;
1432                 case KEY_EXIT:
1433                         return;
1434                 }
1435         }
1436 }
1437
1438 static void conf_save(void)
1439 {
1440         char dialog_input_result[256];
1441         while (1) {
1442                 int res;
1443                 res = dialog_inputbox(main_window,
1444                                 NULL, save_config_text,
1445                                 filename,
1446                                 dialog_input_result,
1447                                 sizeof(dialog_input_result));
1448                 switch (res) {
1449                 case 0:
1450                         if (!dialog_input_result[0])
1451                                 return;
1452                         supress_stdout(0);
1453                         res = conf_write(dialog_input_result);
1454                         supress_stdout(1);
1455                         if (!res) {
1456                                 char buf[1024];
1457                                 sprintf(buf, "%s %s",
1458                                         _("configuration file saved to: "),
1459                                         dialog_input_result);
1460                                 btn_dialog(main_window,
1461                                            buf, 1, "<OK>");
1462                                 set_config_filename(dialog_input_result);
1463                                 return;
1464                         }
1465                         btn_dialog(main_window, _("Can't create file! "
1466                                 "Probably a nonexistent directory."),
1467                                 1, "<OK>");
1468                         break;
1469                 case 1:
1470                         show_scroll_win(main_window,
1471                                 _("Save Alternate Configuration"),
1472                                 save_config_help);
1473                         break;
1474                 case KEY_EXIT:
1475                         return;
1476                 }
1477         }
1478 }
1479
1480 void setup_windows(void)
1481 {
1482         if (main_window != NULL)
1483                 delwin(main_window);
1484
1485         /* set up the menu and menu window */
1486         main_window = newwin(LINES-2, COLS-2, 2, 1);
1487         keypad(main_window, TRUE);
1488         mwin_max_lines = LINES-6;
1489         mwin_max_cols = COLS-6;
1490
1491         /* panels order is from bottom to top */
1492         new_panel(main_window);
1493 }
1494
1495 int main(int ac, char **av)
1496 {
1497         char *mode;
1498
1499         setlocale(LC_ALL, "");
1500         bindtextdomain(PACKAGE, LOCALEDIR);
1501         textdomain(PACKAGE);
1502
1503         conf_parse(av[1]);
1504         conf_read(NULL);
1505
1506         mode = getenv("NCONFIG_MODE");
1507         if (mode) {
1508                 if (!strcasecmp(mode, "single_menu"))
1509                         single_menu_mode = 1;
1510         }
1511
1512         /* Initialize curses */
1513         initscr();
1514         /* set color theme */
1515         set_colors();
1516
1517         cbreak();
1518         noecho();
1519         keypad(stdscr, TRUE);
1520         curs_set(0);
1521
1522         if (COLS < 75 || LINES < 20) {
1523                 endwin();
1524                 printf("Your terminal should have at "
1525                         "least 20 lines and 75 columns\n");
1526                 return 1;
1527         }
1528
1529         notimeout(stdscr, FALSE);
1530         ESCDELAY = 1;
1531
1532         /* set btns menu */
1533         curses_menu = new_menu(curses_menu_items);
1534         menu_opts_off(curses_menu, O_SHOWDESC);
1535         menu_opts_off(curses_menu, O_SHOWMATCH);
1536         menu_opts_on(curses_menu, O_ONEVALUE);
1537         menu_opts_on(curses_menu, O_NONCYCLIC);
1538         set_menu_mark(curses_menu, " ");
1539         set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1540         set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1541         set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1542
1543         set_config_filename(conf_get_configname());
1544         setup_windows();
1545
1546         /* check for KEY_FUNC(1) */
1547         if (has_key(KEY_F(1)) == FALSE) {
1548                 show_scroll_win(main_window,
1549                                 _("Instructions"),
1550                                 _(menu_no_f_instructions));
1551         }
1552
1553
1554
1555         /* do the work */
1556         while (!global_exit) {
1557                 conf(&rootmenu);
1558                 if (!global_exit && do_exit() == 0)
1559                         break;
1560         }
1561         /* ok, we are done */
1562         unpost_menu(curses_menu);
1563         free_menu(curses_menu);
1564         delwin(main_window);
1565         clear();
1566         refresh();
1567         endwin();
1568         return 0;
1569 }
1570