6841e95c0989bcd2007b46ad4178e8ad28dd1bbf
[linux-2.6.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 <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <locale.h>
20
21 #define LKC_DIRECT_LINK
22 #include "lkc.h"
23 #include "lxdialog/dialog.h"
24
25 static const char mconf_readme[] = N_(
26 "Overview\n"
27 "--------\n"
28 "Some kernel features may be built directly into the kernel.\n"
29 "Some may be made into loadable runtime modules.  Some features\n"
30 "may be completely removed altogether.  There are also certain\n"
31 "kernel parameters which are not really features, but must be\n"
32 "entered in as decimal or hexadecimal numbers or possibly text.\n"
33 "\n"
34 "Menu items beginning with following braces represent features that\n"
35 "  [ ] can be built in or removed\n"
36 "  < > can be built in, modularized or removed\n"
37 "  { } can be built in or modularized (selected by other feature)\n"
38 "  - - are selected by other feature,\n"
39 "while *, M or whitespace inside braces means to build in, build as\n"
40 "a module or to exclude the feature respectively.\n"
41 "\n"
42 "To change any of these features, highlight it with the cursor\n"
43 "keys and press <Y> to build it in, <M> to make it a module or\n"
44 "<N> to removed it.  You may also press the <Space Bar> to cycle\n"
45 "through the available options (ie. Y->N->M->Y).\n"
46 "\n"
47 "Some additional keyboard hints:\n"
48 "\n"
49 "Menus\n"
50 "----------\n"
51 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
52 "   you wish to change or submenu wish to select and press <Enter>.\n"
53 "   Submenus are designated by \"--->\".\n"
54 "\n"
55 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
56 "             Pressing a hotkey more than once will sequence\n"
57 "             through all visible items which use that hotkey.\n"
58 "\n"
59 "   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
60 "   unseen options into view.\n"
61 "\n"
62 "o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
63 "   and press <ENTER>.\n"
64 "\n"
65 "   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
66 "             using those letters.  You may press a single <ESC>, but\n"
67 "             there is a delayed response which you may find annoying.\n"
68 "\n"
69 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
70 "   <Exit> and <Help>\n"
71 "\n"
72 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
73 "   and Press <ENTER>.\n"
74 "\n"
75 "   Shortcut: Press <H> or <?>.\n"
76 "\n"
77 "\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 menu *current_menu;
275 static int child_count;
276 static int single_menu_mode;
277
278 static void conf(struct menu *menu);
279 static void conf_choice(struct menu *menu);
280 static void conf_string(struct menu *menu);
281 static void conf_load(void);
282 static void conf_save(void);
283 static void show_textbox(const char *title, const char *text, int r, int c);
284 static void show_helptext(const char *title, const char *text);
285 static void show_help(struct menu *menu);
286
287 static void get_prompt_str(struct gstr *r, struct property *prop)
288 {
289         int i, j;
290         struct menu *submenu[8], *menu;
291
292         str_printf(r, _("Prompt: %s\n"), _(prop->text));
293         str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
294                 prop->menu->lineno);
295         if (!expr_is_yes(prop->visible.expr)) {
296                 str_append(r, _("  Depends on: "));
297                 expr_gstr_print(prop->visible.expr, r);
298                 str_append(r, "\n");
299         }
300         menu = prop->menu->parent;
301         for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
302                 submenu[i++] = menu;
303         if (i > 0) {
304                 str_printf(r, _("  Location:\n"));
305                 for (j = 4; --i >= 0; j += 2) {
306                         menu = submenu[i];
307                         str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
308                         if (menu->sym) {
309                                 str_printf(r, " (%s [=%s])", menu->sym->name ?
310                                         menu->sym->name : _("<choice>"),
311                                         sym_get_string_value(menu->sym));
312                         }
313                         str_append(r, "\n");
314                 }
315         }
316 }
317
318 static void get_symbol_str(struct gstr *r, struct symbol *sym)
319 {
320         bool hit;
321         struct property *prop;
322
323         if (sym && sym->name)
324                 str_printf(r, "Symbol: %s [=%s]\n", sym->name,
325                                                     sym_get_string_value(sym));
326         for_all_prompts(sym, prop)
327                 get_prompt_str(r, prop);
328         hit = false;
329         for_all_properties(sym, prop, P_SELECT) {
330                 if (!hit) {
331                         str_append(r, "  Selects: ");
332                         hit = true;
333                 } else
334                         str_printf(r, " && ");
335                 expr_gstr_print(prop->expr, r);
336         }
337         if (hit)
338                 str_append(r, "\n");
339         if (sym->rev_dep.expr) {
340                 str_append(r, _("  Selected by: "));
341                 expr_gstr_print(sym->rev_dep.expr, r);
342                 str_append(r, "\n");
343         }
344         str_append(r, "\n\n");
345 }
346
347 static struct gstr get_relations_str(struct symbol **sym_arr)
348 {
349         struct symbol *sym;
350         struct gstr res = str_new();
351         int i;
352
353         for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
354                 get_symbol_str(&res, sym);
355         if (!i)
356                 str_append(&res, _("No matches found.\n"));
357         return res;
358 }
359
360 static char filename[PATH_MAX+1];
361 static void set_config_filename(const char *config_filename)
362 {
363         static char menu_backtitle[PATH_MAX+128];
364         int size;
365         struct symbol *sym;
366
367         sym = sym_lookup("KERNELVERSION", 0);
368         sym_calc_value(sym);
369         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
370                         _("%s - Linux Kernel v%s Configuration"),
371                         config_filename, sym_get_string_value(sym));
372         if (size >= sizeof(menu_backtitle))
373                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
374         set_dialog_backtitle(menu_backtitle);
375
376         size = snprintf(filename, sizeof(filename), "%s", config_filename);
377         if (size >= sizeof(filename))
378                 filename[sizeof(filename)-1] = '\0';
379 }
380
381
382 static void search_conf(void)
383 {
384         struct symbol **sym_arr;
385         struct gstr res;
386         char *dialog_input;
387         int dres;
388 again:
389         dialog_clear();
390         dres = dialog_inputbox(_("Search Configuration Parameter"),
391                               _("Enter CONFIG_ (sub)string to search for "
392                                 "(with or without \"CONFIG\")"),
393                               10, 75, "");
394         switch (dres) {
395         case 0:
396                 break;
397         case 1:
398                 show_helptext(_("Search Configuration"), search_help);
399                 goto again;
400         default:
401                 return;
402         }
403
404         /* strip CONFIG_ if necessary */
405         dialog_input = dialog_input_result;
406         if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
407                 dialog_input += 7;
408
409         sym_arr = sym_re_search(dialog_input);
410         res = get_relations_str(sym_arr);
411         free(sym_arr);
412         show_textbox(_("Search Results"), str_get(&res), 0, 0);
413         str_free(&res);
414 }
415
416 static void build_conf(struct menu *menu)
417 {
418         struct symbol *sym;
419         struct property *prop;
420         struct menu *child;
421         int type, tmp, doint = 2;
422         tristate val;
423         char ch;
424
425         if (!menu_is_visible(menu))
426                 return;
427
428         sym = menu->sym;
429         prop = menu->prompt;
430         if (!sym) {
431                 if (prop && menu != current_menu) {
432                         const char *prompt = menu_get_prompt(menu);
433                         switch (prop->type) {
434                         case P_MENU:
435                                 child_count++;
436                                 prompt = _(prompt);
437                                 if (single_menu_mode) {
438                                         item_make("%s%*c%s",
439                                                   menu->data ? "-->" : "++>",
440                                                   indent + 1, ' ', prompt);
441                                 } else
442                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
443
444                                 item_set_tag('m');
445                                 item_set_data(menu);
446                                 if (single_menu_mode && menu->data)
447                                         goto conf_childs;
448                                 return;
449                         case P_COMMENT:
450                                 if (prompt) {
451                                         child_count++;
452                                         item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
453                                         item_set_tag(':');
454                                         item_set_data(menu);
455                                 }
456                                 break;
457                         default:
458                                 if (prompt) {
459                                         child_count++;
460                                         item_make("---%*c%s", indent + 1, ' ', _(prompt));
461                                         item_set_tag(':');
462                                         item_set_data(menu);
463                                 }
464                         }
465                 } else
466                         doint = 0;
467                 goto conf_childs;
468         }
469
470         type = sym_get_type(sym);
471         if (sym_is_choice(sym)) {
472                 struct symbol *def_sym = sym_get_choice_value(sym);
473                 struct menu *def_menu = NULL;
474
475                 child_count++;
476                 for (child = menu->list; child; child = child->next) {
477                         if (menu_is_visible(child) && child->sym == def_sym)
478                                 def_menu = child;
479                 }
480
481                 val = sym_get_tristate_value(sym);
482                 if (sym_is_changable(sym)) {
483                         switch (type) {
484                         case S_BOOLEAN:
485                                 item_make("[%c]", val == no ? ' ' : '*');
486                                 break;
487                         case S_TRISTATE:
488                                 switch (val) {
489                                 case yes: ch = '*'; break;
490                                 case mod: ch = 'M'; break;
491                                 default:  ch = ' '; break;
492                                 }
493                                 item_make("<%c>", ch);
494                                 break;
495                         }
496                         item_set_tag('t');
497                         item_set_data(menu);
498                 } else {
499                         item_make("   ");
500                         item_set_tag(def_menu ? 't' : ':');
501                         item_set_data(menu);
502                 }
503
504                 item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
505                 if (val == yes) {
506                         if (def_menu) {
507                                 item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
508                                 item_add_str("  --->");
509                                 if (def_menu->list) {
510                                         indent += 2;
511                                         build_conf(def_menu);
512                                         indent -= 2;
513                                 }
514                         }
515                         return;
516                 }
517         } else {
518                 if (menu == current_menu) {
519                         item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
520                         item_set_tag(':');
521                         item_set_data(menu);
522                         goto conf_childs;
523                 }
524                 child_count++;
525                 val = sym_get_tristate_value(sym);
526                 if (sym_is_choice_value(sym) && val == yes) {
527                         item_make("   ");
528                         item_set_tag(':');
529                         item_set_data(menu);
530                 } else {
531                         switch (type) {
532                         case S_BOOLEAN:
533                                 if (sym_is_changable(sym))
534                                         item_make("[%c]", val == no ? ' ' : '*');
535                                 else
536                                         item_make("-%c-", val == no ? ' ' : '*');
537                                 item_set_tag('t');
538                                 item_set_data(menu);
539                                 break;
540                         case S_TRISTATE:
541                                 switch (val) {
542                                 case yes: ch = '*'; break;
543                                 case mod: ch = 'M'; break;
544                                 default:  ch = ' '; break;
545                                 }
546                                 if (sym_is_changable(sym)) {
547                                         if (sym->rev_dep.tri == mod)
548                                                 item_make("{%c}", ch);
549                                         else
550                                                 item_make("<%c>", ch);
551                                 } else
552                                         item_make("-%c-", ch);
553                                 item_set_tag('t');
554                                 item_set_data(menu);
555                                 break;
556                         default:
557                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
558                                 item_make("(%s)", sym_get_string_value(sym));
559                                 tmp = indent - tmp + 4;
560                                 if (tmp < 0)
561                                         tmp = 0;
562                                 item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
563                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
564                                              "" : _(" (NEW)"));
565                                 item_set_tag('s');
566                                 item_set_data(menu);
567                                 goto conf_childs;
568                         }
569                 }
570                 item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
571                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
572                           "" : _(" (NEW)"));
573                 if (menu->prompt->type == P_MENU) {
574                         item_add_str("  --->");
575                         return;
576                 }
577         }
578
579 conf_childs:
580         indent += doint;
581         for (child = menu->list; child; child = child->next)
582                 build_conf(child);
583         indent -= doint;
584 }
585
586 static void conf(struct menu *menu)
587 {
588         struct menu *submenu;
589         const char *prompt = menu_get_prompt(menu);
590         struct symbol *sym;
591         struct menu *active_menu = NULL;
592         int res;
593         int s_scroll = 0;
594
595         while (1) {
596                 item_reset();
597                 current_menu = menu;
598                 build_conf(menu);
599                 if (!child_count)
600                         break;
601                 if (menu == &rootmenu) {
602                         item_make("--- ");
603                         item_set_tag(':');
604                         item_make(_("    Load an Alternate Configuration File"));
605                         item_set_tag('L');
606                         item_make(_("    Save an Alternate Configuration File"));
607                         item_set_tag('S');
608                 }
609                 dialog_clear();
610                 res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
611                                   _(menu_instructions),
612                                   active_menu, &s_scroll);
613                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
614                         break;
615                 if (!item_activate_selected())
616                         continue;
617                 if (!item_tag())
618                         continue;
619
620                 submenu = item_data();
621                 active_menu = item_data();
622                 if (submenu)
623                         sym = submenu->sym;
624                 else
625                         sym = NULL;
626
627                 switch (res) {
628                 case 0:
629                         switch (item_tag()) {
630                         case 'm':
631                                 if (single_menu_mode)
632                                         submenu->data = (void *) (long) !submenu->data;
633                                 else
634                                         conf(submenu);
635                                 break;
636                         case 't':
637                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
638                                         conf_choice(submenu);
639                                 else if (submenu->prompt->type == P_MENU)
640                                         conf(submenu);
641                                 break;
642                         case 's':
643                                 conf_string(submenu);
644                                 break;
645                         case 'L':
646                                 conf_load();
647                                 break;
648                         case 'S':
649                                 conf_save();
650                                 break;
651                         }
652                         break;
653                 case 2:
654                         if (sym)
655                                 show_help(submenu);
656                         else
657                                 show_helptext(_("README"), _(mconf_readme));
658                         break;
659                 case 3:
660                         if (item_is_tag('t')) {
661                                 if (sym_set_tristate_value(sym, yes))
662                                         break;
663                                 if (sym_set_tristate_value(sym, mod))
664                                         show_textbox(NULL, setmod_text, 6, 74);
665                         }
666                         break;
667                 case 4:
668                         if (item_is_tag('t'))
669                                 sym_set_tristate_value(sym, no);
670                         break;
671                 case 5:
672                         if (item_is_tag('t'))
673                                 sym_set_tristate_value(sym, mod);
674                         break;
675                 case 6:
676                         if (item_is_tag('t'))
677                                 sym_toggle_tristate_value(sym);
678                         else if (item_is_tag('m'))
679                                 conf(submenu);
680                         break;
681                 case 7:
682                         search_conf();
683                         break;
684                 }
685         }
686 }
687
688 static void show_textbox(const char *title, const char *text, int r, int c)
689 {
690         dialog_clear();
691         dialog_textbox(title, text, r, c);
692 }
693
694 static void show_helptext(const char *title, const char *text)
695 {
696         show_textbox(title, text, 0, 0);
697 }
698
699 static void show_help(struct menu *menu)
700 {
701         struct gstr help = str_new();
702         struct symbol *sym = menu->sym;
703
704         if (menu_has_help(menu))
705         {
706                 if (sym->name) {
707                         str_printf(&help, "CONFIG_%s:\n\n", sym->name);
708                         str_append(&help, _(menu_get_help(menu)));
709                         str_append(&help, "\n");
710                 }
711         } else {
712                 str_append(&help, nohelp_text);
713         }
714         get_symbol_str(&help, sym);
715         show_helptext(_(menu_get_prompt(menu)), str_get(&help));
716         str_free(&help);
717 }
718
719 static void conf_choice(struct menu *menu)
720 {
721         const char *prompt = _(menu_get_prompt(menu));
722         struct menu *child;
723         struct symbol *active;
724
725         active = sym_get_choice_value(menu->sym);
726         while (1) {
727                 int res;
728                 int selected;
729                 item_reset();
730
731                 current_menu = menu;
732                 for (child = menu->list; child; child = child->next) {
733                         if (!menu_is_visible(child))
734                                 continue;
735                         item_make("%s", _(menu_get_prompt(child)));
736                         item_set_data(child);
737                         if (child->sym == active)
738                                 item_set_selected(1);
739                         if (child->sym == sym_get_choice_value(menu->sym))
740                                 item_set_tag('X');
741                 }
742                 dialog_clear();
743                 res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
744                                         _(radiolist_instructions),
745                                          15, 70, 6);
746                 selected = item_activate_selected();
747                 switch (res) {
748                 case 0:
749                         if (selected) {
750                                 child = item_data();
751                                 sym_set_tristate_value(child->sym, yes);
752                         }
753                         return;
754                 case 1:
755                         if (selected) {
756                                 child = item_data();
757                                 show_help(child);
758                                 active = child->sym;
759                         } else
760                                 show_help(menu);
761                         break;
762                 case KEY_ESC:
763                         return;
764                 case -ERRDISPLAYTOOSMALL:
765                         return;
766                 }
767         }
768 }
769
770 static void conf_string(struct menu *menu)
771 {
772         const char *prompt = menu_get_prompt(menu);
773
774         while (1) {
775                 int res;
776                 const char *heading;
777
778                 switch (sym_get_type(menu->sym)) {
779                 case S_INT:
780                         heading = _(inputbox_instructions_int);
781                         break;
782                 case S_HEX:
783                         heading = _(inputbox_instructions_hex);
784                         break;
785                 case S_STRING:
786                         heading = _(inputbox_instructions_string);
787                         break;
788                 default:
789                         heading = _("Internal mconf error!");
790                 }
791                 dialog_clear();
792                 res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
793                                       heading, 10, 75,
794                                       sym_get_string_value(menu->sym));
795                 switch (res) {
796                 case 0:
797                         if (sym_set_string_value(menu->sym, dialog_input_result))
798                                 return;
799                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
800                         break;
801                 case 1:
802                         show_help(menu);
803                         break;
804                 case KEY_ESC:
805                         return;
806                 }
807         }
808 }
809
810 static void conf_load(void)
811 {
812
813         while (1) {
814                 int res;
815                 dialog_clear();
816                 res = dialog_inputbox(NULL, load_config_text,
817                                       11, 55, filename);
818                 switch(res) {
819                 case 0:
820                         if (!dialog_input_result[0])
821                                 return;
822                         if (!conf_read(dialog_input_result)) {
823                                 set_config_filename(dialog_input_result);
824                                 sym_set_change_count(1);
825                                 return;
826                         }
827                         show_textbox(NULL, _("File does not exist!"), 5, 38);
828                         break;
829                 case 1:
830                         show_helptext(_("Load Alternate Configuration"), load_config_help);
831                         break;
832                 case KEY_ESC:
833                         return;
834                 }
835         }
836 }
837
838 static void conf_save(void)
839 {
840         while (1) {
841                 int res;
842                 dialog_clear();
843                 res = dialog_inputbox(NULL, save_config_text,
844                                       11, 55, filename);
845                 switch(res) {
846                 case 0:
847                         if (!dialog_input_result[0])
848                                 return;
849                         if (!conf_write(dialog_input_result)) {
850                                 set_config_filename(dialog_input_result);
851                                 return;
852                         }
853                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
854                         break;
855                 case 1:
856                         show_helptext(_("Save Alternate Configuration"), save_config_help);
857                         break;
858                 case KEY_ESC:
859                         return;
860                 }
861         }
862 }
863
864 int main(int ac, char **av)
865 {
866         int saved_x, saved_y;
867         char *mode;
868         int res;
869
870         setlocale(LC_ALL, "");
871         bindtextdomain(PACKAGE, LOCALEDIR);
872         textdomain(PACKAGE);
873
874         conf_parse(av[1]);
875         conf_read(NULL);
876
877         mode = getenv("MENUCONFIG_MODE");
878         if (mode) {
879                 if (!strcasecmp(mode, "single_menu"))
880                         single_menu_mode = 1;
881         }
882
883         getyx(stdscr, saved_y, saved_x);
884         if (init_dialog(NULL)) {
885                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
886                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
887                 return 1;
888         }
889
890         set_config_filename(conf_get_configname());
891         do {
892                 conf(&rootmenu);
893                 dialog_clear();
894                 if (conf_get_changed())
895                         res = dialog_yesno(NULL,
896                                            _("Do you wish to save your "
897                                              "new kernel configuration?\n"
898                                              "<ESC><ESC> to continue."),
899                                            6, 60);
900                 else
901                         res = -1;
902         } while (res == KEY_ESC);
903         end_dialog(saved_x, saved_y);
904
905         switch (res) {
906         case 0:
907                 if (conf_write(filename)) {
908                         fprintf(stderr, _("\n\n"
909                                 "Error during writing of the kernel configuration.\n"
910                                 "Your kernel configuration changes were NOT saved."
911                                 "\n\n"));
912                         return 1;
913                 }
914         case -1:
915                 printf(_("\n\n"
916                         "*** End of Linux kernel configuration.\n"
917                         "*** Execute 'make' to build the kernel or try 'make help'."
918                         "\n\n"));
919                 break;
920         default:
921                 fprintf(stderr, _("\n\n"
922                         "Your kernel configuration changes were NOT saved."
923                         "\n\n"));
924         }
925
926         return 0;
927 }
928