xref: /openbmc/linux/scripts/kconfig/mconf.c (revision 5e609add)
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 	"Type  : tristate\n"
240 	"Prompt: Foo bus is used to drive the bar HW\n"
241 	"  Defined at drivers/pci/Kconfig:47\n"
242 	"  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
243 	"  Location:\n"
244 	"    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
245 	"      -> PCI support (PCI [=y])\n"
246 	"(1)     -> PCI access mode (<choice> [=y])\n"
247 	"  Selects: LIBCRC32\n"
248 	"  Selected by: BAR\n"
249 	"-----------------------------------------------------------------\n"
250 	"o The line 'Type:' shows the type of the configuration option for\n"
251 	"  this symbol (boolean, tristate, string, ...)\n"
252 	"o The line 'Prompt:' shows the text used in the menu structure for\n"
253 	"  this symbol\n"
254 	"o The 'Defined at' line tell at what file / line number the symbol\n"
255 	"  is defined\n"
256 	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
257 	"  this symbol to be visible in the menu (selectable)\n"
258 	"o The 'Location:' lines tell where in the menu structure this symbol\n"
259 	"  is located\n"
260 	"    A location followed by a [=y] indicates that this is a\n"
261 	"    selectable menu item - and the current value is displayed inside\n"
262 	"    brackets.\n"
263 	"    Press the key in the (#) prefix to jump directly to that\n"
264 	"    location. You will be returned to the current search results\n"
265 	"    after exiting this new menu.\n"
266 	"o The 'Selects:' line tell what symbol will be automatically\n"
267 	"  selected if this symbol is selected (y or m)\n"
268 	"o The 'Selected by' line tell what symbol has selected this symbol\n"
269 	"\n"
270 	"Only relevant lines are shown.\n"
271 	"\n\n"
272 	"Search examples:\n"
273 	"Examples: USB	=> find all symbols containing USB\n"
274 	"          ^USB => find all symbols starting with USB\n"
275 	"          USB$ => find all symbols ending with USB\n"
276 	"\n");
277 
278 static int indent;
279 static struct menu *current_menu;
280 static int child_count;
281 static int single_menu_mode;
282 static int show_all_options;
283 
284 static void conf(struct menu *menu, struct menu *active_menu);
285 static void conf_choice(struct menu *menu);
286 static void conf_string(struct menu *menu);
287 static void conf_load(void);
288 static void conf_save(void);
289 static int show_textbox_ext(const char *title, const char *text, int r, int c,
290 			    int *keys, int *vscroll, int *hscroll);
291 static void show_textbox(const char *title, const char *text, int r, int c);
292 static void show_helptext(const char *title, const char *text);
293 static void show_help(struct menu *menu);
294 
295 static char filename[PATH_MAX+1];
296 static void set_config_filename(const char *config_filename)
297 {
298 	static char menu_backtitle[PATH_MAX+128];
299 	int size;
300 
301 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
302 	                "%s - %s", config_filename, rootmenu.prompt->text);
303 	if (size >= sizeof(menu_backtitle))
304 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
305 	set_dialog_backtitle(menu_backtitle);
306 
307 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
308 	if (size >= sizeof(filename))
309 		filename[sizeof(filename)-1] = '\0';
310 }
311 
312 
313 static void search_conf(void)
314 {
315 	struct symbol **sym_arr;
316 	struct gstr res;
317 	char *dialog_input;
318 	int dres, vscroll = 0, hscroll = 0;
319 	bool again;
320 
321 again:
322 	dialog_clear();
323 	dres = dialog_inputbox(_("Search Configuration Parameter"),
324 			      _("Enter " CONFIG_ " (sub)string to search for "
325 				"(with or without \"" CONFIG_ "\")"),
326 			      10, 75, "");
327 	switch (dres) {
328 	case 0:
329 		break;
330 	case 1:
331 		show_helptext(_("Search Configuration"), search_help);
332 		goto again;
333 	default:
334 		return;
335 	}
336 
337 	/* strip the prefix if necessary */
338 	dialog_input = dialog_input_result;
339 	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
340 		dialog_input += strlen(CONFIG_);
341 
342 	sym_arr = sym_re_search(dialog_input);
343 	do {
344 		struct menu *jumps[JUMP_NB] = {0};
345 		int keys[JUMP_NB + 1] = {0}, i;
346 
347 		res = get_relations_str(sym_arr, jumps);
348 		for (i = 0; i < JUMP_NB && jumps[i]; i++)
349 			keys[i] = '1' + i;
350 		dres = show_textbox_ext(_("Search Results"), str_get(&res), 0,
351 					0, keys, &vscroll, &hscroll);
352 		again = false;
353 		for (i = 0; i < JUMP_NB && jumps[i]; i++)
354 			if (dres == keys[i]) {
355 				conf(jumps[i]->parent, jumps[i]);
356 				again = true;
357 			}
358 		str_free(&res);
359 	} while (again);
360 	free(sym_arr);
361 }
362 
363 static void build_conf(struct menu *menu)
364 {
365 	struct symbol *sym;
366 	struct property *prop;
367 	struct menu *child;
368 	int type, tmp, doint = 2;
369 	tristate val;
370 	char ch;
371 	bool visible;
372 
373 	/*
374 	 * note: menu_is_visible() has side effect that it will
375 	 * recalc the value of the symbol.
376 	 */
377 	visible = menu_is_visible(menu);
378 	if (show_all_options && !menu_has_prompt(menu))
379 		return;
380 	else if (!show_all_options && !visible)
381 		return;
382 
383 	sym = menu->sym;
384 	prop = menu->prompt;
385 	if (!sym) {
386 		if (prop && menu != current_menu) {
387 			const char *prompt = menu_get_prompt(menu);
388 			switch (prop->type) {
389 			case P_MENU:
390 				child_count++;
391 				prompt = _(prompt);
392 				if (single_menu_mode) {
393 					item_make("%s%*c%s",
394 						  menu->data ? "-->" : "++>",
395 						  indent + 1, ' ', prompt);
396 				} else
397 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
398 
399 				item_set_tag('m');
400 				item_set_data(menu);
401 				if (single_menu_mode && menu->data)
402 					goto conf_childs;
403 				return;
404 			case P_COMMENT:
405 				if (prompt) {
406 					child_count++;
407 					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
408 					item_set_tag(':');
409 					item_set_data(menu);
410 				}
411 				break;
412 			default:
413 				if (prompt) {
414 					child_count++;
415 					item_make("---%*c%s", indent + 1, ' ', _(prompt));
416 					item_set_tag(':');
417 					item_set_data(menu);
418 				}
419 			}
420 		} else
421 			doint = 0;
422 		goto conf_childs;
423 	}
424 
425 	type = sym_get_type(sym);
426 	if (sym_is_choice(sym)) {
427 		struct symbol *def_sym = sym_get_choice_value(sym);
428 		struct menu *def_menu = NULL;
429 
430 		child_count++;
431 		for (child = menu->list; child; child = child->next) {
432 			if (menu_is_visible(child) && child->sym == def_sym)
433 				def_menu = child;
434 		}
435 
436 		val = sym_get_tristate_value(sym);
437 		if (sym_is_changable(sym)) {
438 			switch (type) {
439 			case S_BOOLEAN:
440 				item_make("[%c]", val == no ? ' ' : '*');
441 				break;
442 			case S_TRISTATE:
443 				switch (val) {
444 				case yes: ch = '*'; break;
445 				case mod: ch = 'M'; break;
446 				default:  ch = ' '; break;
447 				}
448 				item_make("<%c>", ch);
449 				break;
450 			}
451 			item_set_tag('t');
452 			item_set_data(menu);
453 		} else {
454 			item_make("   ");
455 			item_set_tag(def_menu ? 't' : ':');
456 			item_set_data(menu);
457 		}
458 
459 		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
460 		if (val == yes) {
461 			if (def_menu) {
462 				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
463 				item_add_str("  --->");
464 				if (def_menu->list) {
465 					indent += 2;
466 					build_conf(def_menu);
467 					indent -= 2;
468 				}
469 			}
470 			return;
471 		}
472 	} else {
473 		if (menu == current_menu) {
474 			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
475 			item_set_tag(':');
476 			item_set_data(menu);
477 			goto conf_childs;
478 		}
479 		child_count++;
480 		val = sym_get_tristate_value(sym);
481 		if (sym_is_choice_value(sym) && val == yes) {
482 			item_make("   ");
483 			item_set_tag(':');
484 			item_set_data(menu);
485 		} else {
486 			switch (type) {
487 			case S_BOOLEAN:
488 				if (sym_is_changable(sym))
489 					item_make("[%c]", val == no ? ' ' : '*');
490 				else
491 					item_make("-%c-", val == no ? ' ' : '*');
492 				item_set_tag('t');
493 				item_set_data(menu);
494 				break;
495 			case S_TRISTATE:
496 				switch (val) {
497 				case yes: ch = '*'; break;
498 				case mod: ch = 'M'; break;
499 				default:  ch = ' '; break;
500 				}
501 				if (sym_is_changable(sym)) {
502 					if (sym->rev_dep.tri == mod)
503 						item_make("{%c}", ch);
504 					else
505 						item_make("<%c>", ch);
506 				} else
507 					item_make("-%c-", ch);
508 				item_set_tag('t');
509 				item_set_data(menu);
510 				break;
511 			default:
512 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
513 				item_make("(%s)", sym_get_string_value(sym));
514 				tmp = indent - tmp + 4;
515 				if (tmp < 0)
516 					tmp = 0;
517 				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
518 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
519 					     "" : _(" (NEW)"));
520 				item_set_tag('s');
521 				item_set_data(menu);
522 				goto conf_childs;
523 			}
524 		}
525 		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
526 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
527 			  "" : _(" (NEW)"));
528 		if (menu->prompt->type == P_MENU) {
529 			item_add_str("  --->");
530 			return;
531 		}
532 	}
533 
534 conf_childs:
535 	indent += doint;
536 	for (child = menu->list; child; child = child->next)
537 		build_conf(child);
538 	indent -= doint;
539 }
540 
541 static void conf(struct menu *menu, struct menu *active_menu)
542 {
543 	struct menu *submenu;
544 	const char *prompt = menu_get_prompt(menu);
545 	struct symbol *sym;
546 	int res;
547 	int s_scroll = 0;
548 
549 	while (1) {
550 		item_reset();
551 		current_menu = menu;
552 		build_conf(menu);
553 		if (!child_count)
554 			break;
555 		if (menu == &rootmenu) {
556 			item_make("--- ");
557 			item_set_tag(':');
558 			item_make(_("    Load an Alternate Configuration File"));
559 			item_set_tag('L');
560 			item_make(_("    Save an Alternate Configuration File"));
561 			item_set_tag('S');
562 		}
563 		dialog_clear();
564 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
565 				  _(menu_instructions),
566 				  active_menu, &s_scroll);
567 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
568 			break;
569 		if (!item_activate_selected())
570 			continue;
571 		if (!item_tag())
572 			continue;
573 
574 		submenu = item_data();
575 		active_menu = item_data();
576 		if (submenu)
577 			sym = submenu->sym;
578 		else
579 			sym = NULL;
580 
581 		switch (res) {
582 		case 0:
583 			switch (item_tag()) {
584 			case 'm':
585 				if (single_menu_mode)
586 					submenu->data = (void *) (long) !submenu->data;
587 				else
588 					conf(submenu, NULL);
589 				break;
590 			case 't':
591 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
592 					conf_choice(submenu);
593 				else if (submenu->prompt->type == P_MENU)
594 					conf(submenu, NULL);
595 				break;
596 			case 's':
597 				conf_string(submenu);
598 				break;
599 			case 'L':
600 				conf_load();
601 				break;
602 			case 'S':
603 				conf_save();
604 				break;
605 			}
606 			break;
607 		case 2:
608 			if (sym)
609 				show_help(submenu);
610 			else
611 				show_helptext(_("README"), _(mconf_readme));
612 			break;
613 		case 3:
614 			if (item_is_tag('t')) {
615 				if (sym_set_tristate_value(sym, yes))
616 					break;
617 				if (sym_set_tristate_value(sym, mod))
618 					show_textbox(NULL, setmod_text, 6, 74);
619 			}
620 			break;
621 		case 4:
622 			if (item_is_tag('t'))
623 				sym_set_tristate_value(sym, no);
624 			break;
625 		case 5:
626 			if (item_is_tag('t'))
627 				sym_set_tristate_value(sym, mod);
628 			break;
629 		case 6:
630 			if (item_is_tag('t'))
631 				sym_toggle_tristate_value(sym);
632 			else if (item_is_tag('m'))
633 				conf(submenu, NULL);
634 			break;
635 		case 7:
636 			search_conf();
637 			break;
638 		case 8:
639 			show_all_options = !show_all_options;
640 			break;
641 		}
642 	}
643 }
644 
645 static int show_textbox_ext(const char *title, const char *text, int r, int c,
646 			    int *keys, int *vscroll, int *hscroll)
647 {
648 	dialog_clear();
649 	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll);
650 }
651 
652 static void show_textbox(const char *title, const char *text, int r, int c)
653 {
654 	show_textbox_ext(title, text, r, c, (int []) {0}, NULL, NULL);
655 }
656 
657 static void show_helptext(const char *title, const char *text)
658 {
659 	show_textbox(title, text, 0, 0);
660 }
661 
662 static void show_help(struct menu *menu)
663 {
664 	struct gstr help = str_new();
665 
666 	help.max_width = getmaxx(stdscr) - 10;
667 	menu_get_ext_help(menu, &help);
668 
669 	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
670 	str_free(&help);
671 }
672 
673 static void conf_choice(struct menu *menu)
674 {
675 	const char *prompt = _(menu_get_prompt(menu));
676 	struct menu *child;
677 	struct symbol *active;
678 
679 	active = sym_get_choice_value(menu->sym);
680 	while (1) {
681 		int res;
682 		int selected;
683 		item_reset();
684 
685 		current_menu = menu;
686 		for (child = menu->list; child; child = child->next) {
687 			if (!menu_is_visible(child))
688 				continue;
689 			if (child->sym)
690 				item_make("%s", _(menu_get_prompt(child)));
691 			else {
692 				item_make("*** %s ***", _(menu_get_prompt(child)));
693 				item_set_tag(':');
694 			}
695 			item_set_data(child);
696 			if (child->sym == active)
697 				item_set_selected(1);
698 			if (child->sym == sym_get_choice_value(menu->sym))
699 				item_set_tag('X');
700 		}
701 		dialog_clear();
702 		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
703 					_(radiolist_instructions),
704 					 15, 70, 6);
705 		selected = item_activate_selected();
706 		switch (res) {
707 		case 0:
708 			if (selected) {
709 				child = item_data();
710 				if (!child->sym)
711 					break;
712 
713 				sym_set_tristate_value(child->sym, yes);
714 			}
715 			return;
716 		case 1:
717 			if (selected) {
718 				child = item_data();
719 				show_help(child);
720 				active = child->sym;
721 			} else
722 				show_help(menu);
723 			break;
724 		case KEY_ESC:
725 			return;
726 		case -ERRDISPLAYTOOSMALL:
727 			return;
728 		}
729 	}
730 }
731 
732 static void conf_string(struct menu *menu)
733 {
734 	const char *prompt = menu_get_prompt(menu);
735 
736 	while (1) {
737 		int res;
738 		const char *heading;
739 
740 		switch (sym_get_type(menu->sym)) {
741 		case S_INT:
742 			heading = _(inputbox_instructions_int);
743 			break;
744 		case S_HEX:
745 			heading = _(inputbox_instructions_hex);
746 			break;
747 		case S_STRING:
748 			heading = _(inputbox_instructions_string);
749 			break;
750 		default:
751 			heading = _("Internal mconf error!");
752 		}
753 		dialog_clear();
754 		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
755 				      heading, 10, 75,
756 				      sym_get_string_value(menu->sym));
757 		switch (res) {
758 		case 0:
759 			if (sym_set_string_value(menu->sym, dialog_input_result))
760 				return;
761 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
762 			break;
763 		case 1:
764 			show_help(menu);
765 			break;
766 		case KEY_ESC:
767 			return;
768 		}
769 	}
770 }
771 
772 static void conf_load(void)
773 {
774 
775 	while (1) {
776 		int res;
777 		dialog_clear();
778 		res = dialog_inputbox(NULL, load_config_text,
779 				      11, 55, filename);
780 		switch(res) {
781 		case 0:
782 			if (!dialog_input_result[0])
783 				return;
784 			if (!conf_read(dialog_input_result)) {
785 				set_config_filename(dialog_input_result);
786 				sym_set_change_count(1);
787 				return;
788 			}
789 			show_textbox(NULL, _("File does not exist!"), 5, 38);
790 			break;
791 		case 1:
792 			show_helptext(_("Load Alternate Configuration"), load_config_help);
793 			break;
794 		case KEY_ESC:
795 			return;
796 		}
797 	}
798 }
799 
800 static void conf_save(void)
801 {
802 	while (1) {
803 		int res;
804 		dialog_clear();
805 		res = dialog_inputbox(NULL, save_config_text,
806 				      11, 55, filename);
807 		switch(res) {
808 		case 0:
809 			if (!dialog_input_result[0])
810 				return;
811 			if (!conf_write(dialog_input_result)) {
812 				set_config_filename(dialog_input_result);
813 				return;
814 			}
815 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
816 			break;
817 		case 1:
818 			show_helptext(_("Save Alternate Configuration"), save_config_help);
819 			break;
820 		case KEY_ESC:
821 			return;
822 		}
823 	}
824 }
825 
826 static int handle_exit(void)
827 {
828 	int res;
829 
830 	dialog_clear();
831 	if (conf_get_changed())
832 		res = dialog_yesno(NULL,
833 				   _("Do you wish to save your new configuration ?\n"
834 				     "<ESC><ESC> to continue."),
835 				   6, 60);
836 	else
837 		res = -1;
838 
839 	end_dialog(saved_x, saved_y);
840 
841 	switch (res) {
842 	case 0:
843 		if (conf_write(filename)) {
844 			fprintf(stderr, _("\n\n"
845 					  "Error while writing of the configuration.\n"
846 					  "Your configuration changes were NOT saved."
847 					  "\n\n"));
848 			return 1;
849 		}
850 		/* fall through */
851 	case -1:
852 		printf(_("\n\n"
853 			 "*** End of the configuration.\n"
854 			 "*** Execute 'make' to start the build or try 'make help'."
855 			 "\n\n"));
856 		res = 0;
857 		break;
858 	default:
859 		fprintf(stderr, _("\n\n"
860 				  "Your configuration changes were NOT saved."
861 				  "\n\n"));
862 		if (res != KEY_ESC)
863 			res = 0;
864 	}
865 
866 	return res;
867 }
868 
869 static void sig_handler(int signo)
870 {
871 	exit(handle_exit());
872 }
873 
874 int main(int ac, char **av)
875 {
876 	char *mode;
877 	int res;
878 
879 	setlocale(LC_ALL, "");
880 	bindtextdomain(PACKAGE, LOCALEDIR);
881 	textdomain(PACKAGE);
882 
883 	signal(SIGINT, sig_handler);
884 
885 	conf_parse(av[1]);
886 	conf_read(NULL);
887 
888 	mode = getenv("MENUCONFIG_MODE");
889 	if (mode) {
890 		if (!strcasecmp(mode, "single_menu"))
891 			single_menu_mode = 1;
892 	}
893 
894 	if (init_dialog(NULL)) {
895 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
896 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
897 		return 1;
898 	}
899 
900 	set_config_filename(conf_get_configname());
901 	do {
902 		conf(&rootmenu, NULL);
903 		res = handle_exit();
904 	} while (res == KEY_ESC);
905 
906 	return res;
907 }
908 
909