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