kconfig: make comments stand out in menuconfig
[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         char *dialog_input;
423         int dres;
424 again:
425         dialog_clear();
426         dres = dialog_inputbox(_("Search Configuration Parameter"),
427                               _("Enter CONFIG_ (sub)string to search for "
428                                 "(with or without \"CONFIG\")"),
429                               10, 75, "");
430         switch (dres) {
431         case 0:
432                 break;
433         case 1:
434                 show_helptext(_("Search Configuration"), search_help);
435                 goto again;
436         default:
437                 return;
438         }
439
440         /* strip CONFIG_ if necessary */
441         dialog_input = dialog_input_result;
442         if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
443                 dialog_input += 7;
444
445         sym_arr = sym_re_search(dialog_input);
446         res = get_relations_str(sym_arr);
447         free(sym_arr);
448         show_textbox(_("Search Results"), str_get(&res), 0, 0);
449         str_free(&res);
450 }
451
452 static void build_conf(struct menu *menu)
453 {
454         struct symbol *sym;
455         struct property *prop;
456         struct menu *child;
457         int type, tmp, doint = 2;
458         tristate val;
459         char ch;
460
461         if (!menu_is_visible(menu))
462                 return;
463
464         sym = menu->sym;
465         prop = menu->prompt;
466         if (!sym) {
467                 if (prop && menu != current_menu) {
468                         const char *prompt = menu_get_prompt(menu);
469                         switch (prop->type) {
470                         case P_MENU:
471                                 child_count++;
472                                 if (single_menu_mode) {
473                                         item_make("%s%*c%s",
474                                                   menu->data ? "-->" : "++>",
475                                                   indent + 1, ' ', prompt);
476                                 } else
477                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
478
479                                 item_set_tag('m');
480                                 item_set_data(menu);
481                                 if (single_menu_mode && menu->data)
482                                         goto conf_childs;
483                                 return;
484                         case P_COMMENT:
485                                 if (prompt) {
486                                         child_count++;
487                                         item_make("   %*c*** %s ***", indent + 1, ' ', prompt);
488                                         item_set_tag(':');
489                                         item_set_data(menu);
490                                 }
491                                 break;
492                         default:
493                                 if (prompt) {
494                                         child_count++;
495                                         item_make("---%*c%s", indent + 1, ' ', prompt);
496                                         item_set_tag(':');
497                                         item_set_data(menu);
498                                 }
499                         }
500                 } else
501                         doint = 0;
502                 goto conf_childs;
503         }
504
505         type = sym_get_type(sym);
506         if (sym_is_choice(sym)) {
507                 struct symbol *def_sym = sym_get_choice_value(sym);
508                 struct menu *def_menu = NULL;
509
510                 child_count++;
511                 for (child = menu->list; child; child = child->next) {
512                         if (menu_is_visible(child) && child->sym == def_sym)
513                                 def_menu = child;
514                 }
515
516                 val = sym_get_tristate_value(sym);
517                 if (sym_is_changable(sym)) {
518                         switch (type) {
519                         case S_BOOLEAN:
520                                 item_make("[%c]", val == no ? ' ' : '*');
521                                 break;
522                         case S_TRISTATE:
523                                 switch (val) {
524                                 case yes: ch = '*'; break;
525                                 case mod: ch = 'M'; break;
526                                 default:  ch = ' '; break;
527                                 }
528                                 item_make("<%c>", ch);
529                                 break;
530                         }
531                         item_set_tag('t');
532                         item_set_data(menu);
533                 } else {
534                         item_make("   ");
535                         item_set_tag(def_menu ? 't' : ':');
536                         item_set_data(menu);
537                 }
538
539                 item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
540                 if (val == yes) {
541                         if (def_menu) {
542                                 item_add_str(" (%s)", menu_get_prompt(def_menu));
543                                 item_add_str("  --->");
544                                 if (def_menu->list) {
545                                         indent += 2;
546                                         build_conf(def_menu);
547                                         indent -= 2;
548                                 }
549                         }
550                         return;
551                 }
552         } else {
553                 if (menu == current_menu) {
554                         item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
555                         item_set_tag(':');
556                         item_set_data(menu);
557                         goto conf_childs;
558                 }
559                 child_count++;
560                 val = sym_get_tristate_value(sym);
561                 if (sym_is_choice_value(sym) && val == yes) {
562                         item_make("   ");
563                         item_set_tag(':');
564                         item_set_data(menu);
565                 } else {
566                         switch (type) {
567                         case S_BOOLEAN:
568                                 if (sym_is_changable(sym))
569                                         item_make("[%c]", val == no ? ' ' : '*');
570                                 else
571                                         item_make("---");
572                                 item_set_tag('t');
573                                 item_set_data(menu);
574                                 break;
575                         case S_TRISTATE:
576                                 switch (val) {
577                                 case yes: ch = '*'; break;
578                                 case mod: ch = 'M'; break;
579                                 default:  ch = ' '; break;
580                                 }
581                                 if (sym_is_changable(sym))
582                                         item_make("<%c>", ch);
583                                 else
584                                         item_make("---");
585                                 item_set_tag('t');
586                                 item_set_data(menu);
587                                 break;
588                         default:
589                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
590                                 item_make("(%s)", sym_get_string_value(sym));
591                                 tmp = indent - tmp + 4;
592                                 if (tmp < 0)
593                                         tmp = 0;
594                                 item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
595                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
596                                              "" : " (NEW)");
597                                 item_set_tag('s');
598                                 item_set_data(menu);
599                                 goto conf_childs;
600                         }
601                 }
602                 item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
603                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
604                           "" : " (NEW)");
605                 if (menu->prompt->type == P_MENU) {
606                         item_add_str("  --->");
607                         return;
608                 }
609         }
610
611 conf_childs:
612         indent += doint;
613         for (child = menu->list; child; child = child->next)
614                 build_conf(child);
615         indent -= doint;
616 }
617
618 static void conf(struct menu *menu)
619 {
620         struct menu *submenu;
621         const char *prompt = menu_get_prompt(menu);
622         struct symbol *sym;
623         struct menu *active_menu = NULL;
624         int res;
625         int s_scroll = 0;
626
627         while (1) {
628                 item_reset();
629                 current_menu = menu;
630                 build_conf(menu);
631                 if (!child_count)
632                         break;
633                 if (menu == &rootmenu) {
634                         item_make("--- ");
635                         item_set_tag(':');
636                         item_make(_("    Load an Alternate Configuration File"));
637                         item_set_tag('L');
638                         item_make(_("    Save an Alternate Configuration File"));
639                         item_set_tag('S');
640                 }
641                 dialog_clear();
642                 res = dialog_menu(prompt ? prompt : _("Main Menu"),
643                                   _(menu_instructions),
644                                   active_menu, &s_scroll);
645                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
646                         break;
647                 if (!item_activate_selected())
648                         continue;
649                 if (!item_tag())
650                         continue;
651
652                 submenu = item_data();
653                 active_menu = item_data();
654                 if (submenu)
655                         sym = submenu->sym;
656                 else
657                         sym = NULL;
658
659                 switch (res) {
660                 case 0:
661                         switch (item_tag()) {
662                         case 'm':
663                                 if (single_menu_mode)
664                                         submenu->data = (void *) (long) !submenu->data;
665                                 else
666                                         conf(submenu);
667                                 break;
668                         case 't':
669                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
670                                         conf_choice(submenu);
671                                 else if (submenu->prompt->type == P_MENU)
672                                         conf(submenu);
673                                 break;
674                         case 's':
675                                 conf_string(submenu);
676                                 break;
677                         case 'L':
678                                 conf_load();
679                                 break;
680                         case 'S':
681                                 conf_save();
682                                 break;
683                         }
684                         break;
685                 case 2:
686                         if (sym)
687                                 show_help(submenu);
688                         else
689                                 show_helptext("README", _(mconf_readme));
690                         break;
691                 case 3:
692                         if (item_is_tag('t')) {
693                                 if (sym_set_tristate_value(sym, yes))
694                                         break;
695                                 if (sym_set_tristate_value(sym, mod))
696                                         show_textbox(NULL, setmod_text, 6, 74);
697                         }
698                         break;
699                 case 4:
700                         if (item_is_tag('t'))
701                                 sym_set_tristate_value(sym, no);
702                         break;
703                 case 5:
704                         if (item_is_tag('t'))
705                                 sym_set_tristate_value(sym, mod);
706                         break;
707                 case 6:
708                         if (item_is_tag('t'))
709                                 sym_toggle_tristate_value(sym);
710                         else if (item_is_tag('m'))
711                                 conf(submenu);
712                         break;
713                 case 7:
714                         search_conf();
715                         break;
716                 }
717         }
718 }
719
720 static void show_textbox(const char *title, const char *text, int r, int c)
721 {
722         dialog_clear();
723         dialog_textbox(title, text, r, c);
724 }
725
726 static void show_helptext(const char *title, const char *text)
727 {
728         show_textbox(title, text, 0, 0);
729 }
730
731 static void show_help(struct menu *menu)
732 {
733         struct gstr help = str_new();
734         struct symbol *sym = menu->sym;
735
736         if (menu_has_help(menu))
737         {
738                 if (sym->name) {
739                         str_printf(&help, "CONFIG_%s:\n\n", sym->name);
740                         str_append(&help, _(menu_get_help(menu)));
741                         str_append(&help, "\n");
742                 }
743         } else {
744                 str_append(&help, nohelp_text);
745         }
746         get_symbol_str(&help, sym);
747         show_helptext(menu_get_prompt(menu), str_get(&help));
748         str_free(&help);
749 }
750
751 static void conf_choice(struct menu *menu)
752 {
753         const char *prompt = menu_get_prompt(menu);
754         struct menu *child;
755         struct symbol *active;
756
757         active = sym_get_choice_value(menu->sym);
758         while (1) {
759                 int res;
760                 int selected;
761                 item_reset();
762
763                 current_menu = menu;
764                 for (child = menu->list; child; child = child->next) {
765                         if (!menu_is_visible(child))
766                                 continue;
767                         item_make("%s", menu_get_prompt(child));
768                         item_set_data(child);
769                         if (child->sym == active)
770                                 item_set_selected(1);
771                         if (child->sym == sym_get_choice_value(menu->sym))
772                                 item_set_tag('X');
773                 }
774                 dialog_clear();
775                 res = dialog_checklist(prompt ? prompt : _("Main Menu"),
776                                         _(radiolist_instructions),
777                                          15, 70, 6);
778                 selected = item_activate_selected();
779                 switch (res) {
780                 case 0:
781                         if (selected) {
782                                 child = item_data();
783                                 sym_set_tristate_value(child->sym, yes);
784                         }
785                         return;
786                 case 1:
787                         if (selected) {
788                                 child = item_data();
789                                 show_help(child);
790                                 active = child->sym;
791                         } else
792                                 show_help(menu);
793                         break;
794                 case KEY_ESC:
795                         return;
796                 case -ERRDISPLAYTOOSMALL:
797                         return;
798                 }
799         }
800 }
801
802 static void conf_string(struct menu *menu)
803 {
804         const char *prompt = menu_get_prompt(menu);
805
806         while (1) {
807                 int res;
808                 char *heading;
809
810                 switch (sym_get_type(menu->sym)) {
811                 case S_INT:
812                         heading = _(inputbox_instructions_int);
813                         break;
814                 case S_HEX:
815                         heading = _(inputbox_instructions_hex);
816                         break;
817                 case S_STRING:
818                         heading = _(inputbox_instructions_string);
819                         break;
820                 default:
821                         heading = "Internal mconf error!";
822                 }
823                 dialog_clear();
824                 res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
825                                       heading, 10, 75,
826                                       sym_get_string_value(menu->sym));
827                 switch (res) {
828                 case 0:
829                         if (sym_set_string_value(menu->sym, dialog_input_result))
830                                 return;
831                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
832                         break;
833                 case 1:
834                         show_help(menu);
835                         break;
836                 case KEY_ESC:
837                         return;
838                 }
839         }
840 }
841
842 static void conf_load(void)
843 {
844
845         while (1) {
846                 int res;
847                 dialog_clear();
848                 res = dialog_inputbox(NULL, load_config_text,
849                                       11, 55, filename);
850                 switch(res) {
851                 case 0:
852                         if (!dialog_input_result[0])
853                                 return;
854                         if (!conf_read(dialog_input_result)) {
855                                 set_config_filename(dialog_input_result);
856                                 return;
857                         }
858                         show_textbox(NULL, _("File does not exist!"), 5, 38);
859                         break;
860                 case 1:
861                         show_helptext(_("Load Alternate Configuration"), load_config_help);
862                         break;
863                 case KEY_ESC:
864                         return;
865                 }
866         }
867 }
868
869 static void conf_save(void)
870 {
871         while (1) {
872                 int res;
873                 dialog_clear();
874                 res = dialog_inputbox(NULL, save_config_text,
875                                       11, 55, filename);
876                 switch(res) {
877                 case 0:
878                         if (!dialog_input_result[0])
879                                 return;
880                         if (!conf_write(dialog_input_result)) {
881                                 set_config_filename(dialog_input_result);
882                                 return;
883                         }
884                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
885                         break;
886                 case 1:
887                         show_helptext(_("Save Alternate Configuration"), save_config_help);
888                         break;
889                 case KEY_ESC:
890                         return;
891                 }
892         }
893 }
894
895 static void conf_cleanup(void)
896 {
897         tcsetattr(1, TCSAFLUSH, &ios_org);
898 }
899
900 int main(int ac, char **av)
901 {
902         char *mode;
903         int res;
904
905         setlocale(LC_ALL, "");
906         bindtextdomain(PACKAGE, LOCALEDIR);
907         textdomain(PACKAGE);
908
909         conf_parse(av[1]);
910         conf_read(NULL);
911
912         mode = getenv("MENUCONFIG_MODE");
913         if (mode) {
914                 if (!strcasecmp(mode, "single_menu"))
915                         single_menu_mode = 1;
916         }
917
918         tcgetattr(1, &ios_org);
919         atexit(conf_cleanup);
920         init_wsize();
921         reset_dialog();
922         init_dialog(NULL);
923         set_config_filename(conf_get_configname());
924         do {
925                 conf(&rootmenu);
926                 dialog_clear();
927                 if (conf_get_changed())
928                         res = dialog_yesno(NULL,
929                                            _("Do you wish to save your "
930                                              "new kernel configuration?\n"
931                                              "<ESC><ESC> to continue."),
932                                            6, 60);
933                 else
934                         res = -1;
935         } while (res == KEY_ESC);
936         end_dialog();
937
938         switch (res) {
939         case 0:
940                 if (conf_write(filename)) {
941                         fprintf(stderr, _("\n\n"
942                                 "Error during writing of the kernel configuration.\n"
943                                 "Your kernel configuration changes were NOT saved."
944                                 "\n\n"));
945                         return 1;
946                 }
947         case -1:
948                 printf(_("\n\n"
949                         "*** End of Linux kernel configuration.\n"
950                         "*** Execute 'make' to build the kernel or try 'make help'."
951                         "\n\n"));
952                 break;
953         default:
954                 fprintf(stderr, _("\n\n"
955                         "Your kernel configuration changes were NOT saved."
956                         "\n\n"));
957         }
958
959         return 0;
960 }