cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mconf.c (27843B)


      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"Different color themes available\n"
    165"--------------------------------\n"
    166"It is possible to select different color themes using the variable\n"
    167"MENUCONFIG_COLOR. To select a theme use:\n"
    168"\n"
    169"make MENUCONFIG_COLOR=<theme> menuconfig\n"
    170"\n"
    171"Available themes are\n"
    172" mono       => selects colors suitable for monochrome displays\n"
    173" blackbg    => selects a color scheme with black background\n"
    174" classic    => theme with blue background. The classic look\n"
    175" bluetitle  => an LCD friendly version of classic. (default)\n"
    176"\n",
    177menu_instructions[] =
    178	"Arrow keys navigate the menu.  "
    179	"<Enter> selects submenus ---> (or empty submenus ----).  "
    180	"Highlighted letters are hotkeys.  "
    181	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
    182	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
    183	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable",
    184radiolist_instructions[] =
    185	"Use the arrow keys to navigate this window or "
    186	"press the hotkey of the item you wish to select "
    187	"followed by the <SPACE BAR>. "
    188	"Press <?> for additional information about this option.",
    189inputbox_instructions_int[] =
    190	"Please enter a decimal value. "
    191	"Fractions will not be accepted.  "
    192	"Use the <TAB> key to move from the input field to the buttons below it.",
    193inputbox_instructions_hex[] =
    194	"Please enter a hexadecimal value. "
    195	"Use the <TAB> key to move from the input field to the buttons below it.",
    196inputbox_instructions_string[] =
    197	"Please enter a string value. "
    198	"Use the <TAB> key to move from the input field to the buttons below it.",
    199setmod_text[] =
    200	"This feature depends on another which has been configured as a module.\n"
    201	"As a result, this feature will be built as a module.",
    202load_config_text[] =
    203	"Enter the name of the configuration file you wish to load.  "
    204	"Accept the name shown to restore the configuration you "
    205	"last retrieved.  Leave blank to abort.",
    206load_config_help[] =
    207	"\n"
    208	"For various reasons, one may wish to keep several different\n"
    209	"configurations available on a single machine.\n"
    210	"\n"
    211	"If you have saved a previous configuration in a file other than the\n"
    212	"default one, entering its name here will allow you to modify that\n"
    213	"configuration.\n"
    214	"\n"
    215	"If you are uncertain, then you have probably never used alternate\n"
    216	"configuration files. You should therefore leave this blank to abort.\n",
    217save_config_text[] =
    218	"Enter a filename to which this configuration should be saved "
    219	"as an alternate.  Leave blank to abort.",
    220save_config_help[] =
    221	"\n"
    222	"For various reasons, one may wish to keep different configurations\n"
    223	"available on a single machine.\n"
    224	"\n"
    225	"Entering a file name here will allow you to later retrieve, modify\n"
    226	"and use the current configuration as an alternate to whatever\n"
    227	"configuration options you have selected at that time.\n"
    228	"\n"
    229	"If you are uncertain what all this means then you should probably\n"
    230	"leave this blank.\n",
    231search_help[] =
    232	"\n"
    233	"Search for symbols and display their relations.\n"
    234	"Regular expressions are allowed.\n"
    235	"Example: search for \"^FOO\"\n"
    236	"Result:\n"
    237	"-----------------------------------------------------------------\n"
    238	"Symbol: FOO [=m]\n"
    239	"Type  : tristate\n"
    240	"Prompt: Foo bus is used to drive the bar HW\n"
    241	"  Location:\n"
    242	"    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
    243	"      -> PCI support (PCI [=y])\n"
    244	"(1)     -> PCI access mode (<choice> [=y])\n"
    245	"  Defined at drivers/pci/Kconfig:47\n"
    246	"  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
    247	"  Selects: LIBCRC32\n"
    248	"  Selected by: BAR [=n]\n"
    249	"-----------------------------------------------------------------\n"
    250	"o The line 'Type:' shows the type of the configuration option for\n"
    251	"  this symbol (bool, tristate, string, ...)\n"
    252	"o The line 'Prompt:' shows the text used in the menu structure for\n"
    253	"  this symbol\n"
    254	"o The 'Defined at' line tells at what file / line number the symbol\n"
    255	"  is defined\n"
    256	"o The 'Depends on:' line tells what symbols need to be defined for\n"
    257	"  this symbol to be visible in the menu (selectable)\n"
    258	"o The 'Location:' lines tells where in the menu structure this symbol\n"
    259	"  is located\n"
    260	"    A location followed by a [=y] indicates that this is a\n"
    261	"    selectable menu item - and the current value is displayed inside\n"
    262	"    brackets.\n"
    263	"    Press the key in the (#) prefix to jump directly to that\n"
    264	"    location. You will be returned to the current search results\n"
    265	"    after exiting this new menu.\n"
    266	"o The 'Selects:' line tells what symbols will be automatically\n"
    267	"  selected if this symbol is selected (y or m)\n"
    268	"o The 'Selected by' line tells what symbol has selected this symbol\n"
    269	"\n"
    270	"Only relevant lines are shown.\n"
    271	"\n\n"
    272	"Search examples:\n"
    273	"Examples: USB	=> find all symbols containing USB\n"
    274	"          ^USB => find all symbols starting with USB\n"
    275	"          USB$ => find all symbols ending with USB\n"
    276	"\n";
    277
    278static int indent;
    279static struct menu *current_menu;
    280static int child_count;
    281static int single_menu_mode;
    282static int show_all_options;
    283static int save_and_exit;
    284static int silent;
    285
    286static void conf(struct menu *menu, struct menu *active_menu);
    287static void conf_choice(struct menu *menu);
    288static void conf_string(struct menu *menu);
    289static void conf_load(void);
    290static void conf_save(void);
    291static int show_textbox_ext(const char *title, char *text, int r, int c,
    292			    int *keys, int *vscroll, int *hscroll,
    293			    update_text_fn update_text, void *data);
    294static void show_textbox(const char *title, const char *text, int r, int c);
    295static void show_helptext(const char *title, const char *text);
    296static void show_help(struct menu *menu);
    297
    298static char filename[PATH_MAX+1];
    299static void set_config_filename(const char *config_filename)
    300{
    301	static char menu_backtitle[PATH_MAX+128];
    302
    303	snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
    304		 config_filename, rootmenu.prompt->text);
    305	set_dialog_backtitle(menu_backtitle);
    306
    307	snprintf(filename, sizeof(filename), "%s", config_filename);
    308}
    309
    310struct subtitle_part {
    311	struct list_head entries;
    312	const char *text;
    313};
    314static LIST_HEAD(trail);
    315
    316static struct subtitle_list *subtitles;
    317static void set_subtitle(void)
    318{
    319	struct subtitle_part *sp;
    320	struct subtitle_list *pos, *tmp;
    321
    322	for (pos = subtitles; pos != NULL; pos = tmp) {
    323		tmp = pos->next;
    324		free(pos);
    325	}
    326
    327	subtitles = NULL;
    328	list_for_each_entry(sp, &trail, entries) {
    329		if (sp->text) {
    330			if (pos) {
    331				pos->next = xcalloc(1, sizeof(*pos));
    332				pos = pos->next;
    333			} else {
    334				subtitles = pos = xcalloc(1, sizeof(*pos));
    335			}
    336			pos->text = sp->text;
    337		}
    338	}
    339
    340	set_dialog_subtitles(subtitles);
    341}
    342
    343static void reset_subtitle(void)
    344{
    345	struct subtitle_list *pos, *tmp;
    346
    347	for (pos = subtitles; pos != NULL; pos = tmp) {
    348		tmp = pos->next;
    349		free(pos);
    350	}
    351	subtitles = NULL;
    352	set_dialog_subtitles(subtitles);
    353}
    354
    355struct search_data {
    356	struct list_head *head;
    357	struct menu **targets;
    358	int *keys;
    359};
    360
    361static void update_text(char *buf, size_t start, size_t end, void *_data)
    362{
    363	struct search_data *data = _data;
    364	struct jump_key *pos;
    365	int k = 0;
    366
    367	list_for_each_entry(pos, data->head, entries) {
    368		if (pos->offset >= start && pos->offset < end) {
    369			char header[4];
    370
    371			if (k < JUMP_NB) {
    372				int key = '0' + (pos->index % JUMP_NB) + 1;
    373
    374				sprintf(header, "(%c)", key);
    375				data->keys[k] = key;
    376				data->targets[k] = pos->target;
    377				k++;
    378			} else {
    379				sprintf(header, "   ");
    380			}
    381
    382			memcpy(buf + pos->offset, header, sizeof(header) - 1);
    383		}
    384	}
    385	data->keys[k] = 0;
    386}
    387
    388static void search_conf(void)
    389{
    390	struct symbol **sym_arr;
    391	struct gstr res;
    392	struct gstr title;
    393	char *dialog_input;
    394	int dres, vscroll = 0, hscroll = 0;
    395	bool again;
    396	struct gstr sttext;
    397	struct subtitle_part stpart;
    398
    399	title = str_new();
    400	str_printf( &title, "Enter (sub)string or regexp to search for "
    401			      "(with or without \"%s\")", CONFIG_);
    402
    403again:
    404	dialog_clear();
    405	dres = dialog_inputbox("Search Configuration Parameter",
    406			      str_get(&title),
    407			      10, 75, "");
    408	switch (dres) {
    409	case 0:
    410		break;
    411	case 1:
    412		show_helptext("Search Configuration", search_help);
    413		goto again;
    414	default:
    415		str_free(&title);
    416		return;
    417	}
    418
    419	/* strip the prefix if necessary */
    420	dialog_input = dialog_input_result;
    421	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
    422		dialog_input += strlen(CONFIG_);
    423
    424	sttext = str_new();
    425	str_printf(&sttext, "Search (%s)", dialog_input_result);
    426	stpart.text = str_get(&sttext);
    427	list_add_tail(&stpart.entries, &trail);
    428
    429	sym_arr = sym_re_search(dialog_input);
    430	do {
    431		LIST_HEAD(head);
    432		struct menu *targets[JUMP_NB];
    433		int keys[JUMP_NB + 1], i;
    434		struct search_data data = {
    435			.head = &head,
    436			.targets = targets,
    437			.keys = keys,
    438		};
    439		struct jump_key *pos, *tmp;
    440
    441		res = get_relations_str(sym_arr, &head);
    442		set_subtitle();
    443		dres = show_textbox_ext("Search Results", (char *)
    444					str_get(&res), 0, 0, keys, &vscroll,
    445					&hscroll, &update_text, (void *)
    446					&data);
    447		again = false;
    448		for (i = 0; i < JUMP_NB && keys[i]; i++)
    449			if (dres == keys[i]) {
    450				conf(targets[i]->parent, targets[i]);
    451				again = true;
    452			}
    453		str_free(&res);
    454		list_for_each_entry_safe(pos, tmp, &head, entries)
    455			free(pos);
    456	} while (again);
    457	free(sym_arr);
    458	str_free(&title);
    459	list_del(trail.prev);
    460	str_free(&sttext);
    461}
    462
    463static void build_conf(struct menu *menu)
    464{
    465	struct symbol *sym;
    466	struct property *prop;
    467	struct menu *child;
    468	int type, tmp, doint = 2;
    469	tristate val;
    470	char ch;
    471	bool visible;
    472
    473	/*
    474	 * note: menu_is_visible() has side effect that it will
    475	 * recalc the value of the symbol.
    476	 */
    477	visible = menu_is_visible(menu);
    478	if (show_all_options && !menu_has_prompt(menu))
    479		return;
    480	else if (!show_all_options && !visible)
    481		return;
    482
    483	sym = menu->sym;
    484	prop = menu->prompt;
    485	if (!sym) {
    486		if (prop && menu != current_menu) {
    487			const char *prompt = menu_get_prompt(menu);
    488			switch (prop->type) {
    489			case P_MENU:
    490				child_count++;
    491				if (single_menu_mode) {
    492					item_make("%s%*c%s",
    493						  menu->data ? "-->" : "++>",
    494						  indent + 1, ' ', prompt);
    495				} else
    496					item_make("   %*c%s  %s",
    497						  indent + 1, ' ', prompt,
    498						  menu_is_empty(menu) ? "----" : "--->");
    499				item_set_tag('m');
    500				item_set_data(menu);
    501				if (single_menu_mode && menu->data)
    502					goto conf_childs;
    503				return;
    504			case P_COMMENT:
    505				if (prompt) {
    506					child_count++;
    507					item_make("   %*c*** %s ***", indent + 1, ' ', prompt);
    508					item_set_tag(':');
    509					item_set_data(menu);
    510				}
    511				break;
    512			default:
    513				if (prompt) {
    514					child_count++;
    515					item_make("---%*c%s", indent + 1, ' ', prompt);
    516					item_set_tag(':');
    517					item_set_data(menu);
    518				}
    519			}
    520		} else
    521			doint = 0;
    522		goto conf_childs;
    523	}
    524
    525	type = sym_get_type(sym);
    526	if (sym_is_choice(sym)) {
    527		struct symbol *def_sym = sym_get_choice_value(sym);
    528		struct menu *def_menu = NULL;
    529
    530		child_count++;
    531		for (child = menu->list; child; child = child->next) {
    532			if (menu_is_visible(child) && child->sym == def_sym)
    533				def_menu = child;
    534		}
    535
    536		val = sym_get_tristate_value(sym);
    537		if (sym_is_changeable(sym)) {
    538			switch (type) {
    539			case S_BOOLEAN:
    540				item_make("[%c]", val == no ? ' ' : '*');
    541				break;
    542			case S_TRISTATE:
    543				switch (val) {
    544				case yes: ch = '*'; break;
    545				case mod: ch = 'M'; break;
    546				default:  ch = ' '; break;
    547				}
    548				item_make("<%c>", ch);
    549				break;
    550			}
    551			item_set_tag('t');
    552			item_set_data(menu);
    553		} else {
    554			item_make("   ");
    555			item_set_tag(def_menu ? 't' : ':');
    556			item_set_data(menu);
    557		}
    558
    559		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
    560		if (val == yes) {
    561			if (def_menu) {
    562				item_add_str(" (%s)", menu_get_prompt(def_menu));
    563				item_add_str("  --->");
    564				if (def_menu->list) {
    565					indent += 2;
    566					build_conf(def_menu);
    567					indent -= 2;
    568				}
    569			}
    570			return;
    571		}
    572	} else {
    573		if (menu == current_menu) {
    574			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
    575			item_set_tag(':');
    576			item_set_data(menu);
    577			goto conf_childs;
    578		}
    579		child_count++;
    580		val = sym_get_tristate_value(sym);
    581		if (sym_is_choice_value(sym) && val == yes) {
    582			item_make("   ");
    583			item_set_tag(':');
    584			item_set_data(menu);
    585		} else {
    586			switch (type) {
    587			case S_BOOLEAN:
    588				if (sym_is_changeable(sym))
    589					item_make("[%c]", val == no ? ' ' : '*');
    590				else
    591					item_make("-%c-", val == no ? ' ' : '*');
    592				item_set_tag('t');
    593				item_set_data(menu);
    594				break;
    595			case S_TRISTATE:
    596				switch (val) {
    597				case yes: ch = '*'; break;
    598				case mod: ch = 'M'; break;
    599				default:  ch = ' '; break;
    600				}
    601				if (sym_is_changeable(sym)) {
    602					if (sym->rev_dep.tri == mod)
    603						item_make("{%c}", ch);
    604					else
    605						item_make("<%c>", ch);
    606				} else
    607					item_make("-%c-", ch);
    608				item_set_tag('t');
    609				item_set_data(menu);
    610				break;
    611			default:
    612				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
    613				item_make("(%s)", sym_get_string_value(sym));
    614				tmp = indent - tmp + 4;
    615				if (tmp < 0)
    616					tmp = 0;
    617				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
    618					     (sym_has_value(sym) || !sym_is_changeable(sym)) ?
    619					     "" : " (NEW)");
    620				item_set_tag('s');
    621				item_set_data(menu);
    622				goto conf_childs;
    623			}
    624		}
    625		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
    626			  (sym_has_value(sym) || !sym_is_changeable(sym)) ?
    627			  "" : " (NEW)");
    628		if (menu->prompt->type == P_MENU) {
    629			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
    630			return;
    631		}
    632	}
    633
    634conf_childs:
    635	indent += doint;
    636	for (child = menu->list; child; child = child->next)
    637		build_conf(child);
    638	indent -= doint;
    639}
    640
    641static void conf(struct menu *menu, struct menu *active_menu)
    642{
    643	struct menu *submenu;
    644	const char *prompt = menu_get_prompt(menu);
    645	struct subtitle_part stpart;
    646	struct symbol *sym;
    647	int res;
    648	int s_scroll = 0;
    649
    650	if (menu != &rootmenu)
    651		stpart.text = menu_get_prompt(menu);
    652	else
    653		stpart.text = NULL;
    654	list_add_tail(&stpart.entries, &trail);
    655
    656	while (1) {
    657		item_reset();
    658		current_menu = menu;
    659		build_conf(menu);
    660		if (!child_count)
    661			break;
    662		set_subtitle();
    663		dialog_clear();
    664		res = dialog_menu(prompt ? prompt : "Main Menu",
    665				  menu_instructions,
    666				  active_menu, &s_scroll);
    667		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
    668			break;
    669		if (item_count() != 0) {
    670			if (!item_activate_selected())
    671				continue;
    672			if (!item_tag())
    673				continue;
    674		}
    675		submenu = item_data();
    676		active_menu = item_data();
    677		if (submenu)
    678			sym = submenu->sym;
    679		else
    680			sym = NULL;
    681
    682		switch (res) {
    683		case 0:
    684			switch (item_tag()) {
    685			case 'm':
    686				if (single_menu_mode)
    687					submenu->data = (void *) (long) !submenu->data;
    688				else
    689					conf(submenu, NULL);
    690				break;
    691			case 't':
    692				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
    693					conf_choice(submenu);
    694				else if (submenu->prompt->type == P_MENU)
    695					conf(submenu, NULL);
    696				break;
    697			case 's':
    698				conf_string(submenu);
    699				break;
    700			}
    701			break;
    702		case 2:
    703			if (sym)
    704				show_help(submenu);
    705			else {
    706				reset_subtitle();
    707				show_helptext("README", mconf_readme);
    708			}
    709			break;
    710		case 3:
    711			reset_subtitle();
    712			conf_save();
    713			break;
    714		case 4:
    715			reset_subtitle();
    716			conf_load();
    717			break;
    718		case 5:
    719			if (item_is_tag('t')) {
    720				if (sym_set_tristate_value(sym, yes))
    721					break;
    722				if (sym_set_tristate_value(sym, mod))
    723					show_textbox(NULL, setmod_text, 6, 74);
    724			}
    725			break;
    726		case 6:
    727			if (item_is_tag('t'))
    728				sym_set_tristate_value(sym, no);
    729			break;
    730		case 7:
    731			if (item_is_tag('t'))
    732				sym_set_tristate_value(sym, mod);
    733			break;
    734		case 8:
    735			if (item_is_tag('t'))
    736				sym_toggle_tristate_value(sym);
    737			else if (item_is_tag('m'))
    738				conf(submenu, NULL);
    739			break;
    740		case 9:
    741			search_conf();
    742			break;
    743		case 10:
    744			show_all_options = !show_all_options;
    745			break;
    746		}
    747	}
    748
    749	list_del(trail.prev);
    750}
    751
    752static int show_textbox_ext(const char *title, char *text, int r, int c, int
    753			    *keys, int *vscroll, int *hscroll, update_text_fn
    754			    update_text, void *data)
    755{
    756	dialog_clear();
    757	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
    758			      update_text, data);
    759}
    760
    761static void show_textbox(const char *title, const char *text, int r, int c)
    762{
    763	show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
    764			 NULL, NULL);
    765}
    766
    767static void show_helptext(const char *title, const char *text)
    768{
    769	show_textbox(title, text, 0, 0);
    770}
    771
    772static void conf_message_callback(const char *s)
    773{
    774	if (save_and_exit) {
    775		if (!silent)
    776			printf("%s", s);
    777	} else {
    778		show_textbox(NULL, s, 6, 60);
    779	}
    780}
    781
    782static void show_help(struct menu *menu)
    783{
    784	struct gstr help = str_new();
    785
    786	help.max_width = getmaxx(stdscr) - 10;
    787	menu_get_ext_help(menu, &help);
    788
    789	show_helptext(menu_get_prompt(menu), str_get(&help));
    790	str_free(&help);
    791}
    792
    793static void conf_choice(struct menu *menu)
    794{
    795	const char *prompt = menu_get_prompt(menu);
    796	struct menu *child;
    797	struct symbol *active;
    798
    799	active = sym_get_choice_value(menu->sym);
    800	while (1) {
    801		int res;
    802		int selected;
    803		item_reset();
    804
    805		current_menu = menu;
    806		for (child = menu->list; child; child = child->next) {
    807			if (!menu_is_visible(child))
    808				continue;
    809			if (child->sym)
    810				item_make("%s", menu_get_prompt(child));
    811			else {
    812				item_make("*** %s ***", menu_get_prompt(child));
    813				item_set_tag(':');
    814			}
    815			item_set_data(child);
    816			if (child->sym == active)
    817				item_set_selected(1);
    818			if (child->sym == sym_get_choice_value(menu->sym))
    819				item_set_tag('X');
    820		}
    821		dialog_clear();
    822		res = dialog_checklist(prompt ? prompt : "Main Menu",
    823					radiolist_instructions,
    824					MENUBOX_HEIGTH_MIN,
    825					MENUBOX_WIDTH_MIN,
    826					CHECKLIST_HEIGTH_MIN);
    827		selected = item_activate_selected();
    828		switch (res) {
    829		case 0:
    830			if (selected) {
    831				child = item_data();
    832				if (!child->sym)
    833					break;
    834
    835				sym_set_tristate_value(child->sym, yes);
    836			}
    837			return;
    838		case 1:
    839			if (selected) {
    840				child = item_data();
    841				show_help(child);
    842				active = child->sym;
    843			} else
    844				show_help(menu);
    845			break;
    846		case KEY_ESC:
    847			return;
    848		case -ERRDISPLAYTOOSMALL:
    849			return;
    850		}
    851	}
    852}
    853
    854static void conf_string(struct menu *menu)
    855{
    856	const char *prompt = menu_get_prompt(menu);
    857
    858	while (1) {
    859		int res;
    860		const char *heading;
    861
    862		switch (sym_get_type(menu->sym)) {
    863		case S_INT:
    864			heading = inputbox_instructions_int;
    865			break;
    866		case S_HEX:
    867			heading = inputbox_instructions_hex;
    868			break;
    869		case S_STRING:
    870			heading = inputbox_instructions_string;
    871			break;
    872		default:
    873			heading = "Internal mconf error!";
    874		}
    875		dialog_clear();
    876		res = dialog_inputbox(prompt ? prompt : "Main Menu",
    877				      heading, 10, 75,
    878				      sym_get_string_value(menu->sym));
    879		switch (res) {
    880		case 0:
    881			if (sym_set_string_value(menu->sym, dialog_input_result))
    882				return;
    883			show_textbox(NULL, "You have made an invalid entry.", 5, 43);
    884			break;
    885		case 1:
    886			show_help(menu);
    887			break;
    888		case KEY_ESC:
    889			return;
    890		}
    891	}
    892}
    893
    894static void conf_load(void)
    895{
    896
    897	while (1) {
    898		int res;
    899		dialog_clear();
    900		res = dialog_inputbox(NULL, load_config_text,
    901				      11, 55, filename);
    902		switch(res) {
    903		case 0:
    904			if (!dialog_input_result[0])
    905				return;
    906			if (!conf_read(dialog_input_result)) {
    907				set_config_filename(dialog_input_result);
    908				conf_set_changed(true);
    909				return;
    910			}
    911			show_textbox(NULL, "File does not exist!", 5, 38);
    912			break;
    913		case 1:
    914			show_helptext("Load Alternate Configuration", load_config_help);
    915			break;
    916		case KEY_ESC:
    917			return;
    918		}
    919	}
    920}
    921
    922static void conf_save(void)
    923{
    924	while (1) {
    925		int res;
    926		dialog_clear();
    927		res = dialog_inputbox(NULL, save_config_text,
    928				      11, 55, filename);
    929		switch(res) {
    930		case 0:
    931			if (!dialog_input_result[0])
    932				return;
    933			if (!conf_write(dialog_input_result)) {
    934				set_config_filename(dialog_input_result);
    935				return;
    936			}
    937			show_textbox(NULL, "Can't create file!", 5, 60);
    938			break;
    939		case 1:
    940			show_helptext("Save Alternate Configuration", save_config_help);
    941			break;
    942		case KEY_ESC:
    943			return;
    944		}
    945	}
    946}
    947
    948static int handle_exit(void)
    949{
    950	int res;
    951
    952	save_and_exit = 1;
    953	reset_subtitle();
    954	dialog_clear();
    955	if (conf_get_changed())
    956		res = dialog_yesno(NULL,
    957				   "Do you wish to save your new configuration?\n"
    958				     "(Press <ESC><ESC> to continue kernel configuration.)",
    959				   6, 60);
    960	else
    961		res = -1;
    962
    963	end_dialog(saved_x, saved_y);
    964
    965	switch (res) {
    966	case 0:
    967		if (conf_write(filename)) {
    968			fprintf(stderr, "\n\n"
    969					  "Error while writing of the configuration.\n"
    970					  "Your configuration changes were NOT saved."
    971					  "\n\n");
    972			return 1;
    973		}
    974		conf_write_autoconf(0);
    975		/* fall through */
    976	case -1:
    977		if (!silent)
    978			printf("\n\n"
    979				 "*** End of the configuration.\n"
    980				 "*** Execute 'make' to start the build or try 'make help'."
    981				 "\n\n");
    982		res = 0;
    983		break;
    984	default:
    985		if (!silent)
    986			fprintf(stderr, "\n\n"
    987					  "Your configuration changes were NOT saved."
    988					  "\n\n");
    989		if (res != KEY_ESC)
    990			res = 0;
    991	}
    992
    993	return res;
    994}
    995
    996static void sig_handler(int signo)
    997{
    998	exit(handle_exit());
    999}
   1000
   1001int main(int ac, char **av)
   1002{
   1003	char *mode;
   1004	int res;
   1005
   1006	signal(SIGINT, sig_handler);
   1007
   1008	if (ac > 1 && strcmp(av[1], "-s") == 0) {
   1009		silent = 1;
   1010		/* Silence conf_read() until the real callback is set up */
   1011		conf_set_message_callback(NULL);
   1012		av++;
   1013	}
   1014	conf_parse(av[1]);
   1015	conf_read(NULL);
   1016
   1017	mode = getenv("MENUCONFIG_MODE");
   1018	if (mode) {
   1019		if (!strcasecmp(mode, "single_menu"))
   1020			single_menu_mode = 1;
   1021	}
   1022
   1023	if (init_dialog(NULL)) {
   1024		fprintf(stderr, "Your display is too small to run Menuconfig!\n");
   1025		fprintf(stderr, "It must be at least 19 lines by 80 columns.\n");
   1026		return 1;
   1027	}
   1028
   1029	set_config_filename(conf_get_configname());
   1030	conf_set_message_callback(conf_message_callback);
   1031	do {
   1032		conf(&rootmenu, NULL);
   1033		res = handle_exit();
   1034	} while (res == KEY_ESC);
   1035
   1036	return res;
   1037}