Linux Audio

Check our new training course

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