kconfig/mconf.c
author "Yann E. MORIN" <yann.morin.1998@free.fr>
Tue Jul 17 22:39:53 2012 +0200 (2012-07-17)
branch1.15
changeset 3009 172b72d597f9
parent 2448 a103abae1560
permissions -rw-r--r--
1.15: update version to 1.15.3

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@free.fr>
     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 "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 <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 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, 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 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 void show_textbox(const char *title, const char *text, int r, int c);
   283 static void show_helptext(const char *title, const char *text);
   284 static void show_help(struct menu *menu);
   285 
   286 static char filename[PATH_MAX+1];
   287 static void set_config_filename(const char *config_filename)
   288 {
   289 	static char menu_backtitle[PATH_MAX+128];
   290 	int size;
   291 
   292 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
   293 	                "%s - %s", config_filename, rootmenu.prompt->text);
   294 	if (size >= sizeof(menu_backtitle))
   295 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
   296 	set_dialog_backtitle(menu_backtitle);
   297 
   298 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
   299 	if (size >= sizeof(filename))
   300 		filename[sizeof(filename)-1] = '\0';
   301 }
   302 
   303 
   304 static void search_conf(void)
   305 {
   306 	struct symbol **sym_arr;
   307 	struct gstr res;
   308 	char *dialog_input;
   309 	int dres;
   310 again:
   311 	dialog_clear();
   312 	dres = dialog_inputbox(_("Search Configuration Parameter"),
   313 			      _("Enter " CONFIG_ " (sub)string to search for "
   314 				"(with or without \"" CONFIG_ "\")"),
   315 			      10, 75, "");
   316 	switch (dres) {
   317 	case 0:
   318 		break;
   319 	case 1:
   320 		show_helptext(_("Search Configuration"), search_help);
   321 		goto again;
   322 	default:
   323 		return;
   324 	}
   325 
   326 	/* strip the prefix if necessary */
   327 	dialog_input = dialog_input_result;
   328 	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
   329 		dialog_input += strlen(CONFIG_);
   330 
   331 	sym_arr = sym_re_search(dialog_input);
   332 	res = get_relations_str(sym_arr);
   333 	free(sym_arr);
   334 	show_textbox(_("Search Results"), str_get(&res), 0, 0);
   335 	str_free(&res);
   336 }
   337 
   338 static void build_conf(struct menu *menu)
   339 {
   340 	struct symbol *sym;
   341 	struct property *prop;
   342 	struct menu *child;
   343 	int type, tmp, doint = 2;
   344 	tristate val;
   345 	char ch;
   346 	bool visible;
   347 
   348 	/*
   349 	 * note: menu_is_visible() has side effect that it will
   350 	 * recalc the value of the symbol.
   351 	 */
   352 	visible = menu_is_visible(menu);
   353 	if (show_all_options && !menu_has_prompt(menu))
   354 		return;
   355 	else if (!show_all_options && !visible)
   356 		return;
   357 
   358 	sym = menu->sym;
   359 	prop = menu->prompt;
   360 	if (!sym) {
   361 		if (prop && menu != current_menu) {
   362 			const char *prompt = menu_get_prompt(menu);
   363 			switch (prop->type) {
   364 			case P_MENU:
   365 				child_count++;
   366 				prompt = _(prompt);
   367 				if (single_menu_mode) {
   368 					item_make("%s%*c%s",
   369 						  menu->data ? "-->" : "++>",
   370 						  indent + 1, ' ', prompt);
   371 				} else
   372 					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
   373 
   374 				item_set_tag('m');
   375 				item_set_data(menu);
   376 				if (single_menu_mode && menu->data)
   377 					goto conf_childs;
   378 				return;
   379 			case P_COMMENT:
   380 				if (prompt) {
   381 					child_count++;
   382 					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
   383 					item_set_tag(':');
   384 					item_set_data(menu);
   385 				}
   386 				break;
   387 			default:
   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 			}
   395 		} else
   396 			doint = 0;
   397 		goto conf_childs;
   398 	}
   399 
   400 	type = sym_get_type(sym);
   401 	if (sym_is_choice(sym)) {
   402 		struct symbol *def_sym = sym_get_choice_value(sym);
   403 		struct menu *def_menu = NULL;
   404 
   405 		child_count++;
   406 		for (child = menu->list; child; child = child->next) {
   407 			if (menu_is_visible(child) && child->sym == def_sym)
   408 				def_menu = child;
   409 		}
   410 
   411 		val = sym_get_tristate_value(sym);
   412 		if (sym_is_changable(sym)) {
   413 			switch (type) {
   414 			case S_BOOLEAN:
   415 				item_make("[%c]", val == no ? ' ' : '*');
   416 				break;
   417 			case S_TRISTATE:
   418 				switch (val) {
   419 				case yes: ch = '*'; break;
   420 				case mod: ch = 'M'; break;
   421 				default:  ch = ' '; break;
   422 				}
   423 				item_make("<%c>", ch);
   424 				break;
   425 			}
   426 			item_set_tag('t');
   427 			item_set_data(menu);
   428 		} else {
   429 			item_make("   ");
   430 			item_set_tag(def_menu ? 't' : ':');
   431 			item_set_data(menu);
   432 		}
   433 
   434 		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
   435 		if (val == yes) {
   436 			if (def_menu) {
   437 				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
   438 				item_add_str("  --->");
   439 				if (def_menu->list) {
   440 					indent += 2;
   441 					build_conf(def_menu);
   442 					indent -= 2;
   443 				}
   444 			}
   445 			return;
   446 		}
   447 	} else {
   448 		if (menu == current_menu) {
   449 			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
   450 			item_set_tag(':');
   451 			item_set_data(menu);
   452 			goto conf_childs;
   453 		}
   454 		child_count++;
   455 		val = sym_get_tristate_value(sym);
   456 		if (sym_is_choice_value(sym) && val == yes) {
   457 			item_make("   ");
   458 			item_set_tag(':');
   459 			item_set_data(menu);
   460 		} else {
   461 			switch (type) {
   462 			case S_BOOLEAN:
   463 				if (sym_is_changable(sym))
   464 					item_make("[%c]", val == no ? ' ' : '*');
   465 				else
   466 					item_make("-%c-", val == no ? ' ' : '*');
   467 				item_set_tag('t');
   468 				item_set_data(menu);
   469 				break;
   470 			case S_TRISTATE:
   471 				switch (val) {
   472 				case yes: ch = '*'; break;
   473 				case mod: ch = 'M'; break;
   474 				default:  ch = ' '; break;
   475 				}
   476 				if (sym_is_changable(sym)) {
   477 					if (sym->rev_dep.tri == mod)
   478 						item_make("{%c}", ch);
   479 					else
   480 						item_make("<%c>", ch);
   481 				} else
   482 					item_make("-%c-", ch);
   483 				item_set_tag('t');
   484 				item_set_data(menu);
   485 				break;
   486 			default:
   487 				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
   488 				item_make("(%s)", sym_get_string_value(sym));
   489 				tmp = indent - tmp + 4;
   490 				if (tmp < 0)
   491 					tmp = 0;
   492 				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
   493 					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
   494 					     "" : _(" (NEW)"));
   495 				item_set_tag('s');
   496 				item_set_data(menu);
   497 				goto conf_childs;
   498 			}
   499 		}
   500 		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
   501 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
   502 			  "" : _(" (NEW)"));
   503 		if (menu->prompt->type == P_MENU) {
   504 			item_add_str("  --->");
   505 			return;
   506 		}
   507 	}
   508 
   509 conf_childs:
   510 	indent += doint;
   511 	for (child = menu->list; child; child = child->next)
   512 		build_conf(child);
   513 	indent -= doint;
   514 }
   515 
   516 static void conf(struct menu *menu)
   517 {
   518 	struct menu *submenu;
   519 	const char *prompt = menu_get_prompt(menu);
   520 	struct symbol *sym;
   521 	struct menu *active_menu = NULL;
   522 	int res;
   523 	int s_scroll = 0;
   524 
   525 	while (1) {
   526 		item_reset();
   527 		current_menu = menu;
   528 		build_conf(menu);
   529 		if (!child_count)
   530 			break;
   531 		if (menu == &rootmenu) {
   532 			item_make("--- ");
   533 			item_set_tag(':');
   534 			item_make(_("    Load an Alternate Configuration File"));
   535 			item_set_tag('L');
   536 			item_make(_("    Save an Alternate Configuration File"));
   537 			item_set_tag('S');
   538 		}
   539 		dialog_clear();
   540 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
   541 				  _(menu_instructions),
   542 				  active_menu, &s_scroll);
   543 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
   544 			break;
   545 		if (!item_activate_selected())
   546 			continue;
   547 		if (!item_tag())
   548 			continue;
   549 
   550 		submenu = item_data();
   551 		active_menu = item_data();
   552 		if (submenu)
   553 			sym = submenu->sym;
   554 		else
   555 			sym = NULL;
   556 
   557 		switch (res) {
   558 		case 0:
   559 			switch (item_tag()) {
   560 			case 'm':
   561 				if (single_menu_mode)
   562 					submenu->data = (void *) (long) !submenu->data;
   563 				else
   564 					conf(submenu);
   565 				break;
   566 			case 't':
   567 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
   568 					conf_choice(submenu);
   569 				else if (submenu->prompt->type == P_MENU)
   570 					conf(submenu);
   571 				break;
   572 			case 's':
   573 				conf_string(submenu);
   574 				break;
   575 			case 'L':
   576 				conf_load();
   577 				break;
   578 			case 'S':
   579 				conf_save();
   580 				break;
   581 			}
   582 			break;
   583 		case 2:
   584 			if (sym)
   585 				show_help(submenu);
   586 			else
   587 				show_helptext(_("README"), _(mconf_readme));
   588 			break;
   589 		case 3:
   590 			if (item_is_tag('t')) {
   591 				if (sym_set_tristate_value(sym, yes))
   592 					break;
   593 				if (sym_set_tristate_value(sym, mod))
   594 					show_textbox(NULL, setmod_text, 6, 74);
   595 			}
   596 			break;
   597 		case 4:
   598 			if (item_is_tag('t'))
   599 				sym_set_tristate_value(sym, no);
   600 			break;
   601 		case 5:
   602 			if (item_is_tag('t'))
   603 				sym_set_tristate_value(sym, mod);
   604 			break;
   605 		case 6:
   606 			if (item_is_tag('t'))
   607 				sym_toggle_tristate_value(sym);
   608 			else if (item_is_tag('m'))
   609 				conf(submenu);
   610 			break;
   611 		case 7:
   612 			search_conf();
   613 			break;
   614 		case 8:
   615 			show_all_options = !show_all_options;
   616 			break;
   617 		}
   618 	}
   619 }
   620 
   621 static void show_textbox(const char *title, const char *text, int r, int c)
   622 {
   623 	dialog_clear();
   624 	dialog_textbox(title, text, r, c);
   625 }
   626 
   627 static void show_helptext(const char *title, const char *text)
   628 {
   629 	show_textbox(title, text, 0, 0);
   630 }
   631 
   632 static void show_help(struct menu *menu)
   633 {
   634 	struct gstr help = str_new();
   635 
   636 	help.max_width = getmaxx(stdscr) - 10;
   637 	menu_get_ext_help(menu, &help);
   638 
   639 	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
   640 	str_free(&help);
   641 }
   642 
   643 static void conf_choice(struct menu *menu)
   644 {
   645 	const char *prompt = _(menu_get_prompt(menu));
   646 	struct menu *child;
   647 	struct symbol *active;
   648 
   649 	active = sym_get_choice_value(menu->sym);
   650 	while (1) {
   651 		int res;
   652 		int selected;
   653 		item_reset();
   654 
   655 		current_menu = menu;
   656 		for (child = menu->list; child; child = child->next) {
   657 			if (!menu_is_visible(child))
   658 				continue;
   659 			if (child->sym)
   660 				item_make("%s", _(menu_get_prompt(child)));
   661 			else {
   662 				item_make("*** %s ***", _(menu_get_prompt(child)));
   663 				item_set_tag(':');
   664 			}
   665 			item_set_data(child);
   666 			if (child->sym == active)
   667 				item_set_selected(1);
   668 			if (child->sym == sym_get_choice_value(menu->sym))
   669 				item_set_tag('X');
   670 		}
   671 		dialog_clear();
   672 		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
   673 					_(radiolist_instructions),
   674 					 15, 70, 6);
   675 		selected = item_activate_selected();
   676 		switch (res) {
   677 		case 0:
   678 			if (selected) {
   679 				child = item_data();
   680 				if (!child->sym)
   681 					break;
   682 
   683 				sym_set_tristate_value(child->sym, yes);
   684 			}
   685 			return;
   686 		case 1:
   687 			if (selected) {
   688 				child = item_data();
   689 				show_help(child);
   690 				active = child->sym;
   691 			} else
   692 				show_help(menu);
   693 			break;
   694 		case KEY_ESC:
   695 			return;
   696 		case -ERRDISPLAYTOOSMALL:
   697 			return;
   698 		}
   699 	}
   700 }
   701 
   702 static void conf_string(struct menu *menu)
   703 {
   704 	const char *prompt = menu_get_prompt(menu);
   705 
   706 	while (1) {
   707 		int res;
   708 		const char *heading;
   709 
   710 		switch (sym_get_type(menu->sym)) {
   711 		case S_INT:
   712 			heading = _(inputbox_instructions_int);
   713 			break;
   714 		case S_HEX:
   715 			heading = _(inputbox_instructions_hex);
   716 			break;
   717 		case S_STRING:
   718 			heading = _(inputbox_instructions_string);
   719 			break;
   720 		default:
   721 			heading = _("Internal mconf error!");
   722 		}
   723 		dialog_clear();
   724 		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
   725 				      heading, 10, 75,
   726 				      sym_get_string_value(menu->sym));
   727 		switch (res) {
   728 		case 0:
   729 			if (sym_set_string_value(menu->sym, dialog_input_result))
   730 				return;
   731 			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
   732 			break;
   733 		case 1:
   734 			show_help(menu);
   735 			break;
   736 		case KEY_ESC:
   737 			return;
   738 		}
   739 	}
   740 }
   741 
   742 static void conf_load(void)
   743 {
   744 
   745 	while (1) {
   746 		int res;
   747 		dialog_clear();
   748 		res = dialog_inputbox(NULL, load_config_text,
   749 				      11, 55, filename);
   750 		switch(res) {
   751 		case 0:
   752 			if (!dialog_input_result[0])
   753 				return;
   754 			if (!conf_read(dialog_input_result)) {
   755 				set_config_filename(dialog_input_result);
   756 				sym_set_change_count(1);
   757 				return;
   758 			}
   759 			show_textbox(NULL, _("File does not exist!"), 5, 38);
   760 			break;
   761 		case 1:
   762 			show_helptext(_("Load Alternate Configuration"), load_config_help);
   763 			break;
   764 		case KEY_ESC:
   765 			return;
   766 		}
   767 	}
   768 }
   769 
   770 static void conf_save(void)
   771 {
   772 	while (1) {
   773 		int res;
   774 		dialog_clear();
   775 		res = dialog_inputbox(NULL, save_config_text,
   776 				      11, 55, filename);
   777 		switch(res) {
   778 		case 0:
   779 			if (!dialog_input_result[0])
   780 				return;
   781 			if (!conf_write(dialog_input_result)) {
   782 				set_config_filename(dialog_input_result);
   783 				return;
   784 			}
   785 			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
   786 			break;
   787 		case 1:
   788 			show_helptext(_("Save Alternate Configuration"), save_config_help);
   789 			break;
   790 		case KEY_ESC:
   791 			return;
   792 		}
   793 	}
   794 }
   795 
   796 int main(int ac, char **av)
   797 {
   798 	int saved_x, saved_y;
   799 	char *mode;
   800 	int res;
   801 
   802 	setlocale(LC_ALL, "");
   803 	bindtextdomain(PACKAGE, LOCALEDIR);
   804 	textdomain(PACKAGE);
   805 
   806 	conf_parse(av[1]);
   807 	conf_read(NULL);
   808 
   809 	mode = getenv("MENUCONFIG_MODE");
   810 	if (mode) {
   811 		if (!strcasecmp(mode, "single_menu"))
   812 			single_menu_mode = 1;
   813 	}
   814 
   815 	initscr();
   816 
   817 	getyx(stdscr, saved_y, saved_x);
   818 	if (init_dialog(NULL)) {
   819 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
   820 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
   821 		return 1;
   822 	}
   823 
   824 	set_config_filename(conf_get_configname());
   825 	do {
   826 		conf(&rootmenu);
   827 		dialog_clear();
   828 		if (conf_get_changed())
   829 			res = dialog_yesno(NULL,
   830 					   _("Do you wish to save your "
   831 					     "new configuration?\n"
   832 					     "<ESC><ESC> to continue."),
   833 					   6, 60);
   834 		else
   835 			res = -1;
   836 	} while (res == KEY_ESC);
   837 	end_dialog(saved_x, saved_y);
   838 
   839 	switch (res) {
   840 	case 0:
   841 		if (conf_write(filename)) {
   842 			fprintf(stderr, _("\n\n"
   843 				"Error while writing of the configuration.\n"
   844 				"Your configuration changes were NOT saved."
   845 				"\n\n"));
   846 			return 1;
   847 		}
   848 	case -1:
   849 		break;
   850 	default:
   851 		fprintf(stderr, _("\n\n"
   852 			"Your configuration changes were NOT saved."
   853 			"\n\n"));
   854 	}
   855 
   856 	return 0;
   857 }
   858