d0e4fa594fc799642af61d60c44bf05f7da2f315
[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 <sys/ioctl.h>
12 #include <sys/wait.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <limits.h>
17 #include <signal.h>
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <termios.h>
22 #include <unistd.h>
23 #include <locale.h>
24
25 #define LKC_DIRECT_LINK
26 #include "lkc.h"
27 #include "lxdialog/dialog.h"
28
29 static const char mconf_readme[] = N_(
30 "Overview\n"
31 "--------\n"
32 "Some kernel features may be built directly into the kernel.\n"
33 "Some may be made into loadable runtime modules.  Some features\n"
34 "may be completely removed altogether.  There are also certain\n"
35 "kernel parameters which are not really features, but must be\n"
36 "entered in as decimal or hexadecimal numbers or possibly text.\n"
37 "\n"
38 "Menu items beginning with [*], <M> or [ ] represent features\n"
39 "configured to be built in, modularized or removed respectively.\n"
40 "Pointed brackets <> represent module capable features.\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 "\n"
78 "Radiolists  (Choice lists)\n"
79 "-----------\n"
80 "o  Use the cursor keys to select the option you wish to set and press\n"
81 "   <S> or the <SPACE BAR>.\n"
82 "\n"
83 "   Shortcut: Press the first letter of the option you wish to set then\n"
84 "             press <S> or <SPACE BAR>.\n"
85 "\n"
86 "o  To see available help for the item, use the cursor keys to highlight\n"
87 "   <Help> and Press <ENTER>.\n"
88 "\n"
89 "   Shortcut: Press <H> or <?>.\n"
90 "\n"
91 "   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
92 "   <Help>\n"
93 "\n"
94 "\n"
95 "Data Entry\n"
96 "-----------\n"
97 "o  Enter the requested information and press <ENTER>\n"
98 "   If you are entering hexadecimal values, it is not necessary to\n"
99 "   add the '0x' prefix to the entry.\n"
100 "\n"
101 "o  For help, use the <TAB> or cursor keys to highlight the help option\n"
102 "   and press <ENTER>.  You can try <TAB><H> as well.\n"
103 "\n"
104 "\n"
105 "Text Box    (Help Window)\n"
106 "--------\n"
107 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
108 "   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
109 "   who are familiar with less and lynx.\n"
110 "\n"
111 "o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
112 "\n"
113 "\n"
114 "Alternate Configuration Files\n"
115 "-----------------------------\n"
116 "Menuconfig supports the use of alternate configuration files for\n"
117 "those who, for various reasons, find it necessary to switch\n"
118 "between different kernel configurations.\n"
119 "\n"
120 "At the end of the main menu you will find two options.  One is\n"
121 "for saving the current configuration to a file of your choosing.\n"
122 "The other option is for loading a previously saved alternate\n"
123 "configuration.\n"
124 "\n"
125 "Even if you don't use alternate configuration files, but you\n"
126 "find during a Menuconfig session that you have completely messed\n"
127 "up your settings, you may use the \"Load Alternate...\" option to\n"
128 "restore your previously saved settings from \".config\" without\n"
129 "restarting Menuconfig.\n"
130 "\n"
131 "Other information\n"
132 "-----------------\n"
133 "If you use Menuconfig in an XTERM window make sure you have your\n"
134 "$TERM variable set to point to a xterm definition which supports color.\n"
135 "Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
136 "display correctly in a RXVT window because rxvt displays only one\n"
137 "intensity of color, bright.\n"
138 "\n"
139 "Menuconfig will display larger menus on screens or xterms which are\n"
140 "set to display more than the standard 25 row by 80 column geometry.\n"
141 "In order for this to work, the \"stty size\" command must be able to\n"
142 "display the screen's current row and column geometry.  I STRONGLY\n"
143 "RECOMMEND that you make sure you do NOT have the shell variables\n"
144 "LINES and COLUMNS exported into your environment.  Some distributions\n"
145 "export those variables via /etc/profile.  Some ncurses programs can\n"
146 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
147 "the true screen size.\n"
148 "\n"
149 "Optional personality available\n"
150 "------------------------------\n"
151 "If you prefer to have all of the kernel options listed in a single\n"
152 "menu, rather than the default multimenu hierarchy, run the menuconfig\n"
153 "with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
154 "\n"
155 "make MENUCONFIG_MODE=single_menu menuconfig\n"
156 "\n"
157 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
158 "is already unrolled.\n"
159 "\n"
160 "Note that this mode can eventually be a little more CPU expensive\n"
161 "(especially with a larger number of unrolled categories) than the\n"
162 "default mode.\n"
163 "\n"
164 "Different color themes available\n"
165 "--------------------------------\n"
166 "It is possible to select different color themes using the variable\n"
167 "MENUCONFIG_COLOR. To select a theme use:\n"
168 "\n"
169 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
170 "\n"
171 "Available themes are\n"
172 " mono       => selects colors suitable for monochrome displays\n"
173 " blackbg    => selects a color scheme with black background\n"
174 " classic    => theme with blue background. The classic look\n"
175 " bluetitle  => a LCD friendly version of classic. (default)\n"
176 "\n"),
177 menu_instructions[] = N_(
178         "Arrow keys navigate the menu.  "
179         "<Enter> selects submenus --->.  "
180         "Highlighted letters are hotkeys.  "
181         "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
182         "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
183         "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
184 radiolist_instructions[] = N_(
185         "Use the arrow keys to navigate this window or "
186         "press the hotkey of the item you wish to select "
187         "followed by the <SPACE BAR>. "
188         "Press <?> for additional information about this option."),
189 inputbox_instructions_int[] = N_(
190         "Please enter a decimal value. "
191         "Fractions will not be accepted.  "
192         "Use the <TAB> key to move from the input field to the buttons below it."),
193 inputbox_instructions_hex[] = N_(
194         "Please enter a hexadecimal value. "
195         "Use the <TAB> key to move from the input field to the buttons below it."),
196 inputbox_instructions_string[] = N_(
197         "Please enter a string value. "
198         "Use the <TAB> key to move from the input field to the buttons below it."),
199 setmod_text[] = N_(
200         "This feature depends on another which has been configured as a module.\n"
201         "As a result, this feature will be built as a module."),
202 nohelp_text[] = N_(
203         "There is no help available for this kernel option.\n"),
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 therefor 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 termios ios_org;
275 static int rows = 0, cols = 0;
276 static struct menu *current_menu;
277 static int child_count;
278 static int single_menu_mode;
279
280 static void conf(struct menu *menu);
281 static void conf_choice(struct menu *menu);
282 static void conf_string(struct menu *menu);
283 static void conf_load(void);
284 static void conf_save(void);
285 static void show_textbox(const char *title, const char *text, int r, int c);
286 static void show_helptext(const char *title, const char *text);
287 static void show_help(struct menu *menu);
288
289 static void init_wsize(void)
290 {
291         struct winsize ws;
292         char *env;
293
294         if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
295                 rows = ws.ws_row;
296                 cols = ws.ws_col;
297         }
298
299         if (!rows) {
300                 env = getenv("LINES");
301                 if (env)
302                         rows = atoi(env);
303                 if (!rows)
304                         rows = 24;
305         }
306         if (!cols) {
307                 env = getenv("COLUMNS");
308                 if (env)
309                         cols = atoi(env);
310                 if (!cols)
311                         cols = 80;
312         }
313
314         if (rows < 19 || cols < 80) {
315                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
316                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
317                 exit(1);
318         }
319
320         rows -= 4;
321         cols -= 5;
322 }
323
324 static void get_prompt_str(struct gstr *r, struct property *prop)
325 {
326         int i, j;
327         struct menu *submenu[8], *menu;
328
329         str_printf(r, "Prompt: %s\n", prop->text);
330         str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
331                 prop->menu->lineno);
332         if (!expr_is_yes(prop->visible.expr)) {
333                 str_append(r, "  Depends on: ");
334                 expr_gstr_print(prop->visible.expr, r);
335                 str_append(r, "\n");
336         }
337         menu = prop->menu->parent;
338         for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
339                 submenu[i++] = menu;
340         if (i > 0) {
341                 str_printf(r, "  Location:\n");
342                 for (j = 4; --i >= 0; j += 2) {
343                         menu = submenu[i];
344                         str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
345                         if (menu->sym) {
346                                 str_printf(r, " (%s [=%s])", menu->sym->name ?
347                                         menu->sym->name : "<choice>",
348                                         sym_get_string_value(menu->sym));
349                         }
350                         str_append(r, "\n");
351                 }
352         }
353 }
354
355 static void get_symbol_str(struct gstr *r, struct symbol *sym)
356 {
357         bool hit;
358         struct property *prop;
359
360         str_printf(r, "Symbol: %s [=%s]\n", sym->name,
361                                        sym_get_string_value(sym));
362         for_all_prompts(sym, prop)
363                 get_prompt_str(r, prop);
364         hit = false;
365         for_all_properties(sym, prop, P_SELECT) {
366                 if (!hit) {
367                         str_append(r, "  Selects: ");
368                         hit = true;
369                 } else
370                         str_printf(r, " && ");
371                 expr_gstr_print(prop->expr, r);
372         }
373         if (hit)
374                 str_append(r, "\n");
375         if (sym->rev_dep.expr) {
376                 str_append(r, "  Selected by: ");
377                 expr_gstr_print(sym->rev_dep.expr, r);
378                 str_append(r, "\n");
379         }
380         str_append(r, "\n\n");
381 }
382
383 static struct gstr get_relations_str(struct symbol **sym_arr)
384 {
385         struct symbol *sym;
386         struct gstr res = str_new();
387         int i;
388
389         for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
390                 get_symbol_str(&res, sym);
391         if (!i)
392                 str_append(&res, "No matches found.\n");
393         return res;
394 }
395
396 static char filename[PATH_MAX+1];
397 static void set_config_filename(const char *config_filename)
398 {
399         static char menu_backtitle[PATH_MAX+128];
400         int size;
401         struct symbol *sym;
402
403         sym = sym_lookup("KERNELVERSION", 0);
404         sym_calc_value(sym);
405         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
406                         _("%s - Linux Kernel v%s Configuration"),
407                         config_filename, sym_get_string_value(sym));
408         if (size >= sizeof(menu_backtitle))
409                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
410         set_dialog_backtitle(menu_backtitle);
411
412         size = snprintf(filename, sizeof(filename), "%s", config_filename);
413         if (size >= sizeof(filename))
414                 filename[sizeof(filename)-1] = '\0';
415 }
416
417
418 static void search_conf(void)
419 {
420         struct symbol **sym_arr;
421         struct gstr res;
422         int dres;
423 again:
424         dialog_clear();
425         dres = dialog_inputbox(_("Search Configuration Parameter"),
426                               _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
427                               10, 75, "");
428         switch (dres) {
429         case 0:
430                 break;
431         case 1:
432                 show_helptext(_("Search Configuration"), search_help);
433                 goto again;
434         default:
435                 return;
436         }
437
438         sym_arr = sym_re_search(dialog_input_result);
439         res = get_relations_str(sym_arr);
440         free(sym_arr);
441         show_textbox(_("Search Results"), str_get(&res), 0, 0);
442         str_free(&res);
443 }
444
445 static void build_conf(struct menu *menu)
446 {
447         struct symbol *sym;
448         struct property *prop;
449         struct menu *child;
450         int type, tmp, doint = 2;
451         tristate val;
452         char ch;
453
454         if (!menu_is_visible(menu))
455                 return;
456
457         sym = menu->sym;
458         prop = menu->prompt;
459         if (!sym) {
460                 if (prop && menu != current_menu) {
461                         const char *prompt = menu_get_prompt(menu);
462                         switch (prop->type) {
463                         case P_MENU:
464                                 child_count++;
465                                 if (single_menu_mode) {
466                                         item_make("%s%*c%s",
467                                                   menu->data ? "-->" : "++>",
468                                                   indent + 1, ' ', prompt);
469                                 } else
470                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
471
472                                 item_set_tag('m');
473                                 item_set_data(menu);
474                                 if (single_menu_mode && menu->data)
475                                         goto conf_childs;
476                                 return;
477                         default:
478                                 if (prompt) {
479                                         child_count++;
480                                         item_make("---%*c%s", indent + 1, ' ', prompt);
481                                         item_set_tag(':');
482                                         item_set_data(menu);
483                                 }
484                         }
485                 } else
486                         doint = 0;
487                 goto conf_childs;
488         }
489
490         type = sym_get_type(sym);
491         if (sym_is_choice(sym)) {
492                 struct symbol *def_sym = sym_get_choice_value(sym);
493                 struct menu *def_menu = NULL;
494
495                 child_count++;
496                 for (child = menu->list; child; child = child->next) {
497                         if (menu_is_visible(child) && child->sym == def_sym)
498                                 def_menu = child;
499                 }
500
501                 val = sym_get_tristate_value(sym);
502                 if (sym_is_changable(sym)) {
503                         switch (type) {
504                         case S_BOOLEAN:
505                                 item_make("[%c]", val == no ? ' ' : '*');
506                                 break;
507                         case S_TRISTATE:
508                                 switch (val) {
509                                 case yes: ch = '*'; break;
510                                 case mod: ch = 'M'; break;
511                                 default:  ch = ' '; break;
512                                 }
513                                 item_make("<%c>", ch);
514                                 break;
515                         }
516                         item_set_tag('t');
517                         item_set_data(menu);
518                 } else {
519                         item_make("   ");
520                         item_set_tag(def_menu ? 't' : ':');
521                         item_set_data(menu);
522                 }
523
524                 item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
525                 if (val == yes) {
526                         if (def_menu) {
527                                 item_add_str(" (%s)", menu_get_prompt(def_menu));
528                                 item_add_str("  --->");
529                                 if (def_menu->list) {
530                                         indent += 2;
531                                         build_conf(def_menu);
532                                         indent -= 2;
533                                 }
534                         }
535                         return;
536                 }
537         } else {
538                 if (menu == current_menu) {
539                         item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
540                         item_set_tag(':');
541                         item_set_data(menu);
542                         goto conf_childs;
543                 }
544                 child_count++;
545                 val = sym_get_tristate_value(sym);
546                 if (sym_is_choice_value(sym) && val == yes) {
547                         item_make("   ");
548                         item_set_tag(':');
549                         item_set_data(menu);
550                 } else {
551                         switch (type) {
552                         case S_BOOLEAN:
553                                 if (sym_is_changable(sym))
554                                         item_make("[%c]", val == no ? ' ' : '*');
555                                 else
556                                         item_make("---");
557                                 item_set_tag('t');
558                                 item_set_data(menu);
559                                 break;
560                         case S_TRISTATE:
561                                 switch (val) {
562                                 case yes: ch = '*'; break;
563                                 case mod: ch = 'M'; break;
564                                 default:  ch = ' '; break;
565                                 }
566                                 if (sym_is_changable(sym))
567                                         item_make("<%c>", ch);
568                                 else
569                                         item_make("---");
570                                 item_set_tag('t');
571                                 item_set_data(menu);
572                                 break;
573                         default:
574                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
575                                 item_make("(%s)", sym_get_string_value(sym));
576                                 tmp = indent - tmp + 4;
577                                 if (tmp < 0)
578                                         tmp = 0;
579                                 item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
580                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
581                                              "" : " (NEW)");
582                                 item_set_tag('s');
583                                 item_set_data(menu);
584                                 goto conf_childs;
585                         }
586                 }
587                 item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
588                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
589                           "" : " (NEW)");
590                 if (menu->prompt->type == P_MENU) {
591                         item_add_str("  --->");
592                         return;
593                 }
594         }
595
596 conf_childs:
597         indent += doint;
598         for (child = menu->list; child; child = child->next)
599                 build_conf(child);
600         indent -= doint;
601 }
602
603 static void conf(struct menu *menu)
604 {
605         struct menu *submenu;
606         const char *prompt = menu_get_prompt(menu);
607         struct symbol *sym;
608         struct menu *active_menu = NULL;
609         int res;
610         int s_scroll = 0;
611
612         while (1) {
613                 item_reset();
614                 current_menu = menu;
615                 build_conf(menu);
616                 if (!child_count)
617                         break;
618                 if (menu == &rootmenu) {
619                         item_make("--- ");
620                         item_set_tag(':');
621                         item_make(_("    Load an Alternate Configuration File"));
622                         item_set_tag('L');
623                         item_make(_("    Save an Alternate Configuration File"));
624                         item_set_tag('S');
625                 }
626                 dialog_clear();
627                 res = dialog_menu(prompt ? prompt : _("Main Menu"),
628                                   _(menu_instructions),
629                                   active_menu, &s_scroll);
630                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
631                         break;
632                 if (!item_activate_selected())
633                         continue;
634                 if (!item_tag())
635                         continue;
636
637                 submenu = item_data();
638                 active_menu = item_data();
639                 if (submenu)
640                         sym = submenu->sym;
641                 else
642                         sym = NULL;
643
644                 switch (res) {
645                 case 0:
646                         switch (item_tag()) {
647                         case 'm':
648                                 if (single_menu_mode)
649                                         submenu->data = (void *) (long) !submenu->data;
650                                 else
651                                         conf(submenu);
652                                 break;
653                         case 't':
654                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
655                                         conf_choice(submenu);
656                                 else if (submenu->prompt->type == P_MENU)
657                                         conf(submenu);
658                                 break;
659                         case 's':
660                                 conf_string(submenu);
661                                 break;
662                         case 'L':
663                                 conf_load();
664                                 break;
665                         case 'S':
666                                 conf_save();
667                                 break;
668                         }
669                         break;
670                 case 2:
671                         if (sym)
672                                 show_help(submenu);
673                         else
674                                 show_helptext("README", _(mconf_readme));
675                         break;
676                 case 3:
677                         if (item_is_tag('t')) {
678                                 if (sym_set_tristate_value(sym, yes))
679                                         break;
680                                 if (sym_set_tristate_value(sym, mod))
681                                         show_textbox(NULL, setmod_text, 6, 74);
682                         }
683                         break;
684                 case 4:
685                         if (item_is_tag('t'))
686                                 sym_set_tristate_value(sym, no);
687                         break;
688                 case 5:
689                         if (item_is_tag('t'))
690                                 sym_set_tristate_value(sym, mod);
691                         break;
692                 case 6:
693                         if (item_is_tag('t'))
694                                 sym_toggle_tristate_value(sym);
695                         else if (item_is_tag('m'))
696                                 conf(submenu);
697                         break;
698                 case 7:
699                         search_conf();
700                         break;
701                 }
702         }
703 }
704
705 static void show_textbox(const char *title, const char *text, int r, int c)
706 {
707         dialog_clear();
708         dialog_textbox(title, text, r, c);
709 }
710
711 static void show_helptext(const char *title, const char *text)
712 {
713         show_textbox(title, text, 0, 0);
714 }
715
716 static void show_help(struct menu *menu)
717 {
718         struct gstr help = str_new();
719         struct symbol *sym = menu->sym;
720
721         if (sym->help)
722         {
723                 if (sym->name) {
724                         str_printf(&help, "CONFIG_%s:\n\n", sym->name);
725                         str_append(&help, _(sym->help));
726                         str_append(&help, "\n");
727                 }
728         } else {
729                 str_append(&help, nohelp_text);
730         }
731         get_symbol_str(&help, sym);
732         show_helptext(menu_get_prompt(menu), str_get(&help));
733         str_free(&help);
734 }
735
736 static void conf_choice(struct menu *menu)
737 {
738         const char *prompt = menu_get_prompt(menu);
739         struct menu *child;
740         struct symbol *active;
741
742         active = sym_get_choice_value(menu->sym);
743         while (1) {
744                 int res;
745                 int selected;
746                 item_reset();
747
748                 current_menu = menu;
749                 for (child = menu->list; child; child = child->next) {
750                         if (!menu_is_visible(child))
751                                 continue;
752                         item_make("%s", menu_get_prompt(child));
753                         item_set_data(child);
754                         if (child->sym == active)
755                                 item_set_selected(1);
756                         if (child->sym == sym_get_choice_value(menu->sym))
757                                 item_set_tag('X');
758                 }
759                 dialog_clear();
760                 res = dialog_checklist(prompt ? prompt : _("Main Menu"),
761                                         _(radiolist_instructions),
762                                          15, 70, 6);
763                 selected = item_activate_selected();
764                 switch (res) {
765                 case 0:
766                         if (selected) {
767                                 child = item_data();
768                                 sym_set_tristate_value(child->sym, yes);
769                         }
770                         return;
771                 case 1:
772                         if (selected) {
773                                 child = item_data();
774                                 show_help(child);
775                                 active = child->sym;
776                         } else
777                                 show_help(menu);
778                         break;
779                 case KEY_ESC:
780                         return;
781                 case -ERRDISPLAYTOOSMALL:
782                         return;
783                 }
784         }
785 }
786
787 static void conf_string(struct menu *menu)
788 {
789         const char *prompt = menu_get_prompt(menu);
790
791         while (1) {
792                 int res;
793                 char *heading;
794
795                 switch (sym_get_type(menu->sym)) {
796                 case S_INT:
797                         heading = _(inputbox_instructions_int);
798                         break;
799                 case S_HEX:
800                         heading = _(inputbox_instructions_hex);
801                         break;
802                 case S_STRING:
803                         heading = _(inputbox_instructions_string);
804                         break;
805                 default:
806                         heading = "Internal mconf error!";
807                 }
808                 dialog_clear();
809                 res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
810                                       heading, 10, 75,
811                                       sym_get_string_value(menu->sym));
812                 switch (res) {
813                 case 0:
814                         if (sym_set_string_value(menu->sym, dialog_input_result))
815                                 return;
816                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
817                         break;
818                 case 1:
819                         show_help(menu);
820                         break;
821                 case KEY_ESC:
822                         return;
823                 }
824         }
825 }
826
827 static void conf_load(void)
828 {
829
830         while (1) {
831                 int res;
832                 dialog_clear();
833                 res = dialog_inputbox(NULL, load_config_text,
834                                       11, 55, filename);
835                 switch(res) {
836                 case 0:
837                         if (!dialog_input_result[0])
838                                 return;
839                         if (!conf_read(dialog_input_result)) {
840                                 set_config_filename(dialog_input_result);
841                                 return;
842                         }
843                         show_textbox(NULL, _("File does not exist!"), 5, 38);
844                         break;
845                 case 1:
846                         show_helptext(_("Load Alternate Configuration"), load_config_help);
847                         break;
848                 case KEY_ESC:
849                         return;
850                 }
851         }
852 }
853
854 static void conf_save(void)
855 {
856         while (1) {
857                 int res;
858                 dialog_clear();
859                 res = dialog_inputbox(NULL, save_config_text,
860                                       11, 55, filename);
861                 switch(res) {
862                 case 0:
863                         if (!dialog_input_result[0])
864                                 return;
865                         if (!conf_write(dialog_input_result)) {
866                                 set_config_filename(dialog_input_result);
867                                 return;
868                         }
869                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
870                         break;
871                 case 1:
872                         show_helptext(_("Save Alternate Configuration"), save_config_help);
873                         break;
874                 case KEY_ESC:
875                         return;
876                 }
877         }
878 }
879
880 static void conf_cleanup(void)
881 {
882         tcsetattr(1, TCSAFLUSH, &ios_org);
883 }
884
885 int main(int ac, char **av)
886 {
887         char *mode;
888         int res;
889
890         setlocale(LC_ALL, "");
891         bindtextdomain(PACKAGE, LOCALEDIR);
892         textdomain(PACKAGE);
893
894         conf_parse(av[1]);
895         conf_read(NULL);
896
897         mode = getenv("MENUCONFIG_MODE");
898         if (mode) {
899                 if (!strcasecmp(mode, "single_menu"))
900                         single_menu_mode = 1;
901         }
902
903         tcgetattr(1, &ios_org);
904         atexit(conf_cleanup);
905         init_wsize();
906         reset_dialog();
907         init_dialog(NULL);
908         set_config_filename(conf_get_configname());
909         do {
910                 conf(&rootmenu);
911                 dialog_clear();
912                 if (conf_get_changed())
913                         res = dialog_yesno(NULL,
914                                            _("Do you wish to save your "
915                                              "new kernel configuration?\n"
916                                              "<ESC><ESC> to continue."),
917                                            6, 60);
918                 else
919                         res = -1;
920         } while (res == KEY_ESC);
921         end_dialog();
922
923         switch (res) {
924         case 0:
925                 if (conf_write(filename)) {
926                         fprintf(stderr, _("\n\n"
927                                 "Error during writing of the kernel configuration.\n"
928                                 "Your kernel configuration changes were NOT saved."
929                                 "\n\n"));
930                         return 1;
931                 }
932         case -1:
933                 printf(_("\n\n"
934                         "*** End of Linux kernel configuration.\n"
935                         "*** Execute 'make' to build the kernel or try 'make help'."
936                         "\n\n"));
937                 break;
938         default:
939                 fprintf(stderr, _("\n\n"
940                         "Your kernel configuration changes were NOT saved."
941                         "\n\n"));
942         }
943
944         return 0;
945 }