Merge branch 'for-35' of git://repo.or.cz/linux-kbuild
[safe/jmp/linux-2.6] / scripts / kconfig / mconf.c
1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  *
5  * Introduced single menu mode (show all sub-menus in one large tree).
6  * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7  *
8  * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9  */
10
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <locale.h>
20
21 #define LKC_DIRECT_LINK
22 #include "lkc.h"
23 #include "lxdialog/dialog.h"
24
25 static const char mconf_readme[] = N_(
26 "Overview\n"
27 "--------\n"
28 "Some kernel features may be built directly into the kernel.\n"
29 "Some may be made into loadable runtime modules.  Some features\n"
30 "may be completely removed altogether.  There are also certain\n"
31 "kernel parameters which are not really features, but must be\n"
32 "entered in as decimal or hexadecimal numbers or possibly text.\n"
33 "\n"
34 "Menu items beginning with following braces represent features that\n"
35 "  [ ] can be built in or removed\n"
36 "  < > can be built in, modularized or removed\n"
37 "  { } can be built in or modularized (selected by other feature)\n"
38 "  - - are selected by other feature,\n"
39 "while *, M or whitespace inside braces means to build in, build as\n"
40 "a module or to exclude the feature respectively.\n"
41 "\n"
42 "To change any of these features, highlight it with the cursor\n"
43 "keys and press <Y> to build it in, <M> to make it a module or\n"
44 "<N> to removed it.  You may also press the <Space Bar> to cycle\n"
45 "through the available options (ie. Y->N->M->Y).\n"
46 "\n"
47 "Some additional keyboard hints:\n"
48 "\n"
49 "Menus\n"
50 "----------\n"
51 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
52 "   you wish to change or submenu wish to select and press <Enter>.\n"
53 "   Submenus are designated by \"--->\".\n"
54 "\n"
55 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
56 "             Pressing a hotkey more than once will sequence\n"
57 "             through all visible items which use that hotkey.\n"
58 "\n"
59 "   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
60 "   unseen options into view.\n"
61 "\n"
62 "o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
63 "   and press <ENTER>.\n"
64 "\n"
65 "   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
66 "             using those letters.  You may press a single <ESC>, but\n"
67 "             there is a delayed response which you may find annoying.\n"
68 "\n"
69 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
70 "   <Exit> and <Help>.\n"
71 "\n"
72 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
73 "   and press <ENTER>.\n"
74 "\n"
75 "   Shortcut: Press <H> or <?>.\n"
76 "\n"
77 "o  To show hidden options, press <Z>.\n"
78 "\n"
79 "\n"
80 "Radiolists  (Choice lists)\n"
81 "-----------\n"
82 "o  Use the cursor keys to select the option you wish to set and press\n"
83 "   <S> or the <SPACE BAR>.\n"
84 "\n"
85 "   Shortcut: Press the first letter of the option you wish to set then\n"
86 "             press <S> or <SPACE BAR>.\n"
87 "\n"
88 "o  To see available help for the item, use the cursor keys to highlight\n"
89 "   <Help> and Press <ENTER>.\n"
90 "\n"
91 "   Shortcut: Press <H> or <?>.\n"
92 "\n"
93 "   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
94 "   <Help>\n"
95 "\n"
96 "\n"
97 "Data Entry\n"
98 "-----------\n"
99 "o  Enter the requested information and press <ENTER>\n"
100 "   If you are entering hexadecimal values, it is not necessary to\n"
101 "   add the '0x' prefix to the entry.\n"
102 "\n"
103 "o  For help, use the <TAB> or cursor keys to highlight the help option\n"
104 "   and press <ENTER>.  You can try <TAB><H> as well.\n"
105 "\n"
106 "\n"
107 "Text Box    (Help Window)\n"
108 "--------\n"
109 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
110 "   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
111 "   who are familiar with less and lynx.\n"
112 "\n"
113 "o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
114 "\n"
115 "\n"
116 "Alternate Configuration Files\n"
117 "-----------------------------\n"
118 "Menuconfig supports the use of alternate configuration files for\n"
119 "those who, for various reasons, find it necessary to switch\n"
120 "between different kernel configurations.\n"
121 "\n"
122 "At the end of the main menu you will find two options.  One is\n"
123 "for saving the current configuration to a file of your choosing.\n"
124 "The other option is for loading a previously saved alternate\n"
125 "configuration.\n"
126 "\n"
127 "Even if you don't use alternate configuration files, but you\n"
128 "find during a Menuconfig session that you have completely messed\n"
129 "up your settings, you may use the \"Load Alternate...\" option to\n"
130 "restore your previously saved settings from \".config\" without\n"
131 "restarting Menuconfig.\n"
132 "\n"
133 "Other information\n"
134 "-----------------\n"
135 "If you use Menuconfig in an XTERM window make sure you have your\n"
136 "$TERM variable set to point to a xterm definition which supports color.\n"
137 "Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
138 "display correctly in a RXVT window because rxvt displays only one\n"
139 "intensity of color, bright.\n"
140 "\n"
141 "Menuconfig will display larger menus on screens or xterms which are\n"
142 "set to display more than the standard 25 row by 80 column geometry.\n"
143 "In order for this to work, the \"stty size\" command must be able to\n"
144 "display the screen's current row and column geometry.  I STRONGLY\n"
145 "RECOMMEND that you make sure you do NOT have the shell variables\n"
146 "LINES and COLUMNS exported into your environment.  Some distributions\n"
147 "export those variables via /etc/profile.  Some ncurses programs can\n"
148 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
149 "the true screen size.\n"
150 "\n"
151 "Optional personality available\n"
152 "------------------------------\n"
153 "If you prefer to have all of the kernel options listed in a single\n"
154 "menu, rather than the default multimenu hierarchy, run the menuconfig\n"
155 "with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
156 "\n"
157 "make MENUCONFIG_MODE=single_menu menuconfig\n"
158 "\n"
159 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
160 "is already unrolled.\n"
161 "\n"
162 "Note that this mode can eventually be a little more CPU expensive\n"
163 "(especially with a larger number of unrolled categories) than the\n"
164 "default mode.\n"
165 "\n"
166 "Different color themes available\n"
167 "--------------------------------\n"
168 "It is possible to select different color themes using the variable\n"
169 "MENUCONFIG_COLOR. To select a theme use:\n"
170 "\n"
171 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
172 "\n"
173 "Available themes are\n"
174 " mono       => selects colors suitable for monochrome displays\n"
175 " blackbg    => selects a color scheme with black background\n"
176 " classic    => theme with blue background. The classic look\n"
177 " bluetitle  => a LCD friendly version of classic. (default)\n"
178 "\n"),
179 menu_instructions[] = N_(
180         "Arrow keys navigate the menu.  "
181         "<Enter> selects submenus --->.  "
182         "Highlighted letters are hotkeys.  "
183         "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
184         "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
185         "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
186 radiolist_instructions[] = N_(
187         "Use the arrow keys to navigate this window or "
188         "press the hotkey of the item you wish to select "
189         "followed by the <SPACE BAR>. "
190         "Press <?> for additional information about this option."),
191 inputbox_instructions_int[] = N_(
192         "Please enter a decimal value. "
193         "Fractions will not be accepted.  "
194         "Use the <TAB> key to move from the input field to the buttons below it."),
195 inputbox_instructions_hex[] = N_(
196         "Please enter a hexadecimal value. "
197         "Use the <TAB> key to move from the input field to the buttons below it."),
198 inputbox_instructions_string[] = N_(
199         "Please enter a string value. "
200         "Use the <TAB> key to move from the input field to the buttons below it."),
201 setmod_text[] = N_(
202         "This feature depends on another which has been configured as a module.\n"
203         "As a result, this feature will be built as a module."),
204 load_config_text[] = N_(
205         "Enter the name of the configuration file you wish to load.  "
206         "Accept the name shown to restore the configuration you "
207         "last retrieved.  Leave blank to abort."),
208 load_config_help[] = N_(
209         "\n"
210         "For various reasons, one may wish to keep several different kernel\n"
211         "configurations available on a single machine.\n"
212         "\n"
213         "If you have saved a previous configuration in a file other than the\n"
214         "kernel's default, entering the name of the file here will allow you\n"
215         "to modify that configuration.\n"
216         "\n"
217         "If you are uncertain, then you have probably never used alternate\n"
218         "configuration files. You should therefore leave this blank to abort.\n"),
219 save_config_text[] = N_(
220         "Enter a filename to which this configuration should be saved "
221         "as an alternate.  Leave blank to abort."),
222 save_config_help[] = N_(
223         "\n"
224         "For various reasons, one may wish to keep different kernel\n"
225         "configurations available on a single machine.\n"
226         "\n"
227         "Entering a file name here will allow you to later retrieve, modify\n"
228         "and use the current configuration as an alternate to whatever\n"
229         "configuration options you have selected at that time.\n"
230         "\n"
231         "If you are uncertain what all this means then you should probably\n"
232         "leave this blank.\n"),
233 search_help[] = N_(
234         "\n"
235         "Search for CONFIG_ symbols and display their relations.\n"
236         "Regular expressions are allowed.\n"
237         "Example: search for \"^FOO\"\n"
238         "Result:\n"
239         "-----------------------------------------------------------------\n"
240         "Symbol: FOO [=m]\n"
241         "Prompt: Foo bus is used to drive the bar HW\n"
242         "Defined at drivers/pci/Kconfig:47\n"
243         "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
244         "Location:\n"
245         "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
246         "    -> PCI support (PCI [=y])\n"
247         "      -> PCI access mode (<choice> [=y])\n"
248         "Selects: LIBCRC32\n"
249         "Selected by: BAR\n"
250         "-----------------------------------------------------------------\n"
251         "o The line 'Prompt:' shows the text used in the menu structure for\n"
252         "  this CONFIG_ symbol\n"
253         "o The 'Defined at' line tell at what file / line number the symbol\n"
254         "  is defined\n"
255         "o The 'Depends on:' line tell what symbols needs to be defined for\n"
256         "  this symbol to be visible in the menu (selectable)\n"
257         "o The 'Location:' lines tell where in the menu structure this symbol\n"
258         "  is located\n"
259         "    A location followed by a [=y] indicate that this is a selectable\n"
260         "    menu item - and current value is displayed inside brackets.\n"
261         "o The 'Selects:' line tell what symbol will be automatically\n"
262         "  selected if this symbol is selected (y or m)\n"
263         "o The 'Selected by' line tell what symbol has selected this symbol\n"
264         "\n"
265         "Only relevant lines are shown.\n"
266         "\n\n"
267         "Search examples:\n"
268         "Examples: USB  => find all CONFIG_ symbols containing USB\n"
269         "          ^USB => find all CONFIG_ symbols starting with USB\n"
270         "          USB$ => find all CONFIG_ symbols ending with USB\n"
271         "\n");
272
273 static int indent;
274 static struct menu *current_menu;
275 static int child_count;
276 static int single_menu_mode;
277 static int show_all_options;
278
279 static void conf(struct menu *menu);
280 static void conf_choice(struct menu *menu);
281 static void conf_string(struct menu *menu);
282 static void conf_load(void);
283 static void conf_save(void);
284 static void show_textbox(const char *title, const char *text, int r, int c);
285 static void show_helptext(const char *title, const char *text);
286 static void show_help(struct menu *menu);
287
288 static char filename[PATH_MAX+1];
289 static void set_config_filename(const char *config_filename)
290 {
291         static char menu_backtitle[PATH_MAX+128];
292         int size;
293         struct symbol *sym;
294
295         sym = sym_lookup("KERNELVERSION", 0);
296         sym_calc_value(sym);
297         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
298                         _("%s - Linux Kernel v%s Configuration"),
299                         config_filename, sym_get_string_value(sym));
300         if (size >= sizeof(menu_backtitle))
301                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
302         set_dialog_backtitle(menu_backtitle);
303
304         size = snprintf(filename, sizeof(filename), "%s", config_filename);
305         if (size >= sizeof(filename))
306                 filename[sizeof(filename)-1] = '\0';
307 }
308
309
310 static void search_conf(void)
311 {
312         struct symbol **sym_arr;
313         struct gstr res;
314         char *dialog_input;
315         int dres;
316 again:
317         dialog_clear();
318         dres = dialog_inputbox(_("Search Configuration Parameter"),
319                               _("Enter CONFIG_ (sub)string to search for "
320                                 "(with or without \"CONFIG\")"),
321                               10, 75, "");
322         switch (dres) {
323         case 0:
324                 break;
325         case 1:
326                 show_helptext(_("Search Configuration"), search_help);
327                 goto again;
328         default:
329                 return;
330         }
331
332         /* strip CONFIG_ if necessary */
333         dialog_input = dialog_input_result;
334         if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
335                 dialog_input += 7;
336
337         sym_arr = sym_re_search(dialog_input);
338         res = get_relations_str(sym_arr);
339         free(sym_arr);
340         show_textbox(_("Search Results"), str_get(&res), 0, 0);
341         str_free(&res);
342 }
343
344 static void build_conf(struct menu *menu)
345 {
346         struct symbol *sym;
347         struct property *prop;
348         struct menu *child;
349         int type, tmp, doint = 2;
350         tristate val;
351         char ch;
352         bool visible;
353
354         /*
355          * note: menu_is_visible() has side effect that it will
356          * recalc the value of the symbol.
357          */
358         visible = menu_is_visible(menu);
359         if (show_all_options && !menu_has_prompt(menu))
360                 return;
361         else if (!show_all_options && !visible)
362                 return;
363
364         sym = menu->sym;
365         prop = menu->prompt;
366         if (!sym) {
367                 if (prop && menu != current_menu) {
368                         const char *prompt = menu_get_prompt(menu);
369                         switch (prop->type) {
370                         case P_MENU:
371                                 child_count++;
372                                 prompt = _(prompt);
373                                 if (single_menu_mode) {
374                                         item_make("%s%*c%s",
375                                                   menu->data ? "-->" : "++>",
376                                                   indent + 1, ' ', prompt);
377                                 } else
378                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
379
380                                 item_set_tag('m');
381                                 item_set_data(menu);
382                                 if (single_menu_mode && menu->data)
383                                         goto conf_childs;
384                                 return;
385                         case P_COMMENT:
386                                 if (prompt) {
387                                         child_count++;
388                                         item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
389                                         item_set_tag(':');
390                                         item_set_data(menu);
391                                 }
392                                 break;
393                         default:
394                                 if (prompt) {
395                                         child_count++;
396                                         item_make("---%*c%s", indent + 1, ' ', _(prompt));
397                                         item_set_tag(':');
398                                         item_set_data(menu);
399                                 }
400                         }
401                 } else
402                         doint = 0;
403                 goto conf_childs;
404         }
405
406         type = sym_get_type(sym);
407         if (sym_is_choice(sym)) {
408                 struct symbol *def_sym = sym_get_choice_value(sym);
409                 struct menu *def_menu = NULL;
410
411                 child_count++;
412                 for (child = menu->list; child; child = child->next) {
413                         if (menu_is_visible(child) && child->sym == def_sym)
414                                 def_menu = child;
415                 }
416
417                 val = sym_get_tristate_value(sym);
418                 if (sym_is_changable(sym)) {
419                         switch (type) {
420                         case S_BOOLEAN:
421                                 item_make("[%c]", val == no ? ' ' : '*');
422                                 break;
423                         case S_TRISTATE:
424                                 switch (val) {
425                                 case yes: ch = '*'; break;
426                                 case mod: ch = 'M'; break;
427                                 default:  ch = ' '; break;
428                                 }
429                                 item_make("<%c>", ch);
430                                 break;
431                         }
432                         item_set_tag('t');
433                         item_set_data(menu);
434                 } else {
435                         item_make("   ");
436                         item_set_tag(def_menu ? 't' : ':');
437                         item_set_data(menu);
438                 }
439
440                 item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
441                 if (val == yes) {
442                         if (def_menu) {
443                                 item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
444                                 item_add_str("  --->");
445                                 if (def_menu->list) {
446                                         indent += 2;
447                                         build_conf(def_menu);
448                                         indent -= 2;
449                                 }
450                         }
451                         return;
452                 }
453         } else {
454                 if (menu == current_menu) {
455                         item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
456                         item_set_tag(':');
457                         item_set_data(menu);
458                         goto conf_childs;
459                 }
460                 child_count++;
461                 val = sym_get_tristate_value(sym);
462                 if (sym_is_choice_value(sym) && val == yes) {
463                         item_make("   ");
464                         item_set_tag(':');
465                         item_set_data(menu);
466                 } else {
467                         switch (type) {
468                         case S_BOOLEAN:
469                                 if (sym_is_changable(sym))
470                                         item_make("[%c]", val == no ? ' ' : '*');
471                                 else
472                                         item_make("-%c-", val == no ? ' ' : '*');
473                                 item_set_tag('t');
474                                 item_set_data(menu);
475                                 break;
476                         case S_TRISTATE:
477                                 switch (val) {
478                                 case yes: ch = '*'; break;
479                                 case mod: ch = 'M'; break;
480                                 default:  ch = ' '; break;
481                                 }
482                                 if (sym_is_changable(sym)) {
483                                         if (sym->rev_dep.tri == mod)
484                                                 item_make("{%c}", ch);
485                                         else
486                                                 item_make("<%c>", ch);
487                                 } else
488                                         item_make("-%c-", ch);
489                                 item_set_tag('t');
490                                 item_set_data(menu);
491                                 break;
492                         default:
493                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
494                                 item_make("(%s)", sym_get_string_value(sym));
495                                 tmp = indent - tmp + 4;
496                                 if (tmp < 0)
497                                         tmp = 0;
498                                 item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
499                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
500                                              "" : _(" (NEW)"));
501                                 item_set_tag('s');
502                                 item_set_data(menu);
503                                 goto conf_childs;
504                         }
505                 }
506                 item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
507                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
508                           "" : _(" (NEW)"));
509                 if (menu->prompt->type == P_MENU) {
510                         item_add_str("  --->");
511                         return;
512                 }
513         }
514
515 conf_childs:
516         indent += doint;
517         for (child = menu->list; child; child = child->next)
518                 build_conf(child);
519         indent -= doint;
520 }
521
522 static void conf(struct menu *menu)
523 {
524         struct menu *submenu;
525         const char *prompt = menu_get_prompt(menu);
526         struct symbol *sym;
527         struct menu *active_menu = NULL;
528         int res;
529         int s_scroll = 0;
530
531         while (1) {
532                 item_reset();
533                 current_menu = menu;
534                 build_conf(menu);
535                 if (!child_count)
536                         break;
537                 if (menu == &rootmenu) {
538                         item_make("--- ");
539                         item_set_tag(':');
540                         item_make(_("    Load an Alternate Configuration File"));
541                         item_set_tag('L');
542                         item_make(_("    Save an Alternate Configuration File"));
543                         item_set_tag('S');
544                 }
545                 dialog_clear();
546                 res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
547                                   _(menu_instructions),
548                                   active_menu, &s_scroll);
549                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
550                         break;
551                 if (!item_activate_selected())
552                         continue;
553                 if (!item_tag())
554                         continue;
555
556                 submenu = item_data();
557                 active_menu = item_data();
558                 if (submenu)
559                         sym = submenu->sym;
560                 else
561                         sym = NULL;
562
563                 switch (res) {
564                 case 0:
565                         switch (item_tag()) {
566                         case 'm':
567                                 if (single_menu_mode)
568                                         submenu->data = (void *) (long) !submenu->data;
569                                 else
570                                         conf(submenu);
571                                 break;
572                         case 't':
573                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
574                                         conf_choice(submenu);
575                                 else if (submenu->prompt->type == P_MENU)
576                                         conf(submenu);
577                                 break;
578                         case 's':
579                                 conf_string(submenu);
580                                 break;
581                         case 'L':
582                                 conf_load();
583                                 break;
584                         case 'S':
585                                 conf_save();
586                                 break;
587                         }
588                         break;
589                 case 2:
590                         if (sym)
591                                 show_help(submenu);
592                         else
593                                 show_helptext(_("README"), _(mconf_readme));
594                         break;
595                 case 3:
596                         if (item_is_tag('t')) {
597                                 if (sym_set_tristate_value(sym, yes))
598                                         break;
599                                 if (sym_set_tristate_value(sym, mod))
600                                         show_textbox(NULL, setmod_text, 6, 74);
601                         }
602                         break;
603                 case 4:
604                         if (item_is_tag('t'))
605                                 sym_set_tristate_value(sym, no);
606                         break;
607                 case 5:
608                         if (item_is_tag('t'))
609                                 sym_set_tristate_value(sym, mod);
610                         break;
611                 case 6:
612                         if (item_is_tag('t'))
613                                 sym_toggle_tristate_value(sym);
614                         else if (item_is_tag('m'))
615                                 conf(submenu);
616                         break;
617                 case 7:
618                         search_conf();
619                         break;
620                 case 8:
621                         show_all_options = !show_all_options;
622                         break;
623                 }
624         }
625 }
626
627 static void show_textbox(const char *title, const char *text, int r, int c)
628 {
629         dialog_clear();
630         dialog_textbox(title, text, r, c);
631 }
632
633 static void show_helptext(const char *title, const char *text)
634 {
635         show_textbox(title, text, 0, 0);
636 }
637
638 static void show_help(struct menu *menu)
639 {
640         struct gstr help = str_new();
641
642         help.max_width = getmaxx(stdscr) - 10;
643         menu_get_ext_help(menu, &help);
644
645         show_helptext(_(menu_get_prompt(menu)), str_get(&help));
646         str_free(&help);
647 }
648
649 static void conf_choice(struct menu *menu)
650 {
651         const char *prompt = _(menu_get_prompt(menu));
652         struct menu *child;
653         struct symbol *active;
654
655         active = sym_get_choice_value(menu->sym);
656         while (1) {
657                 int res;
658                 int selected;
659                 item_reset();
660
661                 current_menu = menu;
662                 for (child = menu->list; child; child = child->next) {
663                         if (!menu_is_visible(child))
664                                 continue;
665                         if (child->sym)
666                                 item_make("%s", _(menu_get_prompt(child)));
667                         else {
668                                 item_make("*** %s ***", _(menu_get_prompt(child)));
669                                 item_set_tag(':');
670                         }
671                         item_set_data(child);
672                         if (child->sym == active)
673                                 item_set_selected(1);
674                         if (child->sym == sym_get_choice_value(menu->sym))
675                                 item_set_tag('X');
676                 }
677                 dialog_clear();
678                 res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
679                                         _(radiolist_instructions),
680                                          15, 70, 6);
681                 selected = item_activate_selected();
682                 switch (res) {
683                 case 0:
684                         if (selected) {
685                                 child = item_data();
686                                 if (!child->sym)
687                                         break;
688
689                                 sym_set_tristate_value(child->sym, yes);
690                         }
691                         return;
692                 case 1:
693                         if (selected) {
694                                 child = item_data();
695                                 show_help(child);
696                                 active = child->sym;
697                         } else
698                                 show_help(menu);
699                         break;
700                 case KEY_ESC:
701                         return;
702                 case -ERRDISPLAYTOOSMALL:
703                         return;
704                 }
705         }
706 }
707
708 static void conf_string(struct menu *menu)
709 {
710         const char *prompt = menu_get_prompt(menu);
711
712         while (1) {
713                 int res;
714                 const char *heading;
715
716                 switch (sym_get_type(menu->sym)) {
717                 case S_INT:
718                         heading = _(inputbox_instructions_int);
719                         break;
720                 case S_HEX:
721                         heading = _(inputbox_instructions_hex);
722                         break;
723                 case S_STRING:
724                         heading = _(inputbox_instructions_string);
725                         break;
726                 default:
727                         heading = _("Internal mconf error!");
728                 }
729                 dialog_clear();
730                 res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
731                                       heading, 10, 75,
732                                       sym_get_string_value(menu->sym));
733                 switch (res) {
734                 case 0:
735                         if (sym_set_string_value(menu->sym, dialog_input_result))
736                                 return;
737                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
738                         break;
739                 case 1:
740                         show_help(menu);
741                         break;
742                 case KEY_ESC:
743                         return;
744                 }
745         }
746 }
747
748 static void conf_load(void)
749 {
750
751         while (1) {
752                 int res;
753                 dialog_clear();
754                 res = dialog_inputbox(NULL, load_config_text,
755                                       11, 55, filename);
756                 switch(res) {
757                 case 0:
758                         if (!dialog_input_result[0])
759                                 return;
760                         if (!conf_read(dialog_input_result)) {
761                                 set_config_filename(dialog_input_result);
762                                 sym_set_change_count(1);
763                                 return;
764                         }
765                         show_textbox(NULL, _("File does not exist!"), 5, 38);
766                         break;
767                 case 1:
768                         show_helptext(_("Load Alternate Configuration"), load_config_help);
769                         break;
770                 case KEY_ESC:
771                         return;
772                 }
773         }
774 }
775
776 static void conf_save(void)
777 {
778         while (1) {
779                 int res;
780                 dialog_clear();
781                 res = dialog_inputbox(NULL, save_config_text,
782                                       11, 55, filename);
783                 switch(res) {
784                 case 0:
785                         if (!dialog_input_result[0])
786                                 return;
787                         if (!conf_write(dialog_input_result)) {
788                                 set_config_filename(dialog_input_result);
789                                 return;
790                         }
791                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
792                         break;
793                 case 1:
794                         show_helptext(_("Save Alternate Configuration"), save_config_help);
795                         break;
796                 case KEY_ESC:
797                         return;
798                 }
799         }
800 }
801
802 int main(int ac, char **av)
803 {
804         int saved_x, saved_y;
805         char *mode;
806         int res;
807
808         setlocale(LC_ALL, "");
809         bindtextdomain(PACKAGE, LOCALEDIR);
810         textdomain(PACKAGE);
811
812         conf_parse(av[1]);
813         conf_read(NULL);
814
815         mode = getenv("MENUCONFIG_MODE");
816         if (mode) {
817                 if (!strcasecmp(mode, "single_menu"))
818                         single_menu_mode = 1;
819         }
820
821         initscr();
822
823         getyx(stdscr, saved_y, saved_x);
824         if (init_dialog(NULL)) {
825                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
826                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
827                 return 1;
828         }
829
830         set_config_filename(conf_get_configname());
831         do {
832                 conf(&rootmenu);
833                 dialog_clear();
834                 if (conf_get_changed())
835                         res = dialog_yesno(NULL,
836                                            _("Do you wish to save your "
837                                              "new kernel configuration?\n"
838                                              "<ESC><ESC> to continue."),
839                                            6, 60);
840                 else
841                         res = -1;
842         } while (res == KEY_ESC);
843         end_dialog(saved_x, saved_y);
844
845         switch (res) {
846         case 0:
847                 if (conf_write(filename)) {
848                         fprintf(stderr, _("\n\n"
849                                 "Error during writing of the kernel configuration.\n"
850                                 "Your kernel configuration changes were NOT saved."
851                                 "\n\n"));
852                         return 1;
853                 }
854         case -1:
855                 printf(_("\n\n"
856                         "*** End of Linux kernel configuration.\n"
857                         "*** Execute 'make' to build the kernel or try 'make help'."
858                         "\n\n"));
859                 break;
860         default:
861                 fprintf(stderr, _("\n\n"
862                         "Your kernel configuration changes were NOT saved."
863                         "\n\n"));
864         }
865
866         return 0;
867 }
868