Linux Audio

Check our new training course

Yocto / OpenEmbedded training

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