xref: /openbmc/linux/scripts/kconfig/mconf.c (revision 09af091f)
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 "Some kernel features may be built directly into the kernel.\n"
29 "Some may be made into loadable runtime modules.  Some features\n"
30 "may be completely removed altogether.  There are also certain\n"
31 "kernel parameters which are not really features, but must be\n"
32 "entered in as decimal or hexadecimal numbers or possibly text.\n"
33 "\n"
34 "Menu items beginning with following braces represent features that\n"
35 "  [ ] can be built in or removed\n"
36 "  < > can be built in, modularized or removed\n"
37 "  { } can be built in or modularized (selected by other feature)\n"
38 "  - - are selected by other feature,\n"
39 "while *, M or whitespace inside braces means to build in, build as\n"
40 "a module or to exclude the feature respectively.\n"
41 "\n"
42 "To change any of these features, highlight it with the cursor\n"
43 "keys and press <Y> to build it in, <M> to make it a module or\n"
44 "<N> to removed it.  You may also press the <Space Bar> to cycle\n"
45 "through the available options (ie. Y->N->M->Y).\n"
46 "\n"
47 "Some additional keyboard hints:\n"
48 "\n"
49 "Menus\n"
50 "----------\n"
51 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
52 "   you wish to change or submenu wish to select and press <Enter>.\n"
53 "   Submenus are designated by \"--->\".\n"
54 "\n"
55 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
56 "             Pressing a hotkey more than once will sequence\n"
57 "             through all visible items which use that hotkey.\n"
58 "\n"
59 "   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
60 "   unseen options into view.\n"
61 "\n"
62 "o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
63 "   and press <ENTER>.\n"
64 "\n"
65 "   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
66 "             using those letters.  You may press a single <ESC>, but\n"
67 "             there is a delayed response which you may find annoying.\n"
68 "\n"
69 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
70 "   <Exit> and <Help>\n"
71 "\n"
72 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
73 "   and Press <ENTER>.\n"
74 "\n"
75 "   Shortcut: Press <H> or <?>.\n"
76 "\n"
77 "\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 kernel 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 kernel options listed in a single\n"
152 "menu, rather than the default multimenu hierarchy, run the menuconfig\n"
153 "with 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 nohelp_text[] = N_(
203 	"There is no help available for this kernel option.\n"),
204 load_config_text[] = N_(
205 	"Enter the name of the configuration file you wish to load.  "
206 	"Accept the name shown to restore the configuration you "
207 	"last retrieved.  Leave blank to abort."),
208 load_config_help[] = N_(
209 	"\n"
210 	"For various reasons, one may wish to keep several different kernel\n"
211 	"configurations available on a single machine.\n"
212 	"\n"
213 	"If you have saved a previous configuration in a file other than the\n"
214 	"kernel's default, entering the name of the file here will allow you\n"
215 	"to modify that configuration.\n"
216 	"\n"
217 	"If you are uncertain, then you have probably never used alternate\n"
218 	"configuration files.  You should therefor leave this blank to abort.\n"),
219 save_config_text[] = N_(
220 	"Enter a filename to which this configuration should be saved "
221 	"as an alternate.  Leave blank to abort."),
222 save_config_help[] = N_(
223 	"\n"
224 	"For various reasons, one may wish to keep different kernel\n"
225 	"configurations available on a single machine.\n"
226 	"\n"
227 	"Entering a file name here will allow you to later retrieve, modify\n"
228 	"and use the current configuration as an alternate to whatever\n"
229 	"configuration options you have selected at that time.\n"
230 	"\n"
231 	"If you are uncertain what all this means then you should probably\n"
232 	"leave this blank.\n"),
233 search_help[] = N_(
234 	"\n"
235 	"Search for CONFIG_ symbols and display their relations.\n"
236 	"Regular expressions are allowed.\n"
237 	"Example: search for \"^FOO\"\n"
238 	"Result:\n"
239 	"-----------------------------------------------------------------\n"
240 	"Symbol: FOO [=m]\n"
241 	"Prompt: Foo bus is used to drive the bar HW\n"
242 	"Defined at drivers/pci/Kconfig:47\n"
243 	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
244 	"Location:\n"
245 	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
246 	"    -> PCI support (PCI [=y])\n"
247 	"      -> PCI access mode (<choice> [=y])\n"
248 	"Selects: LIBCRC32\n"
249 	"Selected by: BAR\n"
250 	"-----------------------------------------------------------------\n"
251 	"o The line 'Prompt:' shows the text used in the menu structure for\n"
252 	"  this CONFIG_ symbol\n"
253 	"o The 'Defined at' line tell at what file / line number the symbol\n"
254 	"  is defined\n"
255 	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
256 	"  this symbol to be visible in the menu (selectable)\n"
257 	"o The 'Location:' lines tell where in the menu structure this symbol\n"
258 	"  is located\n"
259 	"    A location followed by a [=y] indicate that this is a selectable\n"
260 	"    menu item - and current value is displayed inside brackets.\n"
261 	"o The 'Selects:' line tell what symbol will be automatically\n"
262 	"  selected if this symbol is selected (y or m)\n"
263 	"o The 'Selected by' line tell what symbol has selected this symbol\n"
264 	"\n"
265 	"Only relevant lines are shown.\n"
266 	"\n\n"
267 	"Search examples:\n"
268 	"Examples: USB	=> find all CONFIG_ symbols containing USB\n"
269 	"          ^USB => find all CONFIG_ symbols starting with USB\n"
270 	"          USB$ => find all CONFIG_ symbols ending with USB\n"
271 	"\n");
272 
273 static int indent;
274 static struct menu *current_menu;
275 static int child_count;
276 static int single_menu_mode;
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 void get_prompt_str(struct gstr *r, struct property *prop)
288 {
289 	int i, j;
290 	struct menu *submenu[8], *menu;
291 
292 	str_printf(r, "Prompt: %s\n", prop->text);
293 	str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
294 		prop->menu->lineno);
295 	if (!expr_is_yes(prop->visible.expr)) {
296 		str_append(r, "  Depends on: ");
297 		expr_gstr_print(prop->visible.expr, r);
298 		str_append(r, "\n");
299 	}
300 	menu = prop->menu->parent;
301 	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
302 		submenu[i++] = menu;
303 	if (i > 0) {
304 		str_printf(r, "  Location:\n");
305 		for (j = 4; --i >= 0; j += 2) {
306 			menu = submenu[i];
307 			str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
308 			if (menu->sym) {
309 				str_printf(r, " (%s [=%s])", menu->sym->name ?
310 					menu->sym->name : "<choice>",
311 					sym_get_string_value(menu->sym));
312 			}
313 			str_append(r, "\n");
314 		}
315 	}
316 }
317 
318 static void get_symbol_str(struct gstr *r, struct symbol *sym)
319 {
320 	bool hit;
321 	struct property *prop;
322 
323 	if (sym && sym->name)
324 		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
325 		                                    sym_get_string_value(sym));
326 	for_all_prompts(sym, prop)
327 		get_prompt_str(r, prop);
328 	hit = false;
329 	for_all_properties(sym, prop, P_SELECT) {
330 		if (!hit) {
331 			str_append(r, "  Selects: ");
332 			hit = true;
333 		} else
334 			str_printf(r, " && ");
335 		expr_gstr_print(prop->expr, r);
336 	}
337 	if (hit)
338 		str_append(r, "\n");
339 	if (sym->rev_dep.expr) {
340 		str_append(r, "  Selected by: ");
341 		expr_gstr_print(sym->rev_dep.expr, r);
342 		str_append(r, "\n");
343 	}
344 	str_append(r, "\n\n");
345 }
346 
347 static struct gstr get_relations_str(struct symbol **sym_arr)
348 {
349 	struct symbol *sym;
350 	struct gstr res = str_new();
351 	int i;
352 
353 	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
354 		get_symbol_str(&res, sym);
355 	if (!i)
356 		str_append(&res, "No matches found.\n");
357 	return res;
358 }
359 
360 static char filename[PATH_MAX+1];
361 static void set_config_filename(const char *config_filename)
362 {
363 	static char menu_backtitle[PATH_MAX+128];
364 	int size;
365 	struct symbol *sym;
366 
367 	sym = sym_lookup("KERNELVERSION", 0);
368 	sym_calc_value(sym);
369 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
370 	                _("%s - Linux Kernel v%s Configuration"),
371 		        config_filename, sym_get_string_value(sym));
372 	if (size >= sizeof(menu_backtitle))
373 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
374 	set_dialog_backtitle(menu_backtitle);
375 
376 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
377 	if (size >= sizeof(filename))
378 		filename[sizeof(filename)-1] = '\0';
379 }
380 
381 
382 static void search_conf(void)
383 {
384 	struct symbol **sym_arr;
385 	struct gstr res;
386 	char *dialog_input;
387 	int dres;
388 again:
389 	dialog_clear();
390 	dres = dialog_inputbox(_("Search Configuration Parameter"),
391 			      _("Enter CONFIG_ (sub)string to search for "
392 				"(with or without \"CONFIG\")"),
393 			      10, 75, "");
394 	switch (dres) {
395 	case 0:
396 		break;
397 	case 1:
398 		show_helptext(_("Search Configuration"), search_help);
399 		goto again;
400 	default:
401 		return;
402 	}
403 
404 	/* strip CONFIG_ if necessary */
405 	dialog_input = dialog_input_result;
406 	if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
407 		dialog_input += 7;
408 
409 	sym_arr = sym_re_search(dialog_input);
410 	res = get_relations_str(sym_arr);
411 	free(sym_arr);
412 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
413 	str_free(&res);
414 }
415 
416 static void build_conf(struct menu *menu)
417 {
418 	struct symbol *sym;
419 	struct property *prop;
420 	struct menu *child;
421 	int type, tmp, doint = 2;
422 	tristate val;
423 	char ch;
424 
425 	if (!menu_is_visible(menu))
426 		return;
427 
428 	sym = menu->sym;
429 	prop = menu->prompt;
430 	if (!sym) {
431 		if (prop && menu != current_menu) {
432 			const char *prompt = menu_get_prompt(menu);
433 			switch (prop->type) {
434 			case P_MENU:
435 				child_count++;
436 				if (single_menu_mode) {
437 					item_make("%s%*c%s",
438 						  menu->data ? "-->" : "++>",
439 						  indent + 1, ' ', prompt);
440 				} else
441 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
442 
443 				item_set_tag('m');
444 				item_set_data(menu);
445 				if (single_menu_mode && menu->data)
446 					goto conf_childs;
447 				return;
448 			case P_COMMENT:
449 				if (prompt) {
450 					child_count++;
451 					item_make("   %*c*** %s ***", indent + 1, ' ', prompt);
452 					item_set_tag(':');
453 					item_set_data(menu);
454 				}
455 				break;
456 			default:
457 				if (prompt) {
458 					child_count++;
459 					item_make("---%*c%s", indent + 1, ' ', prompt);
460 					item_set_tag(':');
461 					item_set_data(menu);
462 				}
463 			}
464 		} else
465 			doint = 0;
466 		goto conf_childs;
467 	}
468 
469 	type = sym_get_type(sym);
470 	if (sym_is_choice(sym)) {
471 		struct symbol *def_sym = sym_get_choice_value(sym);
472 		struct menu *def_menu = NULL;
473 
474 		child_count++;
475 		for (child = menu->list; child; child = child->next) {
476 			if (menu_is_visible(child) && child->sym == def_sym)
477 				def_menu = child;
478 		}
479 
480 		val = sym_get_tristate_value(sym);
481 		if (sym_is_changable(sym)) {
482 			switch (type) {
483 			case S_BOOLEAN:
484 				item_make("[%c]", val == no ? ' ' : '*');
485 				break;
486 			case S_TRISTATE:
487 				switch (val) {
488 				case yes: ch = '*'; break;
489 				case mod: ch = 'M'; break;
490 				default:  ch = ' '; break;
491 				}
492 				item_make("<%c>", ch);
493 				break;
494 			}
495 			item_set_tag('t');
496 			item_set_data(menu);
497 		} else {
498 			item_make("   ");
499 			item_set_tag(def_menu ? 't' : ':');
500 			item_set_data(menu);
501 		}
502 
503 		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
504 		if (val == yes) {
505 			if (def_menu) {
506 				item_add_str(" (%s)", menu_get_prompt(def_menu));
507 				item_add_str("  --->");
508 				if (def_menu->list) {
509 					indent += 2;
510 					build_conf(def_menu);
511 					indent -= 2;
512 				}
513 			}
514 			return;
515 		}
516 	} else {
517 		if (menu == current_menu) {
518 			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
519 			item_set_tag(':');
520 			item_set_data(menu);
521 			goto conf_childs;
522 		}
523 		child_count++;
524 		val = sym_get_tristate_value(sym);
525 		if (sym_is_choice_value(sym) && val == yes) {
526 			item_make("   ");
527 			item_set_tag(':');
528 			item_set_data(menu);
529 		} else {
530 			switch (type) {
531 			case S_BOOLEAN:
532 				if (sym_is_changable(sym))
533 					item_make("[%c]", val == no ? ' ' : '*');
534 				else
535 					item_make("-%c-", val == no ? ' ' : '*');
536 				item_set_tag('t');
537 				item_set_data(menu);
538 				break;
539 			case S_TRISTATE:
540 				switch (val) {
541 				case yes: ch = '*'; break;
542 				case mod: ch = 'M'; break;
543 				default:  ch = ' '; break;
544 				}
545 				if (sym_is_changable(sym)) {
546 					if (sym->rev_dep.tri == mod)
547 						item_make("{%c}", ch);
548 					else
549 						item_make("<%c>", ch);
550 				} else
551 					item_make("-%c-", ch);
552 				item_set_tag('t');
553 				item_set_data(menu);
554 				break;
555 			default:
556 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
557 				item_make("(%s)", sym_get_string_value(sym));
558 				tmp = indent - tmp + 4;
559 				if (tmp < 0)
560 					tmp = 0;
561 				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
562 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
563 					     "" : " (NEW)");
564 				item_set_tag('s');
565 				item_set_data(menu);
566 				goto conf_childs;
567 			}
568 		}
569 		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
570 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
571 			  "" : " (NEW)");
572 		if (menu->prompt->type == P_MENU) {
573 			item_add_str("  --->");
574 			return;
575 		}
576 	}
577 
578 conf_childs:
579 	indent += doint;
580 	for (child = menu->list; child; child = child->next)
581 		build_conf(child);
582 	indent -= doint;
583 }
584 
585 static void conf(struct menu *menu)
586 {
587 	struct menu *submenu;
588 	const char *prompt = menu_get_prompt(menu);
589 	struct symbol *sym;
590 	struct menu *active_menu = NULL;
591 	int res;
592 	int s_scroll = 0;
593 
594 	while (1) {
595 		item_reset();
596 		current_menu = menu;
597 		build_conf(menu);
598 		if (!child_count)
599 			break;
600 		if (menu == &rootmenu) {
601 			item_make("--- ");
602 			item_set_tag(':');
603 			item_make(_("    Load an Alternate Configuration File"));
604 			item_set_tag('L');
605 			item_make(_("    Save an Alternate Configuration File"));
606 			item_set_tag('S');
607 		}
608 		dialog_clear();
609 		res = dialog_menu(prompt ? prompt : _("Main Menu"),
610 				  _(menu_instructions),
611 				  active_menu, &s_scroll);
612 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
613 			break;
614 		if (!item_activate_selected())
615 			continue;
616 		if (!item_tag())
617 			continue;
618 
619 		submenu = item_data();
620 		active_menu = item_data();
621 		if (submenu)
622 			sym = submenu->sym;
623 		else
624 			sym = NULL;
625 
626 		switch (res) {
627 		case 0:
628 			switch (item_tag()) {
629 			case 'm':
630 				if (single_menu_mode)
631 					submenu->data = (void *) (long) !submenu->data;
632 				else
633 					conf(submenu);
634 				break;
635 			case 't':
636 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
637 					conf_choice(submenu);
638 				else if (submenu->prompt->type == P_MENU)
639 					conf(submenu);
640 				break;
641 			case 's':
642 				conf_string(submenu);
643 				break;
644 			case 'L':
645 				conf_load();
646 				break;
647 			case 'S':
648 				conf_save();
649 				break;
650 			}
651 			break;
652 		case 2:
653 			if (sym)
654 				show_help(submenu);
655 			else
656 				show_helptext("README", _(mconf_readme));
657 			break;
658 		case 3:
659 			if (item_is_tag('t')) {
660 				if (sym_set_tristate_value(sym, yes))
661 					break;
662 				if (sym_set_tristate_value(sym, mod))
663 					show_textbox(NULL, setmod_text, 6, 74);
664 			}
665 			break;
666 		case 4:
667 			if (item_is_tag('t'))
668 				sym_set_tristate_value(sym, no);
669 			break;
670 		case 5:
671 			if (item_is_tag('t'))
672 				sym_set_tristate_value(sym, mod);
673 			break;
674 		case 6:
675 			if (item_is_tag('t'))
676 				sym_toggle_tristate_value(sym);
677 			else if (item_is_tag('m'))
678 				conf(submenu);
679 			break;
680 		case 7:
681 			search_conf();
682 			break;
683 		}
684 	}
685 }
686 
687 static void show_textbox(const char *title, const char *text, int r, int c)
688 {
689 	dialog_clear();
690 	dialog_textbox(title, text, r, c);
691 }
692 
693 static void show_helptext(const char *title, const char *text)
694 {
695 	show_textbox(title, text, 0, 0);
696 }
697 
698 static void show_help(struct menu *menu)
699 {
700 	struct gstr help = str_new();
701 	struct symbol *sym = menu->sym;
702 
703 	if (menu_has_help(menu))
704 	{
705 		if (sym->name) {
706 			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
707 			str_append(&help, _(menu_get_help(menu)));
708 			str_append(&help, "\n");
709 		}
710 	} else {
711 		str_append(&help, nohelp_text);
712 	}
713 	get_symbol_str(&help, sym);
714 	show_helptext(menu_get_prompt(menu), str_get(&help));
715 	str_free(&help);
716 }
717 
718 static void conf_choice(struct menu *menu)
719 {
720 	const char *prompt = menu_get_prompt(menu);
721 	struct menu *child;
722 	struct symbol *active;
723 
724 	active = sym_get_choice_value(menu->sym);
725 	while (1) {
726 		int res;
727 		int selected;
728 		item_reset();
729 
730 		current_menu = menu;
731 		for (child = menu->list; child; child = child->next) {
732 			if (!menu_is_visible(child))
733 				continue;
734 			item_make("%s", menu_get_prompt(child));
735 			item_set_data(child);
736 			if (child->sym == active)
737 				item_set_selected(1);
738 			if (child->sym == sym_get_choice_value(menu->sym))
739 				item_set_tag('X');
740 		}
741 		dialog_clear();
742 		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
743 					_(radiolist_instructions),
744 					 15, 70, 6);
745 		selected = item_activate_selected();
746 		switch (res) {
747 		case 0:
748 			if (selected) {
749 				child = item_data();
750 				sym_set_tristate_value(child->sym, yes);
751 			}
752 			return;
753 		case 1:
754 			if (selected) {
755 				child = item_data();
756 				show_help(child);
757 				active = child->sym;
758 			} else
759 				show_help(menu);
760 			break;
761 		case KEY_ESC:
762 			return;
763 		case -ERRDISPLAYTOOSMALL:
764 			return;
765 		}
766 	}
767 }
768 
769 static void conf_string(struct menu *menu)
770 {
771 	const char *prompt = menu_get_prompt(menu);
772 
773 	while (1) {
774 		int res;
775 		char *heading;
776 
777 		switch (sym_get_type(menu->sym)) {
778 		case S_INT:
779 			heading = _(inputbox_instructions_int);
780 			break;
781 		case S_HEX:
782 			heading = _(inputbox_instructions_hex);
783 			break;
784 		case S_STRING:
785 			heading = _(inputbox_instructions_string);
786 			break;
787 		default:
788 			heading = "Internal mconf error!";
789 		}
790 		dialog_clear();
791 		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
792 				      heading, 10, 75,
793 				      sym_get_string_value(menu->sym));
794 		switch (res) {
795 		case 0:
796 			if (sym_set_string_value(menu->sym, dialog_input_result))
797 				return;
798 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
799 			break;
800 		case 1:
801 			show_help(menu);
802 			break;
803 		case KEY_ESC:
804 			return;
805 		}
806 	}
807 }
808 
809 static void conf_load(void)
810 {
811 
812 	while (1) {
813 		int res;
814 		dialog_clear();
815 		res = dialog_inputbox(NULL, load_config_text,
816 				      11, 55, filename);
817 		switch(res) {
818 		case 0:
819 			if (!dialog_input_result[0])
820 				return;
821 			if (!conf_read(dialog_input_result)) {
822 				set_config_filename(dialog_input_result);
823 				return;
824 			}
825 			show_textbox(NULL, _("File does not exist!"), 5, 38);
826 			break;
827 		case 1:
828 			show_helptext(_("Load Alternate Configuration"), load_config_help);
829 			break;
830 		case KEY_ESC:
831 			return;
832 		}
833 	}
834 }
835 
836 static void conf_save(void)
837 {
838 	while (1) {
839 		int res;
840 		dialog_clear();
841 		res = dialog_inputbox(NULL, save_config_text,
842 				      11, 55, filename);
843 		switch(res) {
844 		case 0:
845 			if (!dialog_input_result[0])
846 				return;
847 			if (!conf_write(dialog_input_result)) {
848 				set_config_filename(dialog_input_result);
849 				return;
850 			}
851 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
852 			break;
853 		case 1:
854 			show_helptext(_("Save Alternate Configuration"), save_config_help);
855 			break;
856 		case KEY_ESC:
857 			return;
858 		}
859 	}
860 }
861 
862 int main(int ac, char **av)
863 {
864 	int saved_x, saved_y;
865 	char *mode;
866 	int res;
867 
868 	setlocale(LC_ALL, "");
869 	bindtextdomain(PACKAGE, LOCALEDIR);
870 	textdomain(PACKAGE);
871 
872 	conf_parse(av[1]);
873 	conf_read(NULL);
874 
875 	mode = getenv("MENUCONFIG_MODE");
876 	if (mode) {
877 		if (!strcasecmp(mode, "single_menu"))
878 			single_menu_mode = 1;
879 	}
880 
881 	getyx(stdscr, saved_y, saved_x);
882 	if (init_dialog(NULL)) {
883 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
884 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
885 		return 1;
886 	}
887 
888 	set_config_filename(conf_get_configname());
889 	do {
890 		conf(&rootmenu);
891 		dialog_clear();
892 		if (conf_get_changed())
893 			res = dialog_yesno(NULL,
894 					   _("Do you wish to save your "
895 					     "new kernel configuration?\n"
896 					     "<ESC><ESC> to continue."),
897 					   6, 60);
898 		else
899 			res = -1;
900 	} while (res == KEY_ESC);
901 	end_dialog(saved_x, saved_y);
902 
903 	switch (res) {
904 	case 0:
905 		if (conf_write(filename)) {
906 			fprintf(stderr, _("\n\n"
907 				"Error during writing of the kernel configuration.\n"
908 				"Your kernel configuration changes were NOT saved."
909 				"\n\n"));
910 			return 1;
911 		}
912 	case -1:
913 		printf(_("\n\n"
914 			"*** End of Linux kernel configuration.\n"
915 			"*** Execute 'make' to build the kernel or try 'make help'."
916 			"\n\n"));
917 		break;
918 	default:
919 		fprintf(stderr, _("\n\n"
920 			"Your kernel configuration changes were NOT saved."
921 			"\n\n"));
922 	}
923 
924 	return 0;
925 }
926