xref: /openbmc/linux/scripts/kconfig/mconf.c (revision af901ca1)
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 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 kernel\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 	"kernel's default, entering the name of the file here will allow you\n"
213 	"to modify that 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 kernel\n"
223 	"configurations 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 CONFIG_ 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 CONFIG_ 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 CONFIG_ symbols containing USB\n"
267 	"          ^USB => find all CONFIG_ symbols starting with USB\n"
268 	"          USB$ => find all CONFIG_ 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 
276 static void conf(struct menu *menu);
277 static void conf_choice(struct menu *menu);
278 static void conf_string(struct menu *menu);
279 static void conf_load(void);
280 static void conf_save(void);
281 static void show_textbox(const char *title, const char *text, int r, int c);
282 static void show_helptext(const char *title, const char *text);
283 static void show_help(struct menu *menu);
284 
285 static struct gstr get_relations_str(struct symbol **sym_arr)
286 {
287 	struct symbol *sym;
288 	struct gstr res = str_new();
289 	int i;
290 
291 	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
292 		get_symbol_str(&res, sym);
293 	if (!i)
294 		str_append(&res, _("No matches found.\n"));
295 	return res;
296 }
297 
298 static char filename[PATH_MAX+1];
299 static void set_config_filename(const char *config_filename)
300 {
301 	static char menu_backtitle[PATH_MAX+128];
302 	int size;
303 	struct symbol *sym;
304 
305 	sym = sym_lookup("KERNELVERSION", 0);
306 	sym_calc_value(sym);
307 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
308 	                _("%s - Linux Kernel v%s Configuration"),
309 		        config_filename, sym_get_string_value(sym));
310 	if (size >= sizeof(menu_backtitle))
311 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
312 	set_dialog_backtitle(menu_backtitle);
313 
314 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
315 	if (size >= sizeof(filename))
316 		filename[sizeof(filename)-1] = '\0';
317 }
318 
319 
320 static void search_conf(void)
321 {
322 	struct symbol **sym_arr;
323 	struct gstr res;
324 	char *dialog_input;
325 	int dres;
326 again:
327 	dialog_clear();
328 	dres = dialog_inputbox(_("Search Configuration Parameter"),
329 			      _("Enter CONFIG_ (sub)string to search for "
330 				"(with or without \"CONFIG\")"),
331 			      10, 75, "");
332 	switch (dres) {
333 	case 0:
334 		break;
335 	case 1:
336 		show_helptext(_("Search Configuration"), search_help);
337 		goto again;
338 	default:
339 		return;
340 	}
341 
342 	/* strip CONFIG_ if necessary */
343 	dialog_input = dialog_input_result;
344 	if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
345 		dialog_input += 7;
346 
347 	sym_arr = sym_re_search(dialog_input);
348 	res = get_relations_str(sym_arr);
349 	free(sym_arr);
350 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
351 	str_free(&res);
352 }
353 
354 static void build_conf(struct menu *menu)
355 {
356 	struct symbol *sym;
357 	struct property *prop;
358 	struct menu *child;
359 	int type, tmp, doint = 2;
360 	tristate val;
361 	char ch;
362 
363 	if (!menu_is_visible(menu))
364 		return;
365 
366 	sym = menu->sym;
367 	prop = menu->prompt;
368 	if (!sym) {
369 		if (prop && menu != current_menu) {
370 			const char *prompt = menu_get_prompt(menu);
371 			switch (prop->type) {
372 			case P_MENU:
373 				child_count++;
374 				prompt = _(prompt);
375 				if (single_menu_mode) {
376 					item_make("%s%*c%s",
377 						  menu->data ? "-->" : "++>",
378 						  indent + 1, ' ', prompt);
379 				} else
380 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
381 
382 				item_set_tag('m');
383 				item_set_data(menu);
384 				if (single_menu_mode && menu->data)
385 					goto conf_childs;
386 				return;
387 			case P_COMMENT:
388 				if (prompt) {
389 					child_count++;
390 					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
391 					item_set_tag(':');
392 					item_set_data(menu);
393 				}
394 				break;
395 			default:
396 				if (prompt) {
397 					child_count++;
398 					item_make("---%*c%s", indent + 1, ' ', _(prompt));
399 					item_set_tag(':');
400 					item_set_data(menu);
401 				}
402 			}
403 		} else
404 			doint = 0;
405 		goto conf_childs;
406 	}
407 
408 	type = sym_get_type(sym);
409 	if (sym_is_choice(sym)) {
410 		struct symbol *def_sym = sym_get_choice_value(sym);
411 		struct menu *def_menu = NULL;
412 
413 		child_count++;
414 		for (child = menu->list; child; child = child->next) {
415 			if (menu_is_visible(child) && child->sym == def_sym)
416 				def_menu = child;
417 		}
418 
419 		val = sym_get_tristate_value(sym);
420 		if (sym_is_changable(sym)) {
421 			switch (type) {
422 			case S_BOOLEAN:
423 				item_make("[%c]", val == no ? ' ' : '*');
424 				break;
425 			case S_TRISTATE:
426 				switch (val) {
427 				case yes: ch = '*'; break;
428 				case mod: ch = 'M'; break;
429 				default:  ch = ' '; break;
430 				}
431 				item_make("<%c>", ch);
432 				break;
433 			}
434 			item_set_tag('t');
435 			item_set_data(menu);
436 		} else {
437 			item_make("   ");
438 			item_set_tag(def_menu ? 't' : ':');
439 			item_set_data(menu);
440 		}
441 
442 		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
443 		if (val == yes) {
444 			if (def_menu) {
445 				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
446 				item_add_str("  --->");
447 				if (def_menu->list) {
448 					indent += 2;
449 					build_conf(def_menu);
450 					indent -= 2;
451 				}
452 			}
453 			return;
454 		}
455 	} else {
456 		if (menu == current_menu) {
457 			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
458 			item_set_tag(':');
459 			item_set_data(menu);
460 			goto conf_childs;
461 		}
462 		child_count++;
463 		val = sym_get_tristate_value(sym);
464 		if (sym_is_choice_value(sym) && val == yes) {
465 			item_make("   ");
466 			item_set_tag(':');
467 			item_set_data(menu);
468 		} else {
469 			switch (type) {
470 			case S_BOOLEAN:
471 				if (sym_is_changable(sym))
472 					item_make("[%c]", val == no ? ' ' : '*');
473 				else
474 					item_make("-%c-", val == no ? ' ' : '*');
475 				item_set_tag('t');
476 				item_set_data(menu);
477 				break;
478 			case S_TRISTATE:
479 				switch (val) {
480 				case yes: ch = '*'; break;
481 				case mod: ch = 'M'; break;
482 				default:  ch = ' '; break;
483 				}
484 				if (sym_is_changable(sym)) {
485 					if (sym->rev_dep.tri == mod)
486 						item_make("{%c}", ch);
487 					else
488 						item_make("<%c>", ch);
489 				} else
490 					item_make("-%c-", ch);
491 				item_set_tag('t');
492 				item_set_data(menu);
493 				break;
494 			default:
495 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
496 				item_make("(%s)", sym_get_string_value(sym));
497 				tmp = indent - tmp + 4;
498 				if (tmp < 0)
499 					tmp = 0;
500 				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
501 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
502 					     "" : _(" (NEW)"));
503 				item_set_tag('s');
504 				item_set_data(menu);
505 				goto conf_childs;
506 			}
507 		}
508 		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
509 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
510 			  "" : _(" (NEW)"));
511 		if (menu->prompt->type == P_MENU) {
512 			item_add_str("  --->");
513 			return;
514 		}
515 	}
516 
517 conf_childs:
518 	indent += doint;
519 	for (child = menu->list; child; child = child->next)
520 		build_conf(child);
521 	indent -= doint;
522 }
523 
524 static void conf(struct menu *menu)
525 {
526 	struct menu *submenu;
527 	const char *prompt = menu_get_prompt(menu);
528 	struct symbol *sym;
529 	struct menu *active_menu = NULL;
530 	int res;
531 	int s_scroll = 0;
532 
533 	while (1) {
534 		item_reset();
535 		current_menu = menu;
536 		build_conf(menu);
537 		if (!child_count)
538 			break;
539 		if (menu == &rootmenu) {
540 			item_make("--- ");
541 			item_set_tag(':');
542 			item_make(_("    Load an Alternate Configuration File"));
543 			item_set_tag('L');
544 			item_make(_("    Save an Alternate Configuration File"));
545 			item_set_tag('S');
546 		}
547 		dialog_clear();
548 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
549 				  _(menu_instructions),
550 				  active_menu, &s_scroll);
551 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
552 			break;
553 		if (!item_activate_selected())
554 			continue;
555 		if (!item_tag())
556 			continue;
557 
558 		submenu = item_data();
559 		active_menu = item_data();
560 		if (submenu)
561 			sym = submenu->sym;
562 		else
563 			sym = NULL;
564 
565 		switch (res) {
566 		case 0:
567 			switch (item_tag()) {
568 			case 'm':
569 				if (single_menu_mode)
570 					submenu->data = (void *) (long) !submenu->data;
571 				else
572 					conf(submenu);
573 				break;
574 			case 't':
575 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
576 					conf_choice(submenu);
577 				else if (submenu->prompt->type == P_MENU)
578 					conf(submenu);
579 				break;
580 			case 's':
581 				conf_string(submenu);
582 				break;
583 			case 'L':
584 				conf_load();
585 				break;
586 			case 'S':
587 				conf_save();
588 				break;
589 			}
590 			break;
591 		case 2:
592 			if (sym)
593 				show_help(submenu);
594 			else
595 				show_helptext(_("README"), _(mconf_readme));
596 			break;
597 		case 3:
598 			if (item_is_tag('t')) {
599 				if (sym_set_tristate_value(sym, yes))
600 					break;
601 				if (sym_set_tristate_value(sym, mod))
602 					show_textbox(NULL, setmod_text, 6, 74);
603 			}
604 			break;
605 		case 4:
606 			if (item_is_tag('t'))
607 				sym_set_tristate_value(sym, no);
608 			break;
609 		case 5:
610 			if (item_is_tag('t'))
611 				sym_set_tristate_value(sym, mod);
612 			break;
613 		case 6:
614 			if (item_is_tag('t'))
615 				sym_toggle_tristate_value(sym);
616 			else if (item_is_tag('m'))
617 				conf(submenu);
618 			break;
619 		case 7:
620 			search_conf();
621 			break;
622 		}
623 	}
624 }
625 
626 static void show_textbox(const char *title, const char *text, int r, int c)
627 {
628 	dialog_clear();
629 	dialog_textbox(title, text, r, c);
630 }
631 
632 static void show_helptext(const char *title, const char *text)
633 {
634 	show_textbox(title, text, 0, 0);
635 }
636 
637 static void show_help(struct menu *menu)
638 {
639 	struct gstr help = str_new();
640 
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 kernel 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 during writing of the kernel configuration.\n"
848 				"Your kernel configuration changes were NOT saved."
849 				"\n\n"));
850 			return 1;
851 		}
852 	case -1:
853 		printf(_("\n\n"
854 			"*** End of Linux kernel configuration.\n"
855 			"*** Execute 'make' to build the kernel or try 'make help'."
856 			"\n\n"));
857 		break;
858 	default:
859 		fprintf(stderr, _("\n\n"
860 			"Your kernel configuration changes were NOT saved."
861 			"\n\n"));
862 	}
863 
864 	return 0;
865 }
866 
867