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