xref: /openbmc/linux/scripts/kconfig/mconf.c (revision 652cf982)
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 <unistd.h>
19 #include <locale.h>
20 
21 #define LKC_DIRECT_LINK
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 
277 static void conf(struct menu *menu);
278 static void conf_choice(struct menu *menu);
279 static void conf_string(struct menu *menu);
280 static void conf_load(void);
281 static void conf_save(void);
282 static void show_textbox(const char *title, const char *text, int r, int c);
283 static void show_helptext(const char *title, const char *text);
284 static void show_help(struct menu *menu);
285 
286 static char filename[PATH_MAX+1];
287 static void set_config_filename(const char *config_filename)
288 {
289 	static char menu_backtitle[PATH_MAX+128];
290 	int size;
291 	struct symbol *sym;
292 
293 	sym = sym_lookup("KERNELVERSION", 0);
294 	sym_calc_value(sym);
295 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
296 	                _("%s - Linux Kernel v%s Configuration"),
297 		        config_filename, sym_get_string_value(sym));
298 	if (size >= sizeof(menu_backtitle))
299 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
300 	set_dialog_backtitle(menu_backtitle);
301 
302 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
303 	if (size >= sizeof(filename))
304 		filename[sizeof(filename)-1] = '\0';
305 }
306 
307 
308 static void search_conf(void)
309 {
310 	struct symbol **sym_arr;
311 	struct gstr res;
312 	char *dialog_input;
313 	int dres;
314 again:
315 	dialog_clear();
316 	dres = dialog_inputbox(_("Search Configuration Parameter"),
317 			      _("Enter " CONFIG_ " (sub)string to search for "
318 				"(with or without \"" CONFIG_ "\")"),
319 			      10, 75, "");
320 	switch (dres) {
321 	case 0:
322 		break;
323 	case 1:
324 		show_helptext(_("Search Configuration"), search_help);
325 		goto again;
326 	default:
327 		return;
328 	}
329 
330 	/* strip the prefix if necessary */
331 	dialog_input = dialog_input_result;
332 	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
333 		dialog_input += strlen(CONFIG_);
334 
335 	sym_arr = sym_re_search(dialog_input);
336 	res = get_relations_str(sym_arr);
337 	free(sym_arr);
338 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
339 	str_free(&res);
340 }
341 
342 static void build_conf(struct menu *menu)
343 {
344 	struct symbol *sym;
345 	struct property *prop;
346 	struct menu *child;
347 	int type, tmp, doint = 2;
348 	tristate val;
349 	char ch;
350 	bool visible;
351 
352 	/*
353 	 * note: menu_is_visible() has side effect that it will
354 	 * recalc the value of the symbol.
355 	 */
356 	visible = menu_is_visible(menu);
357 	if (show_all_options && !menu_has_prompt(menu))
358 		return;
359 	else if (!show_all_options && !visible)
360 		return;
361 
362 	sym = menu->sym;
363 	prop = menu->prompt;
364 	if (!sym) {
365 		if (prop && menu != current_menu) {
366 			const char *prompt = menu_get_prompt(menu);
367 			switch (prop->type) {
368 			case P_MENU:
369 				child_count++;
370 				prompt = _(prompt);
371 				if (single_menu_mode) {
372 					item_make("%s%*c%s",
373 						  menu->data ? "-->" : "++>",
374 						  indent + 1, ' ', prompt);
375 				} else
376 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
377 
378 				item_set_tag('m');
379 				item_set_data(menu);
380 				if (single_menu_mode && menu->data)
381 					goto conf_childs;
382 				return;
383 			case P_COMMENT:
384 				if (prompt) {
385 					child_count++;
386 					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
387 					item_set_tag(':');
388 					item_set_data(menu);
389 				}
390 				break;
391 			default:
392 				if (prompt) {
393 					child_count++;
394 					item_make("---%*c%s", indent + 1, ' ', _(prompt));
395 					item_set_tag(':');
396 					item_set_data(menu);
397 				}
398 			}
399 		} else
400 			doint = 0;
401 		goto conf_childs;
402 	}
403 
404 	type = sym_get_type(sym);
405 	if (sym_is_choice(sym)) {
406 		struct symbol *def_sym = sym_get_choice_value(sym);
407 		struct menu *def_menu = NULL;
408 
409 		child_count++;
410 		for (child = menu->list; child; child = child->next) {
411 			if (menu_is_visible(child) && child->sym == def_sym)
412 				def_menu = child;
413 		}
414 
415 		val = sym_get_tristate_value(sym);
416 		if (sym_is_changable(sym)) {
417 			switch (type) {
418 			case S_BOOLEAN:
419 				item_make("[%c]", val == no ? ' ' : '*');
420 				break;
421 			case S_TRISTATE:
422 				switch (val) {
423 				case yes: ch = '*'; break;
424 				case mod: ch = 'M'; break;
425 				default:  ch = ' '; break;
426 				}
427 				item_make("<%c>", ch);
428 				break;
429 			}
430 			item_set_tag('t');
431 			item_set_data(menu);
432 		} else {
433 			item_make("   ");
434 			item_set_tag(def_menu ? 't' : ':');
435 			item_set_data(menu);
436 		}
437 
438 		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
439 		if (val == yes) {
440 			if (def_menu) {
441 				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
442 				item_add_str("  --->");
443 				if (def_menu->list) {
444 					indent += 2;
445 					build_conf(def_menu);
446 					indent -= 2;
447 				}
448 			}
449 			return;
450 		}
451 	} else {
452 		if (menu == current_menu) {
453 			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
454 			item_set_tag(':');
455 			item_set_data(menu);
456 			goto conf_childs;
457 		}
458 		child_count++;
459 		val = sym_get_tristate_value(sym);
460 		if (sym_is_choice_value(sym) && val == yes) {
461 			item_make("   ");
462 			item_set_tag(':');
463 			item_set_data(menu);
464 		} else {
465 			switch (type) {
466 			case S_BOOLEAN:
467 				if (sym_is_changable(sym))
468 					item_make("[%c]", val == no ? ' ' : '*');
469 				else
470 					item_make("-%c-", val == no ? ' ' : '*');
471 				item_set_tag('t');
472 				item_set_data(menu);
473 				break;
474 			case S_TRISTATE:
475 				switch (val) {
476 				case yes: ch = '*'; break;
477 				case mod: ch = 'M'; break;
478 				default:  ch = ' '; break;
479 				}
480 				if (sym_is_changable(sym)) {
481 					if (sym->rev_dep.tri == mod)
482 						item_make("{%c}", ch);
483 					else
484 						item_make("<%c>", ch);
485 				} else
486 					item_make("-%c-", ch);
487 				item_set_tag('t');
488 				item_set_data(menu);
489 				break;
490 			default:
491 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
492 				item_make("(%s)", sym_get_string_value(sym));
493 				tmp = indent - tmp + 4;
494 				if (tmp < 0)
495 					tmp = 0;
496 				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
497 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
498 					     "" : _(" (NEW)"));
499 				item_set_tag('s');
500 				item_set_data(menu);
501 				goto conf_childs;
502 			}
503 		}
504 		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
505 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
506 			  "" : _(" (NEW)"));
507 		if (menu->prompt->type == P_MENU) {
508 			item_add_str("  --->");
509 			return;
510 		}
511 	}
512 
513 conf_childs:
514 	indent += doint;
515 	for (child = menu->list; child; child = child->next)
516 		build_conf(child);
517 	indent -= doint;
518 }
519 
520 static void conf(struct menu *menu)
521 {
522 	struct menu *submenu;
523 	const char *prompt = menu_get_prompt(menu);
524 	struct symbol *sym;
525 	struct menu *active_menu = NULL;
526 	int res;
527 	int s_scroll = 0;
528 
529 	while (1) {
530 		item_reset();
531 		current_menu = menu;
532 		build_conf(menu);
533 		if (!child_count)
534 			break;
535 		if (menu == &rootmenu) {
536 			item_make("--- ");
537 			item_set_tag(':');
538 			item_make(_("    Load an Alternate Configuration File"));
539 			item_set_tag('L');
540 			item_make(_("    Save an Alternate Configuration File"));
541 			item_set_tag('S');
542 		}
543 		dialog_clear();
544 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
545 				  _(menu_instructions),
546 				  active_menu, &s_scroll);
547 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
548 			break;
549 		if (!item_activate_selected())
550 			continue;
551 		if (!item_tag())
552 			continue;
553 
554 		submenu = item_data();
555 		active_menu = item_data();
556 		if (submenu)
557 			sym = submenu->sym;
558 		else
559 			sym = NULL;
560 
561 		switch (res) {
562 		case 0:
563 			switch (item_tag()) {
564 			case 'm':
565 				if (single_menu_mode)
566 					submenu->data = (void *) (long) !submenu->data;
567 				else
568 					conf(submenu);
569 				break;
570 			case 't':
571 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
572 					conf_choice(submenu);
573 				else if (submenu->prompt->type == P_MENU)
574 					conf(submenu);
575 				break;
576 			case 's':
577 				conf_string(submenu);
578 				break;
579 			case 'L':
580 				conf_load();
581 				break;
582 			case 'S':
583 				conf_save();
584 				break;
585 			}
586 			break;
587 		case 2:
588 			if (sym)
589 				show_help(submenu);
590 			else
591 				show_helptext(_("README"), _(mconf_readme));
592 			break;
593 		case 3:
594 			if (item_is_tag('t')) {
595 				if (sym_set_tristate_value(sym, yes))
596 					break;
597 				if (sym_set_tristate_value(sym, mod))
598 					show_textbox(NULL, setmod_text, 6, 74);
599 			}
600 			break;
601 		case 4:
602 			if (item_is_tag('t'))
603 				sym_set_tristate_value(sym, no);
604 			break;
605 		case 5:
606 			if (item_is_tag('t'))
607 				sym_set_tristate_value(sym, mod);
608 			break;
609 		case 6:
610 			if (item_is_tag('t'))
611 				sym_toggle_tristate_value(sym);
612 			else if (item_is_tag('m'))
613 				conf(submenu);
614 			break;
615 		case 7:
616 			search_conf();
617 			break;
618 		case 8:
619 			show_all_options = !show_all_options;
620 			break;
621 		}
622 	}
623 }
624 
625 static void show_textbox(const char *title, const char *text, int r, int c)
626 {
627 	dialog_clear();
628 	dialog_textbox(title, text, r, c);
629 }
630 
631 static void show_helptext(const char *title, const char *text)
632 {
633 	show_textbox(title, text, 0, 0);
634 }
635 
636 static void show_help(struct menu *menu)
637 {
638 	struct gstr help = str_new();
639 
640 	help.max_width = getmaxx(stdscr) - 10;
641 	menu_get_ext_help(menu, &help);
642 
643 	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
644 	str_free(&help);
645 }
646 
647 static void conf_choice(struct menu *menu)
648 {
649 	const char *prompt = _(menu_get_prompt(menu));
650 	struct menu *child;
651 	struct symbol *active;
652 
653 	active = sym_get_choice_value(menu->sym);
654 	while (1) {
655 		int res;
656 		int selected;
657 		item_reset();
658 
659 		current_menu = menu;
660 		for (child = menu->list; child; child = child->next) {
661 			if (!menu_is_visible(child))
662 				continue;
663 			if (child->sym)
664 				item_make("%s", _(menu_get_prompt(child)));
665 			else {
666 				item_make("*** %s ***", _(menu_get_prompt(child)));
667 				item_set_tag(':');
668 			}
669 			item_set_data(child);
670 			if (child->sym == active)
671 				item_set_selected(1);
672 			if (child->sym == sym_get_choice_value(menu->sym))
673 				item_set_tag('X');
674 		}
675 		dialog_clear();
676 		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
677 					_(radiolist_instructions),
678 					 15, 70, 6);
679 		selected = item_activate_selected();
680 		switch (res) {
681 		case 0:
682 			if (selected) {
683 				child = item_data();
684 				if (!child->sym)
685 					break;
686 
687 				sym_set_tristate_value(child->sym, yes);
688 			}
689 			return;
690 		case 1:
691 			if (selected) {
692 				child = item_data();
693 				show_help(child);
694 				active = child->sym;
695 			} else
696 				show_help(menu);
697 			break;
698 		case KEY_ESC:
699 			return;
700 		case -ERRDISPLAYTOOSMALL:
701 			return;
702 		}
703 	}
704 }
705 
706 static void conf_string(struct menu *menu)
707 {
708 	const char *prompt = menu_get_prompt(menu);
709 
710 	while (1) {
711 		int res;
712 		const char *heading;
713 
714 		switch (sym_get_type(menu->sym)) {
715 		case S_INT:
716 			heading = _(inputbox_instructions_int);
717 			break;
718 		case S_HEX:
719 			heading = _(inputbox_instructions_hex);
720 			break;
721 		case S_STRING:
722 			heading = _(inputbox_instructions_string);
723 			break;
724 		default:
725 			heading = _("Internal mconf error!");
726 		}
727 		dialog_clear();
728 		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
729 				      heading, 10, 75,
730 				      sym_get_string_value(menu->sym));
731 		switch (res) {
732 		case 0:
733 			if (sym_set_string_value(menu->sym, dialog_input_result))
734 				return;
735 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
736 			break;
737 		case 1:
738 			show_help(menu);
739 			break;
740 		case KEY_ESC:
741 			return;
742 		}
743 	}
744 }
745 
746 static void conf_load(void)
747 {
748 
749 	while (1) {
750 		int res;
751 		dialog_clear();
752 		res = dialog_inputbox(NULL, load_config_text,
753 				      11, 55, filename);
754 		switch(res) {
755 		case 0:
756 			if (!dialog_input_result[0])
757 				return;
758 			if (!conf_read(dialog_input_result)) {
759 				set_config_filename(dialog_input_result);
760 				sym_set_change_count(1);
761 				return;
762 			}
763 			show_textbox(NULL, _("File does not exist!"), 5, 38);
764 			break;
765 		case 1:
766 			show_helptext(_("Load Alternate Configuration"), load_config_help);
767 			break;
768 		case KEY_ESC:
769 			return;
770 		}
771 	}
772 }
773 
774 static void conf_save(void)
775 {
776 	while (1) {
777 		int res;
778 		dialog_clear();
779 		res = dialog_inputbox(NULL, save_config_text,
780 				      11, 55, filename);
781 		switch(res) {
782 		case 0:
783 			if (!dialog_input_result[0])
784 				return;
785 			if (!conf_write(dialog_input_result)) {
786 				set_config_filename(dialog_input_result);
787 				return;
788 			}
789 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
790 			break;
791 		case 1:
792 			show_helptext(_("Save Alternate Configuration"), save_config_help);
793 			break;
794 		case KEY_ESC:
795 			return;
796 		}
797 	}
798 }
799 
800 int main(int ac, char **av)
801 {
802 	int saved_x, saved_y;
803 	char *mode;
804 	int res;
805 
806 	setlocale(LC_ALL, "");
807 	bindtextdomain(PACKAGE, LOCALEDIR);
808 	textdomain(PACKAGE);
809 
810 	conf_parse(av[1]);
811 	conf_read(NULL);
812 
813 	mode = getenv("MENUCONFIG_MODE");
814 	if (mode) {
815 		if (!strcasecmp(mode, "single_menu"))
816 			single_menu_mode = 1;
817 	}
818 
819 	initscr();
820 
821 	getyx(stdscr, saved_y, saved_x);
822 	if (init_dialog(NULL)) {
823 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
824 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
825 		return 1;
826 	}
827 
828 	set_config_filename(conf_get_configname());
829 	do {
830 		conf(&rootmenu);
831 		dialog_clear();
832 		if (conf_get_changed())
833 			res = dialog_yesno(NULL,
834 					   _("Do you wish to save your "
835 					     "new configuration?\n"
836 					     "<ESC><ESC> to continue."),
837 					   6, 60);
838 		else
839 			res = -1;
840 	} while (res == KEY_ESC);
841 	end_dialog(saved_x, saved_y);
842 
843 	switch (res) {
844 	case 0:
845 		if (conf_write(filename)) {
846 			fprintf(stderr, _("\n\n"
847 				"Error while writing of the configuration.\n"
848 				"Your configuration changes were NOT saved."
849 				"\n\n"));
850 			return 1;
851 		}
852 	case -1:
853 		printf(_("\n\n"
854 			"*** End of the configuration.\n"
855 			"*** Execute 'make' to start the build or try 'make help'."
856 			"\n\n"));
857 		break;
858 	default:
859 		fprintf(stderr, _("\n\n"
860 			"Your configuration changes were NOT saved."
861 			"\n\n"));
862 	}
863 
864 	return 0;
865 }
866 
867