mconf.c 25.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6
/*
 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
 * Released under the terms of the GNU GPL v2.0.
 *
 * Introduced single menu mode (show all sub-menus in one large tree).
 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7 8
 *
 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17
 */

#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
18
#include <signal.h>
L
Linus Torvalds 已提交
19
#include <unistd.h>
20
#include <locale.h>
L
Linus Torvalds 已提交
21 22

#include "lkc.h"
23
#include "lxdialog/dialog.h"
L
Linus Torvalds 已提交
24

25
static const char mconf_readme[] = N_(
L
Linus Torvalds 已提交
26 27
"Overview\n"
"--------\n"
28 29 30
"This interface let you select features and parameters for the build.\n"
"Features can either be built-in, modularized, or ignored. Parameters\n"
"must be entered in as decimal or hexadecimal numbers or text.\n"
L
Linus Torvalds 已提交
31
"\n"
32 33 34 35 36 37 38
"Menu items beginning with following braces represent features that\n"
"  [ ] can be built in or removed\n"
"  < > can be built in, modularized or removed\n"
"  { } can be built in or modularized (selected by other feature)\n"
"  - - are selected by other feature,\n"
"while *, M or whitespace inside braces means to build in, build as\n"
"a module or to exclude the feature respectively.\n"
L
Linus Torvalds 已提交
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
"\n"
"To change any of these features, highlight it with the cursor\n"
"keys and press <Y> to build it in, <M> to make it a module or\n"
"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
"through the available options (ie. Y->N->M->Y).\n"
"\n"
"Some additional keyboard hints:\n"
"\n"
"Menus\n"
"----------\n"
"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
"   you wish to change or submenu wish to select and press <Enter>.\n"
"   Submenus are designated by \"--->\".\n"
"\n"
"   Shortcut: Press the option's highlighted letter (hotkey).\n"
"             Pressing a hotkey more than once will sequence\n"
"             through all visible items which use that hotkey.\n"
"\n"
"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
"   unseen options into view.\n"
"\n"
"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
"   and press <ENTER>.\n"
"\n"
"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
"             using those letters.  You may press a single <ESC>, but\n"
"             there is a delayed response which you may find annoying.\n"
"\n"
"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
68
"   <Exit> and <Help>.\n"
L
Linus Torvalds 已提交
69 70
"\n"
"o  To get help with an item, use the cursor keys to highlight <Help>\n"
71
"   and press <ENTER>.\n"
L
Linus Torvalds 已提交
72 73 74
"\n"
"   Shortcut: Press <H> or <?>.\n"
"\n"
L
Li Zefan 已提交
75
"o  To toggle the display of hidden options, press <Z>.\n"
76
"\n"
L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
"\n"
"Radiolists  (Choice lists)\n"
"-----------\n"
"o  Use the cursor keys to select the option you wish to set and press\n"
"   <S> or the <SPACE BAR>.\n"
"\n"
"   Shortcut: Press the first letter of the option you wish to set then\n"
"             press <S> or <SPACE BAR>.\n"
"\n"
"o  To see available help for the item, use the cursor keys to highlight\n"
"   <Help> and Press <ENTER>.\n"
"\n"
"   Shortcut: Press <H> or <?>.\n"
"\n"
"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
"   <Help>\n"
"\n"
"\n"
"Data Entry\n"
"-----------\n"
"o  Enter the requested information and press <ENTER>\n"
"   If you are entering hexadecimal values, it is not necessary to\n"
"   add the '0x' prefix to the entry.\n"
"\n"
"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
"   and press <ENTER>.  You can try <TAB><H> as well.\n"
"\n"
"\n"
"Text Box    (Help Window)\n"
"--------\n"
"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
108 109
"   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for \n"
"   those who are familiar with less and lynx.\n"
L
Linus Torvalds 已提交
110
"\n"
111
"o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
L
Linus Torvalds 已提交
112 113 114 115 116 117
"\n"
"\n"
"Alternate Configuration Files\n"
"-----------------------------\n"
"Menuconfig supports the use of alternate configuration files for\n"
"those who, for various reasons, find it necessary to switch\n"
118
"between different configurations.\n"
L
Linus Torvalds 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
"\n"
"At the end of the main menu you will find two options.  One is\n"
"for saving the current configuration to a file of your choosing.\n"
"The other option is for loading a previously saved alternate\n"
"configuration.\n"
"\n"
"Even if you don't use alternate configuration files, but you\n"
"find during a Menuconfig session that you have completely messed\n"
"up your settings, you may use the \"Load Alternate...\" option to\n"
"restore your previously saved settings from \".config\" without\n"
"restarting Menuconfig.\n"
"\n"
"Other information\n"
"-----------------\n"
"If you use Menuconfig in an XTERM window make sure you have your\n"
"$TERM variable set to point to a xterm definition which supports color.\n"
"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
"display correctly in a RXVT window because rxvt displays only one\n"
"intensity of color, bright.\n"
"\n"
"Menuconfig will display larger menus on screens or xterms which are\n"
"set to display more than the standard 25 row by 80 column geometry.\n"
"In order for this to work, the \"stty size\" command must be able to\n"
"display the screen's current row and column geometry.  I STRONGLY\n"
"RECOMMEND that you make sure you do NOT have the shell variables\n"
"LINES and COLUMNS exported into your environment.  Some distributions\n"
"export those variables via /etc/profile.  Some ncurses programs can\n"
"become confused when those variables (LINES & COLUMNS) don't reflect\n"
"the true screen size.\n"
"\n"
"Optional personality available\n"
"------------------------------\n"
151 152 153
"If you prefer to have all of the options listed in a single menu, rather\n"
"than the default multimenu hierarchy, run the menuconfig with\n"
"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
L
Linus Torvalds 已提交
154 155 156 157 158 159 160 161
"\n"
"make MENUCONFIG_MODE=single_menu menuconfig\n"
"\n"
"<Enter> will then unroll the appropriate category, or enfold it if it\n"
"is already unrolled.\n"
"\n"
"Note that this mode can eventually be a little more CPU expensive\n"
"(especially with a larger number of unrolled categories) than the\n"
162 163 164 165 166 167 168 169 170 171 172 173
"default mode.\n"
"\n"
"Different color themes available\n"
"--------------------------------\n"
"It is possible to select different color themes using the variable\n"
"MENUCONFIG_COLOR. To select a theme use:\n"
"\n"
"make MENUCONFIG_COLOR=<theme> menuconfig\n"
"\n"
"Available themes are\n"
" mono       => selects colors suitable for monochrome displays\n"
" blackbg    => selects a color scheme with black background\n"
174 175
" classic    => theme with blue background. The classic look\n"
" bluetitle  => a LCD friendly version of classic. (default)\n"
176
"\n"),
177
menu_instructions[] = N_(
L
Linus Torvalds 已提交
178 179 180 181 182
	"Arrow keys navigate the menu.  "
	"<Enter> selects submenus --->.  "
	"Highlighted letters are hotkeys.  "
	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
183 184
	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
radiolist_instructions[] = N_(
L
Linus Torvalds 已提交
185 186 187
	"Use the arrow keys to navigate this window or "
	"press the hotkey of the item you wish to select "
	"followed by the <SPACE BAR>. "
188 189
	"Press <?> for additional information about this option."),
inputbox_instructions_int[] = N_(
L
Linus Torvalds 已提交
190 191
	"Please enter a decimal value. "
	"Fractions will not be accepted.  "
192 193
	"Use the <TAB> key to move from the input field to the buttons below it."),
inputbox_instructions_hex[] = N_(
L
Linus Torvalds 已提交
194
	"Please enter a hexadecimal value. "
195 196
	"Use the <TAB> key to move from the input field to the buttons below it."),
inputbox_instructions_string[] = N_(
L
Linus Torvalds 已提交
197
	"Please enter a string value. "
198 199
	"Use the <TAB> key to move from the input field to the buttons below it."),
setmod_text[] = N_(
L
Linus Torvalds 已提交
200
	"This feature depends on another which has been configured as a module.\n"
201 202
	"As a result, this feature will be built as a module."),
load_config_text[] = N_(
L
Linus Torvalds 已提交
203 204
	"Enter the name of the configuration file you wish to load.  "
	"Accept the name shown to restore the configuration you "
205 206
	"last retrieved.  Leave blank to abort."),
load_config_help[] = N_(
L
Linus Torvalds 已提交
207
	"\n"
208
	"For various reasons, one may wish to keep several different\n"
L
Linus Torvalds 已提交
209 210 211
	"configurations available on a single machine.\n"
	"\n"
	"If you have saved a previous configuration in a file other than the\n"
212 213
	"default one, entering its name here will allow you to modify that\n"
	"configuration.\n"
L
Linus Torvalds 已提交
214 215
	"\n"
	"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_(
L
Linus Torvalds 已提交
218
	"Enter a filename to which this configuration should be saved "
219 220
	"as an alternate.  Leave blank to abort."),
save_config_help[] = N_(
L
Linus Torvalds 已提交
221
	"\n"
222 223
	"For various reasons, one may wish to keep different configurations\n"
	"available on a single machine.\n"
L
Linus Torvalds 已提交
224 225 226 227 228 229
	"\n"
	"Entering a file name here will allow you to later retrieve, modify\n"
	"and use the current configuration as an alternate to whatever\n"
	"configuration options you have selected at that time.\n"
	"\n"
	"If you are uncertain what all this means then you should probably\n"
230 231
	"leave this blank.\n"),
search_help[] = N_(
L
Linus Torvalds 已提交
232
	"\n"
233
	"Search for symbols and display their relations.\n"
234
	"Regular expressions are allowed.\n"
L
Linus Torvalds 已提交
235 236 237 238
	"Example: search for \"^FOO\"\n"
	"Result:\n"
	"-----------------------------------------------------------------\n"
	"Symbol: FOO [=m]\n"
239
	"Type  : tristate\n"
L
Linus Torvalds 已提交
240
	"Prompt: Foo bus is used to drive the bar HW\n"
241 242 243 244 245 246 247 248
	"  Defined at drivers/pci/Kconfig:47\n"
	"  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
	"  Location:\n"
	"    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
	"      -> PCI support (PCI [=y])\n"
	"(1)     -> PCI access mode (<choice> [=y])\n"
	"  Selects: LIBCRC32\n"
	"  Selected by: BAR\n"
L
Linus Torvalds 已提交
249
	"-----------------------------------------------------------------\n"
250 251
	"o The line 'Type:' shows the type of the configuration option for\n"
	"  this symbol (boolean, tristate, string, ...)\n"
L
Linus Torvalds 已提交
252
	"o The line 'Prompt:' shows the text used in the menu structure for\n"
253
	"  this symbol\n"
L
Linus Torvalds 已提交
254 255 256 257 258 259
	"o The 'Defined at' line tell at what file / line number the symbol\n"
	"  is defined\n"
	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
	"  this symbol to be visible in the menu (selectable)\n"
	"o The 'Location:' lines tell where in the menu structure this symbol\n"
	"  is located\n"
260 261 262 263 264 265
	"    A location followed by a [=y] indicates that this is a\n"
	"    selectable menu item - and the current value is displayed inside\n"
	"    brackets.\n"
	"    Press the key in the (#) prefix to jump directly to that\n"
	"    location. You will be returned to the current search results\n"
	"    after exiting this new menu.\n"
L
Linus Torvalds 已提交
266 267 268 269 270 271 272
	"o The 'Selects:' line tell what symbol will be automatically\n"
	"  selected if this symbol is selected (y or m)\n"
	"o The 'Selected by' line tell what symbol has selected this symbol\n"
	"\n"
	"Only relevant lines are shown.\n"
	"\n\n"
	"Search examples:\n"
273 274 275
	"Examples: USB	=> find all symbols containing USB\n"
	"          ^USB => find all symbols starting with USB\n"
	"          USB$ => find all symbols ending with USB\n"
276
	"\n");
L
Linus Torvalds 已提交
277 278 279 280 281

static int indent;
static struct menu *current_menu;
static int child_count;
static int single_menu_mode;
282
static int show_all_options;
W
Wang YanQing 已提交
283
static int save_and_exit;
L
Linus Torvalds 已提交
284

285
static void conf(struct menu *menu, struct menu *active_menu);
L
Linus Torvalds 已提交
286 287 288 289
static void conf_choice(struct menu *menu);
static void conf_string(struct menu *menu);
static void conf_load(void);
static void conf_save(void);
290 291 292
static int show_textbox_ext(const char *title, char *text, int r, int c,
			    int *keys, int *vscroll, int *hscroll,
			    update_text_fn update_text, void *data);
L
Linus Torvalds 已提交
293 294 295 296
static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);

297 298 299 300 301 302 303
static char filename[PATH_MAX+1];
static void set_config_filename(const char *config_filename)
{
	static char menu_backtitle[PATH_MAX+128];
	int size;

	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
304
	                "%s - %s", config_filename, rootmenu.prompt->text);
305 306 307 308 309 310 311 312 313 314
	if (size >= sizeof(menu_backtitle))
		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
	set_dialog_backtitle(menu_backtitle);

	size = snprintf(filename, sizeof(filename), "%s", config_filename);
	if (size >= sizeof(filename))
		filename[sizeof(filename)-1] = '\0';
}


315
struct search_data {
316
	struct list_head *head;
317 318 319 320 321 322 323 324 325 326
	struct menu **targets;
	int *keys;
};

static void update_text(char *buf, size_t start, size_t end, void *_data)
{
	struct search_data *data = _data;
	struct jump_key *pos;
	int k = 0;

327
	list_for_each_entry(pos, data->head, entries) {
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
		if (pos->offset >= start && pos->offset < end) {
			char header[4];

			if (k < JUMP_NB) {
				int key = '0' + (pos->index % JUMP_NB) + 1;

				sprintf(header, "(%c)", key);
				data->keys[k] = key;
				data->targets[k] = pos->target;
				k++;
			} else {
				sprintf(header, "   ");
			}

			memcpy(buf + pos->offset, header, sizeof(header) - 1);
		}
	}
	data->keys[k] = 0;
}

L
Linus Torvalds 已提交
348 349 350 351
static void search_conf(void)
{
	struct symbol **sym_arr;
	struct gstr res;
352
	struct gstr title;
353
	char *dialog_input;
354 355 356
	int dres, vscroll = 0, hscroll = 0;
	bool again;

357 358 359 360
	title = str_new();
	str_printf( &title, _("Enter %s (sub)string to search for "
			      "(with or without \"%s\")"), CONFIG_, CONFIG_);

L
Linus Torvalds 已提交
361
again:
362
	dialog_clear();
363
	dres = dialog_inputbox(_("Search Configuration Parameter"),
364
			      str_get(&title),
365 366
			      10, 75, "");
	switch (dres) {
L
Linus Torvalds 已提交
367 368 369
	case 0:
		break;
	case 1:
370
		show_helptext(_("Search Configuration"), search_help);
L
Linus Torvalds 已提交
371 372
		goto again;
	default:
373
		str_free(&title);
L
Linus Torvalds 已提交
374 375 376
		return;
	}

377
	/* strip the prefix if necessary */
378
	dialog_input = dialog_input_result;
379 380
	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
		dialog_input += strlen(CONFIG_);
381 382

	sym_arr = sym_re_search(dialog_input);
383
	do {
384
		LIST_HEAD(head);
385 386 387 388 389 390 391
		struct menu *targets[JUMP_NB];
		int keys[JUMP_NB + 1], i;
		struct search_data data = {
			.head = &head,
			.targets = targets,
			.keys = keys,
		};
392
		struct jump_key *pos, *tmp;
393 394 395 396 397 398

		res = get_relations_str(sym_arr, &head);
		dres = show_textbox_ext(_("Search Results"), (char *)
					str_get(&res), 0, 0, keys, &vscroll,
					&hscroll, &update_text, (void *)
					&data);
399
		again = false;
400
		for (i = 0; i < JUMP_NB && keys[i]; i++)
401
			if (dres == keys[i]) {
402
				conf(targets[i]->parent, targets[i]);
403 404 405
				again = true;
			}
		str_free(&res);
406 407
		list_for_each_entry_safe(pos, tmp, &head, entries)
			free(pos);
408
	} while (again);
L
Linus Torvalds 已提交
409
	free(sym_arr);
410
	str_free(&title);
L
Linus Torvalds 已提交
411 412 413 414 415 416 417 418 419 420
}

static void build_conf(struct menu *menu)
{
	struct symbol *sym;
	struct property *prop;
	struct menu *child;
	int type, tmp, doint = 2;
	tristate val;
	char ch;
421 422 423 424 425 426 427 428 429 430
	bool visible;

	/*
	 * note: menu_is_visible() has side effect that it will
	 * recalc the value of the symbol.
	 */
	visible = menu_is_visible(menu);
	if (show_all_options && !menu_has_prompt(menu))
		return;
	else if (!show_all_options && !visible)
L
Linus Torvalds 已提交
431 432 433 434 435 436 437 438 439 440
		return;

	sym = menu->sym;
	prop = menu->prompt;
	if (!sym) {
		if (prop && menu != current_menu) {
			const char *prompt = menu_get_prompt(menu);
			switch (prop->type) {
			case P_MENU:
				child_count++;
441
				prompt = _(prompt);
L
Linus Torvalds 已提交
442
				if (single_menu_mode) {
443 444 445
					item_make("%s%*c%s",
						  menu->data ? "-->" : "++>",
						  indent + 1, ' ', prompt);
L
Linus Torvalds 已提交
446
				} else
447
					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
L
Linus Torvalds 已提交
448

449 450
				item_set_tag('m');
				item_set_data(menu);
L
Linus Torvalds 已提交
451 452 453
				if (single_menu_mode && menu->data)
					goto conf_childs;
				return;
454 455 456
			case P_COMMENT:
				if (prompt) {
					child_count++;
457
					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
458 459 460 461
					item_set_tag(':');
					item_set_data(menu);
				}
				break;
L
Linus Torvalds 已提交
462 463 464
			default:
				if (prompt) {
					child_count++;
465
					item_make("---%*c%s", indent + 1, ' ', _(prompt));
466 467
					item_set_tag(':');
					item_set_data(menu);
L
Linus Torvalds 已提交
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
				}
			}
		} else
			doint = 0;
		goto conf_childs;
	}

	type = sym_get_type(sym);
	if (sym_is_choice(sym)) {
		struct symbol *def_sym = sym_get_choice_value(sym);
		struct menu *def_menu = NULL;

		child_count++;
		for (child = menu->list; child; child = child->next) {
			if (menu_is_visible(child) && child->sym == def_sym)
				def_menu = child;
		}

		val = sym_get_tristate_value(sym);
		if (sym_is_changable(sym)) {
			switch (type) {
			case S_BOOLEAN:
490
				item_make("[%c]", val == no ? ' ' : '*');
L
Linus Torvalds 已提交
491 492 493 494 495 496 497
				break;
			case S_TRISTATE:
				switch (val) {
				case yes: ch = '*'; break;
				case mod: ch = 'M'; break;
				default:  ch = ' '; break;
				}
498
				item_make("<%c>", ch);
L
Linus Torvalds 已提交
499 500
				break;
			}
501 502
			item_set_tag('t');
			item_set_data(menu);
L
Linus Torvalds 已提交
503
		} else {
504 505 506
			item_make("   ");
			item_set_tag(def_menu ? 't' : ':');
			item_set_data(menu);
L
Linus Torvalds 已提交
507 508
		}

509
		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
L
Linus Torvalds 已提交
510 511
		if (val == yes) {
			if (def_menu) {
512
				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
513
				item_add_str("  --->");
L
Linus Torvalds 已提交
514 515 516 517 518
				if (def_menu->list) {
					indent += 2;
					build_conf(def_menu);
					indent -= 2;
				}
519
			}
L
Linus Torvalds 已提交
520 521 522 523
			return;
		}
	} else {
		if (menu == current_menu) {
524
			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
525 526
			item_set_tag(':');
			item_set_data(menu);
L
Linus Torvalds 已提交
527 528 529 530 531
			goto conf_childs;
		}
		child_count++;
		val = sym_get_tristate_value(sym);
		if (sym_is_choice_value(sym) && val == yes) {
532 533 534
			item_make("   ");
			item_set_tag(':');
			item_set_data(menu);
L
Linus Torvalds 已提交
535 536 537 538
		} else {
			switch (type) {
			case S_BOOLEAN:
				if (sym_is_changable(sym))
539
					item_make("[%c]", val == no ? ' ' : '*');
L
Linus Torvalds 已提交
540
				else
541
					item_make("-%c-", val == no ? ' ' : '*');
542 543
				item_set_tag('t');
				item_set_data(menu);
L
Linus Torvalds 已提交
544 545 546 547 548 549 550
				break;
			case S_TRISTATE:
				switch (val) {
				case yes: ch = '*'; break;
				case mod: ch = 'M'; break;
				default:  ch = ' '; break;
				}
551 552 553 554 555 556 557
				if (sym_is_changable(sym)) {
					if (sym->rev_dep.tri == mod)
						item_make("{%c}", ch);
					else
						item_make("<%c>", ch);
				} else
					item_make("-%c-", ch);
558 559
				item_set_tag('t');
				item_set_data(menu);
L
Linus Torvalds 已提交
560 561
				break;
			default:
562 563
				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
				item_make("(%s)", sym_get_string_value(sym));
L
Linus Torvalds 已提交
564 565 566
				tmp = indent - tmp + 4;
				if (tmp < 0)
					tmp = 0;
567
				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
568
					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
569
					     "" : _(" (NEW)"));
570 571
				item_set_tag('s');
				item_set_data(menu);
L
Linus Torvalds 已提交
572 573 574
				goto conf_childs;
			}
		}
575
		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
576
			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
577
			  "" : _(" (NEW)"));
L
Linus Torvalds 已提交
578
		if (menu->prompt->type == P_MENU) {
579
			item_add_str("  --->");
L
Linus Torvalds 已提交
580 581 582 583 584 585 586 587 588 589 590
			return;
		}
	}

conf_childs:
	indent += doint;
	for (child = menu->list; child; child = child->next)
		build_conf(child);
	indent -= doint;
}

591
static void conf(struct menu *menu, struct menu *active_menu)
L
Linus Torvalds 已提交
592 593 594 595
{
	struct menu *submenu;
	const char *prompt = menu_get_prompt(menu);
	struct symbol *sym;
596 597
	int res;
	int s_scroll = 0;
L
Linus Torvalds 已提交
598 599

	while (1) {
600
		item_reset();
L
Linus Torvalds 已提交
601 602 603 604
		current_menu = menu;
		build_conf(menu);
		if (!child_count)
			break;
605
		dialog_clear();
606
		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
607 608
				  _(menu_instructions),
				  active_menu, &s_scroll);
S
Sam Ravnborg 已提交
609
		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
L
Linus Torvalds 已提交
610
			break;
611 612 613
		if (!item_activate_selected())
			continue;
		if (!item_tag())
L
Linus Torvalds 已提交
614 615
			continue;

616 617
		submenu = item_data();
		active_menu = item_data();
S
Sam Ravnborg 已提交
618 619 620 621
		if (submenu)
			sym = submenu->sym;
		else
			sym = NULL;
L
Linus Torvalds 已提交
622

623
		switch (res) {
L
Linus Torvalds 已提交
624
		case 0:
625
			switch (item_tag()) {
L
Linus Torvalds 已提交
626 627 628 629
			case 'm':
				if (single_menu_mode)
					submenu->data = (void *) (long) !submenu->data;
				else
630
					conf(submenu, NULL);
L
Linus Torvalds 已提交
631 632 633 634 635
				break;
			case 't':
				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
					conf_choice(submenu);
				else if (submenu->prompt->type == P_MENU)
636
					conf(submenu, NULL);
L
Linus Torvalds 已提交
637 638 639 640 641 642 643 644 645 646
				break;
			case 's':
				conf_string(submenu);
				break;
			}
			break;
		case 2:
			if (sym)
				show_help(submenu);
			else
647
				show_helptext(_("README"), _(mconf_readme));
L
Linus Torvalds 已提交
648 649
			break;
		case 3:
W
Wang YanQing 已提交
650 651 652 653 654 655
			conf_save();
			break;
		case 4:
			conf_load();
			break;
		case 5:
656
			if (item_is_tag('t')) {
L
Linus Torvalds 已提交
657 658 659 660 661 662
				if (sym_set_tristate_value(sym, yes))
					break;
				if (sym_set_tristate_value(sym, mod))
					show_textbox(NULL, setmod_text, 6, 74);
			}
			break;
W
Wang YanQing 已提交
663
		case 6:
664
			if (item_is_tag('t'))
L
Linus Torvalds 已提交
665 666
				sym_set_tristate_value(sym, no);
			break;
W
Wang YanQing 已提交
667
		case 7:
668
			if (item_is_tag('t'))
L
Linus Torvalds 已提交
669 670
				sym_set_tristate_value(sym, mod);
			break;
W
Wang YanQing 已提交
671
		case 8:
672
			if (item_is_tag('t'))
L
Linus Torvalds 已提交
673
				sym_toggle_tristate_value(sym);
674
			else if (item_is_tag('m'))
675
				conf(submenu, NULL);
L
Linus Torvalds 已提交
676
			break;
W
Wang YanQing 已提交
677
		case 9:
L
Linus Torvalds 已提交
678 679
			search_conf();
			break;
W
Wang YanQing 已提交
680
		case 10:
681 682
			show_all_options = !show_all_options;
			break;
L
Linus Torvalds 已提交
683 684 685 686
		}
	}
}

687 688 689
static int show_textbox_ext(const char *title, char *text, int r, int c, int
			    *keys, int *vscroll, int *hscroll, update_text_fn
			    update_text, void *data)
L
Linus Torvalds 已提交
690
{
691
	dialog_clear();
692 693
	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
			      update_text, data);
694 695 696 697
}

static void show_textbox(const char *title, const char *text, int r, int c)
{
698 699
	show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
			 NULL, NULL);
L
Linus Torvalds 已提交
700 701 702 703 704 705 706
}

static void show_helptext(const char *title, const char *text)
{
	show_textbox(title, text, 0, 0);
}

W
Wang YanQing 已提交
707 708 709 710 711 712 713 714 715 716 717
static void conf_message_callback(const char *fmt, va_list ap)
{
	char buf[PATH_MAX+1];

	vsnprintf(buf, sizeof(buf), fmt, ap);
	if (save_and_exit)
		printf("%s", buf);
	else
		show_textbox(NULL, buf, 6, 60);
}

L
Linus Torvalds 已提交
718 719 720
static void show_help(struct menu *menu)
{
	struct gstr help = str_new();
721

722
	help.max_width = getmaxx(stdscr) - 10;
723 724
	menu_get_ext_help(menu, &help);

725
	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
L
Linus Torvalds 已提交
726 727 728 729 730
	str_free(&help);
}

static void conf_choice(struct menu *menu)
{
731
	const char *prompt = _(menu_get_prompt(menu));
L
Linus Torvalds 已提交
732 733 734 735 736
	struct menu *child;
	struct symbol *active;

	active = sym_get_choice_value(menu->sym);
	while (1) {
737 738 739
		int res;
		int selected;
		item_reset();
L
Linus Torvalds 已提交
740 741 742 743 744

		current_menu = menu;
		for (child = menu->list; child; child = child->next) {
			if (!menu_is_visible(child))
				continue;
745 746 747 748 749 750
			if (child->sym)
				item_make("%s", _(menu_get_prompt(child)));
			else {
				item_make("*** %s ***", _(menu_get_prompt(child)));
				item_set_tag(':');
			}
751 752 753
			item_set_data(child);
			if (child->sym == active)
				item_set_selected(1);
L
Linus Torvalds 已提交
754
			if (child->sym == sym_get_choice_value(menu->sym))
755
				item_set_tag('X');
L
Linus Torvalds 已提交
756
		}
757
		dialog_clear();
758
		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
759 760 761 762
					_(radiolist_instructions),
					 15, 70, 6);
		selected = item_activate_selected();
		switch (res) {
L
Linus Torvalds 已提交
763
		case 0:
764 765
			if (selected) {
				child = item_data();
766 767 768
				if (!child->sym)
					break;

769 770
				sym_set_tristate_value(child->sym, yes);
			}
L
Linus Torvalds 已提交
771 772
			return;
		case 1:
773 774
			if (selected) {
				child = item_data();
L
Linus Torvalds 已提交
775 776 777 778 779
				show_help(child);
				active = child->sym;
			} else
				show_help(menu);
			break;
780
		case KEY_ESC:
L
Linus Torvalds 已提交
781
			return;
S
Sam Ravnborg 已提交
782 783
		case -ERRDISPLAYTOOSMALL:
			return;
L
Linus Torvalds 已提交
784 785 786 787 788 789 790 791 792
		}
	}
}

static void conf_string(struct menu *menu)
{
	const char *prompt = menu_get_prompt(menu);

	while (1) {
793
		int res;
794
		const char *heading;
795

L
Linus Torvalds 已提交
796 797
		switch (sym_get_type(menu->sym)) {
		case S_INT:
798
			heading = _(inputbox_instructions_int);
L
Linus Torvalds 已提交
799 800
			break;
		case S_HEX:
801
			heading = _(inputbox_instructions_hex);
L
Linus Torvalds 已提交
802 803
			break;
		case S_STRING:
804
			heading = _(inputbox_instructions_string);
L
Linus Torvalds 已提交
805 806
			break;
		default:
807
			heading = _("Internal mconf error!");
L
Linus Torvalds 已提交
808
		}
809
		dialog_clear();
810
		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
811 812 813
				      heading, 10, 75,
				      sym_get_string_value(menu->sym));
		switch (res) {
L
Linus Torvalds 已提交
814
		case 0:
815
			if (sym_set_string_value(menu->sym, dialog_input_result))
L
Linus Torvalds 已提交
816
				return;
817
			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
L
Linus Torvalds 已提交
818 819 820 821
			break;
		case 1:
			show_help(menu);
			break;
822
		case KEY_ESC:
L
Linus Torvalds 已提交
823 824 825 826 827 828 829 830 831
			return;
		}
	}
}

static void conf_load(void)
{

	while (1) {
832
		int res;
833
		dialog_clear();
834 835 836
		res = dialog_inputbox(NULL, load_config_text,
				      11, 55, filename);
		switch(res) {
L
Linus Torvalds 已提交
837
		case 0:
838
			if (!dialog_input_result[0])
L
Linus Torvalds 已提交
839
				return;
840 841
			if (!conf_read(dialog_input_result)) {
				set_config_filename(dialog_input_result);
842
				sym_set_change_count(1);
L
Linus Torvalds 已提交
843
				return;
844
			}
845
			show_textbox(NULL, _("File does not exist!"), 5, 38);
L
Linus Torvalds 已提交
846 847
			break;
		case 1:
848
			show_helptext(_("Load Alternate Configuration"), load_config_help);
L
Linus Torvalds 已提交
849
			break;
850
		case KEY_ESC:
L
Linus Torvalds 已提交
851 852 853 854 855 856 857 858
			return;
		}
	}
}

static void conf_save(void)
{
	while (1) {
859
		int res;
860
		dialog_clear();
861 862 863
		res = dialog_inputbox(NULL, save_config_text,
				      11, 55, filename);
		switch(res) {
L
Linus Torvalds 已提交
864
		case 0:
865
			if (!dialog_input_result[0])
L
Linus Torvalds 已提交
866
				return;
867 868
			if (!conf_write(dialog_input_result)) {
				set_config_filename(dialog_input_result);
L
Linus Torvalds 已提交
869
				return;
870
			}
871
			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
L
Linus Torvalds 已提交
872 873
			break;
		case 1:
874
			show_helptext(_("Save Alternate Configuration"), save_config_help);
L
Linus Torvalds 已提交
875
			break;
876
		case KEY_ESC:
L
Linus Torvalds 已提交
877 878 879 880 881
			return;
		}
	}
}

882 883 884 885
static int handle_exit(void)
{
	int res;

W
Wang YanQing 已提交
886
	save_and_exit = 1;
887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918
	dialog_clear();
	if (conf_get_changed())
		res = dialog_yesno(NULL,
				   _("Do you wish to save your new configuration ?\n"
				     "<ESC><ESC> to continue."),
				   6, 60);
	else
		res = -1;

	end_dialog(saved_x, saved_y);

	switch (res) {
	case 0:
		if (conf_write(filename)) {
			fprintf(stderr, _("\n\n"
					  "Error while writing of the configuration.\n"
					  "Your configuration changes were NOT saved."
					  "\n\n"));
			return 1;
		}
		/* fall through */
	case -1:
		printf(_("\n\n"
			 "*** End of the configuration.\n"
			 "*** Execute 'make' to start the build or try 'make help'."
			 "\n\n"));
		res = 0;
		break;
	default:
		fprintf(stderr, _("\n\n"
				  "Your configuration changes were NOT saved."
				  "\n\n"));
919 920
		if (res != KEY_ESC)
			res = 0;
921 922 923 924 925 926 927 928 929 930
	}

	return res;
}

static void sig_handler(int signo)
{
	exit(handle_exit());
}

L
Linus Torvalds 已提交
931 932 933
int main(int ac, char **av)
{
	char *mode;
934
	int res;
L
Linus Torvalds 已提交
935

936 937 938 939
	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);

940 941
	signal(SIGINT, sig_handler);

L
Linus Torvalds 已提交
942 943 944 945 946 947 948 949 950
	conf_parse(av[1]);
	conf_read(NULL);

	mode = getenv("MENUCONFIG_MODE");
	if (mode) {
		if (!strcasecmp(mode, "single_menu"))
			single_menu_mode = 1;
	}

951 952 953 954 955 956
	if (init_dialog(NULL)) {
		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
		return 1;
	}

957
	set_config_filename(conf_get_configname());
W
Wang YanQing 已提交
958
	conf_set_message_callback(conf_message_callback);
959
	do {
960
		conf(&rootmenu, NULL);
961
		res = handle_exit();
962
	} while (res == KEY_ESC);
L
Linus Torvalds 已提交
963

964
	return res;
L
Linus Torvalds 已提交
965
}
966