Merge branch 'master' into for-next
[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 load_config_text[] = N_(
203         "Enter the name of the configuration file you wish to load.  "
204         "Accept the name shown to restore the configuration you "
205         "last retrieved.  Leave blank to abort."),
206 load_config_help[] = N_(
207         "\n"
208         "For various reasons, one may wish to keep several different kernel\n"
209         "configurations available on a single machine.\n"
210         "\n"
211         "If you have saved a previous configuration in a file other than the\n"
212         "kernel's default, entering the name of the file here will allow you\n"
213         "to modify that configuration.\n"
214         "\n"
215         "If you are uncertain, then you have probably never used alternate\n"
216         "configuration files. You should therefore leave this blank to abort.\n"),
217 save_config_text[] = N_(
218         "Enter a filename to which this configuration should be saved "
219         "as an alternate.  Leave blank to abort."),
220 save_config_help[] = N_(
221         "\n"
222         "For various reasons, one may wish to keep different kernel\n"
223         "configurations available on a single machine.\n"
224         "\n"
225         "Entering a file name here will allow you to later retrieve, modify\n"
226         "and use the current configuration as an alternate to whatever\n"
227         "configuration options you have selected at that time.\n"
228         "\n"
229         "If you are uncertain what all this means then you should probably\n"
230         "leave this blank.\n"),
231 search_help[] = N_(
232         "\n"
233         "Search for CONFIG_ symbols and display their relations.\n"
234         "Regular expressions are allowed.\n"
235         "Example: search for \"^FOO\"\n"
236         "Result:\n"
237         "-----------------------------------------------------------------\n"
238         "Symbol: FOO [=m]\n"
239         "Prompt: Foo bus is used to drive the bar HW\n"
240         "Defined at drivers/pci/Kconfig:47\n"
241         "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
242         "Location:\n"
243         "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
244         "    -> PCI support (PCI [=y])\n"
245         "      -> PCI access mode (<choice> [=y])\n"
246         "Selects: LIBCRC32\n"
247         "Selected by: BAR\n"
248         "-----------------------------------------------------------------\n"
249         "o The line 'Prompt:' shows the text used in the menu structure for\n"
250         "  this CONFIG_ symbol\n"
251         "o The 'Defined at' line tell at what file / line number the symbol\n"
252         "  is defined\n"
253         "o The 'Depends on:' line tell what symbols needs to be defined for\n"
254         "  this symbol to be visible in the menu (selectable)\n"
255         "o The 'Location:' lines tell where in the menu structure this symbol\n"
256         "  is located\n"
257         "    A location followed by a [=y] indicate that this is a selectable\n"
258         "    menu item - and current value is displayed inside brackets.\n"
259         "o The 'Selects:' line tell what symbol will be automatically\n"
260         "  selected if this symbol is selected (y or m)\n"
261         "o The 'Selected by' line tell what symbol has selected this symbol\n"
262         "\n"
263         "Only relevant lines are shown.\n"
264         "\n\n"
265         "Search examples:\n"
266         "Examples: USB  => find all CONFIG_ symbols containing USB\n"
267         "          ^USB => find all CONFIG_ symbols starting with USB\n"
268         "          USB$ => find all CONFIG_ symbols ending with USB\n"
269         "\n");
270
271 static int indent;
272 static struct menu *current_menu;
273 static int child_count;
274 static int single_menu_mode;
275
276 static void conf(struct menu *menu);
277 static void conf_choice(struct menu *menu);
278 static void conf_string(struct menu *menu);
279 static void conf_load(void);
280 static void conf_save(void);
281 static void show_textbox(const char *title, const char *text, int r, int c);
282 static void show_helptext(const char *title, const char *text);
283 static void show_help(struct menu *menu);
284
285 static struct gstr get_relations_str(struct symbol **sym_arr)
286 {
287         struct symbol *sym;
288         struct gstr res = str_new();
289         int i;
290
291         for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
292                 get_symbol_str(&res, sym);
293         if (!i)
294                 str_append(&res, _("No matches found.\n"));
295         return res;
296 }
297
298 static char filename[PATH_MAX+1];
299 static void set_config_filename(const char *config_filename)
300 {
301         static char menu_backtitle[PATH_MAX+128];
302         int size;
303         struct symbol *sym;
304
305         sym = sym_lookup("KERNELVERSION", 0);
306         sym_calc_value(sym);
307         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
308                         _("%s - Linux Kernel v%s Configuration"),
309                         config_filename, sym_get_string_value(sym));
310         if (size >= sizeof(menu_backtitle))
311                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
312         set_dialog_backtitle(menu_backtitle);
313
314         size = snprintf(filename, sizeof(filename), "%s", config_filename);
315         if (size >= sizeof(filename))
316                 filename[sizeof(filename)-1] = '\0';
317 }
318
319
320 static void search_conf(void)
321 {
322         struct symbol **sym_arr;
323         struct gstr res;
324         char *dialog_input;
325         int dres;
326 again:
327         dialog_clear();
328         dres = dialog_inputbox(_("Search Configuration Parameter"),
329                               _("Enter CONFIG_ (sub)string to search for "
330                                 "(with or without \"CONFIG\")"),
331                               10, 75, "");
332         switch (dres) {
333         case 0:
334                 break;
335         case 1:
336                 show_helptext(_("Search Configuration"), search_help);
337                 goto again;
338         default:
339                 return;
340         }
341
342         /* strip CONFIG_ if necessary */
343         dialog_input = dialog_input_result;
344         if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
345                 dialog_input += 7;
346
347         sym_arr = sym_re_search(dialog_input);
348         res = get_relations_str(sym_arr);
349         free(sym_arr);
350         show_textbox(_("Search Results"), str_get(&res), 0, 0);
351         str_free(&res);
352 }
353
354 static void build_conf(struct menu *menu)
355 {
356         struct symbol *sym;
357         struct property *prop;
358         struct menu *child;
359         int type, tmp, doint = 2;
360         tristate val;
361         char ch;
362
363         if (!menu_is_visible(menu))
364                 return;
365
366         sym = menu->sym;
367         prop = menu->prompt;
368         if (!sym) {
369                 if (prop && menu != current_menu) {
370                         const char *prompt = menu_get_prompt(menu);
371                         switch (prop->type) {
372                         case P_MENU:
373                                 child_count++;
374                                 prompt = _(prompt);
375                                 if (single_menu_mode) {
376                                         item_make("%s%*c%s",
377                                                   menu->data ? "-->" : "++>",
378                                                   indent + 1, ' ', prompt);
379                                 } else
380                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
381
382                                 item_set_tag('m');
383                                 item_set_data(menu);
384                                 if (single_menu_mode && menu->data)
385                                         goto conf_childs;
386                                 return;
387                         case P_COMMENT:
388                                 if (prompt) {
389                                         child_count++;
390                                         item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
391                                         item_set_tag(':');
392                                         item_set_data(menu);
393                                 }
394                                 break;
395                         default:
396                                 if (prompt) {
397                                         child_count++;
398                                         item_make("---%*c%s", indent + 1, ' ', _(prompt));
399                                         item_set_tag(':');
400                                         item_set_data(menu);
401                                 }
402                         }
403                 } else
404                         doint = 0;
405                 goto conf_childs;
406         }
407
408         type = sym_get_type(sym);
409         if (sym_is_choice(sym)) {
410                 struct symbol *def_sym = sym_get_choice_value(sym);
411                 struct menu *def_menu = NULL;
412
413                 child_count++;
414                 for (child = menu->list; child; child = child->next) {
415                         if (menu_is_visible(child) && child->sym == def_sym)
416                                 def_menu = child;
417                 }
418
419                 val = sym_get_tristate_value(sym);
420                 if (sym_is_changable(sym)) {
421                         switch (type) {
422                         case S_BOOLEAN:
423                                 item_make("[%c]", val == no ? ' ' : '*');
424                                 break;
425                         case S_TRISTATE:
426                                 switch (val) {
427                                 case yes: ch = '*'; break;
428                                 case mod: ch = 'M'; break;
429                                 default:  ch = ' '; break;
430                                 }
431                                 item_make("<%c>", ch);
432                                 break;
433                         }
434                         item_set_tag('t');
435                         item_set_data(menu);
436                 } else {
437                         item_make("   ");
438                         item_set_tag(def_menu ? 't' : ':');
439                         item_set_data(menu);
440                 }
441
442                 item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
443                 if (val == yes) {
444                         if (def_menu) {
445                                 item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
446                                 item_add_str("  --->");
447                                 if (def_menu->list) {
448                                         indent += 2;
449                                         build_conf(def_menu);
450                                         indent -= 2;
451                                 }
452                         }
453                         return;
454                 }
455         } else {
456                 if (menu == current_menu) {
457                         item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
458                         item_set_tag(':');
459                         item_set_data(menu);
460                         goto conf_childs;
461                 }
462                 child_count++;
463                 val = sym_get_tristate_value(sym);
464                 if (sym_is_choice_value(sym) && val == yes) {
465                         item_make("   ");
466                         item_set_tag(':');
467                         item_set_data(menu);
468                 } else {
469                         switch (type) {
470                         case S_BOOLEAN:
471                                 if (sym_is_changable(sym))
472                                         item_make("[%c]", val == no ? ' ' : '*');
473                                 else
474                                         item_make("-%c-", val == no ? ' ' : '*');
475                                 item_set_tag('t');
476                                 item_set_data(menu);
477                                 break;
478                         case S_TRISTATE:
479                                 switch (val) {
480                                 case yes: ch = '*'; break;
481                                 case mod: ch = 'M'; break;
482                                 default:  ch = ' '; break;
483                                 }
484                                 if (sym_is_changable(sym)) {
485                                         if (sym->rev_dep.tri == mod)
486                                                 item_make("{%c}", ch);
487                                         else
488                                                 item_make("<%c>", ch);
489                                 } else
490                                         item_make("-%c-", ch);
491                                 item_set_tag('t');
492                                 item_set_data(menu);
493                                 break;
494                         default:
495                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
496                                 item_make("(%s)", sym_get_string_value(sym));
497                                 tmp = indent - tmp + 4;
498                                 if (tmp < 0)
499                                         tmp = 0;
500                                 item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
501                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
502                                              "" : _(" (NEW)"));
503                                 item_set_tag('s');
504                                 item_set_data(menu);
505                                 goto conf_childs;
506                         }
507                 }
508                 item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
509                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
510                           "" : _(" (NEW)"));
511                 if (menu->prompt->type == P_MENU) {
512                         item_add_str("  --->");
513                         return;
514                 }
515         }
516
517 conf_childs:
518         indent += doint;
519         for (child = menu->list; child; child = child->next)
520                 build_conf(child);
521         indent -= doint;
522 }
523
524 static void conf(struct menu *menu)
525 {
526         struct menu *submenu;
527         const char *prompt = menu_get_prompt(menu);
528         struct symbol *sym;
529         struct menu *active_menu = NULL;
530         int res;
531         int s_scroll = 0;
532
533         while (1) {
534                 item_reset();
535                 current_menu = menu;
536                 build_conf(menu);
537                 if (!child_count)
538                         break;
539                 if (menu == &rootmenu) {
540                         item_make("--- ");
541                         item_set_tag(':');
542                         item_make(_("    Load an Alternate Configuration File"));
543                         item_set_tag('L');
544                         item_make(_("    Save an Alternate Configuration File"));
545                         item_set_tag('S');
546                 }
547                 dialog_clear();
548                 res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
549                                   _(menu_instructions),
550                                   active_menu, &s_scroll);
551                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
552                         break;
553                 if (!item_activate_selected())
554                         continue;
555                 if (!item_tag())
556                         continue;
557
558                 submenu = item_data();
559                 active_menu = item_data();
560                 if (submenu)
561                         sym = submenu->sym;
562                 else
563                         sym = NULL;
564
565                 switch (res) {
566                 case 0:
567                         switch (item_tag()) {
568                         case 'm':
569                                 if (single_menu_mode)
570                                         submenu->data = (void *) (long) !submenu->data;
571                                 else
572                                         conf(submenu);
573                                 break;
574                         case 't':
575                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
576                                         conf_choice(submenu);
577                                 else if (submenu->prompt->type == P_MENU)
578                                         conf(submenu);
579                                 break;
580                         case 's':
581                                 conf_string(submenu);
582                                 break;
583                         case 'L':
584                                 conf_load();
585                                 break;
586                         case 'S':
587                                 conf_save();
588                                 break;
589                         }
590                         break;
591                 case 2:
592                         if (sym)
593                                 show_help(submenu);
594                         else
595                                 show_helptext(_("README"), _(mconf_readme));
596                         break;
597                 case 3:
598                         if (item_is_tag('t')) {
599                                 if (sym_set_tristate_value(sym, yes))
600                                         break;
601                                 if (sym_set_tristate_value(sym, mod))
602                                         show_textbox(NULL, setmod_text, 6, 74);
603                         }
604                         break;
605                 case 4:
606                         if (item_is_tag('t'))
607                                 sym_set_tristate_value(sym, no);
608                         break;
609                 case 5:
610                         if (item_is_tag('t'))
611                                 sym_set_tristate_value(sym, mod);
612                         break;
613                 case 6:
614                         if (item_is_tag('t'))
615                                 sym_toggle_tristate_value(sym);
616                         else if (item_is_tag('m'))
617                                 conf(submenu);
618                         break;
619                 case 7:
620                         search_conf();
621                         break;
622                 }
623         }
624 }
625
626 static void show_textbox(const char *title, const char *text, int r, int c)
627 {
628         dialog_clear();
629         dialog_textbox(title, text, r, c);
630 }
631
632 static void show_helptext(const char *title, const char *text)
633 {
634         show_textbox(title, text, 0, 0);
635 }
636
637 static void show_help(struct menu *menu)
638 {
639         struct gstr help = str_new();
640
641         menu_get_ext_help(menu, &help);
642
643         show_helptext(_(menu_get_prompt(menu)), str_get(&help));
644         str_free(&help);
645 }
646
647 static void conf_choice(struct menu *menu)
648 {
649         const char *prompt = _(menu_get_prompt(menu));
650         struct menu *child;
651         struct symbol *active;
652
653         active = sym_get_choice_value(menu->sym);
654         while (1) {
655                 int res;
656                 int selected;
657                 item_reset();
658
659                 current_menu = menu;
660                 for (child = menu->list; child; child = child->next) {
661                         if (!menu_is_visible(child))
662                                 continue;
663                         if (child->sym)
664                                 item_make("%s", _(menu_get_prompt(child)));
665                         else {
666                                 item_make("*** %s ***", _(menu_get_prompt(child)));
667                                 item_set_tag(':');
668                         }
669                         item_set_data(child);
670                         if (child->sym == active)
671                                 item_set_selected(1);
672                         if (child->sym == sym_get_choice_value(menu->sym))
673                                 item_set_tag('X');
674                 }
675                 dialog_clear();
676                 res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
677                                         _(radiolist_instructions),
678                                          15, 70, 6);
679                 selected = item_activate_selected();
680                 switch (res) {
681                 case 0:
682                         if (selected) {
683                                 child = item_data();
684                                 if (!child->sym)
685                                         break;
686
687                                 sym_set_tristate_value(child->sym, yes);
688                         }
689                         return;
690                 case 1:
691                         if (selected) {
692                                 child = item_data();
693                                 show_help(child);
694                                 active = child->sym;
695                         } else
696                                 show_help(menu);
697                         break;
698                 case KEY_ESC:
699                         return;
700                 case -ERRDISPLAYTOOSMALL:
701                         return;
702                 }
703         }
704 }
705
706 static void conf_string(struct menu *menu)
707 {
708         const char *prompt = menu_get_prompt(menu);
709
710         while (1) {
711                 int res;
712                 const char *heading;
713
714                 switch (sym_get_type(menu->sym)) {
715                 case S_INT:
716                         heading = _(inputbox_instructions_int);
717                         break;
718                 case S_HEX:
719                         heading = _(inputbox_instructions_hex);
720                         break;
721                 case S_STRING:
722                         heading = _(inputbox_instructions_string);
723                         break;
724                 default:
725                         heading = _("Internal mconf error!");
726                 }
727                 dialog_clear();
728                 res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
729                                       heading, 10, 75,
730                                       sym_get_string_value(menu->sym));
731                 switch (res) {
732                 case 0:
733                         if (sym_set_string_value(menu->sym, dialog_input_result))
734                                 return;
735                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
736                         break;
737                 case 1:
738                         show_help(menu);
739                         break;
740                 case KEY_ESC:
741                         return;
742                 }
743         }
744 }
745
746 static void conf_load(void)
747 {
748
749         while (1) {
750                 int res;
751                 dialog_clear();
752                 res = dialog_inputbox(NULL, load_config_text,
753                                       11, 55, filename);
754                 switch(res) {
755                 case 0:
756                         if (!dialog_input_result[0])
757                                 return;
758                         if (!conf_read(dialog_input_result)) {
759                                 set_config_filename(dialog_input_result);
760                                 sym_set_change_count(1);
761                                 return;
762                         }
763                         show_textbox(NULL, _("File does not exist!"), 5, 38);
764                         break;
765                 case 1:
766                         show_helptext(_("Load Alternate Configuration"), load_config_help);
767                         break;
768                 case KEY_ESC:
769                         return;
770                 }
771         }
772 }
773
774 static void conf_save(void)
775 {
776         while (1) {
777                 int res;
778                 dialog_clear();
779                 res = dialog_inputbox(NULL, save_config_text,
780                                       11, 55, filename);
781                 switch(res) {
782                 case 0:
783                         if (!dialog_input_result[0])
784                                 return;
785                         if (!conf_write(dialog_input_result)) {
786                                 set_config_filename(dialog_input_result);
787                                 return;
788                         }
789                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
790                         break;
791                 case 1:
792                         show_helptext(_("Save Alternate Configuration"), save_config_help);
793                         break;
794                 case KEY_ESC:
795                         return;
796                 }
797         }
798 }
799
800 int main(int ac, char **av)
801 {
802         int saved_x, saved_y;
803         char *mode;
804         int res;
805
806         setlocale(LC_ALL, "");
807         bindtextdomain(PACKAGE, LOCALEDIR);
808         textdomain(PACKAGE);
809
810         conf_parse(av[1]);
811         conf_read(NULL);
812
813         mode = getenv("MENUCONFIG_MODE");
814         if (mode) {
815                 if (!strcasecmp(mode, "single_menu"))
816                         single_menu_mode = 1;
817         }
818
819         initscr();
820
821         getyx(stdscr, saved_y, saved_x);
822         if (init_dialog(NULL)) {
823                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
824                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
825                 return 1;
826         }
827
828         set_config_filename(conf_get_configname());
829         do {
830                 conf(&rootmenu);
831                 dialog_clear();
832                 if (conf_get_changed())
833                         res = dialog_yesno(NULL,
834                                            _("Do you wish to save your "
835                                              "new kernel configuration?\n"
836                                              "<ESC><ESC> to continue."),
837                                            6, 60);
838                 else
839                         res = -1;
840         } while (res == KEY_ESC);
841         end_dialog(saved_x, saved_y);
842
843         switch (res) {
844         case 0:
845                 if (conf_write(filename)) {
846                         fprintf(stderr, _("\n\n"
847                                 "Error during writing of the kernel configuration.\n"
848                                 "Your kernel configuration changes were NOT saved."
849                                 "\n\n"));
850                         return 1;
851                 }
852         case -1:
853                 printf(_("\n\n"
854                         "*** End of Linux kernel configuration.\n"
855                         "*** Execute 'make' to build the kernel or try 'make help'."
856                         "\n\n"));
857                 break;
858         default:
859                 fprintf(stderr, _("\n\n"
860                         "Your kernel configuration changes were NOT saved."
861                         "\n\n"));
862         }
863
864         return 0;
865 }
866