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