Merge branch 'drm-intel-fixes' of git://people.freedesktop.org/~danvet/drm-intel...
[platform/adaptation/renesas_rcar/renesas_kernel.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         "Type  : tristate\n"
240         "Prompt: Foo bus is used to drive the bar HW\n"
241         "  Defined at drivers/pci/Kconfig:47\n"
242         "  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
243         "  Location:\n"
244         "    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
245         "      -> PCI support (PCI [=y])\n"
246         "(1)     -> PCI access mode (<choice> [=y])\n"
247         "  Selects: LIBCRC32\n"
248         "  Selected by: BAR\n"
249         "-----------------------------------------------------------------\n"
250         "o The line 'Type:' shows the type of the configuration option for\n"
251         "  this symbol (boolean, tristate, string, ...)\n"
252         "o The line 'Prompt:' shows the text used in the menu structure for\n"
253         "  this symbol\n"
254         "o The 'Defined at' line tell at what file / line number the symbol\n"
255         "  is defined\n"
256         "o The 'Depends on:' line tell what symbols needs to be defined for\n"
257         "  this symbol to be visible in the menu (selectable)\n"
258         "o The 'Location:' lines tell where in the menu structure this symbol\n"
259         "  is located\n"
260         "    A location followed by a [=y] indicates that this is a\n"
261         "    selectable menu item - and the current value is displayed inside\n"
262         "    brackets.\n"
263         "    Press the key in the (#) prefix to jump directly to that\n"
264         "    location. You will be returned to the current search results\n"
265         "    after exiting this new menu.\n"
266         "o The 'Selects:' line tell what symbol will be automatically\n"
267         "  selected if this symbol is selected (y or m)\n"
268         "o The 'Selected by' line tell what symbol has selected this symbol\n"
269         "\n"
270         "Only relevant lines are shown.\n"
271         "\n\n"
272         "Search examples:\n"
273         "Examples: USB  => find all symbols containing USB\n"
274         "          ^USB => find all symbols starting with USB\n"
275         "          USB$ => find all symbols ending with USB\n"
276         "\n");
277
278 static int indent;
279 static struct menu *current_menu;
280 static int child_count;
281 static int single_menu_mode;
282 static int show_all_options;
283
284 static void conf(struct menu *menu, struct menu *active_menu);
285 static void conf_choice(struct menu *menu);
286 static void conf_string(struct menu *menu);
287 static void conf_load(void);
288 static void conf_save(void);
289 static int show_textbox_ext(const char *title, char *text, int r, int c,
290                             int *keys, int *vscroll, int *hscroll,
291                             update_text_fn update_text, void *data);
292 static void show_textbox(const char *title, const char *text, int r, int c);
293 static void show_helptext(const char *title, const char *text);
294 static void show_help(struct menu *menu);
295
296 static char filename[PATH_MAX+1];
297 static void set_config_filename(const char *config_filename)
298 {
299         static char menu_backtitle[PATH_MAX+128];
300         int size;
301
302         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
303                         "%s - %s", config_filename, rootmenu.prompt->text);
304         if (size >= sizeof(menu_backtitle))
305                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
306         set_dialog_backtitle(menu_backtitle);
307
308         size = snprintf(filename, sizeof(filename), "%s", config_filename);
309         if (size >= sizeof(filename))
310                 filename[sizeof(filename)-1] = '\0';
311 }
312
313
314 struct search_data {
315         struct jk_head *head;
316         struct menu **targets;
317         int *keys;
318 };
319
320 static void update_text(char *buf, size_t start, size_t end, void *_data)
321 {
322         struct search_data *data = _data;
323         struct jump_key *pos;
324         int k = 0;
325
326         CIRCLEQ_FOREACH(pos, data->head, entries) {
327                 if (pos->offset >= start && pos->offset < end) {
328                         char header[4];
329
330                         if (k < JUMP_NB) {
331                                 int key = '0' + (pos->index % JUMP_NB) + 1;
332
333                                 sprintf(header, "(%c)", key);
334                                 data->keys[k] = key;
335                                 data->targets[k] = pos->target;
336                                 k++;
337                         } else {
338                                 sprintf(header, "   ");
339                         }
340
341                         memcpy(buf + pos->offset, header, sizeof(header) - 1);
342                 }
343         }
344         data->keys[k] = 0;
345 }
346
347 static void search_conf(void)
348 {
349         struct symbol **sym_arr;
350         struct gstr res;
351         char *dialog_input;
352         int dres, vscroll = 0, hscroll = 0;
353         bool again;
354
355 again:
356         dialog_clear();
357         dres = dialog_inputbox(_("Search Configuration Parameter"),
358                               _("Enter " CONFIG_ " (sub)string to search for "
359                                 "(with or without \"" CONFIG_ "\")"),
360                               10, 75, "");
361         switch (dres) {
362         case 0:
363                 break;
364         case 1:
365                 show_helptext(_("Search Configuration"), search_help);
366                 goto again;
367         default:
368                 return;
369         }
370
371         /* strip the prefix if necessary */
372         dialog_input = dialog_input_result;
373         if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
374                 dialog_input += strlen(CONFIG_);
375
376         sym_arr = sym_re_search(dialog_input);
377         do {
378                 struct jk_head head = CIRCLEQ_HEAD_INITIALIZER(head);
379                 struct menu *targets[JUMP_NB];
380                 int keys[JUMP_NB + 1], i;
381                 struct search_data data = {
382                         .head = &head,
383                         .targets = targets,
384                         .keys = keys,
385                 };
386
387                 res = get_relations_str(sym_arr, &head);
388                 dres = show_textbox_ext(_("Search Results"), (char *)
389                                         str_get(&res), 0, 0, keys, &vscroll,
390                                         &hscroll, &update_text, (void *)
391                                         &data);
392                 again = false;
393                 for (i = 0; i < JUMP_NB && keys[i]; i++)
394                         if (dres == keys[i]) {
395                                 conf(targets[i]->parent, targets[i]);
396                                 again = true;
397                         }
398                 str_free(&res);
399         } while (again);
400         free(sym_arr);
401 }
402
403 static void build_conf(struct menu *menu)
404 {
405         struct symbol *sym;
406         struct property *prop;
407         struct menu *child;
408         int type, tmp, doint = 2;
409         tristate val;
410         char ch;
411         bool visible;
412
413         /*
414          * note: menu_is_visible() has side effect that it will
415          * recalc the value of the symbol.
416          */
417         visible = menu_is_visible(menu);
418         if (show_all_options && !menu_has_prompt(menu))
419                 return;
420         else if (!show_all_options && !visible)
421                 return;
422
423         sym = menu->sym;
424         prop = menu->prompt;
425         if (!sym) {
426                 if (prop && menu != current_menu) {
427                         const char *prompt = menu_get_prompt(menu);
428                         switch (prop->type) {
429                         case P_MENU:
430                                 child_count++;
431                                 prompt = _(prompt);
432                                 if (single_menu_mode) {
433                                         item_make("%s%*c%s",
434                                                   menu->data ? "-->" : "++>",
435                                                   indent + 1, ' ', prompt);
436                                 } else
437                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
438
439                                 item_set_tag('m');
440                                 item_set_data(menu);
441                                 if (single_menu_mode && menu->data)
442                                         goto conf_childs;
443                                 return;
444                         case P_COMMENT:
445                                 if (prompt) {
446                                         child_count++;
447                                         item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
448                                         item_set_tag(':');
449                                         item_set_data(menu);
450                                 }
451                                 break;
452                         default:
453                                 if (prompt) {
454                                         child_count++;
455                                         item_make("---%*c%s", indent + 1, ' ', _(prompt));
456                                         item_set_tag(':');
457                                         item_set_data(menu);
458                                 }
459                         }
460                 } else
461                         doint = 0;
462                 goto conf_childs;
463         }
464
465         type = sym_get_type(sym);
466         if (sym_is_choice(sym)) {
467                 struct symbol *def_sym = sym_get_choice_value(sym);
468                 struct menu *def_menu = NULL;
469
470                 child_count++;
471                 for (child = menu->list; child; child = child->next) {
472                         if (menu_is_visible(child) && child->sym == def_sym)
473                                 def_menu = child;
474                 }
475
476                 val = sym_get_tristate_value(sym);
477                 if (sym_is_changable(sym)) {
478                         switch (type) {
479                         case S_BOOLEAN:
480                                 item_make("[%c]", val == no ? ' ' : '*');
481                                 break;
482                         case S_TRISTATE:
483                                 switch (val) {
484                                 case yes: ch = '*'; break;
485                                 case mod: ch = 'M'; break;
486                                 default:  ch = ' '; break;
487                                 }
488                                 item_make("<%c>", ch);
489                                 break;
490                         }
491                         item_set_tag('t');
492                         item_set_data(menu);
493                 } else {
494                         item_make("   ");
495                         item_set_tag(def_menu ? 't' : ':');
496                         item_set_data(menu);
497                 }
498
499                 item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
500                 if (val == yes) {
501                         if (def_menu) {
502                                 item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
503                                 item_add_str("  --->");
504                                 if (def_menu->list) {
505                                         indent += 2;
506                                         build_conf(def_menu);
507                                         indent -= 2;
508                                 }
509                         }
510                         return;
511                 }
512         } else {
513                 if (menu == current_menu) {
514                         item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
515                         item_set_tag(':');
516                         item_set_data(menu);
517                         goto conf_childs;
518                 }
519                 child_count++;
520                 val = sym_get_tristate_value(sym);
521                 if (sym_is_choice_value(sym) && val == yes) {
522                         item_make("   ");
523                         item_set_tag(':');
524                         item_set_data(menu);
525                 } else {
526                         switch (type) {
527                         case S_BOOLEAN:
528                                 if (sym_is_changable(sym))
529                                         item_make("[%c]", val == no ? ' ' : '*');
530                                 else
531                                         item_make("-%c-", val == no ? ' ' : '*');
532                                 item_set_tag('t');
533                                 item_set_data(menu);
534                                 break;
535                         case S_TRISTATE:
536                                 switch (val) {
537                                 case yes: ch = '*'; break;
538                                 case mod: ch = 'M'; break;
539                                 default:  ch = ' '; break;
540                                 }
541                                 if (sym_is_changable(sym)) {
542                                         if (sym->rev_dep.tri == mod)
543                                                 item_make("{%c}", ch);
544                                         else
545                                                 item_make("<%c>", ch);
546                                 } else
547                                         item_make("-%c-", ch);
548                                 item_set_tag('t');
549                                 item_set_data(menu);
550                                 break;
551                         default:
552                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
553                                 item_make("(%s)", sym_get_string_value(sym));
554                                 tmp = indent - tmp + 4;
555                                 if (tmp < 0)
556                                         tmp = 0;
557                                 item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
558                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
559                                              "" : _(" (NEW)"));
560                                 item_set_tag('s');
561                                 item_set_data(menu);
562                                 goto conf_childs;
563                         }
564                 }
565                 item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
566                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
567                           "" : _(" (NEW)"));
568                 if (menu->prompt->type == P_MENU) {
569                         item_add_str("  --->");
570                         return;
571                 }
572         }
573
574 conf_childs:
575         indent += doint;
576         for (child = menu->list; child; child = child->next)
577                 build_conf(child);
578         indent -= doint;
579 }
580
581 static void conf(struct menu *menu, struct menu *active_menu)
582 {
583         struct menu *submenu;
584         const char *prompt = menu_get_prompt(menu);
585         struct symbol *sym;
586         int res;
587         int s_scroll = 0;
588
589         while (1) {
590                 item_reset();
591                 current_menu = menu;
592                 build_conf(menu);
593                 if (!child_count)
594                         break;
595                 if (menu == &rootmenu) {
596                         item_make("--- ");
597                         item_set_tag(':');
598                         item_make(_("    Load an Alternate Configuration File"));
599                         item_set_tag('L');
600                         item_make(_("    Save an Alternate Configuration File"));
601                         item_set_tag('S');
602                 }
603                 dialog_clear();
604                 res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
605                                   _(menu_instructions),
606                                   active_menu, &s_scroll);
607                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
608                         break;
609                 if (!item_activate_selected())
610                         continue;
611                 if (!item_tag())
612                         continue;
613
614                 submenu = item_data();
615                 active_menu = item_data();
616                 if (submenu)
617                         sym = submenu->sym;
618                 else
619                         sym = NULL;
620
621                 switch (res) {
622                 case 0:
623                         switch (item_tag()) {
624                         case 'm':
625                                 if (single_menu_mode)
626                                         submenu->data = (void *) (long) !submenu->data;
627                                 else
628                                         conf(submenu, NULL);
629                                 break;
630                         case 't':
631                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
632                                         conf_choice(submenu);
633                                 else if (submenu->prompt->type == P_MENU)
634                                         conf(submenu, NULL);
635                                 break;
636                         case 's':
637                                 conf_string(submenu);
638                                 break;
639                         case 'L':
640                                 conf_load();
641                                 break;
642                         case 'S':
643                                 conf_save();
644                                 break;
645                         }
646                         break;
647                 case 2:
648                         if (sym)
649                                 show_help(submenu);
650                         else
651                                 show_helptext(_("README"), _(mconf_readme));
652                         break;
653                 case 3:
654                         if (item_is_tag('t')) {
655                                 if (sym_set_tristate_value(sym, yes))
656                                         break;
657                                 if (sym_set_tristate_value(sym, mod))
658                                         show_textbox(NULL, setmod_text, 6, 74);
659                         }
660                         break;
661                 case 4:
662                         if (item_is_tag('t'))
663                                 sym_set_tristate_value(sym, no);
664                         break;
665                 case 5:
666                         if (item_is_tag('t'))
667                                 sym_set_tristate_value(sym, mod);
668                         break;
669                 case 6:
670                         if (item_is_tag('t'))
671                                 sym_toggle_tristate_value(sym);
672                         else if (item_is_tag('m'))
673                                 conf(submenu, NULL);
674                         break;
675                 case 7:
676                         search_conf();
677                         break;
678                 case 8:
679                         show_all_options = !show_all_options;
680                         break;
681                 }
682         }
683 }
684
685 static int show_textbox_ext(const char *title, char *text, int r, int c, int
686                             *keys, int *vscroll, int *hscroll, update_text_fn
687                             update_text, void *data)
688 {
689         dialog_clear();
690         return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
691                               update_text, data);
692 }
693
694 static void show_textbox(const char *title, const char *text, int r, int c)
695 {
696         show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
697                          NULL, NULL);
698 }
699
700 static void show_helptext(const char *title, const char *text)
701 {
702         show_textbox(title, text, 0, 0);
703 }
704
705 static void show_help(struct menu *menu)
706 {
707         struct gstr help = str_new();
708
709         help.max_width = getmaxx(stdscr) - 10;
710         menu_get_ext_help(menu, &help);
711
712         show_helptext(_(menu_get_prompt(menu)), str_get(&help));
713         str_free(&help);
714 }
715
716 static void conf_choice(struct menu *menu)
717 {
718         const char *prompt = _(menu_get_prompt(menu));
719         struct menu *child;
720         struct symbol *active;
721
722         active = sym_get_choice_value(menu->sym);
723         while (1) {
724                 int res;
725                 int selected;
726                 item_reset();
727
728                 current_menu = menu;
729                 for (child = menu->list; child; child = child->next) {
730                         if (!menu_is_visible(child))
731                                 continue;
732                         if (child->sym)
733                                 item_make("%s", _(menu_get_prompt(child)));
734                         else {
735                                 item_make("*** %s ***", _(menu_get_prompt(child)));
736                                 item_set_tag(':');
737                         }
738                         item_set_data(child);
739                         if (child->sym == active)
740                                 item_set_selected(1);
741                         if (child->sym == sym_get_choice_value(menu->sym))
742                                 item_set_tag('X');
743                 }
744                 dialog_clear();
745                 res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
746                                         _(radiolist_instructions),
747                                          15, 70, 6);
748                 selected = item_activate_selected();
749                 switch (res) {
750                 case 0:
751                         if (selected) {
752                                 child = item_data();
753                                 if (!child->sym)
754                                         break;
755
756                                 sym_set_tristate_value(child->sym, yes);
757                         }
758                         return;
759                 case 1:
760                         if (selected) {
761                                 child = item_data();
762                                 show_help(child);
763                                 active = child->sym;
764                         } else
765                                 show_help(menu);
766                         break;
767                 case KEY_ESC:
768                         return;
769                 case -ERRDISPLAYTOOSMALL:
770                         return;
771                 }
772         }
773 }
774
775 static void conf_string(struct menu *menu)
776 {
777         const char *prompt = menu_get_prompt(menu);
778
779         while (1) {
780                 int res;
781                 const char *heading;
782
783                 switch (sym_get_type(menu->sym)) {
784                 case S_INT:
785                         heading = _(inputbox_instructions_int);
786                         break;
787                 case S_HEX:
788                         heading = _(inputbox_instructions_hex);
789                         break;
790                 case S_STRING:
791                         heading = _(inputbox_instructions_string);
792                         break;
793                 default:
794                         heading = _("Internal mconf error!");
795                 }
796                 dialog_clear();
797                 res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
798                                       heading, 10, 75,
799                                       sym_get_string_value(menu->sym));
800                 switch (res) {
801                 case 0:
802                         if (sym_set_string_value(menu->sym, dialog_input_result))
803                                 return;
804                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
805                         break;
806                 case 1:
807                         show_help(menu);
808                         break;
809                 case KEY_ESC:
810                         return;
811                 }
812         }
813 }
814
815 static void conf_load(void)
816 {
817
818         while (1) {
819                 int res;
820                 dialog_clear();
821                 res = dialog_inputbox(NULL, load_config_text,
822                                       11, 55, filename);
823                 switch(res) {
824                 case 0:
825                         if (!dialog_input_result[0])
826                                 return;
827                         if (!conf_read(dialog_input_result)) {
828                                 set_config_filename(dialog_input_result);
829                                 sym_set_change_count(1);
830                                 return;
831                         }
832                         show_textbox(NULL, _("File does not exist!"), 5, 38);
833                         break;
834                 case 1:
835                         show_helptext(_("Load Alternate Configuration"), load_config_help);
836                         break;
837                 case KEY_ESC:
838                         return;
839                 }
840         }
841 }
842
843 static void conf_save(void)
844 {
845         while (1) {
846                 int res;
847                 dialog_clear();
848                 res = dialog_inputbox(NULL, save_config_text,
849                                       11, 55, filename);
850                 switch(res) {
851                 case 0:
852                         if (!dialog_input_result[0])
853                                 return;
854                         if (!conf_write(dialog_input_result)) {
855                                 set_config_filename(dialog_input_result);
856                                 return;
857                         }
858                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
859                         break;
860                 case 1:
861                         show_helptext(_("Save Alternate Configuration"), save_config_help);
862                         break;
863                 case KEY_ESC:
864                         return;
865                 }
866         }
867 }
868
869 static int handle_exit(void)
870 {
871         int res;
872
873         dialog_clear();
874         if (conf_get_changed())
875                 res = dialog_yesno(NULL,
876                                    _("Do you wish to save your new configuration ?\n"
877                                      "<ESC><ESC> to continue."),
878                                    6, 60);
879         else
880                 res = -1;
881
882         end_dialog(saved_x, saved_y);
883
884         switch (res) {
885         case 0:
886                 if (conf_write(filename)) {
887                         fprintf(stderr, _("\n\n"
888                                           "Error while writing of the configuration.\n"
889                                           "Your configuration changes were NOT saved."
890                                           "\n\n"));
891                         return 1;
892                 }
893                 /* fall through */
894         case -1:
895                 printf(_("\n\n"
896                          "*** End of the configuration.\n"
897                          "*** Execute 'make' to start the build or try 'make help'."
898                          "\n\n"));
899                 res = 0;
900                 break;
901         default:
902                 fprintf(stderr, _("\n\n"
903                                   "Your configuration changes were NOT saved."
904                                   "\n\n"));
905                 if (res != KEY_ESC)
906                         res = 0;
907         }
908
909         return res;
910 }
911
912 static void sig_handler(int signo)
913 {
914         exit(handle_exit());
915 }
916
917 int main(int ac, char **av)
918 {
919         char *mode;
920         int res;
921
922         setlocale(LC_ALL, "");
923         bindtextdomain(PACKAGE, LOCALEDIR);
924         textdomain(PACKAGE);
925
926         signal(SIGINT, sig_handler);
927
928         conf_parse(av[1]);
929         conf_read(NULL);
930
931         mode = getenv("MENUCONFIG_MODE");
932         if (mode) {
933                 if (!strcasecmp(mode, "single_menu"))
934                         single_menu_mode = 1;
935         }
936
937         if (init_dialog(NULL)) {
938                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
939                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
940                 return 1;
941         }
942
943         set_config_filename(conf_get_configname());
944         do {
945                 conf(&rootmenu, NULL);
946                 res = handle_exit();
947         } while (res == KEY_ESC);
948
949         return res;
950 }
951