regmap: maple: Fix uninitialized symbol 'ret' warnings
[sfrench/cifs-2.6.git] / scripts / kconfig / mconf.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
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 <strings.h>
19 #include <signal.h>
20 #include <unistd.h>
21
22 #include "list.h"
23 #include "lkc.h"
24 #include "lxdialog/dialog.h"
25 #include "mnconf-common.h"
26
27 static const char mconf_readme[] =
28 "Overview\n"
29 "--------\n"
30 "This interface lets you select features and parameters for the build.\n"
31 "Features can either be built-in, modularized, or ignored. Parameters\n"
32 "must be entered in as decimal or hexadecimal numbers or 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 remove it.  You may also press the <Space Bar> to cycle\n"
45 "through the available options (i.e. 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 you\n"
52 "   wish to change or the submenu you wish to select and press <Enter>.\n"
53 "   Submenus are designated by \"--->\", empty ones 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>, <Help>, <Save>, and <Load>.\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 "o  To toggle the display of hidden options, press <Z>.\n"
78 "\n"
79 "\n"
80 "Radiolists  (Choice lists)\n"
81 "-----------\n"
82 "o  Use the cursor keys to select the option you wish to set and press\n"
83 "   <S> or the <SPACE BAR>.\n"
84 "\n"
85 "   Shortcut: Press the first letter of the option you wish to set then\n"
86 "             press <S> or <SPACE BAR>.\n"
87 "\n"
88 "o  To see available help for the item, use the cursor keys to highlight\n"
89 "   <Help> and Press <ENTER>.\n"
90 "\n"
91 "   Shortcut: Press <H> or <?>.\n"
92 "\n"
93 "   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
94 "   <Help>\n"
95 "\n"
96 "\n"
97 "Data Entry\n"
98 "-----------\n"
99 "o  Enter the requested information and press <ENTER>\n"
100 "   If you are entering hexadecimal values, it is not necessary to\n"
101 "   add the '0x' prefix to the entry.\n"
102 "\n"
103 "o  For help, use the <TAB> or cursor keys to highlight the help option\n"
104 "   and press <ENTER>.  You can try <TAB><H> as well.\n"
105 "\n"
106 "\n"
107 "Text Box    (Help Window)\n"
108 "--------\n"
109 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
110 "   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n"
111 "   those who are familiar with less and lynx.\n"
112 "\n"
113 "o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
114 "\n"
115 "\n"
116 "Alternate Configuration Files\n"
117 "-----------------------------\n"
118 "Menuconfig supports the use of alternate configuration files for\n"
119 "those who, for various reasons, find it necessary to switch\n"
120 "between different configurations.\n"
121 "\n"
122 "The <Save> button will let you save the current configuration to\n"
123 "a file of your choosing.  Use the <Load> button to load a previously\n"
124 "saved alternate configuration.\n"
125 "\n"
126 "Even if you don't use alternate configuration files, but you find\n"
127 "during a Menuconfig session that you have completely messed up your\n"
128 "settings, you may use the <Load> button to restore your previously\n"
129 "saved settings from \".config\" without 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 an xterm definition which supports\n"
135 "color.  Otherwise, Menuconfig will look rather bad.  Menuconfig will\n"
136 "not display correctly in an 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,\n"
152 "rather 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
165 "Search\n"
166 "-------\n"
167 "Pressing the forward-slash (/) anywhere brings up a search dialog box.\n"
168 "\n"
169
170 "Different color themes available\n"
171 "--------------------------------\n"
172 "It is possible to select different color themes using the variable\n"
173 "MENUCONFIG_COLOR. To select a theme use:\n"
174 "\n"
175 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
176 "\n"
177 "Available themes are\n"
178 " mono       => selects colors suitable for monochrome displays\n"
179 " blackbg    => selects a color scheme with black background\n"
180 " classic    => theme with blue background. The classic look\n"
181 " bluetitle  => an LCD friendly version of classic. (default)\n"
182 "\n",
183 menu_instructions[] =
184         "Arrow keys navigate the menu.  "
185         "<Enter> selects submenus ---> (or empty submenus ----).  "
186         "Highlighted letters are hotkeys.  "
187         "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
188         "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
189         "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable",
190 radiolist_instructions[] =
191         "Use the arrow keys to navigate this window or "
192         "press the hotkey of the item you wish to select "
193         "followed by the <SPACE BAR>. "
194         "Press <?> for additional information about this option.",
195 inputbox_instructions_int[] =
196         "Please enter a decimal value. "
197         "Fractions will not be accepted.  "
198         "Use the <TAB> key to move from the input field to the buttons below it.",
199 inputbox_instructions_hex[] =
200         "Please enter a hexadecimal value. "
201         "Use the <TAB> key to move from the input field to the buttons below it.",
202 inputbox_instructions_string[] =
203         "Please enter a string value. "
204         "Use the <TAB> key to move from the input field to the buttons below it.",
205 setmod_text[] =
206         "This feature depends on another which has been configured as a module.\n"
207         "As a result, this feature will be built as a module.",
208 load_config_text[] =
209         "Enter the name of the configuration file you wish to load.  "
210         "Accept the name shown to restore the configuration you "
211         "last retrieved.  Leave blank to abort.",
212 load_config_help[] =
213         "\n"
214         "For various reasons, one may wish to keep several different\n"
215         "configurations available on a single machine.\n"
216         "\n"
217         "If you have saved a previous configuration in a file other than the\n"
218         "default one, entering its name here will allow you to modify that\n"
219         "configuration.\n"
220         "\n"
221         "If you are uncertain, then you have probably never used alternate\n"
222         "configuration files. You should therefore leave this blank to abort.\n",
223 save_config_text[] =
224         "Enter a filename to which this configuration should be saved "
225         "as an alternate.  Leave blank to abort.",
226 save_config_help[] =
227         "\n"
228         "For various reasons, one may wish to keep different configurations\n"
229         "available on a single machine.\n"
230         "\n"
231         "Entering a file name here will allow you to later retrieve, modify\n"
232         "and use the current configuration as an alternate to whatever\n"
233         "configuration options you have selected at that time.\n"
234         "\n"
235         "If you are uncertain what all this means then you should probably\n"
236         "leave this blank.\n",
237 search_help[] =
238         "\n"
239         "Search for symbols and display their relations.\n"
240         "Regular expressions are allowed.\n"
241         "Example: search for \"^FOO\"\n"
242         "Result:\n"
243         "-----------------------------------------------------------------\n"
244         "Symbol: FOO [=m]\n"
245         "Type  : tristate\n"
246         "Prompt: Foo bus is used to drive the bar HW\n"
247         "  Location:\n"
248         "    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
249         "      -> PCI support (PCI [=y])\n"
250         "(1)     -> PCI access mode (<choice> [=y])\n"
251         "  Defined at drivers/pci/Kconfig:47\n"
252         "  Depends on: X86_LOCAL_APIC && X86_IO_APIC\n"
253         "  Selects: LIBCRC32\n"
254         "  Selected by: BAR [=n]\n"
255         "-----------------------------------------------------------------\n"
256         "o The line 'Type:' shows the type of the configuration option for\n"
257         "  this symbol (bool, tristate, string, ...)\n"
258         "o The line 'Prompt:' shows the text used in the menu structure for\n"
259         "  this symbol\n"
260         "o The 'Defined at' line tells at what file / line number the symbol\n"
261         "  is defined\n"
262         "o The 'Depends on:' line tells what symbols need to be defined for\n"
263         "  this symbol to be visible in the menu (selectable)\n"
264         "o The 'Location:' lines tells where in the menu structure this symbol\n"
265         "  is located\n"
266         "    A location followed by a [=y] indicates that this is a\n"
267         "    selectable menu item - and the current value is displayed inside\n"
268         "    brackets.\n"
269         "    Press the key in the (#) prefix to jump directly to that\n"
270         "    location. You will be returned to the current search results\n"
271         "    after exiting this new menu.\n"
272         "o The 'Selects:' line tells what symbols will be automatically\n"
273         "  selected if this symbol is selected (y or m)\n"
274         "o The 'Selected by' line tells what symbol has selected this symbol\n"
275         "\n"
276         "Only relevant lines are shown.\n"
277         "\n\n"
278         "Search examples:\n"
279         "Examples: USB  => find all symbols containing USB\n"
280         "          ^USB => find all symbols starting with USB\n"
281         "          USB$ => find all symbols ending with USB\n"
282         "\n";
283
284 static int indent;
285 static struct menu *current_menu;
286 static int child_count;
287 static int single_menu_mode;
288 static int show_all_options;
289 static int save_and_exit;
290 static int silent;
291
292 static void conf(struct menu *menu, struct menu *active_menu);
293
294 static char filename[PATH_MAX+1];
295 static void set_config_filename(const char *config_filename)
296 {
297         static char menu_backtitle[PATH_MAX+128];
298
299         snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
300                  config_filename, rootmenu.prompt->text);
301         set_dialog_backtitle(menu_backtitle);
302
303         snprintf(filename, sizeof(filename), "%s", config_filename);
304 }
305
306 struct subtitle_part {
307         struct list_head entries;
308         const char *text;
309 };
310 static LIST_HEAD(trail);
311
312 static struct subtitle_list *subtitles;
313 static void set_subtitle(void)
314 {
315         struct subtitle_part *sp;
316         struct subtitle_list *pos, *tmp;
317
318         for (pos = subtitles; pos != NULL; pos = tmp) {
319                 tmp = pos->next;
320                 free(pos);
321         }
322
323         subtitles = NULL;
324         list_for_each_entry(sp, &trail, entries) {
325                 if (sp->text) {
326                         if (pos) {
327                                 pos->next = xcalloc(1, sizeof(*pos));
328                                 pos = pos->next;
329                         } else {
330                                 subtitles = pos = xcalloc(1, sizeof(*pos));
331                         }
332                         pos->text = sp->text;
333                 }
334         }
335
336         set_dialog_subtitles(subtitles);
337 }
338
339 static void reset_subtitle(void)
340 {
341         struct subtitle_list *pos, *tmp;
342
343         for (pos = subtitles; pos != NULL; pos = tmp) {
344                 tmp = pos->next;
345                 free(pos);
346         }
347         subtitles = NULL;
348         set_dialog_subtitles(subtitles);
349 }
350
351 static int show_textbox_ext(const char *title, const char *text, int r, int c,
352                             int *vscroll, int *hscroll,
353                             int (*extra_key_cb)(int, size_t, size_t, void *),
354                             void *data)
355 {
356         dialog_clear();
357         return dialog_textbox(title, text, r, c, vscroll, hscroll,
358                               extra_key_cb, data);
359 }
360
361 static void show_textbox(const char *title, const char *text, int r, int c)
362 {
363         show_textbox_ext(title, text, r, c, NULL, NULL, NULL, NULL);
364 }
365
366 static void show_helptext(const char *title, const char *text)
367 {
368         show_textbox(title, text, 0, 0);
369 }
370
371 static void show_help(struct menu *menu)
372 {
373         struct gstr help = str_new();
374
375         help.max_width = getmaxx(stdscr) - 10;
376         menu_get_ext_help(menu, &help);
377
378         show_helptext(menu_get_prompt(menu), str_get(&help));
379         str_free(&help);
380 }
381
382 static void search_conf(void)
383 {
384         struct symbol **sym_arr;
385         struct gstr res;
386         struct gstr title;
387         char *dialog_input;
388         int dres, vscroll = 0, hscroll = 0;
389         bool again;
390         struct gstr sttext;
391         struct subtitle_part stpart;
392
393         title = str_new();
394         str_printf( &title, "Enter (sub)string or regexp to search for "
395                               "(with or without \"%s\")", CONFIG_);
396
397 again:
398         dialog_clear();
399         dres = dialog_inputbox("Search Configuration Parameter",
400                               str_get(&title),
401                               10, 75, "");
402         switch (dres) {
403         case 0:
404                 break;
405         case 1:
406                 show_helptext("Search Configuration", search_help);
407                 goto again;
408         default:
409                 str_free(&title);
410                 return;
411         }
412
413         /* strip the prefix if necessary */
414         dialog_input = dialog_input_result;
415         if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
416                 dialog_input += strlen(CONFIG_);
417
418         sttext = str_new();
419         str_printf(&sttext, "Search (%s)", dialog_input_result);
420         stpart.text = str_get(&sttext);
421         list_add_tail(&stpart.entries, &trail);
422
423         sym_arr = sym_re_search(dialog_input);
424         do {
425                 LIST_HEAD(head);
426                 struct search_data data = {
427                         .head = &head,
428                 };
429                 struct jump_key *pos, *tmp;
430
431                 jump_key_char = 0;
432                 res = get_relations_str(sym_arr, &head);
433                 set_subtitle();
434                 dres = show_textbox_ext("Search Results", str_get(&res), 0, 0,
435                                         &vscroll, &hscroll,
436                                         handle_search_keys, &data);
437                 again = false;
438                 if (dres >= '1' && dres <= '9') {
439                         assert(data.target != NULL);
440                         conf(data.target->parent, data.target);
441                         again = true;
442                 }
443                 str_free(&res);
444                 list_for_each_entry_safe(pos, tmp, &head, entries)
445                         free(pos);
446         } while (again);
447         free(sym_arr);
448         str_free(&title);
449         list_del(trail.prev);
450         str_free(&sttext);
451 }
452
453 static void build_conf(struct menu *menu)
454 {
455         struct symbol *sym;
456         struct property *prop;
457         struct menu *child;
458         int type, tmp, doint = 2;
459         tristate val;
460         char ch;
461         bool visible;
462
463         /*
464          * note: menu_is_visible() has side effect that it will
465          * recalc the value of the symbol.
466          */
467         visible = menu_is_visible(menu);
468         if (show_all_options && !menu_has_prompt(menu))
469                 return;
470         else if (!show_all_options && !visible)
471                 return;
472
473         sym = menu->sym;
474         prop = menu->prompt;
475         if (!sym) {
476                 if (prop && menu != current_menu) {
477                         const char *prompt = menu_get_prompt(menu);
478                         switch (prop->type) {
479                         case P_MENU:
480                                 child_count++;
481                                 if (single_menu_mode) {
482                                         item_make("%s%*c%s",
483                                                   menu->data ? "-->" : "++>",
484                                                   indent + 1, ' ', prompt);
485                                 } else
486                                         item_make("   %*c%s  %s",
487                                                   indent + 1, ' ', prompt,
488                                                   menu_is_empty(menu) ? "----" : "--->");
489                                 item_set_tag('m');
490                                 item_set_data(menu);
491                                 if (single_menu_mode && menu->data)
492                                         goto conf_childs;
493                                 return;
494                         case P_COMMENT:
495                                 if (prompt) {
496                                         child_count++;
497                                         item_make("   %*c*** %s ***", indent + 1, ' ', prompt);
498                                         item_set_tag(':');
499                                         item_set_data(menu);
500                                 }
501                                 break;
502                         default:
503                                 if (prompt) {
504                                         child_count++;
505                                         item_make("---%*c%s", indent + 1, ' ', prompt);
506                                         item_set_tag(':');
507                                         item_set_data(menu);
508                                 }
509                         }
510                 } else
511                         doint = 0;
512                 goto conf_childs;
513         }
514
515         type = sym_get_type(sym);
516         if (sym_is_choice(sym)) {
517                 struct symbol *def_sym = sym_get_choice_value(sym);
518                 struct menu *def_menu = NULL;
519
520                 child_count++;
521                 for (child = menu->list; child; child = child->next) {
522                         if (menu_is_visible(child) && child->sym == def_sym)
523                                 def_menu = child;
524                 }
525
526                 val = sym_get_tristate_value(sym);
527                 if (sym_is_changeable(sym)) {
528                         switch (type) {
529                         case S_BOOLEAN:
530                                 item_make("[%c]", val == no ? ' ' : '*');
531                                 break;
532                         case S_TRISTATE:
533                                 switch (val) {
534                                 case yes: ch = '*'; break;
535                                 case mod: ch = 'M'; break;
536                                 default:  ch = ' '; break;
537                                 }
538                                 item_make("<%c>", ch);
539                                 break;
540                         }
541                         item_set_tag('t');
542                         item_set_data(menu);
543                 } else {
544                         item_make("   ");
545                         item_set_tag(def_menu ? 't' : ':');
546                         item_set_data(menu);
547                 }
548
549                 item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
550                 if (val == yes) {
551                         if (def_menu) {
552                                 item_add_str(" (%s)", menu_get_prompt(def_menu));
553                                 item_add_str("  --->");
554                                 if (def_menu->list) {
555                                         indent += 2;
556                                         build_conf(def_menu);
557                                         indent -= 2;
558                                 }
559                         }
560                         return;
561                 }
562         } else {
563                 if (menu == current_menu) {
564                         item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
565                         item_set_tag(':');
566                         item_set_data(menu);
567                         goto conf_childs;
568                 }
569                 child_count++;
570                 val = sym_get_tristate_value(sym);
571                 if (sym_is_choice_value(sym) && val == yes) {
572                         item_make("   ");
573                         item_set_tag(':');
574                         item_set_data(menu);
575                 } else {
576                         switch (type) {
577                         case S_BOOLEAN:
578                                 if (sym_is_changeable(sym))
579                                         item_make("[%c]", val == no ? ' ' : '*');
580                                 else
581                                         item_make("-%c-", val == no ? ' ' : '*');
582                                 item_set_tag('t');
583                                 item_set_data(menu);
584                                 break;
585                         case S_TRISTATE:
586                                 switch (val) {
587                                 case yes: ch = '*'; break;
588                                 case mod: ch = 'M'; break;
589                                 default:  ch = ' '; break;
590                                 }
591                                 if (sym_is_changeable(sym)) {
592                                         if (sym->rev_dep.tri == mod)
593                                                 item_make("{%c}", ch);
594                                         else
595                                                 item_make("<%c>", ch);
596                                 } else
597                                         item_make("-%c-", ch);
598                                 item_set_tag('t');
599                                 item_set_data(menu);
600                                 break;
601                         default:
602                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
603                                 item_make("(%s)", sym_get_string_value(sym));
604                                 tmp = indent - tmp + 4;
605                                 if (tmp < 0)
606                                         tmp = 0;
607                                 item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
608                                              (sym_has_value(sym) || !sym_is_changeable(sym)) ?
609                                              "" : " (NEW)");
610                                 item_set_tag('s');
611                                 item_set_data(menu);
612                                 goto conf_childs;
613                         }
614                 }
615                 item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
616                           (sym_has_value(sym) || !sym_is_changeable(sym)) ?
617                           "" : " (NEW)");
618                 if (menu->prompt->type == P_MENU) {
619                         item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
620                         return;
621                 }
622         }
623
624 conf_childs:
625         indent += doint;
626         for (child = menu->list; child; child = child->next)
627                 build_conf(child);
628         indent -= doint;
629 }
630
631 static void conf_choice(struct menu *menu)
632 {
633         const char *prompt = menu_get_prompt(menu);
634         struct menu *child;
635         struct symbol *active;
636
637         active = sym_get_choice_value(menu->sym);
638         while (1) {
639                 int res;
640                 int selected;
641                 item_reset();
642
643                 current_menu = menu;
644                 for (child = menu->list; child; child = child->next) {
645                         if (!menu_is_visible(child))
646                                 continue;
647                         if (child->sym)
648                                 item_make("%s", menu_get_prompt(child));
649                         else {
650                                 item_make("*** %s ***", menu_get_prompt(child));
651                                 item_set_tag(':');
652                         }
653                         item_set_data(child);
654                         if (child->sym == active)
655                                 item_set_selected(1);
656                         if (child->sym == sym_get_choice_value(menu->sym))
657                                 item_set_tag('X');
658                 }
659                 dialog_clear();
660                 res = dialog_checklist(prompt ? prompt : "Main Menu",
661                                         radiolist_instructions,
662                                         MENUBOX_HEIGTH_MIN,
663                                         MENUBOX_WIDTH_MIN,
664                                         CHECKLIST_HEIGTH_MIN);
665                 selected = item_activate_selected();
666                 switch (res) {
667                 case 0:
668                         if (selected) {
669                                 child = item_data();
670                                 if (!child->sym)
671                                         break;
672
673                                 sym_set_tristate_value(child->sym, yes);
674                         }
675                         return;
676                 case 1:
677                         if (selected) {
678                                 child = item_data();
679                                 show_help(child);
680                                 active = child->sym;
681                         } else
682                                 show_help(menu);
683                         break;
684                 case KEY_ESC:
685                         return;
686                 case -ERRDISPLAYTOOSMALL:
687                         return;
688                 }
689         }
690 }
691
692 static void conf_string(struct menu *menu)
693 {
694         const char *prompt = menu_get_prompt(menu);
695
696         while (1) {
697                 int res;
698                 const char *heading;
699
700                 switch (sym_get_type(menu->sym)) {
701                 case S_INT:
702                         heading = inputbox_instructions_int;
703                         break;
704                 case S_HEX:
705                         heading = inputbox_instructions_hex;
706                         break;
707                 case S_STRING:
708                         heading = inputbox_instructions_string;
709                         break;
710                 default:
711                         heading = "Internal mconf error!";
712                 }
713                 dialog_clear();
714                 res = dialog_inputbox(prompt ? prompt : "Main Menu",
715                                       heading, 10, 75,
716                                       sym_get_string_value(menu->sym));
717                 switch (res) {
718                 case 0:
719                         if (sym_set_string_value(menu->sym, dialog_input_result))
720                                 return;
721                         show_textbox(NULL, "You have made an invalid entry.", 5, 43);
722                         break;
723                 case 1:
724                         show_help(menu);
725                         break;
726                 case KEY_ESC:
727                         return;
728                 }
729         }
730 }
731
732 static void conf_load(void)
733 {
734
735         while (1) {
736                 int res;
737                 dialog_clear();
738                 res = dialog_inputbox(NULL, load_config_text,
739                                       11, 55, filename);
740                 switch(res) {
741                 case 0:
742                         if (!dialog_input_result[0])
743                                 return;
744                         if (!conf_read(dialog_input_result)) {
745                                 set_config_filename(dialog_input_result);
746                                 conf_set_changed(true);
747                                 return;
748                         }
749                         show_textbox(NULL, "File does not exist!", 5, 38);
750                         break;
751                 case 1:
752                         show_helptext("Load Alternate Configuration", load_config_help);
753                         break;
754                 case KEY_ESC:
755                         return;
756                 }
757         }
758 }
759
760 static void conf_save(void)
761 {
762         while (1) {
763                 int res;
764                 dialog_clear();
765                 res = dialog_inputbox(NULL, save_config_text,
766                                       11, 55, filename);
767                 switch(res) {
768                 case 0:
769                         if (!dialog_input_result[0])
770                                 return;
771                         if (!conf_write(dialog_input_result)) {
772                                 set_config_filename(dialog_input_result);
773                                 return;
774                         }
775                         show_textbox(NULL, "Can't create file!", 5, 60);
776                         break;
777                 case 1:
778                         show_helptext("Save Alternate Configuration", save_config_help);
779                         break;
780                 case KEY_ESC:
781                         return;
782                 }
783         }
784 }
785
786 static void conf(struct menu *menu, struct menu *active_menu)
787 {
788         struct menu *submenu;
789         const char *prompt = menu_get_prompt(menu);
790         struct subtitle_part stpart;
791         struct symbol *sym;
792         int res;
793         int s_scroll = 0;
794
795         if (menu != &rootmenu)
796                 stpart.text = menu_get_prompt(menu);
797         else
798                 stpart.text = NULL;
799         list_add_tail(&stpart.entries, &trail);
800
801         while (1) {
802                 item_reset();
803                 current_menu = menu;
804                 build_conf(menu);
805                 if (!child_count)
806                         break;
807                 set_subtitle();
808                 dialog_clear();
809                 res = dialog_menu(prompt ? prompt : "Main Menu",
810                                   menu_instructions,
811                                   active_menu, &s_scroll);
812                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
813                         break;
814                 if (item_count() != 0) {
815                         if (!item_activate_selected())
816                                 continue;
817                         if (!item_tag())
818                                 continue;
819                 }
820                 submenu = item_data();
821                 active_menu = item_data();
822                 if (submenu)
823                         sym = submenu->sym;
824                 else
825                         sym = NULL;
826
827                 switch (res) {
828                 case 0:
829                         switch (item_tag()) {
830                         case 'm':
831                                 if (single_menu_mode)
832                                         submenu->data = (void *) (long) !submenu->data;
833                                 else
834                                         conf(submenu, NULL);
835                                 break;
836                         case 't':
837                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
838                                         conf_choice(submenu);
839                                 else if (submenu->prompt->type == P_MENU)
840                                         conf(submenu, NULL);
841                                 break;
842                         case 's':
843                                 conf_string(submenu);
844                                 break;
845                         }
846                         break;
847                 case 2:
848                         if (sym)
849                                 show_help(submenu);
850                         else {
851                                 reset_subtitle();
852                                 show_helptext("README", mconf_readme);
853                         }
854                         break;
855                 case 3:
856                         reset_subtitle();
857                         conf_save();
858                         break;
859                 case 4:
860                         reset_subtitle();
861                         conf_load();
862                         break;
863                 case 5:
864                         if (item_is_tag('t')) {
865                                 if (sym_set_tristate_value(sym, yes))
866                                         break;
867                                 if (sym_set_tristate_value(sym, mod))
868                                         show_textbox(NULL, setmod_text, 6, 74);
869                         }
870                         break;
871                 case 6:
872                         if (item_is_tag('t'))
873                                 sym_set_tristate_value(sym, no);
874                         break;
875                 case 7:
876                         if (item_is_tag('t'))
877                                 sym_set_tristate_value(sym, mod);
878                         break;
879                 case 8:
880                         if (item_is_tag('t'))
881                                 sym_toggle_tristate_value(sym);
882                         else if (item_is_tag('m'))
883                                 conf(submenu, NULL);
884                         break;
885                 case 9:
886                         search_conf();
887                         break;
888                 case 10:
889                         show_all_options = !show_all_options;
890                         break;
891                 }
892         }
893
894         list_del(trail.prev);
895 }
896
897 static void conf_message_callback(const char *s)
898 {
899         if (save_and_exit) {
900                 if (!silent)
901                         printf("%s", s);
902         } else {
903                 show_textbox(NULL, s, 6, 60);
904         }
905 }
906
907 static int handle_exit(void)
908 {
909         int res;
910
911         save_and_exit = 1;
912         reset_subtitle();
913         dialog_clear();
914         if (conf_get_changed())
915                 res = dialog_yesno(NULL,
916                                    "Do you wish to save your new configuration?\n"
917                                      "(Press <ESC><ESC> to continue kernel configuration.)",
918                                    6, 60);
919         else
920                 res = -1;
921
922         end_dialog(saved_x, saved_y);
923
924         switch (res) {
925         case 0:
926                 if (conf_write(filename)) {
927                         fprintf(stderr, "\n\n"
928                                           "Error while writing of the configuration.\n"
929                                           "Your configuration changes were NOT saved."
930                                           "\n\n");
931                         return 1;
932                 }
933                 conf_write_autoconf(0);
934                 /* fall through */
935         case -1:
936                 if (!silent)
937                         printf("\n\n"
938                                  "*** End of the configuration.\n"
939                                  "*** Execute 'make' to start the build or try 'make help'."
940                                  "\n\n");
941                 res = 0;
942                 break;
943         default:
944                 if (!silent)
945                         fprintf(stderr, "\n\n"
946                                           "Your configuration changes were NOT saved."
947                                           "\n\n");
948                 if (res != KEY_ESC)
949                         res = 0;
950         }
951
952         return res;
953 }
954
955 static void sig_handler(int signo)
956 {
957         exit(handle_exit());
958 }
959
960 int main(int ac, char **av)
961 {
962         char *mode;
963         int res;
964
965         signal(SIGINT, sig_handler);
966
967         if (ac > 1 && strcmp(av[1], "-s") == 0) {
968                 silent = 1;
969                 /* Silence conf_read() until the real callback is set up */
970                 conf_set_message_callback(NULL);
971                 av++;
972         }
973         conf_parse(av[1]);
974         conf_read(NULL);
975
976         mode = getenv("MENUCONFIG_MODE");
977         if (mode) {
978                 if (!strcasecmp(mode, "single_menu"))
979                         single_menu_mode = 1;
980         }
981
982         if (init_dialog(NULL)) {
983                 fprintf(stderr, "Your display is too small to run Menuconfig!\n");
984                 fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
985                 return 1;
986         }
987
988         set_config_filename(conf_get_configname());
989         conf_set_message_callback(conf_message_callback);
990         do {
991                 conf(&rootmenu, NULL);
992                 res = handle_exit();
993         } while (res == KEY_ESC);
994
995         return res;
996 }