xref: /openbmc/linux/scripts/kconfig/mconf.c (revision 1d1e2cae)
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 <signal.h>
19 #include <unistd.h>
20 #include <locale.h>
21 
22 #include "lkc.h"
23 #include "lxdialog/dialog.h"
24 
25 static const char mconf_readme[] = N_(
26 "Overview\n"
27 "--------\n"
28 "This interface let you select features and parameters for the build.\n"
29 "Features can either be built-in, modularized, or ignored. Parameters\n"
30 "must be entered in as decimal or hexadecimal numbers or text.\n"
31 "\n"
32 "Menu items beginning with following braces represent features that\n"
33 "  [ ] can be built in or removed\n"
34 "  < > can be built in, modularized or removed\n"
35 "  { } can be built in or modularized (selected by other feature)\n"
36 "  - - are selected by other feature,\n"
37 "while *, M or whitespace inside braces means to build in, build as\n"
38 "a module or to exclude the feature respectively.\n"
39 "\n"
40 "To change any of these features, highlight it with the cursor\n"
41 "keys and press <Y> to build it in, <M> to make it a module or\n"
42 "<N> to removed it.  You may also press the <Space Bar> to cycle\n"
43 "through the available options (ie. Y->N->M->Y).\n"
44 "\n"
45 "Some additional keyboard hints:\n"
46 "\n"
47 "Menus\n"
48 "----------\n"
49 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
50 "   you wish to change or submenu wish to select and press <Enter>.\n"
51 "   Submenus are designated by \"--->\".\n"
52 "\n"
53 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
54 "             Pressing a hotkey more than once will sequence\n"
55 "             through all visible items which use that hotkey.\n"
56 "\n"
57 "   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
58 "   unseen options into view.\n"
59 "\n"
60 "o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
61 "   and press <ENTER>.\n"
62 "\n"
63 "   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
64 "             using those letters.  You may press a single <ESC>, but\n"
65 "             there is a delayed response which you may find annoying.\n"
66 "\n"
67 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
68 "   <Exit> and <Help>.\n"
69 "\n"
70 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
71 "   and press <ENTER>.\n"
72 "\n"
73 "   Shortcut: Press <H> or <?>.\n"
74 "\n"
75 "o  To toggle the display of hidden options, press <Z>.\n"
76 "\n"
77 "\n"
78 "Radiolists  (Choice lists)\n"
79 "-----------\n"
80 "o  Use the cursor keys to select the option you wish to set and press\n"
81 "   <S> or the <SPACE BAR>.\n"
82 "\n"
83 "   Shortcut: Press the first letter of the option you wish to set then\n"
84 "             press <S> or <SPACE BAR>.\n"
85 "\n"
86 "o  To see available help for the item, use the cursor keys to highlight\n"
87 "   <Help> and Press <ENTER>.\n"
88 "\n"
89 "   Shortcut: Press <H> or <?>.\n"
90 "\n"
91 "   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
92 "   <Help>\n"
93 "\n"
94 "\n"
95 "Data Entry\n"
96 "-----------\n"
97 "o  Enter the requested information and press <ENTER>\n"
98 "   If you are entering hexadecimal values, it is not necessary to\n"
99 "   add the '0x' prefix to the entry.\n"
100 "\n"
101 "o  For help, use the <TAB> or cursor keys to highlight the help option\n"
102 "   and press <ENTER>.  You can try <TAB><H> as well.\n"
103 "\n"
104 "\n"
105 "Text Box    (Help Window)\n"
106 "--------\n"
107 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
108 "   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for \n"
109 "   those who are familiar with less and lynx.\n"
110 "\n"
111 "o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
112 "\n"
113 "\n"
114 "Alternate Configuration Files\n"
115 "-----------------------------\n"
116 "Menuconfig supports the use of alternate configuration files for\n"
117 "those who, for various reasons, find it necessary to switch\n"
118 "between different configurations.\n"
119 "\n"
120 "At the end of the main menu you will find two options.  One is\n"
121 "for saving the current configuration to a file of your choosing.\n"
122 "The other option is for loading a previously saved alternate\n"
123 "configuration.\n"
124 "\n"
125 "Even if you don't use alternate configuration files, but you\n"
126 "find during a Menuconfig session that you have completely messed\n"
127 "up your settings, you may use the \"Load Alternate...\" option to\n"
128 "restore your previously saved settings from \".config\" without\n"
129 "restarting Menuconfig.\n"
130 "\n"
131 "Other information\n"
132 "-----------------\n"
133 "If you use Menuconfig in an XTERM window make sure you have your\n"
134 "$TERM variable set to point to a xterm definition which supports color.\n"
135 "Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
136 "display correctly in a RXVT window because rxvt displays only one\n"
137 "intensity of color, bright.\n"
138 "\n"
139 "Menuconfig will display larger menus on screens or xterms which are\n"
140 "set to display more than the standard 25 row by 80 column geometry.\n"
141 "In order for this to work, the \"stty size\" command must be able to\n"
142 "display the screen's current row and column geometry.  I STRONGLY\n"
143 "RECOMMEND that you make sure you do NOT have the shell variables\n"
144 "LINES and COLUMNS exported into your environment.  Some distributions\n"
145 "export those variables via /etc/profile.  Some ncurses programs can\n"
146 "become confused when those variables (LINES & COLUMNS) don't reflect\n"
147 "the true screen size.\n"
148 "\n"
149 "Optional personality available\n"
150 "------------------------------\n"
151 "If you prefer to have all of the options listed in a single menu, rather\n"
152 "than the default multimenu hierarchy, run the menuconfig with\n"
153 "MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
154 "\n"
155 "make MENUCONFIG_MODE=single_menu menuconfig\n"
156 "\n"
157 "<Enter> will then unroll the appropriate category, or enfold it if it\n"
158 "is already unrolled.\n"
159 "\n"
160 "Note that this mode can eventually be a little more CPU expensive\n"
161 "(especially with a larger number of unrolled categories) than the\n"
162 "default mode.\n"
163 "\n"
164 "Different color themes available\n"
165 "--------------------------------\n"
166 "It is possible to select different color themes using the variable\n"
167 "MENUCONFIG_COLOR. To select a theme use:\n"
168 "\n"
169 "make MENUCONFIG_COLOR=<theme> menuconfig\n"
170 "\n"
171 "Available themes are\n"
172 " mono       => selects colors suitable for monochrome displays\n"
173 " blackbg    => selects a color scheme with black background\n"
174 " classic    => theme with blue background. The classic look\n"
175 " bluetitle  => a LCD friendly version of classic. (default)\n"
176 "\n"),
177 menu_instructions[] = N_(
178 	"Arrow keys navigate the menu.  "
179 	"<Enter> selects submenus --->.  "
180 	"Highlighted letters are hotkeys.  "
181 	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
182 	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
183 	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
184 radiolist_instructions[] = N_(
185 	"Use the arrow keys to navigate this window or "
186 	"press the hotkey of the item you wish to select "
187 	"followed by the <SPACE BAR>. "
188 	"Press <?> for additional information about this option."),
189 inputbox_instructions_int[] = N_(
190 	"Please enter a decimal value. "
191 	"Fractions will not be accepted.  "
192 	"Use the <TAB> key to move from the input field to the buttons below it."),
193 inputbox_instructions_hex[] = N_(
194 	"Please enter a hexadecimal value. "
195 	"Use the <TAB> key to move from the input field to the buttons below it."),
196 inputbox_instructions_string[] = N_(
197 	"Please enter a string value. "
198 	"Use the <TAB> key to move from the input field to the buttons below it."),
199 setmod_text[] = N_(
200 	"This feature depends on another which has been configured as a module.\n"
201 	"As a result, this feature will be built as a module."),
202 load_config_text[] = N_(
203 	"Enter the name of the configuration file you wish to load.  "
204 	"Accept the name shown to restore the configuration you "
205 	"last retrieved.  Leave blank to abort."),
206 load_config_help[] = N_(
207 	"\n"
208 	"For various reasons, one may wish to keep several different\n"
209 	"configurations available on a single machine.\n"
210 	"\n"
211 	"If you have saved a previous configuration in a file other than the\n"
212 	"default one, entering its name here will allow you to modify that\n"
213 	"configuration.\n"
214 	"\n"
215 	"If you are uncertain, then you have probably never used alternate\n"
216 	"configuration files. You should therefore leave this blank to abort.\n"),
217 save_config_text[] = N_(
218 	"Enter a filename to which this configuration should be saved "
219 	"as an alternate.  Leave blank to abort."),
220 save_config_help[] = N_(
221 	"\n"
222 	"For various reasons, one may wish to keep different configurations\n"
223 	"available on a single machine.\n"
224 	"\n"
225 	"Entering a file name here will allow you to later retrieve, modify\n"
226 	"and use the current configuration as an alternate to whatever\n"
227 	"configuration options you have selected at that time.\n"
228 	"\n"
229 	"If you are uncertain what all this means then you should probably\n"
230 	"leave this blank.\n"),
231 search_help[] = N_(
232 	"\n"
233 	"Search for symbols and display their relations.\n"
234 	"Regular expressions are allowed.\n"
235 	"Example: search for \"^FOO\"\n"
236 	"Result:\n"
237 	"-----------------------------------------------------------------\n"
238 	"Symbol: FOO [=m]\n"
239 	"Prompt: Foo bus is used to drive the bar HW\n"
240 	"Defined at drivers/pci/Kconfig:47\n"
241 	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
242 	"Location:\n"
243 	"  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
244 	"    -> PCI support (PCI [=y])\n"
245 	"      -> PCI access mode (<choice> [=y])\n"
246 	"Selects: LIBCRC32\n"
247 	"Selected by: BAR\n"
248 	"-----------------------------------------------------------------\n"
249 	"o The line 'Prompt:' shows the text used in the menu structure for\n"
250 	"  this symbol\n"
251 	"o The 'Defined at' line tell at what file / line number the symbol\n"
252 	"  is defined\n"
253 	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
254 	"  this symbol to be visible in the menu (selectable)\n"
255 	"o The 'Location:' lines tell where in the menu structure this symbol\n"
256 	"  is located\n"
257 	"    A location followed by a [=y] indicate that this is a selectable\n"
258 	"    menu item - and current value is displayed inside brackets.\n"
259 	"o The 'Selects:' line tell what symbol will be automatically\n"
260 	"  selected if this symbol is selected (y or m)\n"
261 	"o The 'Selected by' line tell what symbol has selected this symbol\n"
262 	"\n"
263 	"Only relevant lines are shown.\n"
264 	"\n\n"
265 	"Search examples:\n"
266 	"Examples: USB	=> find all symbols containing USB\n"
267 	"          ^USB => find all symbols starting with USB\n"
268 	"          USB$ => find all symbols ending with USB\n"
269 	"\n");
270 
271 static int indent;
272 static struct menu *current_menu;
273 static int child_count;
274 static int single_menu_mode;
275 static int show_all_options;
276 
277 static void conf(struct menu *menu);
278 static void conf_choice(struct menu *menu);
279 static void conf_string(struct menu *menu);
280 static void conf_load(void);
281 static void conf_save(void);
282 static int show_textbox_ext(const char *title, const char *text, int r, int c,
283 			    int *keys, int *vscroll, int *hscroll);
284 static void show_textbox(const char *title, const char *text, int r, int c);
285 static void show_helptext(const char *title, const char *text);
286 static void show_help(struct menu *menu);
287 
288 static char filename[PATH_MAX+1];
289 static void set_config_filename(const char *config_filename)
290 {
291 	static char menu_backtitle[PATH_MAX+128];
292 	int size;
293 
294 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
295 	                "%s - %s", config_filename, rootmenu.prompt->text);
296 	if (size >= sizeof(menu_backtitle))
297 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
298 	set_dialog_backtitle(menu_backtitle);
299 
300 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
301 	if (size >= sizeof(filename))
302 		filename[sizeof(filename)-1] = '\0';
303 }
304 
305 
306 static void search_conf(void)
307 {
308 	struct symbol **sym_arr;
309 	struct gstr res;
310 	char *dialog_input;
311 	int dres;
312 again:
313 	dialog_clear();
314 	dres = dialog_inputbox(_("Search Configuration Parameter"),
315 			      _("Enter " CONFIG_ " (sub)string to search for "
316 				"(with or without \"" CONFIG_ "\")"),
317 			      10, 75, "");
318 	switch (dres) {
319 	case 0:
320 		break;
321 	case 1:
322 		show_helptext(_("Search Configuration"), search_help);
323 		goto again;
324 	default:
325 		return;
326 	}
327 
328 	/* strip the prefix if necessary */
329 	dialog_input = dialog_input_result;
330 	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
331 		dialog_input += strlen(CONFIG_);
332 
333 	sym_arr = sym_re_search(dialog_input);
334 	res = get_relations_str(sym_arr);
335 	free(sym_arr);
336 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
337 	str_free(&res);
338 }
339 
340 static void build_conf(struct menu *menu)
341 {
342 	struct symbol *sym;
343 	struct property *prop;
344 	struct menu *child;
345 	int type, tmp, doint = 2;
346 	tristate val;
347 	char ch;
348 	bool visible;
349 
350 	/*
351 	 * note: menu_is_visible() has side effect that it will
352 	 * recalc the value of the symbol.
353 	 */
354 	visible = menu_is_visible(menu);
355 	if (show_all_options && !menu_has_prompt(menu))
356 		return;
357 	else if (!show_all_options && !visible)
358 		return;
359 
360 	sym = menu->sym;
361 	prop = menu->prompt;
362 	if (!sym) {
363 		if (prop && menu != current_menu) {
364 			const char *prompt = menu_get_prompt(menu);
365 			switch (prop->type) {
366 			case P_MENU:
367 				child_count++;
368 				prompt = _(prompt);
369 				if (single_menu_mode) {
370 					item_make("%s%*c%s",
371 						  menu->data ? "-->" : "++>",
372 						  indent + 1, ' ', prompt);
373 				} else
374 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
375 
376 				item_set_tag('m');
377 				item_set_data(menu);
378 				if (single_menu_mode && menu->data)
379 					goto conf_childs;
380 				return;
381 			case P_COMMENT:
382 				if (prompt) {
383 					child_count++;
384 					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
385 					item_set_tag(':');
386 					item_set_data(menu);
387 				}
388 				break;
389 			default:
390 				if (prompt) {
391 					child_count++;
392 					item_make("---%*c%s", indent + 1, ' ', _(prompt));
393 					item_set_tag(':');
394 					item_set_data(menu);
395 				}
396 			}
397 		} else
398 			doint = 0;
399 		goto conf_childs;
400 	}
401 
402 	type = sym_get_type(sym);
403 	if (sym_is_choice(sym)) {
404 		struct symbol *def_sym = sym_get_choice_value(sym);
405 		struct menu *def_menu = NULL;
406 
407 		child_count++;
408 		for (child = menu->list; child; child = child->next) {
409 			if (menu_is_visible(child) && child->sym == def_sym)
410 				def_menu = child;
411 		}
412 
413 		val = sym_get_tristate_value(sym);
414 		if (sym_is_changable(sym)) {
415 			switch (type) {
416 			case S_BOOLEAN:
417 				item_make("[%c]", val == no ? ' ' : '*');
418 				break;
419 			case S_TRISTATE:
420 				switch (val) {
421 				case yes: ch = '*'; break;
422 				case mod: ch = 'M'; break;
423 				default:  ch = ' '; break;
424 				}
425 				item_make("<%c>", ch);
426 				break;
427 			}
428 			item_set_tag('t');
429 			item_set_data(menu);
430 		} else {
431 			item_make("   ");
432 			item_set_tag(def_menu ? 't' : ':');
433 			item_set_data(menu);
434 		}
435 
436 		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
437 		if (val == yes) {
438 			if (def_menu) {
439 				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
440 				item_add_str("  --->");
441 				if (def_menu->list) {
442 					indent += 2;
443 					build_conf(def_menu);
444 					indent -= 2;
445 				}
446 			}
447 			return;
448 		}
449 	} else {
450 		if (menu == current_menu) {
451 			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
452 			item_set_tag(':');
453 			item_set_data(menu);
454 			goto conf_childs;
455 		}
456 		child_count++;
457 		val = sym_get_tristate_value(sym);
458 		if (sym_is_choice_value(sym) && val == yes) {
459 			item_make("   ");
460 			item_set_tag(':');
461 			item_set_data(menu);
462 		} else {
463 			switch (type) {
464 			case S_BOOLEAN:
465 				if (sym_is_changable(sym))
466 					item_make("[%c]", val == no ? ' ' : '*');
467 				else
468 					item_make("-%c-", val == no ? ' ' : '*');
469 				item_set_tag('t');
470 				item_set_data(menu);
471 				break;
472 			case S_TRISTATE:
473 				switch (val) {
474 				case yes: ch = '*'; break;
475 				case mod: ch = 'M'; break;
476 				default:  ch = ' '; break;
477 				}
478 				if (sym_is_changable(sym)) {
479 					if (sym->rev_dep.tri == mod)
480 						item_make("{%c}", ch);
481 					else
482 						item_make("<%c>", ch);
483 				} else
484 					item_make("-%c-", ch);
485 				item_set_tag('t');
486 				item_set_data(menu);
487 				break;
488 			default:
489 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
490 				item_make("(%s)", sym_get_string_value(sym));
491 				tmp = indent - tmp + 4;
492 				if (tmp < 0)
493 					tmp = 0;
494 				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
495 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
496 					     "" : _(" (NEW)"));
497 				item_set_tag('s');
498 				item_set_data(menu);
499 				goto conf_childs;
500 			}
501 		}
502 		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
503 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
504 			  "" : _(" (NEW)"));
505 		if (menu->prompt->type == P_MENU) {
506 			item_add_str("  --->");
507 			return;
508 		}
509 	}
510 
511 conf_childs:
512 	indent += doint;
513 	for (child = menu->list; child; child = child->next)
514 		build_conf(child);
515 	indent -= doint;
516 }
517 
518 static void conf(struct menu *menu)
519 {
520 	struct menu *submenu;
521 	const char *prompt = menu_get_prompt(menu);
522 	struct symbol *sym;
523 	struct menu *active_menu = NULL;
524 	int res;
525 	int s_scroll = 0;
526 
527 	while (1) {
528 		item_reset();
529 		current_menu = menu;
530 		build_conf(menu);
531 		if (!child_count)
532 			break;
533 		if (menu == &rootmenu) {
534 			item_make("--- ");
535 			item_set_tag(':');
536 			item_make(_("    Load an Alternate Configuration File"));
537 			item_set_tag('L');
538 			item_make(_("    Save an Alternate Configuration File"));
539 			item_set_tag('S');
540 		}
541 		dialog_clear();
542 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
543 				  _(menu_instructions),
544 				  active_menu, &s_scroll);
545 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
546 			break;
547 		if (!item_activate_selected())
548 			continue;
549 		if (!item_tag())
550 			continue;
551 
552 		submenu = item_data();
553 		active_menu = item_data();
554 		if (submenu)
555 			sym = submenu->sym;
556 		else
557 			sym = NULL;
558 
559 		switch (res) {
560 		case 0:
561 			switch (item_tag()) {
562 			case 'm':
563 				if (single_menu_mode)
564 					submenu->data = (void *) (long) !submenu->data;
565 				else
566 					conf(submenu);
567 				break;
568 			case 't':
569 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
570 					conf_choice(submenu);
571 				else if (submenu->prompt->type == P_MENU)
572 					conf(submenu);
573 				break;
574 			case 's':
575 				conf_string(submenu);
576 				break;
577 			case 'L':
578 				conf_load();
579 				break;
580 			case 'S':
581 				conf_save();
582 				break;
583 			}
584 			break;
585 		case 2:
586 			if (sym)
587 				show_help(submenu);
588 			else
589 				show_helptext(_("README"), _(mconf_readme));
590 			break;
591 		case 3:
592 			if (item_is_tag('t')) {
593 				if (sym_set_tristate_value(sym, yes))
594 					break;
595 				if (sym_set_tristate_value(sym, mod))
596 					show_textbox(NULL, setmod_text, 6, 74);
597 			}
598 			break;
599 		case 4:
600 			if (item_is_tag('t'))
601 				sym_set_tristate_value(sym, no);
602 			break;
603 		case 5:
604 			if (item_is_tag('t'))
605 				sym_set_tristate_value(sym, mod);
606 			break;
607 		case 6:
608 			if (item_is_tag('t'))
609 				sym_toggle_tristate_value(sym);
610 			else if (item_is_tag('m'))
611 				conf(submenu);
612 			break;
613 		case 7:
614 			search_conf();
615 			break;
616 		case 8:
617 			show_all_options = !show_all_options;
618 			break;
619 		}
620 	}
621 }
622 
623 static int show_textbox_ext(const char *title, const char *text, int r, int c,
624 			    int *keys, int *vscroll, int *hscroll)
625 {
626 	dialog_clear();
627 	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll);
628 }
629 
630 static void show_textbox(const char *title, const char *text, int r, int c)
631 {
632 	show_textbox_ext(title, text, r, c, (int []) {0}, NULL, NULL);
633 }
634 
635 static void show_helptext(const char *title, const char *text)
636 {
637 	show_textbox(title, text, 0, 0);
638 }
639 
640 static void show_help(struct menu *menu)
641 {
642 	struct gstr help = str_new();
643 
644 	help.max_width = getmaxx(stdscr) - 10;
645 	menu_get_ext_help(menu, &help);
646 
647 	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
648 	str_free(&help);
649 }
650 
651 static void conf_choice(struct menu *menu)
652 {
653 	const char *prompt = _(menu_get_prompt(menu));
654 	struct menu *child;
655 	struct symbol *active;
656 
657 	active = sym_get_choice_value(menu->sym);
658 	while (1) {
659 		int res;
660 		int selected;
661 		item_reset();
662 
663 		current_menu = menu;
664 		for (child = menu->list; child; child = child->next) {
665 			if (!menu_is_visible(child))
666 				continue;
667 			if (child->sym)
668 				item_make("%s", _(menu_get_prompt(child)));
669 			else {
670 				item_make("*** %s ***", _(menu_get_prompt(child)));
671 				item_set_tag(':');
672 			}
673 			item_set_data(child);
674 			if (child->sym == active)
675 				item_set_selected(1);
676 			if (child->sym == sym_get_choice_value(menu->sym))
677 				item_set_tag('X');
678 		}
679 		dialog_clear();
680 		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
681 					_(radiolist_instructions),
682 					 15, 70, 6);
683 		selected = item_activate_selected();
684 		switch (res) {
685 		case 0:
686 			if (selected) {
687 				child = item_data();
688 				if (!child->sym)
689 					break;
690 
691 				sym_set_tristate_value(child->sym, yes);
692 			}
693 			return;
694 		case 1:
695 			if (selected) {
696 				child = item_data();
697 				show_help(child);
698 				active = child->sym;
699 			} else
700 				show_help(menu);
701 			break;
702 		case KEY_ESC:
703 			return;
704 		case -ERRDISPLAYTOOSMALL:
705 			return;
706 		}
707 	}
708 }
709 
710 static void conf_string(struct menu *menu)
711 {
712 	const char *prompt = menu_get_prompt(menu);
713 
714 	while (1) {
715 		int res;
716 		const char *heading;
717 
718 		switch (sym_get_type(menu->sym)) {
719 		case S_INT:
720 			heading = _(inputbox_instructions_int);
721 			break;
722 		case S_HEX:
723 			heading = _(inputbox_instructions_hex);
724 			break;
725 		case S_STRING:
726 			heading = _(inputbox_instructions_string);
727 			break;
728 		default:
729 			heading = _("Internal mconf error!");
730 		}
731 		dialog_clear();
732 		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
733 				      heading, 10, 75,
734 				      sym_get_string_value(menu->sym));
735 		switch (res) {
736 		case 0:
737 			if (sym_set_string_value(menu->sym, dialog_input_result))
738 				return;
739 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
740 			break;
741 		case 1:
742 			show_help(menu);
743 			break;
744 		case KEY_ESC:
745 			return;
746 		}
747 	}
748 }
749 
750 static void conf_load(void)
751 {
752 
753 	while (1) {
754 		int res;
755 		dialog_clear();
756 		res = dialog_inputbox(NULL, load_config_text,
757 				      11, 55, filename);
758 		switch(res) {
759 		case 0:
760 			if (!dialog_input_result[0])
761 				return;
762 			if (!conf_read(dialog_input_result)) {
763 				set_config_filename(dialog_input_result);
764 				sym_set_change_count(1);
765 				return;
766 			}
767 			show_textbox(NULL, _("File does not exist!"), 5, 38);
768 			break;
769 		case 1:
770 			show_helptext(_("Load Alternate Configuration"), load_config_help);
771 			break;
772 		case KEY_ESC:
773 			return;
774 		}
775 	}
776 }
777 
778 static void conf_save(void)
779 {
780 	while (1) {
781 		int res;
782 		dialog_clear();
783 		res = dialog_inputbox(NULL, save_config_text,
784 				      11, 55, filename);
785 		switch(res) {
786 		case 0:
787 			if (!dialog_input_result[0])
788 				return;
789 			if (!conf_write(dialog_input_result)) {
790 				set_config_filename(dialog_input_result);
791 				return;
792 			}
793 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
794 			break;
795 		case 1:
796 			show_helptext(_("Save Alternate Configuration"), save_config_help);
797 			break;
798 		case KEY_ESC:
799 			return;
800 		}
801 	}
802 }
803 
804 static int handle_exit(void)
805 {
806 	int res;
807 
808 	dialog_clear();
809 	if (conf_get_changed())
810 		res = dialog_yesno(NULL,
811 				   _("Do you wish to save your new configuration ?\n"
812 				     "<ESC><ESC> to continue."),
813 				   6, 60);
814 	else
815 		res = -1;
816 
817 	end_dialog(saved_x, saved_y);
818 
819 	switch (res) {
820 	case 0:
821 		if (conf_write(filename)) {
822 			fprintf(stderr, _("\n\n"
823 					  "Error while writing of the configuration.\n"
824 					  "Your configuration changes were NOT saved."
825 					  "\n\n"));
826 			return 1;
827 		}
828 		/* fall through */
829 	case -1:
830 		printf(_("\n\n"
831 			 "*** End of the configuration.\n"
832 			 "*** Execute 'make' to start the build or try 'make help'."
833 			 "\n\n"));
834 		res = 0;
835 		break;
836 	default:
837 		fprintf(stderr, _("\n\n"
838 				  "Your configuration changes were NOT saved."
839 				  "\n\n"));
840 		if (res != KEY_ESC)
841 			res = 0;
842 	}
843 
844 	return res;
845 }
846 
847 static void sig_handler(int signo)
848 {
849 	exit(handle_exit());
850 }
851 
852 int main(int ac, char **av)
853 {
854 	char *mode;
855 	int res;
856 
857 	setlocale(LC_ALL, "");
858 	bindtextdomain(PACKAGE, LOCALEDIR);
859 	textdomain(PACKAGE);
860 
861 	signal(SIGINT, sig_handler);
862 
863 	conf_parse(av[1]);
864 	conf_read(NULL);
865 
866 	mode = getenv("MENUCONFIG_MODE");
867 	if (mode) {
868 		if (!strcasecmp(mode, "single_menu"))
869 			single_menu_mode = 1;
870 	}
871 
872 	if (init_dialog(NULL)) {
873 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
874 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
875 		return 1;
876 	}
877 
878 	set_config_filename(conf_get_configname());
879 	do {
880 		conf(&rootmenu);
881 		res = handle_exit();
882 	} while (res == KEY_ESC);
883 
884 	return res;
885 }
886 
887