xref: /openbmc/linux/scripts/kconfig/mconf.c (revision 48874077)
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 	char *dialog_input;
423 	int dres;
424 again:
425 	dialog_clear();
426 	dres = dialog_inputbox(_("Search Configuration Parameter"),
427 			      _("Enter CONFIG_ (sub)string to search for "
428 				"(with or without \"CONFIG\")"),
429 			      10, 75, "");
430 	switch (dres) {
431 	case 0:
432 		break;
433 	case 1:
434 		show_helptext(_("Search Configuration"), search_help);
435 		goto again;
436 	default:
437 		return;
438 	}
439 
440 	/* strip CONFIG_ if necessary */
441 	dialog_input = dialog_input_result;
442 	if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
443 		dialog_input += 7;
444 
445 	sym_arr = sym_re_search(dialog_input);
446 	res = get_relations_str(sym_arr);
447 	free(sym_arr);
448 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
449 	str_free(&res);
450 }
451 
452 static void build_conf(struct menu *menu)
453 {
454 	struct symbol *sym;
455 	struct property *prop;
456 	struct menu *child;
457 	int type, tmp, doint = 2;
458 	tristate val;
459 	char ch;
460 
461 	if (!menu_is_visible(menu))
462 		return;
463 
464 	sym = menu->sym;
465 	prop = menu->prompt;
466 	if (!sym) {
467 		if (prop && menu != current_menu) {
468 			const char *prompt = menu_get_prompt(menu);
469 			switch (prop->type) {
470 			case P_MENU:
471 				child_count++;
472 				if (single_menu_mode) {
473 					item_make("%s%*c%s",
474 						  menu->data ? "-->" : "++>",
475 						  indent + 1, ' ', prompt);
476 				} else
477 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
478 
479 				item_set_tag('m');
480 				item_set_data(menu);
481 				if (single_menu_mode && menu->data)
482 					goto conf_childs;
483 				return;
484 			case P_COMMENT:
485 				if (prompt) {
486 					child_count++;
487 					item_make("   %*c*** %s ***", indent + 1, ' ', prompt);
488 					item_set_tag(':');
489 					item_set_data(menu);
490 				}
491 				break;
492 			default:
493 				if (prompt) {
494 					child_count++;
495 					item_make("---%*c%s", indent + 1, ' ', prompt);
496 					item_set_tag(':');
497 					item_set_data(menu);
498 				}
499 			}
500 		} else
501 			doint = 0;
502 		goto conf_childs;
503 	}
504 
505 	type = sym_get_type(sym);
506 	if (sym_is_choice(sym)) {
507 		struct symbol *def_sym = sym_get_choice_value(sym);
508 		struct menu *def_menu = NULL;
509 
510 		child_count++;
511 		for (child = menu->list; child; child = child->next) {
512 			if (menu_is_visible(child) && child->sym == def_sym)
513 				def_menu = child;
514 		}
515 
516 		val = sym_get_tristate_value(sym);
517 		if (sym_is_changable(sym)) {
518 			switch (type) {
519 			case S_BOOLEAN:
520 				item_make("[%c]", val == no ? ' ' : '*');
521 				break;
522 			case S_TRISTATE:
523 				switch (val) {
524 				case yes: ch = '*'; break;
525 				case mod: ch = 'M'; break;
526 				default:  ch = ' '; break;
527 				}
528 				item_make("<%c>", ch);
529 				break;
530 			}
531 			item_set_tag('t');
532 			item_set_data(menu);
533 		} else {
534 			item_make("   ");
535 			item_set_tag(def_menu ? 't' : ':');
536 			item_set_data(menu);
537 		}
538 
539 		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
540 		if (val == yes) {
541 			if (def_menu) {
542 				item_add_str(" (%s)", menu_get_prompt(def_menu));
543 				item_add_str("  --->");
544 				if (def_menu->list) {
545 					indent += 2;
546 					build_conf(def_menu);
547 					indent -= 2;
548 				}
549 			}
550 			return;
551 		}
552 	} else {
553 		if (menu == current_menu) {
554 			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
555 			item_set_tag(':');
556 			item_set_data(menu);
557 			goto conf_childs;
558 		}
559 		child_count++;
560 		val = sym_get_tristate_value(sym);
561 		if (sym_is_choice_value(sym) && val == yes) {
562 			item_make("   ");
563 			item_set_tag(':');
564 			item_set_data(menu);
565 		} else {
566 			switch (type) {
567 			case S_BOOLEAN:
568 				if (sym_is_changable(sym))
569 					item_make("[%c]", val == no ? ' ' : '*');
570 				else
571 					item_make("---");
572 				item_set_tag('t');
573 				item_set_data(menu);
574 				break;
575 			case S_TRISTATE:
576 				switch (val) {
577 				case yes: ch = '*'; break;
578 				case mod: ch = 'M'; break;
579 				default:  ch = ' '; break;
580 				}
581 				if (sym_is_changable(sym))
582 					item_make("<%c>", ch);
583 				else
584 					item_make("---");
585 				item_set_tag('t');
586 				item_set_data(menu);
587 				break;
588 			default:
589 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
590 				item_make("(%s)", sym_get_string_value(sym));
591 				tmp = indent - tmp + 4;
592 				if (tmp < 0)
593 					tmp = 0;
594 				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
595 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
596 					     "" : " (NEW)");
597 				item_set_tag('s');
598 				item_set_data(menu);
599 				goto conf_childs;
600 			}
601 		}
602 		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
603 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
604 			  "" : " (NEW)");
605 		if (menu->prompt->type == P_MENU) {
606 			item_add_str("  --->");
607 			return;
608 		}
609 	}
610 
611 conf_childs:
612 	indent += doint;
613 	for (child = menu->list; child; child = child->next)
614 		build_conf(child);
615 	indent -= doint;
616 }
617 
618 static void conf(struct menu *menu)
619 {
620 	struct menu *submenu;
621 	const char *prompt = menu_get_prompt(menu);
622 	struct symbol *sym;
623 	struct menu *active_menu = NULL;
624 	int res;
625 	int s_scroll = 0;
626 
627 	while (1) {
628 		item_reset();
629 		current_menu = menu;
630 		build_conf(menu);
631 		if (!child_count)
632 			break;
633 		if (menu == &rootmenu) {
634 			item_make("--- ");
635 			item_set_tag(':');
636 			item_make(_("    Load an Alternate Configuration File"));
637 			item_set_tag('L');
638 			item_make(_("    Save an Alternate Configuration File"));
639 			item_set_tag('S');
640 		}
641 		dialog_clear();
642 		res = dialog_menu(prompt ? prompt : _("Main Menu"),
643 				  _(menu_instructions),
644 				  active_menu, &s_scroll);
645 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
646 			break;
647 		if (!item_activate_selected())
648 			continue;
649 		if (!item_tag())
650 			continue;
651 
652 		submenu = item_data();
653 		active_menu = item_data();
654 		if (submenu)
655 			sym = submenu->sym;
656 		else
657 			sym = NULL;
658 
659 		switch (res) {
660 		case 0:
661 			switch (item_tag()) {
662 			case 'm':
663 				if (single_menu_mode)
664 					submenu->data = (void *) (long) !submenu->data;
665 				else
666 					conf(submenu);
667 				break;
668 			case 't':
669 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
670 					conf_choice(submenu);
671 				else if (submenu->prompt->type == P_MENU)
672 					conf(submenu);
673 				break;
674 			case 's':
675 				conf_string(submenu);
676 				break;
677 			case 'L':
678 				conf_load();
679 				break;
680 			case 'S':
681 				conf_save();
682 				break;
683 			}
684 			break;
685 		case 2:
686 			if (sym)
687 				show_help(submenu);
688 			else
689 				show_helptext("README", _(mconf_readme));
690 			break;
691 		case 3:
692 			if (item_is_tag('t')) {
693 				if (sym_set_tristate_value(sym, yes))
694 					break;
695 				if (sym_set_tristate_value(sym, mod))
696 					show_textbox(NULL, setmod_text, 6, 74);
697 			}
698 			break;
699 		case 4:
700 			if (item_is_tag('t'))
701 				sym_set_tristate_value(sym, no);
702 			break;
703 		case 5:
704 			if (item_is_tag('t'))
705 				sym_set_tristate_value(sym, mod);
706 			break;
707 		case 6:
708 			if (item_is_tag('t'))
709 				sym_toggle_tristate_value(sym);
710 			else if (item_is_tag('m'))
711 				conf(submenu);
712 			break;
713 		case 7:
714 			search_conf();
715 			break;
716 		}
717 	}
718 }
719 
720 static void show_textbox(const char *title, const char *text, int r, int c)
721 {
722 	dialog_clear();
723 	dialog_textbox(title, text, r, c);
724 }
725 
726 static void show_helptext(const char *title, const char *text)
727 {
728 	show_textbox(title, text, 0, 0);
729 }
730 
731 static void show_help(struct menu *menu)
732 {
733 	struct gstr help = str_new();
734 	struct symbol *sym = menu->sym;
735 
736 	if (menu_has_help(menu))
737 	{
738 		if (sym->name) {
739 			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
740 			str_append(&help, _(menu_get_help(menu)));
741 			str_append(&help, "\n");
742 		}
743 	} else {
744 		str_append(&help, nohelp_text);
745 	}
746 	get_symbol_str(&help, sym);
747 	show_helptext(menu_get_prompt(menu), str_get(&help));
748 	str_free(&help);
749 }
750 
751 static void conf_choice(struct menu *menu)
752 {
753 	const char *prompt = menu_get_prompt(menu);
754 	struct menu *child;
755 	struct symbol *active;
756 
757 	active = sym_get_choice_value(menu->sym);
758 	while (1) {
759 		int res;
760 		int selected;
761 		item_reset();
762 
763 		current_menu = menu;
764 		for (child = menu->list; child; child = child->next) {
765 			if (!menu_is_visible(child))
766 				continue;
767 			item_make("%s", menu_get_prompt(child));
768 			item_set_data(child);
769 			if (child->sym == active)
770 				item_set_selected(1);
771 			if (child->sym == sym_get_choice_value(menu->sym))
772 				item_set_tag('X');
773 		}
774 		dialog_clear();
775 		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
776 					_(radiolist_instructions),
777 					 15, 70, 6);
778 		selected = item_activate_selected();
779 		switch (res) {
780 		case 0:
781 			if (selected) {
782 				child = item_data();
783 				sym_set_tristate_value(child->sym, yes);
784 			}
785 			return;
786 		case 1:
787 			if (selected) {
788 				child = item_data();
789 				show_help(child);
790 				active = child->sym;
791 			} else
792 				show_help(menu);
793 			break;
794 		case KEY_ESC:
795 			return;
796 		case -ERRDISPLAYTOOSMALL:
797 			return;
798 		}
799 	}
800 }
801 
802 static void conf_string(struct menu *menu)
803 {
804 	const char *prompt = menu_get_prompt(menu);
805 
806 	while (1) {
807 		int res;
808 		char *heading;
809 
810 		switch (sym_get_type(menu->sym)) {
811 		case S_INT:
812 			heading = _(inputbox_instructions_int);
813 			break;
814 		case S_HEX:
815 			heading = _(inputbox_instructions_hex);
816 			break;
817 		case S_STRING:
818 			heading = _(inputbox_instructions_string);
819 			break;
820 		default:
821 			heading = "Internal mconf error!";
822 		}
823 		dialog_clear();
824 		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
825 				      heading, 10, 75,
826 				      sym_get_string_value(menu->sym));
827 		switch (res) {
828 		case 0:
829 			if (sym_set_string_value(menu->sym, dialog_input_result))
830 				return;
831 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
832 			break;
833 		case 1:
834 			show_help(menu);
835 			break;
836 		case KEY_ESC:
837 			return;
838 		}
839 	}
840 }
841 
842 static void conf_load(void)
843 {
844 
845 	while (1) {
846 		int res;
847 		dialog_clear();
848 		res = dialog_inputbox(NULL, load_config_text,
849 				      11, 55, filename);
850 		switch(res) {
851 		case 0:
852 			if (!dialog_input_result[0])
853 				return;
854 			if (!conf_read(dialog_input_result)) {
855 				set_config_filename(dialog_input_result);
856 				return;
857 			}
858 			show_textbox(NULL, _("File does not exist!"), 5, 38);
859 			break;
860 		case 1:
861 			show_helptext(_("Load Alternate Configuration"), load_config_help);
862 			break;
863 		case KEY_ESC:
864 			return;
865 		}
866 	}
867 }
868 
869 static void conf_save(void)
870 {
871 	while (1) {
872 		int res;
873 		dialog_clear();
874 		res = dialog_inputbox(NULL, save_config_text,
875 				      11, 55, filename);
876 		switch(res) {
877 		case 0:
878 			if (!dialog_input_result[0])
879 				return;
880 			if (!conf_write(dialog_input_result)) {
881 				set_config_filename(dialog_input_result);
882 				return;
883 			}
884 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
885 			break;
886 		case 1:
887 			show_helptext(_("Save Alternate Configuration"), save_config_help);
888 			break;
889 		case KEY_ESC:
890 			return;
891 		}
892 	}
893 }
894 
895 static void conf_cleanup(void)
896 {
897 	tcsetattr(1, TCSAFLUSH, &ios_org);
898 }
899 
900 int main(int ac, char **av)
901 {
902 	char *mode;
903 	int res;
904 
905 	setlocale(LC_ALL, "");
906 	bindtextdomain(PACKAGE, LOCALEDIR);
907 	textdomain(PACKAGE);
908 
909 	conf_parse(av[1]);
910 	conf_read(NULL);
911 
912 	mode = getenv("MENUCONFIG_MODE");
913 	if (mode) {
914 		if (!strcasecmp(mode, "single_menu"))
915 			single_menu_mode = 1;
916 	}
917 
918 	tcgetattr(1, &ios_org);
919 	atexit(conf_cleanup);
920 	init_wsize();
921 	reset_dialog();
922 	init_dialog(NULL);
923 	set_config_filename(conf_get_configname());
924 	do {
925 		conf(&rootmenu);
926 		dialog_clear();
927 		if (conf_get_changed())
928 			res = dialog_yesno(NULL,
929 					   _("Do you wish to save your "
930 					     "new kernel configuration?\n"
931 					     "<ESC><ESC> to continue."),
932 					   6, 60);
933 		else
934 			res = -1;
935 	} while (res == KEY_ESC);
936 	end_dialog();
937 
938 	switch (res) {
939 	case 0:
940 		if (conf_write(filename)) {
941 			fprintf(stderr, _("\n\n"
942 				"Error during writing of the kernel configuration.\n"
943 				"Your kernel configuration changes were NOT saved."
944 				"\n\n"));
945 			return 1;
946 		}
947 	case -1:
948 		printf(_("\n\n"
949 			"*** End of Linux kernel configuration.\n"
950 			"*** Execute 'make' to build the kernel or try 'make help'."
951 			"\n\n"));
952 		break;
953 	default:
954 		fprintf(stderr, _("\n\n"
955 			"Your kernel configuration changes were NOT saved."
956 			"\n\n"));
957 	}
958 
959 	return 0;
960 }
961