Linux Audio

Check our new training course

Loading...
v6.2
   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 "lkc.h"
  23#include "lxdialog/dialog.h"
  24
  25#define JUMP_NB			9
  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 || IA64\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);
 293static void conf_choice(struct menu *menu);
 294static void conf_string(struct menu *menu);
 295static void conf_load(void);
 296static void conf_save(void);
 297static int show_textbox_ext(const char *title, char *text, int r, int c,
 298			    int *keys, int *vscroll, int *hscroll,
 299			    update_text_fn update_text, void *data);
 300static void show_textbox(const char *title, const char *text, int r, int c);
 301static void show_helptext(const char *title, const char *text);
 302static void show_help(struct menu *menu);
 303
 304static char filename[PATH_MAX+1];
 305static void set_config_filename(const char *config_filename)
 306{
 307	static char menu_backtitle[PATH_MAX+128];
 
 308
 309	snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
 310		 config_filename, rootmenu.prompt->text);
 
 
 311	set_dialog_backtitle(menu_backtitle);
 312
 313	snprintf(filename, sizeof(filename), "%s", config_filename);
 
 
 314}
 315
 316struct subtitle_part {
 317	struct list_head entries;
 318	const char *text;
 319};
 320static LIST_HEAD(trail);
 321
 322static struct subtitle_list *subtitles;
 323static void set_subtitle(void)
 324{
 325	struct subtitle_part *sp;
 326	struct subtitle_list *pos, *tmp;
 327
 328	for (pos = subtitles; pos != NULL; pos = tmp) {
 329		tmp = pos->next;
 330		free(pos);
 331	}
 332
 333	subtitles = NULL;
 334	list_for_each_entry(sp, &trail, entries) {
 335		if (sp->text) {
 336			if (pos) {
 337				pos->next = xcalloc(1, sizeof(*pos));
 338				pos = pos->next;
 339			} else {
 340				subtitles = pos = xcalloc(1, sizeof(*pos));
 341			}
 342			pos->text = sp->text;
 343		}
 344	}
 345
 346	set_dialog_subtitles(subtitles);
 347}
 348
 349static void reset_subtitle(void)
 350{
 351	struct subtitle_list *pos, *tmp;
 352
 353	for (pos = subtitles; pos != NULL; pos = tmp) {
 354		tmp = pos->next;
 355		free(pos);
 356	}
 357	subtitles = NULL;
 358	set_dialog_subtitles(subtitles);
 359}
 360
 361struct search_data {
 362	struct list_head *head;
 363	struct menu **targets;
 364	int *keys;
 365};
 366
 367static void update_text(char *buf, size_t start, size_t end, void *_data)
 368{
 369	struct search_data *data = _data;
 370	struct jump_key *pos;
 371	int k = 0;
 372
 373	list_for_each_entry(pos, data->head, entries) {
 374		if (pos->offset >= start && pos->offset < end) {
 375			char header[4];
 376
 377			if (k < JUMP_NB) {
 378				int key = '0' + (pos->index % JUMP_NB) + 1;
 379
 380				sprintf(header, "(%c)", key);
 381				data->keys[k] = key;
 382				data->targets[k] = pos->target;
 383				k++;
 384			} else {
 385				sprintf(header, "   ");
 386			}
 387
 388			memcpy(buf + pos->offset, header, sizeof(header) - 1);
 389		}
 390	}
 391	data->keys[k] = 0;
 392}
 393
 394static void search_conf(void)
 395{
 396	struct symbol **sym_arr;
 397	struct gstr res;
 398	struct gstr title;
 399	char *dialog_input;
 400	int dres, vscroll = 0, hscroll = 0;
 401	bool again;
 402	struct gstr sttext;
 403	struct subtitle_part stpart;
 404
 405	title = str_new();
 406	str_printf( &title, "Enter (sub)string or regexp to search for "
 407			      "(with or without \"%s\")", CONFIG_);
 408
 409again:
 410	dialog_clear();
 411	dres = dialog_inputbox("Search Configuration Parameter",
 412			      str_get(&title),
 413			      10, 75, "");
 414	switch (dres) {
 415	case 0:
 416		break;
 417	case 1:
 418		show_helptext("Search Configuration", search_help);
 419		goto again;
 420	default:
 421		str_free(&title);
 422		return;
 423	}
 424
 425	/* strip the prefix if necessary */
 426	dialog_input = dialog_input_result;
 427	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
 428		dialog_input += strlen(CONFIG_);
 429
 430	sttext = str_new();
 431	str_printf(&sttext, "Search (%s)", dialog_input_result);
 432	stpart.text = str_get(&sttext);
 433	list_add_tail(&stpart.entries, &trail);
 434
 435	sym_arr = sym_re_search(dialog_input);
 436	do {
 437		LIST_HEAD(head);
 438		struct menu *targets[JUMP_NB];
 439		int keys[JUMP_NB + 1], i;
 440		struct search_data data = {
 441			.head = &head,
 442			.targets = targets,
 443			.keys = keys,
 444		};
 445		struct jump_key *pos, *tmp;
 446
 447		res = get_relations_str(sym_arr, &head);
 448		set_subtitle();
 449		dres = show_textbox_ext("Search Results", str_get(&res), 0, 0,
 450					keys, &vscroll, &hscroll, &update_text,
 
 451					&data);
 452		again = false;
 453		for (i = 0; i < JUMP_NB && keys[i]; i++)
 454			if (dres == keys[i]) {
 455				conf(targets[i]->parent, targets[i]);
 456				again = true;
 457			}
 458		str_free(&res);
 459		list_for_each_entry_safe(pos, tmp, &head, entries)
 460			free(pos);
 461	} while (again);
 462	free(sym_arr);
 463	str_free(&title);
 464	list_del(trail.prev);
 465	str_free(&sttext);
 466}
 467
 468static void build_conf(struct menu *menu)
 469{
 470	struct symbol *sym;
 471	struct property *prop;
 472	struct menu *child;
 473	int type, tmp, doint = 2;
 474	tristate val;
 475	char ch;
 476	bool visible;
 477
 478	/*
 479	 * note: menu_is_visible() has side effect that it will
 480	 * recalc the value of the symbol.
 481	 */
 482	visible = menu_is_visible(menu);
 483	if (show_all_options && !menu_has_prompt(menu))
 484		return;
 485	else if (!show_all_options && !visible)
 486		return;
 487
 488	sym = menu->sym;
 489	prop = menu->prompt;
 490	if (!sym) {
 491		if (prop && menu != current_menu) {
 492			const char *prompt = menu_get_prompt(menu);
 493			switch (prop->type) {
 494			case P_MENU:
 495				child_count++;
 
 496				if (single_menu_mode) {
 497					item_make("%s%*c%s",
 498						  menu->data ? "-->" : "++>",
 499						  indent + 1, ' ', prompt);
 500				} else
 501					item_make("   %*c%s  %s",
 502						  indent + 1, ' ', prompt,
 503						  menu_is_empty(menu) ? "----" : "--->");
 504				item_set_tag('m');
 505				item_set_data(menu);
 506				if (single_menu_mode && menu->data)
 507					goto conf_childs;
 508				return;
 509			case P_COMMENT:
 510				if (prompt) {
 511					child_count++;
 512					item_make("   %*c*** %s ***", indent + 1, ' ', prompt);
 513					item_set_tag(':');
 514					item_set_data(menu);
 515				}
 516				break;
 517			default:
 518				if (prompt) {
 519					child_count++;
 520					item_make("---%*c%s", indent + 1, ' ', prompt);
 521					item_set_tag(':');
 522					item_set_data(menu);
 523				}
 524			}
 525		} else
 526			doint = 0;
 527		goto conf_childs;
 528	}
 529
 530	type = sym_get_type(sym);
 531	if (sym_is_choice(sym)) {
 532		struct symbol *def_sym = sym_get_choice_value(sym);
 533		struct menu *def_menu = NULL;
 534
 535		child_count++;
 536		for (child = menu->list; child; child = child->next) {
 537			if (menu_is_visible(child) && child->sym == def_sym)
 538				def_menu = child;
 539		}
 540
 541		val = sym_get_tristate_value(sym);
 542		if (sym_is_changeable(sym)) {
 543			switch (type) {
 544			case S_BOOLEAN:
 545				item_make("[%c]", val == no ? ' ' : '*');
 546				break;
 547			case S_TRISTATE:
 548				switch (val) {
 549				case yes: ch = '*'; break;
 550				case mod: ch = 'M'; break;
 551				default:  ch = ' '; break;
 552				}
 553				item_make("<%c>", ch);
 554				break;
 555			}
 556			item_set_tag('t');
 557			item_set_data(menu);
 558		} else {
 559			item_make("   ");
 560			item_set_tag(def_menu ? 't' : ':');
 561			item_set_data(menu);
 562		}
 563
 564		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
 565		if (val == yes) {
 566			if (def_menu) {
 567				item_add_str(" (%s)", menu_get_prompt(def_menu));
 568				item_add_str("  --->");
 569				if (def_menu->list) {
 570					indent += 2;
 571					build_conf(def_menu);
 572					indent -= 2;
 573				}
 574			}
 575			return;
 576		}
 577	} else {
 578		if (menu == current_menu) {
 579			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
 580			item_set_tag(':');
 581			item_set_data(menu);
 582			goto conf_childs;
 583		}
 584		child_count++;
 585		val = sym_get_tristate_value(sym);
 586		if (sym_is_choice_value(sym) && val == yes) {
 587			item_make("   ");
 588			item_set_tag(':');
 589			item_set_data(menu);
 590		} else {
 591			switch (type) {
 592			case S_BOOLEAN:
 593				if (sym_is_changeable(sym))
 594					item_make("[%c]", val == no ? ' ' : '*');
 595				else
 596					item_make("-%c-", val == no ? ' ' : '*');
 597				item_set_tag('t');
 598				item_set_data(menu);
 599				break;
 600			case S_TRISTATE:
 601				switch (val) {
 602				case yes: ch = '*'; break;
 603				case mod: ch = 'M'; break;
 604				default:  ch = ' '; break;
 605				}
 606				if (sym_is_changeable(sym)) {
 607					if (sym->rev_dep.tri == mod)
 608						item_make("{%c}", ch);
 609					else
 610						item_make("<%c>", ch);
 611				} else
 612					item_make("-%c-", ch);
 613				item_set_tag('t');
 614				item_set_data(menu);
 615				break;
 616			default:
 617				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
 618				item_make("(%s)", sym_get_string_value(sym));
 619				tmp = indent - tmp + 4;
 620				if (tmp < 0)
 621					tmp = 0;
 622				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
 623					     (sym_has_value(sym) || !sym_is_changeable(sym)) ?
 624					     "" : " (NEW)");
 625				item_set_tag('s');
 626				item_set_data(menu);
 627				goto conf_childs;
 628			}
 629		}
 630		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
 631			  (sym_has_value(sym) || !sym_is_changeable(sym)) ?
 632			  "" : " (NEW)");
 633		if (menu->prompt->type == P_MENU) {
 634			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
 635			return;
 636		}
 637	}
 638
 639conf_childs:
 640	indent += doint;
 641	for (child = menu->list; child; child = child->next)
 642		build_conf(child);
 643	indent -= doint;
 644}
 645
 646static void conf(struct menu *menu, struct menu *active_menu)
 647{
 648	struct menu *submenu;
 649	const char *prompt = menu_get_prompt(menu);
 650	struct subtitle_part stpart;
 651	struct symbol *sym;
 652	int res;
 653	int s_scroll = 0;
 654
 655	if (menu != &rootmenu)
 656		stpart.text = menu_get_prompt(menu);
 657	else
 658		stpart.text = NULL;
 659	list_add_tail(&stpart.entries, &trail);
 660
 661	while (1) {
 662		item_reset();
 663		current_menu = menu;
 664		build_conf(menu);
 665		if (!child_count)
 666			break;
 667		set_subtitle();
 668		dialog_clear();
 669		res = dialog_menu(prompt ? prompt : "Main Menu",
 670				  menu_instructions,
 671				  active_menu, &s_scroll);
 672		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 673			break;
 674		if (item_count() != 0) {
 675			if (!item_activate_selected())
 676				continue;
 677			if (!item_tag())
 678				continue;
 679		}
 680		submenu = item_data();
 681		active_menu = item_data();
 682		if (submenu)
 683			sym = submenu->sym;
 684		else
 685			sym = NULL;
 686
 687		switch (res) {
 688		case 0:
 689			switch (item_tag()) {
 690			case 'm':
 691				if (single_menu_mode)
 692					submenu->data = (void *) (long) !submenu->data;
 693				else
 694					conf(submenu, NULL);
 695				break;
 696			case 't':
 697				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 698					conf_choice(submenu);
 699				else if (submenu->prompt->type == P_MENU)
 700					conf(submenu, NULL);
 701				break;
 702			case 's':
 703				conf_string(submenu);
 704				break;
 705			}
 706			break;
 707		case 2:
 708			if (sym)
 709				show_help(submenu);
 710			else {
 711				reset_subtitle();
 712				show_helptext("README", mconf_readme);
 713			}
 714			break;
 715		case 3:
 716			reset_subtitle();
 717			conf_save();
 718			break;
 719		case 4:
 720			reset_subtitle();
 721			conf_load();
 722			break;
 723		case 5:
 724			if (item_is_tag('t')) {
 725				if (sym_set_tristate_value(sym, yes))
 726					break;
 727				if (sym_set_tristate_value(sym, mod))
 728					show_textbox(NULL, setmod_text, 6, 74);
 729			}
 730			break;
 731		case 6:
 732			if (item_is_tag('t'))
 733				sym_set_tristate_value(sym, no);
 734			break;
 735		case 7:
 736			if (item_is_tag('t'))
 737				sym_set_tristate_value(sym, mod);
 738			break;
 739		case 8:
 740			if (item_is_tag('t'))
 741				sym_toggle_tristate_value(sym);
 742			else if (item_is_tag('m'))
 743				conf(submenu, NULL);
 744			break;
 745		case 9:
 746			search_conf();
 747			break;
 748		case 10:
 749			show_all_options = !show_all_options;
 750			break;
 751		}
 752	}
 753
 754	list_del(trail.prev);
 755}
 756
 757static int show_textbox_ext(const char *title, char *text, int r, int c, int
 758			    *keys, int *vscroll, int *hscroll, update_text_fn
 759			    update_text, void *data)
 760{
 761	dialog_clear();
 762	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
 763			      update_text, data);
 764}
 765
 766static void show_textbox(const char *title, const char *text, int r, int c)
 767{
 768	show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
 769			 NULL, NULL);
 770}
 771
 772static void show_helptext(const char *title, const char *text)
 773{
 774	show_textbox(title, text, 0, 0);
 775}
 776
 777static void conf_message_callback(const char *s)
 778{
 779	if (save_and_exit) {
 780		if (!silent)
 781			printf("%s", s);
 782	} else {
 783		show_textbox(NULL, s, 6, 60);
 784	}
 
 785}
 786
 787static void show_help(struct menu *menu)
 788{
 789	struct gstr help = str_new();
 790
 791	help.max_width = getmaxx(stdscr) - 10;
 792	menu_get_ext_help(menu, &help);
 793
 794	show_helptext(menu_get_prompt(menu), str_get(&help));
 795	str_free(&help);
 796}
 797
 798static void conf_choice(struct menu *menu)
 799{
 800	const char *prompt = menu_get_prompt(menu);
 801	struct menu *child;
 802	struct symbol *active;
 803
 804	active = sym_get_choice_value(menu->sym);
 805	while (1) {
 806		int res;
 807		int selected;
 808		item_reset();
 809
 810		current_menu = menu;
 811		for (child = menu->list; child; child = child->next) {
 812			if (!menu_is_visible(child))
 813				continue;
 814			if (child->sym)
 815				item_make("%s", menu_get_prompt(child));
 816			else {
 817				item_make("*** %s ***", menu_get_prompt(child));
 818				item_set_tag(':');
 819			}
 820			item_set_data(child);
 821			if (child->sym == active)
 822				item_set_selected(1);
 823			if (child->sym == sym_get_choice_value(menu->sym))
 824				item_set_tag('X');
 825		}
 826		dialog_clear();
 827		res = dialog_checklist(prompt ? prompt : "Main Menu",
 828					radiolist_instructions,
 829					MENUBOX_HEIGTH_MIN,
 830					MENUBOX_WIDTH_MIN,
 831					CHECKLIST_HEIGTH_MIN);
 832		selected = item_activate_selected();
 833		switch (res) {
 834		case 0:
 835			if (selected) {
 836				child = item_data();
 837				if (!child->sym)
 838					break;
 839
 840				sym_set_tristate_value(child->sym, yes);
 841			}
 842			return;
 843		case 1:
 844			if (selected) {
 845				child = item_data();
 846				show_help(child);
 847				active = child->sym;
 848			} else
 849				show_help(menu);
 850			break;
 851		case KEY_ESC:
 852			return;
 853		case -ERRDISPLAYTOOSMALL:
 854			return;
 855		}
 856	}
 857}
 858
 859static void conf_string(struct menu *menu)
 860{
 861	const char *prompt = menu_get_prompt(menu);
 862
 863	while (1) {
 864		int res;
 865		const char *heading;
 866
 867		switch (sym_get_type(menu->sym)) {
 868		case S_INT:
 869			heading = inputbox_instructions_int;
 870			break;
 871		case S_HEX:
 872			heading = inputbox_instructions_hex;
 873			break;
 874		case S_STRING:
 875			heading = inputbox_instructions_string;
 876			break;
 877		default:
 878			heading = "Internal mconf error!";
 879		}
 880		dialog_clear();
 881		res = dialog_inputbox(prompt ? prompt : "Main Menu",
 882				      heading, 10, 75,
 883				      sym_get_string_value(menu->sym));
 884		switch (res) {
 885		case 0:
 886			if (sym_set_string_value(menu->sym, dialog_input_result))
 887				return;
 888			show_textbox(NULL, "You have made an invalid entry.", 5, 43);
 889			break;
 890		case 1:
 891			show_help(menu);
 892			break;
 893		case KEY_ESC:
 894			return;
 895		}
 896	}
 897}
 898
 899static void conf_load(void)
 900{
 901
 902	while (1) {
 903		int res;
 904		dialog_clear();
 905		res = dialog_inputbox(NULL, load_config_text,
 906				      11, 55, filename);
 907		switch(res) {
 908		case 0:
 909			if (!dialog_input_result[0])
 910				return;
 911			if (!conf_read(dialog_input_result)) {
 912				set_config_filename(dialog_input_result);
 913				conf_set_changed(true);
 914				return;
 915			}
 916			show_textbox(NULL, "File does not exist!", 5, 38);
 917			break;
 918		case 1:
 919			show_helptext("Load Alternate Configuration", load_config_help);
 920			break;
 921		case KEY_ESC:
 922			return;
 923		}
 924	}
 925}
 926
 927static void conf_save(void)
 928{
 929	while (1) {
 930		int res;
 931		dialog_clear();
 932		res = dialog_inputbox(NULL, save_config_text,
 933				      11, 55, filename);
 934		switch(res) {
 935		case 0:
 936			if (!dialog_input_result[0])
 937				return;
 938			if (!conf_write(dialog_input_result)) {
 939				set_config_filename(dialog_input_result);
 940				return;
 941			}
 942			show_textbox(NULL, "Can't create file!", 5, 60);
 943			break;
 944		case 1:
 945			show_helptext("Save Alternate Configuration", save_config_help);
 946			break;
 947		case KEY_ESC:
 948			return;
 949		}
 950	}
 951}
 952
 953static int handle_exit(void)
 954{
 955	int res;
 956
 957	save_and_exit = 1;
 958	reset_subtitle();
 959	dialog_clear();
 960	if (conf_get_changed())
 961		res = dialog_yesno(NULL,
 962				   "Do you wish to save your new configuration?\n"
 963				     "(Press <ESC><ESC> to continue kernel configuration.)",
 964				   6, 60);
 965	else
 966		res = -1;
 967
 968	end_dialog(saved_x, saved_y);
 969
 970	switch (res) {
 971	case 0:
 972		if (conf_write(filename)) {
 973			fprintf(stderr, "\n\n"
 974					  "Error while writing of the configuration.\n"
 975					  "Your configuration changes were NOT saved."
 976					  "\n\n");
 977			return 1;
 978		}
 979		conf_write_autoconf(0);
 980		/* fall through */
 981	case -1:
 982		if (!silent)
 983			printf("\n\n"
 984				 "*** End of the configuration.\n"
 985				 "*** Execute 'make' to start the build or try 'make help'."
 986				 "\n\n");
 987		res = 0;
 988		break;
 989	default:
 990		if (!silent)
 991			fprintf(stderr, "\n\n"
 992					  "Your configuration changes were NOT saved."
 993					  "\n\n");
 994		if (res != KEY_ESC)
 995			res = 0;
 996	}
 997
 998	return res;
 999}
1000
1001static void sig_handler(int signo)
1002{
1003	exit(handle_exit());
1004}
1005
1006int main(int ac, char **av)
1007{
1008	char *mode;
1009	int res;
1010
 
 
 
 
1011	signal(SIGINT, sig_handler);
1012
1013	if (ac > 1 && strcmp(av[1], "-s") == 0) {
1014		silent = 1;
1015		/* Silence conf_read() until the real callback is set up */
1016		conf_set_message_callback(NULL);
1017		av++;
1018	}
1019	conf_parse(av[1]);
1020	conf_read(NULL);
1021
1022	mode = getenv("MENUCONFIG_MODE");
1023	if (mode) {
1024		if (!strcasecmp(mode, "single_menu"))
1025			single_menu_mode = 1;
1026	}
1027
1028	if (init_dialog(NULL)) {
1029		fprintf(stderr, "Your display is too small to run Menuconfig!\n");
1030		fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
1031		return 1;
1032	}
1033
1034	set_config_filename(conf_get_configname());
1035	conf_set_message_callback(conf_message_callback);
1036	do {
1037		conf(&rootmenu, NULL);
1038		res = handle_exit();
1039	} while (res == KEY_ESC);
1040
1041	return res;
1042}
v3.15
 
   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 (boolean, 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;
 
 282
 283static void conf(struct menu *menu, struct menu *active_menu);
 284static void conf_choice(struct menu *menu);
 285static void conf_string(struct menu *menu);
 286static void conf_load(void);
 287static void conf_save(void);
 288static int show_textbox_ext(const char *title, char *text, int r, int c,
 289			    int *keys, int *vscroll, int *hscroll,
 290			    update_text_fn update_text, void *data);
 291static void show_textbox(const char *title, const char *text, int r, int c);
 292static void show_helptext(const char *title, const char *text);
 293static void show_help(struct menu *menu);
 294
 295static char filename[PATH_MAX+1];
 296static void set_config_filename(const char *config_filename)
 297{
 298	static char menu_backtitle[PATH_MAX+128];
 299	int size;
 300
 301	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
 302	                "%s - %s", config_filename, rootmenu.prompt->text);
 303	if (size >= sizeof(menu_backtitle))
 304		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
 305	set_dialog_backtitle(menu_backtitle);
 306
 307	size = snprintf(filename, sizeof(filename), "%s", config_filename);
 308	if (size >= sizeof(filename))
 309		filename[sizeof(filename)-1] = '\0';
 310}
 311
 312struct subtitle_part {
 313	struct list_head entries;
 314	const char *text;
 315};
 316static LIST_HEAD(trail);
 317
 318static struct subtitle_list *subtitles;
 319static void set_subtitle(void)
 320{
 321	struct subtitle_part *sp;
 322	struct subtitle_list *pos, *tmp;
 323
 324	for (pos = subtitles; pos != NULL; pos = tmp) {
 325		tmp = pos->next;
 326		free(pos);
 327	}
 328
 329	subtitles = NULL;
 330	list_for_each_entry(sp, &trail, entries) {
 331		if (sp->text) {
 332			if (pos) {
 333				pos->next = xcalloc(sizeof(*pos), 1);
 334				pos = pos->next;
 335			} else {
 336				subtitles = pos = xcalloc(sizeof(*pos), 1);
 337			}
 338			pos->text = sp->text;
 339		}
 340	}
 341
 342	set_dialog_subtitles(subtitles);
 343}
 344
 345static void reset_subtitle(void)
 346{
 347	struct subtitle_list *pos, *tmp;
 348
 349	for (pos = subtitles; pos != NULL; pos = tmp) {
 350		tmp = pos->next;
 351		free(pos);
 352	}
 353	subtitles = NULL;
 354	set_dialog_subtitles(subtitles);
 355}
 356
 357struct search_data {
 358	struct list_head *head;
 359	struct menu **targets;
 360	int *keys;
 361};
 362
 363static void update_text(char *buf, size_t start, size_t end, void *_data)
 364{
 365	struct search_data *data = _data;
 366	struct jump_key *pos;
 367	int k = 0;
 368
 369	list_for_each_entry(pos, data->head, entries) {
 370		if (pos->offset >= start && pos->offset < end) {
 371			char header[4];
 372
 373			if (k < JUMP_NB) {
 374				int key = '0' + (pos->index % JUMP_NB) + 1;
 375
 376				sprintf(header, "(%c)", key);
 377				data->keys[k] = key;
 378				data->targets[k] = pos->target;
 379				k++;
 380			} else {
 381				sprintf(header, "   ");
 382			}
 383
 384			memcpy(buf + pos->offset, header, sizeof(header) - 1);
 385		}
 386	}
 387	data->keys[k] = 0;
 388}
 389
 390static void search_conf(void)
 391{
 392	struct symbol **sym_arr;
 393	struct gstr res;
 394	struct gstr title;
 395	char *dialog_input;
 396	int dres, vscroll = 0, hscroll = 0;
 397	bool again;
 398	struct gstr sttext;
 399	struct subtitle_part stpart;
 400
 401	title = str_new();
 402	str_printf( &title, _("Enter (sub)string or regexp to search for "
 403			      "(with or without \"%s\")"), CONFIG_);
 404
 405again:
 406	dialog_clear();
 407	dres = dialog_inputbox(_("Search Configuration Parameter"),
 408			      str_get(&title),
 409			      10, 75, "");
 410	switch (dres) {
 411	case 0:
 412		break;
 413	case 1:
 414		show_helptext(_("Search Configuration"), search_help);
 415		goto again;
 416	default:
 417		str_free(&title);
 418		return;
 419	}
 420
 421	/* strip the prefix if necessary */
 422	dialog_input = dialog_input_result;
 423	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
 424		dialog_input += strlen(CONFIG_);
 425
 426	sttext = str_new();
 427	str_printf(&sttext, "Search (%s)", dialog_input_result);
 428	stpart.text = str_get(&sttext);
 429	list_add_tail(&stpart.entries, &trail);
 430
 431	sym_arr = sym_re_search(dialog_input);
 432	do {
 433		LIST_HEAD(head);
 434		struct menu *targets[JUMP_NB];
 435		int keys[JUMP_NB + 1], i;
 436		struct search_data data = {
 437			.head = &head,
 438			.targets = targets,
 439			.keys = keys,
 440		};
 441		struct jump_key *pos, *tmp;
 442
 443		res = get_relations_str(sym_arr, &head);
 444		set_subtitle();
 445		dres = show_textbox_ext(_("Search Results"), (char *)
 446					str_get(&res), 0, 0, keys, &vscroll,
 447					&hscroll, &update_text, (void *)
 448					&data);
 449		again = false;
 450		for (i = 0; i < JUMP_NB && keys[i]; i++)
 451			if (dres == keys[i]) {
 452				conf(targets[i]->parent, targets[i]);
 453				again = true;
 454			}
 455		str_free(&res);
 456		list_for_each_entry_safe(pos, tmp, &head, entries)
 457			free(pos);
 458	} while (again);
 459	free(sym_arr);
 460	str_free(&title);
 461	list_del(trail.prev);
 462	str_free(&sttext);
 463}
 464
 465static void build_conf(struct menu *menu)
 466{
 467	struct symbol *sym;
 468	struct property *prop;
 469	struct menu *child;
 470	int type, tmp, doint = 2;
 471	tristate val;
 472	char ch;
 473	bool visible;
 474
 475	/*
 476	 * note: menu_is_visible() has side effect that it will
 477	 * recalc the value of the symbol.
 478	 */
 479	visible = menu_is_visible(menu);
 480	if (show_all_options && !menu_has_prompt(menu))
 481		return;
 482	else if (!show_all_options && !visible)
 483		return;
 484
 485	sym = menu->sym;
 486	prop = menu->prompt;
 487	if (!sym) {
 488		if (prop && menu != current_menu) {
 489			const char *prompt = menu_get_prompt(menu);
 490			switch (prop->type) {
 491			case P_MENU:
 492				child_count++;
 493				prompt = _(prompt);
 494				if (single_menu_mode) {
 495					item_make("%s%*c%s",
 496						  menu->data ? "-->" : "++>",
 497						  indent + 1, ' ', prompt);
 498				} else
 499					item_make("   %*c%s  %s",
 500						  indent + 1, ' ', prompt,
 501						  menu_is_empty(menu) ? "----" : "--->");
 502				item_set_tag('m');
 503				item_set_data(menu);
 504				if (single_menu_mode && menu->data)
 505					goto conf_childs;
 506				return;
 507			case P_COMMENT:
 508				if (prompt) {
 509					child_count++;
 510					item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
 511					item_set_tag(':');
 512					item_set_data(menu);
 513				}
 514				break;
 515			default:
 516				if (prompt) {
 517					child_count++;
 518					item_make("---%*c%s", indent + 1, ' ', _(prompt));
 519					item_set_tag(':');
 520					item_set_data(menu);
 521				}
 522			}
 523		} else
 524			doint = 0;
 525		goto conf_childs;
 526	}
 527
 528	type = sym_get_type(sym);
 529	if (sym_is_choice(sym)) {
 530		struct symbol *def_sym = sym_get_choice_value(sym);
 531		struct menu *def_menu = NULL;
 532
 533		child_count++;
 534		for (child = menu->list; child; child = child->next) {
 535			if (menu_is_visible(child) && child->sym == def_sym)
 536				def_menu = child;
 537		}
 538
 539		val = sym_get_tristate_value(sym);
 540		if (sym_is_changable(sym)) {
 541			switch (type) {
 542			case S_BOOLEAN:
 543				item_make("[%c]", val == no ? ' ' : '*');
 544				break;
 545			case S_TRISTATE:
 546				switch (val) {
 547				case yes: ch = '*'; break;
 548				case mod: ch = 'M'; break;
 549				default:  ch = ' '; break;
 550				}
 551				item_make("<%c>", ch);
 552				break;
 553			}
 554			item_set_tag('t');
 555			item_set_data(menu);
 556		} else {
 557			item_make("   ");
 558			item_set_tag(def_menu ? 't' : ':');
 559			item_set_data(menu);
 560		}
 561
 562		item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
 563		if (val == yes) {
 564			if (def_menu) {
 565				item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
 566				item_add_str("  --->");
 567				if (def_menu->list) {
 568					indent += 2;
 569					build_conf(def_menu);
 570					indent -= 2;
 571				}
 572			}
 573			return;
 574		}
 575	} else {
 576		if (menu == current_menu) {
 577			item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
 578			item_set_tag(':');
 579			item_set_data(menu);
 580			goto conf_childs;
 581		}
 582		child_count++;
 583		val = sym_get_tristate_value(sym);
 584		if (sym_is_choice_value(sym) && val == yes) {
 585			item_make("   ");
 586			item_set_tag(':');
 587			item_set_data(menu);
 588		} else {
 589			switch (type) {
 590			case S_BOOLEAN:
 591				if (sym_is_changable(sym))
 592					item_make("[%c]", val == no ? ' ' : '*');
 593				else
 594					item_make("-%c-", val == no ? ' ' : '*');
 595				item_set_tag('t');
 596				item_set_data(menu);
 597				break;
 598			case S_TRISTATE:
 599				switch (val) {
 600				case yes: ch = '*'; break;
 601				case mod: ch = 'M'; break;
 602				default:  ch = ' '; break;
 603				}
 604				if (sym_is_changable(sym)) {
 605					if (sym->rev_dep.tri == mod)
 606						item_make("{%c}", ch);
 607					else
 608						item_make("<%c>", ch);
 609				} else
 610					item_make("-%c-", ch);
 611				item_set_tag('t');
 612				item_set_data(menu);
 613				break;
 614			default:
 615				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
 616				item_make("(%s)", sym_get_string_value(sym));
 617				tmp = indent - tmp + 4;
 618				if (tmp < 0)
 619					tmp = 0;
 620				item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
 621					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
 622					     "" : _(" (NEW)"));
 623				item_set_tag('s');
 624				item_set_data(menu);
 625				goto conf_childs;
 626			}
 627		}
 628		item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
 629			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
 630			  "" : _(" (NEW)"));
 631		if (menu->prompt->type == P_MENU) {
 632			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
 633			return;
 634		}
 635	}
 636
 637conf_childs:
 638	indent += doint;
 639	for (child = menu->list; child; child = child->next)
 640		build_conf(child);
 641	indent -= doint;
 642}
 643
 644static void conf(struct menu *menu, struct menu *active_menu)
 645{
 646	struct menu *submenu;
 647	const char *prompt = menu_get_prompt(menu);
 648	struct subtitle_part stpart;
 649	struct symbol *sym;
 650	int res;
 651	int s_scroll = 0;
 652
 653	if (menu != &rootmenu)
 654		stpart.text = menu_get_prompt(menu);
 655	else
 656		stpart.text = NULL;
 657	list_add_tail(&stpart.entries, &trail);
 658
 659	while (1) {
 660		item_reset();
 661		current_menu = menu;
 662		build_conf(menu);
 663		if (!child_count)
 664			break;
 665		set_subtitle();
 666		dialog_clear();
 667		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
 668				  _(menu_instructions),
 669				  active_menu, &s_scroll);
 670		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 671			break;
 672		if (item_count() != 0) {
 673			if (!item_activate_selected())
 674				continue;
 675			if (!item_tag())
 676				continue;
 677		}
 678		submenu = item_data();
 679		active_menu = item_data();
 680		if (submenu)
 681			sym = submenu->sym;
 682		else
 683			sym = NULL;
 684
 685		switch (res) {
 686		case 0:
 687			switch (item_tag()) {
 688			case 'm':
 689				if (single_menu_mode)
 690					submenu->data = (void *) (long) !submenu->data;
 691				else
 692					conf(submenu, NULL);
 693				break;
 694			case 't':
 695				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 696					conf_choice(submenu);
 697				else if (submenu->prompt->type == P_MENU)
 698					conf(submenu, NULL);
 699				break;
 700			case 's':
 701				conf_string(submenu);
 702				break;
 703			}
 704			break;
 705		case 2:
 706			if (sym)
 707				show_help(submenu);
 708			else {
 709				reset_subtitle();
 710				show_helptext(_("README"), _(mconf_readme));
 711			}
 712			break;
 713		case 3:
 714			reset_subtitle();
 715			conf_save();
 716			break;
 717		case 4:
 718			reset_subtitle();
 719			conf_load();
 720			break;
 721		case 5:
 722			if (item_is_tag('t')) {
 723				if (sym_set_tristate_value(sym, yes))
 724					break;
 725				if (sym_set_tristate_value(sym, mod))
 726					show_textbox(NULL, setmod_text, 6, 74);
 727			}
 728			break;
 729		case 6:
 730			if (item_is_tag('t'))
 731				sym_set_tristate_value(sym, no);
 732			break;
 733		case 7:
 734			if (item_is_tag('t'))
 735				sym_set_tristate_value(sym, mod);
 736			break;
 737		case 8:
 738			if (item_is_tag('t'))
 739				sym_toggle_tristate_value(sym);
 740			else if (item_is_tag('m'))
 741				conf(submenu, NULL);
 742			break;
 743		case 9:
 744			search_conf();
 745			break;
 746		case 10:
 747			show_all_options = !show_all_options;
 748			break;
 749		}
 750	}
 751
 752	list_del(trail.prev);
 753}
 754
 755static int show_textbox_ext(const char *title, char *text, int r, int c, int
 756			    *keys, int *vscroll, int *hscroll, update_text_fn
 757			    update_text, void *data)
 758{
 759	dialog_clear();
 760	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
 761			      update_text, data);
 762}
 763
 764static void show_textbox(const char *title, const char *text, int r, int c)
 765{
 766	show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
 767			 NULL, NULL);
 768}
 769
 770static void show_helptext(const char *title, const char *text)
 771{
 772	show_textbox(title, text, 0, 0);
 773}
 774
 775static void conf_message_callback(const char *fmt, va_list ap)
 776{
 777	char buf[PATH_MAX+1];
 778
 779	vsnprintf(buf, sizeof(buf), fmt, ap);
 780	if (save_and_exit)
 781		printf("%s", buf);
 782	else
 783		show_textbox(NULL, buf, 6, 60);
 784}
 785
 786static void show_help(struct menu *menu)
 787{
 788	struct gstr help = str_new();
 789
 790	help.max_width = getmaxx(stdscr) - 10;
 791	menu_get_ext_help(menu, &help);
 792
 793	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
 794	str_free(&help);
 795}
 796
 797static void conf_choice(struct menu *menu)
 798{
 799	const char *prompt = _(menu_get_prompt(menu));
 800	struct menu *child;
 801	struct symbol *active;
 802
 803	active = sym_get_choice_value(menu->sym);
 804	while (1) {
 805		int res;
 806		int selected;
 807		item_reset();
 808
 809		current_menu = menu;
 810		for (child = menu->list; child; child = child->next) {
 811			if (!menu_is_visible(child))
 812				continue;
 813			if (child->sym)
 814				item_make("%s", _(menu_get_prompt(child)));
 815			else {
 816				item_make("*** %s ***", _(menu_get_prompt(child)));
 817				item_set_tag(':');
 818			}
 819			item_set_data(child);
 820			if (child->sym == active)
 821				item_set_selected(1);
 822			if (child->sym == sym_get_choice_value(menu->sym))
 823				item_set_tag('X');
 824		}
 825		dialog_clear();
 826		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
 827					_(radiolist_instructions),
 828					MENUBOX_HEIGTH_MIN,
 829					MENUBOX_WIDTH_MIN,
 830					CHECKLIST_HEIGTH_MIN);
 831		selected = item_activate_selected();
 832		switch (res) {
 833		case 0:
 834			if (selected) {
 835				child = item_data();
 836				if (!child->sym)
 837					break;
 838
 839				sym_set_tristate_value(child->sym, yes);
 840			}
 841			return;
 842		case 1:
 843			if (selected) {
 844				child = item_data();
 845				show_help(child);
 846				active = child->sym;
 847			} else
 848				show_help(menu);
 849			break;
 850		case KEY_ESC:
 851			return;
 852		case -ERRDISPLAYTOOSMALL:
 853			return;
 854		}
 855	}
 856}
 857
 858static void conf_string(struct menu *menu)
 859{
 860	const char *prompt = menu_get_prompt(menu);
 861
 862	while (1) {
 863		int res;
 864		const char *heading;
 865
 866		switch (sym_get_type(menu->sym)) {
 867		case S_INT:
 868			heading = _(inputbox_instructions_int);
 869			break;
 870		case S_HEX:
 871			heading = _(inputbox_instructions_hex);
 872			break;
 873		case S_STRING:
 874			heading = _(inputbox_instructions_string);
 875			break;
 876		default:
 877			heading = _("Internal mconf error!");
 878		}
 879		dialog_clear();
 880		res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
 881				      heading, 10, 75,
 882				      sym_get_string_value(menu->sym));
 883		switch (res) {
 884		case 0:
 885			if (sym_set_string_value(menu->sym, dialog_input_result))
 886				return;
 887			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
 888			break;
 889		case 1:
 890			show_help(menu);
 891			break;
 892		case KEY_ESC:
 893			return;
 894		}
 895	}
 896}
 897
 898static void conf_load(void)
 899{
 900
 901	while (1) {
 902		int res;
 903		dialog_clear();
 904		res = dialog_inputbox(NULL, load_config_text,
 905				      11, 55, filename);
 906		switch(res) {
 907		case 0:
 908			if (!dialog_input_result[0])
 909				return;
 910			if (!conf_read(dialog_input_result)) {
 911				set_config_filename(dialog_input_result);
 912				sym_set_change_count(1);
 913				return;
 914			}
 915			show_textbox(NULL, _("File does not exist!"), 5, 38);
 916			break;
 917		case 1:
 918			show_helptext(_("Load Alternate Configuration"), load_config_help);
 919			break;
 920		case KEY_ESC:
 921			return;
 922		}
 923	}
 924}
 925
 926static void conf_save(void)
 927{
 928	while (1) {
 929		int res;
 930		dialog_clear();
 931		res = dialog_inputbox(NULL, save_config_text,
 932				      11, 55, filename);
 933		switch(res) {
 934		case 0:
 935			if (!dialog_input_result[0])
 936				return;
 937			if (!conf_write(dialog_input_result)) {
 938				set_config_filename(dialog_input_result);
 939				return;
 940			}
 941			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
 942			break;
 943		case 1:
 944			show_helptext(_("Save Alternate Configuration"), save_config_help);
 945			break;
 946		case KEY_ESC:
 947			return;
 948		}
 949	}
 950}
 951
 952static int handle_exit(void)
 953{
 954	int res;
 955
 956	save_and_exit = 1;
 957	reset_subtitle();
 958	dialog_clear();
 959	if (conf_get_changed())
 960		res = dialog_yesno(NULL,
 961				   _("Do you wish to save your new configuration?\n"
 962				     "(Press <ESC><ESC> to continue kernel configuration.)"),
 963				   6, 60);
 964	else
 965		res = -1;
 966
 967	end_dialog(saved_x, saved_y);
 968
 969	switch (res) {
 970	case 0:
 971		if (conf_write(filename)) {
 972			fprintf(stderr, _("\n\n"
 973					  "Error while writing of the configuration.\n"
 974					  "Your configuration changes were NOT saved."
 975					  "\n\n"));
 976			return 1;
 977		}
 
 978		/* fall through */
 979	case -1:
 980		printf(_("\n\n"
 981			 "*** End of the configuration.\n"
 982			 "*** Execute 'make' to start the build or try 'make help'."
 983			 "\n\n"));
 
 984		res = 0;
 985		break;
 986	default:
 987		fprintf(stderr, _("\n\n"
 988				  "Your configuration changes were NOT saved."
 989				  "\n\n"));
 
 990		if (res != KEY_ESC)
 991			res = 0;
 992	}
 993
 994	return res;
 995}
 996
 997static void sig_handler(int signo)
 998{
 999	exit(handle_exit());
1000}
1001
1002int main(int ac, char **av)
1003{
1004	char *mode;
1005	int res;
1006
1007	setlocale(LC_ALL, "");
1008	bindtextdomain(PACKAGE, LOCALEDIR);
1009	textdomain(PACKAGE);
1010
1011	signal(SIGINT, sig_handler);
1012
 
 
 
 
 
 
1013	conf_parse(av[1]);
1014	conf_read(NULL);
1015
1016	mode = getenv("MENUCONFIG_MODE");
1017	if (mode) {
1018		if (!strcasecmp(mode, "single_menu"))
1019			single_menu_mode = 1;
1020	}
1021
1022	if (init_dialog(NULL)) {
1023		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
1024		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
1025		return 1;
1026	}
1027
1028	set_config_filename(conf_get_configname());
1029	conf_set_message_callback(conf_message_callback);
1030	do {
1031		conf(&rootmenu, NULL);
1032		res = handle_exit();
1033	} while (res == KEY_ESC);
1034
1035	return res;
1036}
1037