xref: /openbmc/linux/scripts/kconfig/mconf.c (revision 30c4eaaf)
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 		if (res != KEY_ESC)
834 			res = 0;
835 	}
836 
837 	return res;
838 }
839 
840 static void sig_handler(int signo)
841 {
842 	exit(handle_exit());
843 }
844 
845 int main(int ac, char **av)
846 {
847 	char *mode;
848 	int res;
849 
850 	setlocale(LC_ALL, "");
851 	bindtextdomain(PACKAGE, LOCALEDIR);
852 	textdomain(PACKAGE);
853 
854 	signal(SIGINT, sig_handler);
855 
856 	conf_parse(av[1]);
857 	conf_read(NULL);
858 
859 	mode = getenv("MENUCONFIG_MODE");
860 	if (mode) {
861 		if (!strcasecmp(mode, "single_menu"))
862 			single_menu_mode = 1;
863 	}
864 
865 	initscr();
866 
867 	getyx(stdscr, saved_y, saved_x);
868 	if (init_dialog(NULL)) {
869 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
870 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
871 		return 1;
872 	}
873 
874 	set_config_filename(conf_get_configname());
875 	do {
876 		conf(&rootmenu);
877 		res = handle_exit();
878 	} while (res == KEY_ESC);
879 
880 	return res;
881 }
882 
883