xref: /openbmc/linux/scripts/kconfig/mconf.c (revision d802b50f)
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 <sys/ioctl.h>
12 #include <sys/wait.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <limits.h>
17 #include <signal.h>
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <termios.h>
22 #include <unistd.h>
23 #include <locale.h>
24 
25 #define LKC_DIRECT_LINK
26 #include "lkc.h"
27 #include "lxdialog/dialog.h"
28 
29 static const char mconf_readme[] = N_(
30 "Overview\n"
31 "--------\n"
32 "Some kernel features may be built directly into the kernel.\n"
33 "Some may be made into loadable runtime modules.  Some features\n"
34 "may be completely removed altogether.  There are also certain\n"
35 "kernel parameters which are not really features, but must be\n"
36 "entered in as decimal or hexadecimal numbers or possibly text.\n"
37 "\n"
38 "Menu items beginning with [*], <M> or [ ] represent features\n"
39 "configured to be built in, modularized or removed respectively.\n"
40 "Pointed brackets <> represent module capable features.\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 termios ios_org;
275 static int rows = 0, cols = 0;
276 static struct menu *current_menu;
277 static int child_count;
278 static int single_menu_mode;
279 
280 static void conf(struct menu *menu);
281 static void conf_choice(struct menu *menu);
282 static void conf_string(struct menu *menu);
283 static void conf_load(void);
284 static void conf_save(void);
285 static void show_textbox(const char *title, const char *text, int r, int c);
286 static void show_helptext(const char *title, const char *text);
287 static void show_help(struct menu *menu);
288 
289 static void init_wsize(void)
290 {
291 	struct winsize ws;
292 	char *env;
293 
294 	if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
295 		rows = ws.ws_row;
296 		cols = ws.ws_col;
297 	}
298 
299 	if (!rows) {
300 		env = getenv("LINES");
301 		if (env)
302 			rows = atoi(env);
303 		if (!rows)
304 			rows = 24;
305 	}
306 	if (!cols) {
307 		env = getenv("COLUMNS");
308 		if (env)
309 			cols = atoi(env);
310 		if (!cols)
311 			cols = 80;
312 	}
313 
314 	if (rows < 19 || cols < 80) {
315 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
316 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
317 		exit(1);
318 	}
319 
320 	rows -= 4;
321 	cols -= 5;
322 }
323 
324 static void get_prompt_str(struct gstr *r, struct property *prop)
325 {
326 	int i, j;
327 	struct menu *submenu[8], *menu;
328 
329 	str_printf(r, "Prompt: %s\n", prop->text);
330 	str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
331 		prop->menu->lineno);
332 	if (!expr_is_yes(prop->visible.expr)) {
333 		str_append(r, "  Depends on: ");
334 		expr_gstr_print(prop->visible.expr, r);
335 		str_append(r, "\n");
336 	}
337 	menu = prop->menu->parent;
338 	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
339 		submenu[i++] = menu;
340 	if (i > 0) {
341 		str_printf(r, "  Location:\n");
342 		for (j = 4; --i >= 0; j += 2) {
343 			menu = submenu[i];
344 			str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
345 			if (menu->sym) {
346 				str_printf(r, " (%s [=%s])", menu->sym->name ?
347 					menu->sym->name : "<choice>",
348 					sym_get_string_value(menu->sym));
349 			}
350 			str_append(r, "\n");
351 		}
352 	}
353 }
354 
355 static void get_symbol_str(struct gstr *r, struct symbol *sym)
356 {
357 	bool hit;
358 	struct property *prop;
359 
360 	str_printf(r, "Symbol: %s [=%s]\n", sym->name,
361 	                               sym_get_string_value(sym));
362 	for_all_prompts(sym, prop)
363 		get_prompt_str(r, prop);
364 	hit = false;
365 	for_all_properties(sym, prop, P_SELECT) {
366 		if (!hit) {
367 			str_append(r, "  Selects: ");
368 			hit = true;
369 		} else
370 			str_printf(r, " && ");
371 		expr_gstr_print(prop->expr, r);
372 	}
373 	if (hit)
374 		str_append(r, "\n");
375 	if (sym->rev_dep.expr) {
376 		str_append(r, "  Selected by: ");
377 		expr_gstr_print(sym->rev_dep.expr, r);
378 		str_append(r, "\n");
379 	}
380 	str_append(r, "\n\n");
381 }
382 
383 static struct gstr get_relations_str(struct symbol **sym_arr)
384 {
385 	struct symbol *sym;
386 	struct gstr res = str_new();
387 	int i;
388 
389 	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
390 		get_symbol_str(&res, sym);
391 	if (!i)
392 		str_append(&res, "No matches found.\n");
393 	return res;
394 }
395 
396 static char filename[PATH_MAX+1];
397 static void set_config_filename(const char *config_filename)
398 {
399 	static char menu_backtitle[PATH_MAX+128];
400 	int size;
401 	struct symbol *sym;
402 
403 	sym = sym_lookup("KERNELVERSION", 0);
404 	sym_calc_value(sym);
405 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
406 	                _("%s - Linux Kernel v%s Configuration"),
407 		        config_filename, sym_get_string_value(sym));
408 	if (size >= sizeof(menu_backtitle))
409 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
410 	set_dialog_backtitle(menu_backtitle);
411 
412 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
413 	if (size >= sizeof(filename))
414 		filename[sizeof(filename)-1] = '\0';
415 }
416 
417 
418 static void search_conf(void)
419 {
420 	struct symbol **sym_arr;
421 	struct gstr res;
422 	int dres;
423 again:
424 	dialog_clear();
425 	dres = dialog_inputbox(_("Search Configuration Parameter"),
426 			      _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
427 			      10, 75, "");
428 	switch (dres) {
429 	case 0:
430 		break;
431 	case 1:
432 		show_helptext(_("Search Configuration"), search_help);
433 		goto again;
434 	default:
435 		return;
436 	}
437 
438 	sym_arr = sym_re_search(dialog_input_result);
439 	res = get_relations_str(sym_arr);
440 	free(sym_arr);
441 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
442 	str_free(&res);
443 }
444 
445 static void build_conf(struct menu *menu)
446 {
447 	struct symbol *sym;
448 	struct property *prop;
449 	struct menu *child;
450 	int type, tmp, doint = 2;
451 	tristate val;
452 	char ch;
453 
454 	if (!menu_is_visible(menu))
455 		return;
456 
457 	sym = menu->sym;
458 	prop = menu->prompt;
459 	if (!sym) {
460 		if (prop && menu != current_menu) {
461 			const char *prompt = menu_get_prompt(menu);
462 			switch (prop->type) {
463 			case P_MENU:
464 				child_count++;
465 				if (single_menu_mode) {
466 					item_make("%s%*c%s",
467 						  menu->data ? "-->" : "++>",
468 						  indent + 1, ' ', prompt);
469 				} else
470 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
471 
472 				item_set_tag('m');
473 				item_set_data(menu);
474 				if (single_menu_mode && menu->data)
475 					goto conf_childs;
476 				return;
477 			default:
478 				if (prompt) {
479 					child_count++;
480 					item_make("---%*c%s", indent + 1, ' ', prompt);
481 					item_set_tag(':');
482 					item_set_data(menu);
483 				}
484 			}
485 		} else
486 			doint = 0;
487 		goto conf_childs;
488 	}
489 
490 	type = sym_get_type(sym);
491 	if (sym_is_choice(sym)) {
492 		struct symbol *def_sym = sym_get_choice_value(sym);
493 		struct menu *def_menu = NULL;
494 
495 		child_count++;
496 		for (child = menu->list; child; child = child->next) {
497 			if (menu_is_visible(child) && child->sym == def_sym)
498 				def_menu = child;
499 		}
500 
501 		val = sym_get_tristate_value(sym);
502 		if (sym_is_changable(sym)) {
503 			switch (type) {
504 			case S_BOOLEAN:
505 				item_make("[%c]", val == no ? ' ' : '*');
506 				break;
507 			case S_TRISTATE:
508 				switch (val) {
509 				case yes: ch = '*'; break;
510 				case mod: ch = 'M'; break;
511 				default:  ch = ' '; break;
512 				}
513 				item_make("<%c>", ch);
514 				break;
515 			}
516 			item_set_tag('t');
517 			item_set_data(menu);
518 		} else {
519 			item_make("   ");
520 			item_set_tag(def_menu ? 't' : ':');
521 			item_set_data(menu);
522 		}
523 
524 		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
525 		if (val == yes) {
526 			if (def_menu) {
527 				item_add_str(" (%s)", menu_get_prompt(def_menu));
528 				item_add_str("  --->");
529 				if (def_menu->list) {
530 					indent += 2;
531 					build_conf(def_menu);
532 					indent -= 2;
533 				}
534 			}
535 			return;
536 		}
537 	} else {
538 		if (menu == current_menu) {
539 			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
540 			item_set_tag(':');
541 			item_set_data(menu);
542 			goto conf_childs;
543 		}
544 		child_count++;
545 		val = sym_get_tristate_value(sym);
546 		if (sym_is_choice_value(sym) && val == yes) {
547 			item_make("   ");
548 			item_set_tag(':');
549 			item_set_data(menu);
550 		} else {
551 			switch (type) {
552 			case S_BOOLEAN:
553 				if (sym_is_changable(sym))
554 					item_make("[%c]", val == no ? ' ' : '*');
555 				else
556 					item_make("---");
557 				item_set_tag('t');
558 				item_set_data(menu);
559 				break;
560 			case S_TRISTATE:
561 				switch (val) {
562 				case yes: ch = '*'; break;
563 				case mod: ch = 'M'; break;
564 				default:  ch = ' '; break;
565 				}
566 				if (sym_is_changable(sym))
567 					item_make("<%c>", ch);
568 				else
569 					item_make("---");
570 				item_set_tag('t');
571 				item_set_data(menu);
572 				break;
573 			default:
574 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
575 				item_make("(%s)", sym_get_string_value(sym));
576 				tmp = indent - tmp + 4;
577 				if (tmp < 0)
578 					tmp = 0;
579 				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
580 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
581 					     "" : " (NEW)");
582 				item_set_tag('s');
583 				item_set_data(menu);
584 				goto conf_childs;
585 			}
586 		}
587 		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
588 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
589 			  "" : " (NEW)");
590 		if (menu->prompt->type == P_MENU) {
591 			item_add_str("  --->");
592 			return;
593 		}
594 	}
595 
596 conf_childs:
597 	indent += doint;
598 	for (child = menu->list; child; child = child->next)
599 		build_conf(child);
600 	indent -= doint;
601 }
602 
603 static void conf(struct menu *menu)
604 {
605 	struct menu *submenu;
606 	const char *prompt = menu_get_prompt(menu);
607 	struct symbol *sym;
608 	struct menu *active_menu = NULL;
609 	int res;
610 	int s_scroll = 0;
611 
612 	while (1) {
613 		item_reset();
614 		current_menu = menu;
615 		build_conf(menu);
616 		if (!child_count)
617 			break;
618 		if (menu == &rootmenu) {
619 			item_make("--- ");
620 			item_set_tag(':');
621 			item_make(_("    Load an Alternate Configuration File"));
622 			item_set_tag('L');
623 			item_make(_("    Save an Alternate Configuration File"));
624 			item_set_tag('S');
625 		}
626 		dialog_clear();
627 		res = dialog_menu(prompt ? prompt : _("Main Menu"),
628 				  _(menu_instructions),
629 				  active_menu, &s_scroll);
630 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
631 			break;
632 		if (!item_activate_selected())
633 			continue;
634 		if (!item_tag())
635 			continue;
636 
637 		submenu = item_data();
638 		active_menu = item_data();
639 		if (submenu)
640 			sym = submenu->sym;
641 		else
642 			sym = NULL;
643 
644 		switch (res) {
645 		case 0:
646 			switch (item_tag()) {
647 			case 'm':
648 				if (single_menu_mode)
649 					submenu->data = (void *) (long) !submenu->data;
650 				else
651 					conf(submenu);
652 				break;
653 			case 't':
654 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
655 					conf_choice(submenu);
656 				else if (submenu->prompt->type == P_MENU)
657 					conf(submenu);
658 				break;
659 			case 's':
660 				conf_string(submenu);
661 				break;
662 			case 'L':
663 				conf_load();
664 				break;
665 			case 'S':
666 				conf_save();
667 				break;
668 			}
669 			break;
670 		case 2:
671 			if (sym)
672 				show_help(submenu);
673 			else
674 				show_helptext("README", _(mconf_readme));
675 			break;
676 		case 3:
677 			if (item_is_tag('t')) {
678 				if (sym_set_tristate_value(sym, yes))
679 					break;
680 				if (sym_set_tristate_value(sym, mod))
681 					show_textbox(NULL, setmod_text, 6, 74);
682 			}
683 			break;
684 		case 4:
685 			if (item_is_tag('t'))
686 				sym_set_tristate_value(sym, no);
687 			break;
688 		case 5:
689 			if (item_is_tag('t'))
690 				sym_set_tristate_value(sym, mod);
691 			break;
692 		case 6:
693 			if (item_is_tag('t'))
694 				sym_toggle_tristate_value(sym);
695 			else if (item_is_tag('m'))
696 				conf(submenu);
697 			break;
698 		case 7:
699 			search_conf();
700 			break;
701 		}
702 	}
703 }
704 
705 static void show_textbox(const char *title, const char *text, int r, int c)
706 {
707 	dialog_clear();
708 	dialog_textbox(title, text, r, c);
709 }
710 
711 static void show_helptext(const char *title, const char *text)
712 {
713 	show_textbox(title, text, 0, 0);
714 }
715 
716 static void show_help(struct menu *menu)
717 {
718 	struct gstr help = str_new();
719 	struct symbol *sym = menu->sym;
720 
721 	if (sym->help)
722 	{
723 		if (sym->name) {
724 			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
725 			str_append(&help, _(sym->help));
726 			str_append(&help, "\n");
727 		}
728 	} else {
729 		str_append(&help, nohelp_text);
730 	}
731 	get_symbol_str(&help, sym);
732 	show_helptext(menu_get_prompt(menu), str_get(&help));
733 	str_free(&help);
734 }
735 
736 static void conf_choice(struct menu *menu)
737 {
738 	const char *prompt = menu_get_prompt(menu);
739 	struct menu *child;
740 	struct symbol *active;
741 
742 	active = sym_get_choice_value(menu->sym);
743 	while (1) {
744 		int res;
745 		int selected;
746 		item_reset();
747 
748 		current_menu = menu;
749 		for (child = menu->list; child; child = child->next) {
750 			if (!menu_is_visible(child))
751 				continue;
752 			item_make("%s", menu_get_prompt(child));
753 			item_set_data(child);
754 			if (child->sym == active)
755 				item_set_selected(1);
756 			if (child->sym == sym_get_choice_value(menu->sym))
757 				item_set_tag('X');
758 		}
759 		dialog_clear();
760 		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
761 					_(radiolist_instructions),
762 					 15, 70, 6);
763 		selected = item_activate_selected();
764 		switch (res) {
765 		case 0:
766 			if (selected) {
767 				child = item_data();
768 				sym_set_tristate_value(child->sym, yes);
769 			}
770 			return;
771 		case 1:
772 			if (selected) {
773 				child = item_data();
774 				show_help(child);
775 				active = child->sym;
776 			} else
777 				show_help(menu);
778 			break;
779 		case KEY_ESC:
780 			return;
781 		case -ERRDISPLAYTOOSMALL:
782 			return;
783 		}
784 	}
785 }
786 
787 static void conf_string(struct menu *menu)
788 {
789 	const char *prompt = menu_get_prompt(menu);
790 
791 	while (1) {
792 		int res;
793 		char *heading;
794 
795 		switch (sym_get_type(menu->sym)) {
796 		case S_INT:
797 			heading = _(inputbox_instructions_int);
798 			break;
799 		case S_HEX:
800 			heading = _(inputbox_instructions_hex);
801 			break;
802 		case S_STRING:
803 			heading = _(inputbox_instructions_string);
804 			break;
805 		default:
806 			heading = "Internal mconf error!";
807 		}
808 		dialog_clear();
809 		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
810 				      heading, 10, 75,
811 				      sym_get_string_value(menu->sym));
812 		switch (res) {
813 		case 0:
814 			if (sym_set_string_value(menu->sym, dialog_input_result))
815 				return;
816 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
817 			break;
818 		case 1:
819 			show_help(menu);
820 			break;
821 		case KEY_ESC:
822 			return;
823 		}
824 	}
825 }
826 
827 static void conf_load(void)
828 {
829 
830 	while (1) {
831 		int res;
832 		dialog_clear();
833 		res = dialog_inputbox(NULL, load_config_text,
834 				      11, 55, filename);
835 		switch(res) {
836 		case 0:
837 			if (!dialog_input_result[0])
838 				return;
839 			if (!conf_read(dialog_input_result)) {
840 				set_config_filename(dialog_input_result);
841 				return;
842 			}
843 			show_textbox(NULL, _("File does not exist!"), 5, 38);
844 			break;
845 		case 1:
846 			show_helptext(_("Load Alternate Configuration"), load_config_help);
847 			break;
848 		case KEY_ESC:
849 			return;
850 		}
851 	}
852 }
853 
854 static void conf_save(void)
855 {
856 	while (1) {
857 		int res;
858 		dialog_clear();
859 		res = dialog_inputbox(NULL, save_config_text,
860 				      11, 55, filename);
861 		switch(res) {
862 		case 0:
863 			if (!dialog_input_result[0])
864 				return;
865 			if (!conf_write(dialog_input_result)) {
866 				set_config_filename(dialog_input_result);
867 				return;
868 			}
869 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
870 			break;
871 		case 1:
872 			show_helptext(_("Save Alternate Configuration"), save_config_help);
873 			break;
874 		case KEY_ESC:
875 			return;
876 		}
877 	}
878 }
879 
880 static void conf_cleanup(void)
881 {
882 	tcsetattr(1, TCSAFLUSH, &ios_org);
883 }
884 
885 int main(int ac, char **av)
886 {
887 	char *mode;
888 	int res;
889 
890 	setlocale(LC_ALL, "");
891 	bindtextdomain(PACKAGE, LOCALEDIR);
892 	textdomain(PACKAGE);
893 
894 	conf_parse(av[1]);
895 	conf_read(NULL);
896 
897 	mode = getenv("MENUCONFIG_MODE");
898 	if (mode) {
899 		if (!strcasecmp(mode, "single_menu"))
900 			single_menu_mode = 1;
901 	}
902 
903 	tcgetattr(1, &ios_org);
904 	atexit(conf_cleanup);
905 	init_wsize();
906 	reset_dialog();
907 	init_dialog(NULL);
908 	set_config_filename(conf_get_configname());
909 	do {
910 		conf(&rootmenu);
911 		dialog_clear();
912 		if (conf_get_changed())
913 			res = dialog_yesno(NULL,
914 					   _("Do you wish to save your "
915 					     "new kernel configuration?\n"
916 					     "<ESC><ESC> to continue."),
917 					   6, 60);
918 		else
919 			res = -1;
920 	} while (res == KEY_ESC);
921 	end_dialog();
922 
923 	switch (res) {
924 	case 0:
925 		if (conf_write(filename)) {
926 			fprintf(stderr, _("\n\n"
927 				"Error during writing of the kernel configuration.\n"
928 				"Your kernel configuration changes were NOT saved."
929 				"\n\n"));
930 			return 1;
931 		}
932 	case -1:
933 		printf(_("\n\n"
934 			"*** End of Linux kernel configuration.\n"
935 			"*** Execute 'make' to build the kernel or try 'make help'."
936 			"\n\n"));
937 		break;
938 	default:
939 		fprintf(stderr, _("\n\n"
940 			"Your kernel configuration changes were NOT saved."
941 			"\n\n"));
942 	}
943 
944 	return 0;
945 }
946