kconfig: handle SIGINT in menuconfig
[linux-2.6.git] / scripts / kconfig / mconf.c
1 /*
2  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3  * Released under the terms of the GNU GPL v2.0.
4  *
5  * Introduced single menu mode (show all sub-menus in one large tree).
6  * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7  *
8  * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9  */
10
11 #include <ctype.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <limits.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <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 <SPACE BAR> and <B> for those\n"
109 "   who are familiar with less and lynx.\n"
110 "\n"
111 "o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
112 "\n"
113 "\n"
114 "Alternate Configuration Files\n"
115 "-----------------------------\n"
116 "Menuconfig supports the use of alternate configuration files for\n"
117 "those who, for various reasons, find it necessary to switch\n"
118 "between different configurations.\n"
119 "\n"
120 "At the end of the main menu you will find two options.  One is\n"
121 "for saving the current configuration to a file of your choosing.\n"
122 "The other option is for loading a previously saved alternate\n"
123 "configuration.\n"
124 "\n"
125 "Even if you don't use alternate configuration files, but you\n"
126 "find during a Menuconfig session that you have completely messed\n"
127 "up your settings, you may use the \"Load Alternate...\" option to\n"
128 "restore your previously saved settings from \".config\" without\n"
129 "restarting Menuconfig.\n"
130 "\n"
131 "Other information\n"
132 "-----------------\n"
133 "If you use Menuconfig in an XTERM window make sure you have your\n"
134 "$TERM variable set to point to a xterm definition which supports color.\n"
135 "Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
136 "display correctly in a RXVT window because rxvt displays only one\n"
137 "intensity of color, bright.\n"
138 "\n"
139 "Menuconfig will display larger menus on screens or xterms which are\n"
140 "set to display more than the standard 25 row by 80 column geometry.\n"
141 "In order for this to work, the \"stty size\" command must be able to\n"
142 "display the screen's current row and column geometry.  I STRONGLY\n"
143 "RECOMMEND that you make sure you do NOT have the shell variables\n"
144 "LINES and COLUMNS exported into your environment.  Some distributions\n"
145 "export those variables via /etc/profile.  Some ncurses programs can\n"
146 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
147 "the true screen size.\n"
148 "\n"
149 "Optional personality available\n"
150 "------------------------------\n"
151 "If you prefer to have all of the options listed in a single 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, MCA, 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 static int saved_x, saved_y;
277
278 static void conf(struct menu *menu);
279 static void conf_choice(struct menu *menu);
280 static void conf_string(struct menu *menu);
281 static void conf_load(void);
282 static void conf_save(void);
283 static void show_textbox(const char *title, const char *text, int r, int c);
284 static void show_helptext(const char *title, const char *text);
285 static void show_help(struct menu *menu);
286
287 static char filename[PATH_MAX+1];
288 static void set_config_filename(const char *config_filename)
289 {
290         static char menu_backtitle[PATH_MAX+128];
291         int size;
292
293         size = snprintf(menu_backtitle, sizeof(menu_backtitle),
294                         "%s - %s", config_filename, rootmenu.prompt->text);
295         if (size >= sizeof(menu_backtitle))
296                 menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
297         set_dialog_backtitle(menu_backtitle);
298
299         size = snprintf(filename, sizeof(filename), "%s", config_filename);
300         if (size >= sizeof(filename))
301                 filename[sizeof(filename)-1] = '\0';
302 }
303
304
305 static void search_conf(void)
306 {
307         struct symbol **sym_arr;
308         struct gstr res;
309         char *dialog_input;
310         int dres;
311 again:
312         dialog_clear();
313         dres = dialog_inputbox(_("Search Configuration Parameter"),
314                               _("Enter " CONFIG_ " (sub)string to search for "
315                                 "(with or without \"" CONFIG_ "\")"),
316                               10, 75, "");
317         switch (dres) {
318         case 0:
319                 break;
320         case 1:
321                 show_helptext(_("Search Configuration"), search_help);
322                 goto again;
323         default:
324                 return;
325         }
326
327         /* strip the prefix if necessary */
328         dialog_input = dialog_input_result;
329         if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
330                 dialog_input += strlen(CONFIG_);
331
332         sym_arr = sym_re_search(dialog_input);
333         res = get_relations_str(sym_arr);
334         free(sym_arr);
335         show_textbox(_("Search Results"), str_get(&res), 0, 0);
336         str_free(&res);
337 }
338
339 static void build_conf(struct menu *menu)
340 {
341         struct symbol *sym;
342         struct property *prop;
343         struct menu *child;
344         int type, tmp, doint = 2;
345         tristate val;
346         char ch;
347         bool visible;
348
349         /*
350          * note: menu_is_visible() has side effect that it will
351          * recalc the value of the symbol.
352          */
353         visible = menu_is_visible(menu);
354         if (show_all_options && !menu_has_prompt(menu))
355                 return;
356         else if (!show_all_options && !visible)
357                 return;
358
359         sym = menu->sym;
360         prop = menu->prompt;
361         if (!sym) {
362                 if (prop && menu != current_menu) {
363                         const char *prompt = menu_get_prompt(menu);
364                         switch (prop->type) {
365                         case P_MENU:
366                                 child_count++;
367                                 prompt = _(prompt);
368                                 if (single_menu_mode) {
369                                         item_make("%s%*c%s",
370                                                   menu->data ? "-->" : "++>",
371                                                   indent + 1, ' ', prompt);
372                                 } else
373                                         item_make("   %*c%s  --->", indent + 1, ' ', prompt);
374
375                                 item_set_tag('m');
376                                 item_set_data(menu);
377                                 if (single_menu_mode && menu->data)
378                                         goto conf_childs;
379                                 return;
380                         case P_COMMENT:
381                                 if (prompt) {
382                                         child_count++;
383                                         item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
384                                         item_set_tag(':');
385                                         item_set_data(menu);
386                                 }
387                                 break;
388                         default:
389                                 if (prompt) {
390                                         child_count++;
391                                         item_make("---%*c%s", indent + 1, ' ', _(prompt));
392                                         item_set_tag(':');
393                                         item_set_data(menu);
394                                 }
395                         }
396                 } else
397                         doint = 0;
398                 goto conf_childs;
399         }
400
401         type = sym_get_type(sym);
402         if (sym_is_choice(sym)) {
403                 struct symbol *def_sym = sym_get_choice_value(sym);
404                 struct menu *def_menu = NULL;
405
406                 child_count++;
407                 for (child = menu->list; child; child = child->next) {
408                         if (menu_is_visible(child) && child->sym == def_sym)
409                                 def_menu = child;
410                 }
411
412                 val = sym_get_tristate_value(sym);
413                 if (sym_is_changable(sym)) {
414                         switch (type) {
415                         case S_BOOLEAN:
416                                 item_make("[%c]", val == no ? ' ' : '*');
417                                 break;
418                         case S_TRISTATE:
419                                 switch (val) {
420                                 case yes: ch = '*'; break;
421                                 case mod: ch = 'M'; break;
422                                 default:  ch = ' '; break;
423                                 }
424                                 item_make("<%c>", ch);
425                                 break;
426                         }
427                         item_set_tag('t');
428                         item_set_data(menu);
429                 } else {
430                         item_make("   ");
431                         item_set_tag(def_menu ? 't' : ':');
432                         item_set_data(menu);
433                 }
434
435                 item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
436                 if (val == yes) {
437                         if (def_menu) {
438                                 item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
439                                 item_add_str("  --->");
440                                 if (def_menu->list) {
441                                         indent += 2;
442                                         build_conf(def_menu);
443                                         indent -= 2;
444                                 }
445                         }
446                         return;
447                 }
448         } else {
449                 if (menu == current_menu) {
450                         item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
451                         item_set_tag(':');
452                         item_set_data(menu);
453                         goto conf_childs;
454                 }
455                 child_count++;
456                 val = sym_get_tristate_value(sym);
457                 if (sym_is_choice_value(sym) && val == yes) {
458                         item_make("   ");
459                         item_set_tag(':');
460                         item_set_data(menu);
461                 } else {
462                         switch (type) {
463                         case S_BOOLEAN:
464                                 if (sym_is_changable(sym))
465                                         item_make("[%c]", val == no ? ' ' : '*');
466                                 else
467                                         item_make("-%c-", val == no ? ' ' : '*');
468                                 item_set_tag('t');
469                                 item_set_data(menu);
470                                 break;
471                         case S_TRISTATE:
472                                 switch (val) {
473                                 case yes: ch = '*'; break;
474                                 case mod: ch = 'M'; break;
475                                 default:  ch = ' '; break;
476                                 }
477                                 if (sym_is_changable(sym)) {
478                                         if (sym->rev_dep.tri == mod)
479                                                 item_make("{%c}", ch);
480                                         else
481                                                 item_make("<%c>", ch);
482                                 } else
483                                         item_make("-%c-", ch);
484                                 item_set_tag('t');
485                                 item_set_data(menu);
486                                 break;
487                         default:
488                                 tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
489                                 item_make("(%s)", sym_get_string_value(sym));
490                                 tmp = indent - tmp + 4;
491                                 if (tmp < 0)
492                                         tmp = 0;
493                                 item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
494                                              (sym_has_value(sym) || !sym_is_changable(sym)) ?
495                                              "" : _(" (NEW)"));
496                                 item_set_tag('s');
497                                 item_set_data(menu);
498                                 goto conf_childs;
499                         }
500                 }
501                 item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
502                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
503                           "" : _(" (NEW)"));
504                 if (menu->prompt->type == P_MENU) {
505                         item_add_str("  --->");
506                         return;
507                 }
508         }
509
510 conf_childs:
511         indent += doint;
512         for (child = menu->list; child; child = child->next)
513                 build_conf(child);
514         indent -= doint;
515 }
516
517 static void conf(struct menu *menu)
518 {
519         struct menu *submenu;
520         const char *prompt = menu_get_prompt(menu);
521         struct symbol *sym;
522         struct menu *active_menu = NULL;
523         int res;
524         int s_scroll = 0;
525
526         while (1) {
527                 item_reset();
528                 current_menu = menu;
529                 build_conf(menu);
530                 if (!child_count)
531                         break;
532                 if (menu == &rootmenu) {
533                         item_make("--- ");
534                         item_set_tag(':');
535                         item_make(_("    Load an Alternate Configuration File"));
536                         item_set_tag('L');
537                         item_make(_("    Save an Alternate Configuration File"));
538                         item_set_tag('S');
539                 }
540                 dialog_clear();
541                 res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
542                                   _(menu_instructions),
543                                   active_menu, &s_scroll);
544                 if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
545                         break;
546                 if (!item_activate_selected())
547                         continue;
548                 if (!item_tag())
549                         continue;
550
551                 submenu = item_data();
552                 active_menu = item_data();
553                 if (submenu)
554                         sym = submenu->sym;
555                 else
556                         sym = NULL;
557
558                 switch (res) {
559                 case 0:
560                         switch (item_tag()) {
561                         case 'm':
562                                 if (single_menu_mode)
563                                         submenu->data = (void *) (long) !submenu->data;
564                                 else
565                                         conf(submenu);
566                                 break;
567                         case 't':
568                                 if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
569                                         conf_choice(submenu);
570                                 else if (submenu->prompt->type == P_MENU)
571                                         conf(submenu);
572                                 break;
573                         case 's':
574                                 conf_string(submenu);
575                                 break;
576                         case 'L':
577                                 conf_load();
578                                 break;
579                         case 'S':
580                                 conf_save();
581                                 break;
582                         }
583                         break;
584                 case 2:
585                         if (sym)
586                                 show_help(submenu);
587                         else
588                                 show_helptext(_("README"), _(mconf_readme));
589                         break;
590                 case 3:
591                         if (item_is_tag('t')) {
592                                 if (sym_set_tristate_value(sym, yes))
593                                         break;
594                                 if (sym_set_tristate_value(sym, mod))
595                                         show_textbox(NULL, setmod_text, 6, 74);
596                         }
597                         break;
598                 case 4:
599                         if (item_is_tag('t'))
600                                 sym_set_tristate_value(sym, no);
601                         break;
602                 case 5:
603                         if (item_is_tag('t'))
604                                 sym_set_tristate_value(sym, mod);
605                         break;
606                 case 6:
607                         if (item_is_tag('t'))
608                                 sym_toggle_tristate_value(sym);
609                         else if (item_is_tag('m'))
610                                 conf(submenu);
611                         break;
612                 case 7:
613                         search_conf();
614                         break;
615                 case 8:
616                         show_all_options = !show_all_options;
617                         break;
618                 }
619         }
620 }
621
622 static void show_textbox(const char *title, const char *text, int r, int c)
623 {
624         dialog_clear();
625         dialog_textbox(title, text, r, c);
626 }
627
628 static void show_helptext(const char *title, const char *text)
629 {
630         show_textbox(title, text, 0, 0);
631 }
632
633 static void show_help(struct menu *menu)
634 {
635         struct gstr help = str_new();
636
637         help.max_width = getmaxx(stdscr) - 10;
638         menu_get_ext_help(menu, &help);
639
640         show_helptext(_(menu_get_prompt(menu)), str_get(&help));
641         str_free(&help);
642 }
643
644 static void conf_choice(struct menu *menu)
645 {
646         const char *prompt = _(menu_get_prompt(menu));
647         struct menu *child;
648         struct symbol *active;
649
650         active = sym_get_choice_value(menu->sym);
651         while (1) {
652                 int res;
653                 int selected;
654                 item_reset();
655
656                 current_menu = menu;
657                 for (child = menu->list; child; child = child->next) {
658                         if (!menu_is_visible(child))
659                                 continue;
660                         if (child->sym)
661                                 item_make("%s", _(menu_get_prompt(child)));
662                         else {
663                                 item_make("*** %s ***", _(menu_get_prompt(child)));
664                                 item_set_tag(':');
665                         }
666                         item_set_data(child);
667                         if (child->sym == active)
668                                 item_set_selected(1);
669                         if (child->sym == sym_get_choice_value(menu->sym))
670                                 item_set_tag('X');
671                 }
672                 dialog_clear();
673                 res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
674                                         _(radiolist_instructions),
675                                          15, 70, 6);
676                 selected = item_activate_selected();
677                 switch (res) {
678                 case 0:
679                         if (selected) {
680                                 child = item_data();
681                                 if (!child->sym)
682                                         break;
683
684                                 sym_set_tristate_value(child->sym, yes);
685                         }
686                         return;
687                 case 1:
688                         if (selected) {
689                                 child = item_data();
690                                 show_help(child);
691                                 active = child->sym;
692                         } else
693                                 show_help(menu);
694                         break;
695                 case KEY_ESC:
696                         return;
697                 case -ERRDISPLAYTOOSMALL:
698                         return;
699                 }
700         }
701 }
702
703 static void conf_string(struct menu *menu)
704 {
705         const char *prompt = menu_get_prompt(menu);
706
707         while (1) {
708                 int res;
709                 const char *heading;
710
711                 switch (sym_get_type(menu->sym)) {
712                 case S_INT:
713                         heading = _(inputbox_instructions_int);
714                         break;
715                 case S_HEX:
716                         heading = _(inputbox_instructions_hex);
717                         break;
718                 case S_STRING:
719                         heading = _(inputbox_instructions_string);
720                         break;
721                 default:
722                         heading = _("Internal mconf error!");
723                 }
724                 dialog_clear();
725                 res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
726                                       heading, 10, 75,
727                                       sym_get_string_value(menu->sym));
728                 switch (res) {
729                 case 0:
730                         if (sym_set_string_value(menu->sym, dialog_input_result))
731                                 return;
732                         show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
733                         break;
734                 case 1:
735                         show_help(menu);
736                         break;
737                 case KEY_ESC:
738                         return;
739                 }
740         }
741 }
742
743 static void conf_load(void)
744 {
745
746         while (1) {
747                 int res;
748                 dialog_clear();
749                 res = dialog_inputbox(NULL, load_config_text,
750                                       11, 55, filename);
751                 switch(res) {
752                 case 0:
753                         if (!dialog_input_result[0])
754                                 return;
755                         if (!conf_read(dialog_input_result)) {
756                                 set_config_filename(dialog_input_result);
757                                 sym_set_change_count(1);
758                                 return;
759                         }
760                         show_textbox(NULL, _("File does not exist!"), 5, 38);
761                         break;
762                 case 1:
763                         show_helptext(_("Load Alternate Configuration"), load_config_help);
764                         break;
765                 case KEY_ESC:
766                         return;
767                 }
768         }
769 }
770
771 static void conf_save(void)
772 {
773         while (1) {
774                 int res;
775                 dialog_clear();
776                 res = dialog_inputbox(NULL, save_config_text,
777                                       11, 55, filename);
778                 switch(res) {
779                 case 0:
780                         if (!dialog_input_result[0])
781                                 return;
782                         if (!conf_write(dialog_input_result)) {
783                                 set_config_filename(dialog_input_result);
784                                 return;
785                         }
786                         show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
787                         break;
788                 case 1:
789                         show_helptext(_("Save Alternate Configuration"), save_config_help);
790                         break;
791                 case KEY_ESC:
792                         return;
793                 }
794         }
795 }
796
797 static int handle_exit(void)
798 {
799         int res;
800
801         dialog_clear();
802         if (conf_get_changed())
803                 res = dialog_yesno(NULL,
804                                    _("Do you wish to save your new configuration ?\n"
805                                      "<ESC><ESC> to continue."),
806                                    6, 60);
807         else
808                 res = -1;
809
810         end_dialog(saved_x, saved_y);
811
812         switch (res) {
813         case 0:
814                 if (conf_write(filename)) {
815                         fprintf(stderr, _("\n\n"
816                                           "Error while writing of the configuration.\n"
817                                           "Your configuration changes were NOT saved."
818                                           "\n\n"));
819                         return 1;
820                 }
821                 /* fall through */
822         case -1:
823                 printf(_("\n\n"
824                          "*** End of the configuration.\n"
825                          "*** Execute 'make' to start the build or try 'make help'."
826                          "\n\n"));
827                 res = 0;
828                 break;
829         default:
830                 fprintf(stderr, _("\n\n"
831                                   "Your configuration changes were NOT saved."
832                                   "\n\n"));
833         }
834
835         return res;
836 }
837
838 static void sig_handler(int signo)
839 {
840         exit(handle_exit());
841 }
842
843 int main(int ac, char **av)
844 {
845         char *mode;
846         int res;
847
848         setlocale(LC_ALL, "");
849         bindtextdomain(PACKAGE, LOCALEDIR);
850         textdomain(PACKAGE);
851
852         signal(SIGINT, sig_handler);
853
854         conf_parse(av[1]);
855         conf_read(NULL);
856
857         mode = getenv("MENUCONFIG_MODE");
858         if (mode) {
859                 if (!strcasecmp(mode, "single_menu"))
860                         single_menu_mode = 1;
861         }
862
863         initscr();
864
865         getyx(stdscr, saved_y, saved_x);
866         if (init_dialog(NULL)) {
867                 fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
868                 fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
869                 return 1;
870         }
871
872         set_config_filename(conf_get_configname());
873         do {
874                 conf(&rootmenu);
875                 res = handle_exit();
876         } while (res == KEY_ESC);
877
878         return res;
879 }
880