kconfig/conf: add command line options' description
[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 #include "lkc.h"
22 #include "lxdialog/dialog.h"
23
24 static const char mconf_readme[] = N_(
25 "Overview\n"
26 "--------\n"
27 "This interface let you select features and parameters for the build.\n"
28 "Features can either be built-in, modularized, or ignored. Parameters\n"
29 "must be entered in as decimal or hexadecimal numbers or text.\n"
30 "\n"
31 "Menu items beginning with following braces represent features that\n"
32 "  [ ] can be built in or removed\n"
33 "  < > can be built in, modularized or removed\n"
34 "  { } can be built in or modularized (selected by other feature)\n"
35 "  - - are selected by other feature,\n"
36 "while *, M or whitespace inside braces means to build in, build as\n"
37 "a module or to exclude the feature respectively.\n"
38 "\n"
39 "To change any of these features, highlight it with the cursor\n"
40 "keys and press <Y> to build it in, <M> to make it a module or\n"
41 "<N> to removed it.  You may also press the <Space Bar> to cycle\n"
42 "through the available options (ie. Y->N->M->Y).\n"
43 "\n"
44 "Some additional keyboard hints:\n"
45 "\n"
46 "Menus\n"
47 "----------\n"
48 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
49 "   you wish to change or submenu wish to select and press <Enter>.\n"
50 "   Submenus are designated by \"--->\".\n"
51 "\n"
52 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
53 "             Pressing a hotkey more than once will sequence\n"
54 "             through all visible items which use that hotkey.\n"
55 "\n"
56 "   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
57 "   unseen options into view.\n"
58 "\n"
59 "o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
60 "   and press <ENTER>.\n"
61 "\n"
62 "   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
63 "             using those letters.  You may press a single <ESC>, but\n"
64 "             there is a delayed response which you may find annoying.\n"
65 "\n"
66 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
67 "   <Exit> and <Help>.\n"
68 "\n"
69 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
70 "   and press <ENTER>.\n"
71 "\n"
72 "   Shortcut: Press <H> or <?>.\n"
73 "\n"
74 "o  To toggle the display of hidden options, press <Z>.\n"
75 "\n"
76 "\n"
77 "Radiolists  (Choice lists)\n"
78 "-----------\n"
79 "o  Use the cursor keys to select the option you wish to set and press\n"
80 "   <S> or the <SPACE BAR>.\n"
81 "\n"
82 "   Shortcut: Press the first letter of the option you wish to set then\n"
83 "             press <S> or <SPACE BAR>.\n"
84 "\n"
85 "o  To see available help for the item, use the cursor keys to highlight\n"
86 "   <Help> and Press <ENTER>.\n"
87 "\n"
88 "   Shortcut: Press <H> or <?>.\n"
89 "\n"
90 "   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
91 "   <Help>\n"
92 "\n"
93 "\n"
94 "Data Entry\n"
95 "-----------\n"
96 "o  Enter the requested information and press <ENTER>\n"
97 "   If you are entering hexadecimal values, it is not necessary to\n"
98 "   add the '0x' prefix to the entry.\n"
99 "\n"
100 "o  For help, use the <TAB> or cursor keys to highlight the help option\n"
101 "   and press <ENTER>.  You can try <TAB><H> as well.\n"
102 "\n"
103 "\n"
104 "Text Box    (Help Window)\n"
105 "--------\n"
106 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
107 "   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
108 "   who are familiar with less and lynx.\n"
109 "\n"
110 "o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
111 "\n"
112 "\n"
113 "Alternate Configuration Files\n"
114 "-----------------------------\n"
115 "Menuconfig supports the use of alternate configuration files for\n"
116 "those who, for various reasons, find it necessary to switch\n"
117 "between different configurations.\n"
118 "\n"
119 "At the end of the main menu you will find two options.  One is\n"
120 "for saving the current configuration to a file of your choosing.\n"
121 "The other option is for loading a previously saved alternate\n"
122 "configuration.\n"
123 "\n"
124 "Even if you don't use alternate configuration files, but you\n"
125 "find during a Menuconfig session that you have completely messed\n"
126 "up your settings, you may use the \"Load Alternate...\" option to\n"
127 "restore your previously saved settings from \".config\" without\n"
128 "restarting Menuconfig.\n"
129 "\n"
130 "Other information\n"
131 "-----------------\n"
132 "If you use Menuconfig in an XTERM window make sure you have your\n"
133 "$TERM variable set to point to a xterm definition which supports color.\n"
134 "Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
135 "display correctly in a RXVT window because rxvt displays only one\n"
136 "intensity of color, bright.\n"
137 "\n"
138 "Menuconfig will display larger menus on screens or xterms which are\n"
139 "set to display more than the standard 25 row by 80 column geometry.\n"
140 "In order for this to work, the \"stty size\" command must be able to\n"
141 "display the screen's current row and column geometry.  I STRONGLY\n"
142 "RECOMMEND that you make sure you do NOT have the shell variables\n"
143 "LINES and COLUMNS exported into your environment.  Some distributions\n"
144 "export those variables via /etc/profile.  Some ncurses programs can\n"
145 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
146 "the true screen size.\n"
147 "\n"
148 "Optional personality available\n"
149 "------------------------------\n"
150 "If you prefer to have all of the options listed in a single menu, rather\n"
151 "than the default multimenu hierarchy, run the menuconfig with\n"
152 "MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
153 "\n"
154 "make MENUCONFIG_MODE=single_menu menuconfig\n"
155 "\n"
156 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
157 "is already unrolled.\n"
158 "\n"
159 "Note that this mode can eventually be a little more CPU expensive\n"
160 "(especially with a larger number of unrolled categories) than the\n"
161 "default mode.\n"
162 "\n"
163 "Different color themes available\n"
164 "--------------------------------\n"
165 "It is possible to select different color themes using the variable\n"
166 "MENUCONFIG_COLOR. To select a theme use:\n"
167 "\n"
168 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
169 "\n"
170 "Available themes are\n"
171 " mono       => selects colors suitable for monochrome displays\n"
172 " blackbg    => selects a color scheme with black background\n"
173 " classic    => theme with blue background. The classic look\n"
174 " bluetitle  => a LCD friendly version of classic. (default)\n"
175 "\n"),
176 menu_instructions[] = N_(
177         "Arrow keys navigate the menu.  "
178         "<Enter> selects submenus --->.  "
179         "Highlighted letters are hotkeys.  "
180         "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
181         "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
182         "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
183 radiolist_instructions[] = N_(
184         "Use the arrow keys to navigate this window or "
185         "press the hotkey of the item you wish to select "
186         "followed by the <SPACE BAR>. "
187         "Press <?> for additional information about this option."),
188 inputbox_instructions_int[] = N_(
189         "Please enter a decimal value. "
190         "Fractions will not be accepted.  "
191         "Use the <TAB> key to move from the input field to the buttons below it."),
192 inputbox_instructions_hex[] = N_(
193         "Please enter a hexadecimal value. "
194         "Use the <TAB> key to move from the input field to the buttons below it."),
195 inputbox_instructions_string[] = N_(
196         "Please enter a string value. "
197         "Use the <TAB> key to move from the input field to the buttons below it."),
198 setmod_text[] = N_(
199         "This feature depends on another which has been configured as a module.\n"
200         "As a result, this feature will be built as a module."),
201 load_config_text[] = N_(
202         "Enter the name of the configuration file you wish to load.  "
203         "Accept the name shown to restore the configuration you "
204         "last retrieved.  Leave blank to abort."),
205 load_config_help[] = N_(
206         "\n"
207         "For various reasons, one may wish to keep several different\n"
208         "configurations available on a single machine.\n"
209         "\n"
210         "If you have saved a previous configuration in a file other than the\n"
211         "default one, entering its name here will allow you to modify that\n"
212         "configuration.\n"
213         "\n"
214         "If you are uncertain, then you have probably never used alternate\n"
215         "configuration files. You should therefore leave this blank to abort.\n"),
216 save_config_text[] = N_(
217         "Enter a filename to which this configuration should be saved "
218         "as an alternate.  Leave blank to abort."),
219 save_config_help[] = N_(
220         "\n"
221         "For various reasons, one may wish to keep different configurations\n"
222         "available on a single machine.\n"
223         "\n"
224         "Entering a file name here will allow you to later retrieve, modify\n"
225         "and use the current configuration as an alternate to whatever\n"
226         "configuration options you have selected at that time.\n"
227         "\n"
228         "If you are uncertain what all this means then you should probably\n"
229         "leave this blank.\n"),
230 search_help[] = N_(
231         "\n"
232         "Search for symbols and display their relations.\n"
233         "Regular expressions are allowed.\n"
234         "Example: search for \"^FOO\"\n"
235         "Result:\n"
236         "-----------------------------------------------------------------\n"
237         "Symbol: FOO [=m]\n"
238         "Prompt: Foo bus is used to drive the bar HW\n"
239         "Defined at drivers/pci/Kconfig:47\n"
240         "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
241         "Location:\n"
242         "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
243         "    -> PCI support (PCI [=y])\n"
244         "      -> PCI access mode (<choice> [=y])\n"
245         "Selects: LIBCRC32\n"
246         "Selected by: BAR\n"
247         "-----------------------------------------------------------------\n"
248         "o The line 'Prompt:' shows the text used in the menu structure for\n"
249         "  this symbol\n"
250         "o The 'Defined at' line tell at what file / line number the symbol\n"
251         "  is defined\n"
252         "o The 'Depends on:' line tell what symbols needs to be defined for\n"
253         "  this symbol to be visible in the menu (selectable)\n"
254         "o The 'Location:' lines tell where in the menu structure this symbol\n"
255         "  is located\n"
256         "    A location followed by a [=y] indicate that this is a selectable\n"
257         "    menu item - and current value is displayed inside brackets.\n"
258         "o The 'Selects:' line tell what symbol will be automatically\n"
259         "  selected if this symbol is selected (y or m)\n"
260         "o The 'Selected by' line tell what symbol has selected this symbol\n"
261         "\n"
262         "Only relevant lines are shown.\n"
263         "\n\n"
264         "Search examples:\n"
265         "Examples: USB  => find all symbols containing USB\n"
266         "          ^USB => find all symbols starting with USB\n"
267         "          USB$ => find all symbols ending with USB\n"
268         "\n");
269
270 static int indent;
271 static struct menu *current_menu;
272 static int child_count;
273 static int single_menu_mode;
274 static int show_all_options;
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 char filename[PATH_MAX+1];
286 static void set_config_filename(const char *config_filename)
287 {
288         static char menu_backtitle[PATH_MAX+128];
289         int size;
290
291         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
292                         "%s - %s", config_filename, rootmenu.prompt->text);
293         if (size >= sizeof(menu_backtitle))
294                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
295         set_dialog_backtitle(menu_backtitle);
296
297         size = snprintf(filename, sizeof(filename), "%s", config_filename);
298         if (size >= sizeof(filename))
299                 filename[sizeof(filename)-1] = '\0';
300 }
301
302
303 static void search_conf(void)
304 {
305         struct symbol **sym_arr;
306         struct gstr res;
307         char *dialog_input;
308         int dres;
309 again:
310         dialog_clear();
311         dres = dialog_inputbox(_("Search Configuration Parameter"),
312                               _("Enter " CONFIG_ " (sub)string to search for "
313                                 "(with or without \"" CONFIG_ "\")"),
314                               10, 75, "");
315         switch (dres) {
316         case 0:
317                 break;
318         case 1:
319                 show_helptext(_("Search Configuration"), search_help);
320                 goto again;
321         default:
322                 return;
323         }
324
325         /* strip the prefix if necessary */
326         dialog_input = dialog_input_result;
327         if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
328                 dialog_input += strlen(CONFIG_);
329
330         sym_arr = sym_re_search(dialog_input);
331         res = get_relations_str(sym_arr);
332         free(sym_arr);
333         show_textbox(_("Search Results"), str_get(&res), 0, 0);
334         str_free(&res);
335 }
336
337 static void build_conf(struct menu *menu)
338 {
339         struct symbol *sym;
340         struct property *prop;
341         struct menu *child;
342         int type, tmp, doint = 2;
343         tristate val;
344         char ch;
345         bool visible;
346
347         /*
348          * note: menu_is_visible() has side effect that it will
349          * recalc the value of the symbol.
350          */
351         visible = menu_is_visible(menu);
352         if (show_all_options && !menu_has_prompt(menu))
353                 return;
354         else if (!show_all_options && !visible)
355                 return;
356
357         sym = menu->sym;
358         prop = menu->prompt;
359         if (!sym) {
360                 if (prop && menu != current_menu) {
361                         const char *prompt = menu_get_prompt(menu);
362                         switch (prop->type) {
363                         case P_MENU:
364                                 child_count++;
365                                 prompt = _(prompt);
366                                 if (single_menu_mode) {
367                                         item_make("%s%*c%s",
368                                                   menu->data ? "-->" : "++>",
369                                                   indent + 1, ' ', prompt);
370                                 } else
371                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
372
373                                 item_set_tag('m');
374                                 item_set_data(menu);
375                                 if (single_menu_mode && menu->data)
376                                         goto conf_childs;
377                                 return;
378                         case P_COMMENT:
379                                 if (prompt) {
380                                         child_count++;
381                                         item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
382                                         item_set_tag(':');
383                                         item_set_data(menu);
384                                 }
385                                 break;
386                         default:
387                                 if (prompt) {
388                                         child_count++;
389                                         item_make("---%*c%s", indent + 1, ' ', _(prompt));
390                                         item_set_tag(':');
391                                         item_set_data(menu);
392                                 }
393                         }
394                 } else
395                         doint = 0;
396                 goto conf_childs;
397         }
398
399         type = sym_get_type(sym);
400         if (sym_is_choice(sym)) {
401                 struct symbol *def_sym = sym_get_choice_value(sym);
402                 struct menu *def_menu = NULL;
403
404                 child_count++;
405                 for (child = menu->list; child; child = child->next) {
406                         if (menu_is_visible(child) && child->sym == def_sym)
407                                 def_menu = child;
408                 }
409
410                 val = sym_get_tristate_value(sym);
411                 if (sym_is_changable(sym)) {
412                         switch (type) {
413                         case S_BOOLEAN:
414                                 item_make("[%c]", val == no ? ' ' : '*');
415                                 break;
416                         case S_TRISTATE:
417                                 switch (val) {
418                                 case yes: ch = '*'; break;
419                                 case mod: ch = 'M'; break;
420                                 default:  ch = ' '; break;
421                                 }
422                                 item_make("<%c>", ch);
423                                 break;
424                         }
425                         item_set_tag('t');
426                         item_set_data(menu);
427                 } else {
428                         item_make("   ");
429                         item_set_tag(def_menu ? 't' : ':');
430                         item_set_data(menu);
431                 }
432
433                 item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
434                 if (val == yes) {
435                         if (def_menu) {
436                                 item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
437                                 item_add_str("  --->");
438                                 if (def_menu->list) {
439                                         indent += 2;
440                                         build_conf(def_menu);
441                                         indent -= 2;
442                                 }
443                         }
444                         return;
445                 }
446         } else {
447                 if (menu == current_menu) {
448                         item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
449                         item_set_tag(':');
450                         item_set_data(menu);
451                         goto conf_childs;
452                 }
453                 child_count++;
454                 val = sym_get_tristate_value(sym);
455                 if (sym_is_choice_value(sym) && val == yes) {
456                         item_make("   ");
457                         item_set_tag(':');
458                         item_set_data(menu);
459                 } else {
460                         switch (type) {
461                         case S_BOOLEAN:
462                                 if (sym_is_changable(sym))
463                                         item_make("[%c]", val == no ? ' ' : '*');
464                                 else
465                                         item_make("-%c-", val == no ? ' ' : '*');
466                                 item_set_tag('t');
467                                 item_set_data(menu);
468                                 break;
469                         case S_TRISTATE:
470                                 switch (val) {
471                                 case yes: ch = '*'; break;
472                                 case mod: ch = 'M'; break;
473                                 default:  ch = ' '; break;
474                                 }
475                                 if (sym_is_changable(sym)) {
476                                         if (sym->rev_dep.tri == mod)
477                                                 item_make("{%c}", ch);
478                                         else
479                                                 item_make("<%c>", ch);
480                                 } else
481                                         item_make("-%c-", ch);
482                                 item_set_tag('t');
483                                 item_set_data(menu);
484                                 break;
485                         default:
486                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
487                                 item_make("(%s)", sym_get_string_value(sym));
488                                 tmp = indent - tmp + 4;
489                                 if (tmp < 0)
490                                         tmp = 0;
491                                 item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
492                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
493                                              "" : _(" (NEW)"));
494                                 item_set_tag('s');
495                                 item_set_data(menu);
496                                 goto conf_childs;
497                         }
498                 }
499                 item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
500                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
501                           "" : _(" (NEW)"));
502                 if (menu->prompt->type == P_MENU) {
503                         item_add_str("  --->");
504                         return;
505                 }
506         }
507
508 conf_childs:
509         indent += doint;
510         for (child = menu->list; child; child = child->next)
511                 build_conf(child);
512         indent -= doint;
513 }
514
515 static void conf(struct menu *menu)
516 {
517         struct menu *submenu;
518         const char *prompt = menu_get_prompt(menu);
519         struct symbol *sym;
520         struct menu *active_menu = NULL;
521         int res;
522         int s_scroll = 0;
523
524         while (1) {
525                 item_reset();
526                 current_menu = menu;
527                 build_conf(menu);
528                 if (!child_count)
529                         break;
530                 if (menu == &rootmenu) {
531                         item_make("--- ");
532                         item_set_tag(':');
533                         item_make(_("    Load an Alternate Configuration File"));
534                         item_set_tag('L');
535                         item_make(_("    Save an Alternate Configuration File"));
536                         item_set_tag('S');
537                 }
538                 dialog_clear();
539                 res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
540                                   _(menu_instructions),
541                                   active_menu, &s_scroll);
542                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
543                         break;
544                 if (!item_activate_selected())
545                         continue;
546                 if (!item_tag())
547                         continue;
548
549                 submenu = item_data();
550                 active_menu = item_data();
551                 if (submenu)
552                         sym = submenu->sym;
553                 else
554                         sym = NULL;
555
556                 switch (res) {
557                 case 0:
558                         switch (item_tag()) {
559                         case 'm':
560                                 if (single_menu_mode)
561                                         submenu->data = (void *) (long) !submenu->data;
562                                 else
563                                         conf(submenu);
564                                 break;
565                         case 't':
566                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
567                                         conf_choice(submenu);
568                                 else if (submenu->prompt->type == P_MENU)
569                                         conf(submenu);
570                                 break;
571                         case 's':
572                                 conf_string(submenu);
573                                 break;
574                         case 'L':
575                                 conf_load();
576                                 break;
577                         case 'S':
578                                 conf_save();
579                                 break;
580                         }
581                         break;
582                 case 2:
583                         if (sym)
584                                 show_help(submenu);
585                         else
586                                 show_helptext(_("README"), _(mconf_readme));
587                         break;
588                 case 3:
589                         if (item_is_tag('t')) {
590                                 if (sym_set_tristate_value(sym, yes))
591                                         break;
592                                 if (sym_set_tristate_value(sym, mod))
593                                         show_textbox(NULL, setmod_text, 6, 74);
594                         }
595                         break;
596                 case 4:
597                         if (item_is_tag('t'))
598                                 sym_set_tristate_value(sym, no);
599                         break;
600                 case 5:
601                         if (item_is_tag('t'))
602                                 sym_set_tristate_value(sym, mod);
603                         break;
604                 case 6:
605                         if (item_is_tag('t'))
606                                 sym_toggle_tristate_value(sym);
607                         else if (item_is_tag('m'))
608                                 conf(submenu);
609                         break;
610                 case 7:
611                         search_conf();
612                         break;
613                 case 8:
614                         show_all_options = !show_all_options;
615                         break;
616                 }
617         }
618 }
619
620 static void show_textbox(const char *title, const char *text, int r, int c)
621 {
622         dialog_clear();
623         dialog_textbox(title, text, r, c);
624 }
625
626 static void show_helptext(const char *title, const char *text)
627 {
628         show_textbox(title, text, 0, 0);
629 }
630
631 static void show_help(struct menu *menu)
632 {
633         struct gstr help = str_new();
634
635         help.max_width = getmaxx(stdscr) - 10;
636         menu_get_ext_help(menu, &help);
637
638         show_helptext(_(menu_get_prompt(menu)), str_get(&help));
639         str_free(&help);
640 }
641
642 static void conf_choice(struct menu *menu)
643 {
644         const char *prompt = _(menu_get_prompt(menu));
645         struct menu *child;
646         struct symbol *active;
647
648         active = sym_get_choice_value(menu->sym);
649         while (1) {
650                 int res;
651                 int selected;
652                 item_reset();
653
654                 current_menu = menu;
655                 for (child = menu->list; child; child = child->next) {
656                         if (!menu_is_visible(child))
657                                 continue;
658                         if (child->sym)
659                                 item_make("%s", _(menu_get_prompt(child)));
660                         else {
661                                 item_make("*** %s ***", _(menu_get_prompt(child)));
662                                 item_set_tag(':');
663                         }
664                         item_set_data(child);
665                         if (child->sym == active)
666                                 item_set_selected(1);
667                         if (child->sym == sym_get_choice_value(menu->sym))
668                                 item_set_tag('X');
669                 }
670                 dialog_clear();
671                 res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
672                                         _(radiolist_instructions),
673                                          15, 70, 6);
674                 selected = item_activate_selected();
675                 switch (res) {
676                 case 0:
677                         if (selected) {
678                                 child = item_data();
679                                 if (!child->sym)
680                                         break;
681
682                                 sym_set_tristate_value(child->sym, yes);
683                         }
684                         return;
685                 case 1:
686                         if (selected) {
687                                 child = item_data();
688                                 show_help(child);
689                                 active = child->sym;
690                         } else
691                                 show_help(menu);
692                         break;
693                 case KEY_ESC:
694                         return;
695                 case -ERRDISPLAYTOOSMALL:
696                         return;
697                 }
698         }
699 }
700
701 static void conf_string(struct menu *menu)
702 {
703         const char *prompt = menu_get_prompt(menu);
704
705         while (1) {
706                 int res;
707                 const char *heading;
708
709                 switch (sym_get_type(menu->sym)) {
710                 case S_INT:
711                         heading = _(inputbox_instructions_int);
712                         break;
713                 case S_HEX:
714                         heading = _(inputbox_instructions_hex);
715                         break;
716                 case S_STRING:
717                         heading = _(inputbox_instructions_string);
718                         break;
719                 default:
720                         heading = _("Internal mconf error!");
721                 }
722                 dialog_clear();
723                 res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
724                                       heading, 10, 75,
725                                       sym_get_string_value(menu->sym));
726                 switch (res) {
727                 case 0:
728                         if (sym_set_string_value(menu->sym, dialog_input_result))
729                                 return;
730                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
731                         break;
732                 case 1:
733                         show_help(menu);
734                         break;
735                 case KEY_ESC:
736                         return;
737                 }
738         }
739 }
740
741 static void conf_load(void)
742 {
743
744         while (1) {
745                 int res;
746                 dialog_clear();
747                 res = dialog_inputbox(NULL, load_config_text,
748                                       11, 55, filename);
749                 switch(res) {
750                 case 0:
751                         if (!dialog_input_result[0])
752                                 return;
753                         if (!conf_read(dialog_input_result)) {
754                                 set_config_filename(dialog_input_result);
755                                 sym_set_change_count(1);
756                                 return;
757                         }
758                         show_textbox(NULL, _("File does not exist!"), 5, 38);
759                         break;
760                 case 1:
761                         show_helptext(_("Load Alternate Configuration"), load_config_help);
762                         break;
763                 case KEY_ESC:
764                         return;
765                 }
766         }
767 }
768
769 static void conf_save(void)
770 {
771         while (1) {
772                 int res;
773                 dialog_clear();
774                 res = dialog_inputbox(NULL, save_config_text,
775                                       11, 55, filename);
776                 switch(res) {
777                 case 0:
778                         if (!dialog_input_result[0])
779                                 return;
780                         if (!conf_write(dialog_input_result)) {
781                                 set_config_filename(dialog_input_result);
782                                 return;
783                         }
784                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
785                         break;
786                 case 1:
787                         show_helptext(_("Save Alternate Configuration"), save_config_help);
788                         break;
789                 case KEY_ESC:
790                         return;
791                 }
792         }
793 }
794
795 int main(int ac, char **av)
796 {
797         int saved_x, saved_y;
798         char *mode;
799         int res;
800
801         setlocale(LC_ALL, "");
802         bindtextdomain(PACKAGE, LOCALEDIR);
803         textdomain(PACKAGE);
804
805         conf_parse(av[1]);
806         conf_read(NULL);
807
808         mode = getenv("MENUCONFIG_MODE");
809         if (mode) {
810                 if (!strcasecmp(mode, "single_menu"))
811                         single_menu_mode = 1;
812         }
813
814         initscr();
815
816         getyx(stdscr, saved_y, saved_x);
817         if (init_dialog(NULL)) {
818                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
819                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
820                 return 1;
821         }
822
823         set_config_filename(conf_get_configname());
824         do {
825                 conf(&rootmenu);
826                 dialog_clear();
827                 if (conf_get_changed())
828                         res = dialog_yesno(NULL,
829                                            _("Do you wish to save your "
830                                              "new configuration?\n"
831                                              "<ESC><ESC> to continue."),
832                                            6, 60);
833                 else
834                         res = -1;
835         } while (res == KEY_ESC);
836         end_dialog(saved_x, saved_y);
837
838         switch (res) {
839         case 0:
840                 if (conf_write(filename)) {
841                         fprintf(stderr, _("\n\n"
842                                 "Error while writing of the configuration.\n"
843                                 "Your configuration changes were NOT saved."
844                                 "\n\n"));
845                         return 1;
846                 }
847                 /* fall through */
848         case -1:
849                 printf(_("\n\n"
850                         "*** End of the configuration.\n"
851                         "*** Execute 'make' to start the build or try 'make help'."
852                         "\n\n"));
853                 break;
854         default:
855                 fprintf(stderr, _("\n\n"
856                         "Your configuration changes were NOT saved."
857                         "\n\n"));
858         }
859
860         return 0;
861 }
862