1/*
2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
3 * Released under the terms of the GNU GPL v2.0.
4 *
5 * Introduced single menu mode (show all sub-menus in one large tree).
6 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
7 *
8 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
9 */
10
11#include <sys/ioctl.h>
12#include <sys/wait.h>
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <limits.h>
17#include <signal.h>
18#include <stdarg.h>
19#include <stdlib.h>
20#include <string.h>
21#include <termios.h>
22#include <unistd.h>
23#include <locale.h>
24
25#define LKC_DIRECT_LINK
26#include "lkc.h"
27#include "lxdialog/dialog.h"
28
29static const char mconf_readme[] = N_(
30"Overview\n"
31"--------\n"
32"Some kernel features may be built directly into the kernel.\n"
33"Some may be made into loadable runtime modules.  Some features\n"
34"may be completely removed altogether.  There are also certain\n"
35"kernel parameters which are not really features, but must be\n"
36"entered in as decimal or hexadecimal numbers or possibly text.\n"
37"\n"
38"Menu items beginning with [*], <M> or [ ] represent features\n"
39"configured to be built in, modularized or removed respectively.\n"
40"Pointed brackets <> represent module capable features.\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 removed it.  You may also press the <Space Bar> to cycle\n"
45"through the available options (ie. 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\n"
52"   you wish to change or submenu wish to select and press <Enter>.\n"
53"   Submenus are designated 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> and <Help>\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"\n"
78"Radiolists  (Choice lists)\n"
79"-----------\n"
80"o  Use the cursor keys to select the option you wish to set and press\n"
81"   <S> or the <SPACE BAR>.\n"
82"\n"
83"   Shortcut: Press the first letter of the option you wish to set then\n"
84"             press <S> or <SPACE BAR>.\n"
85"\n"
86"o  To see available help for the item, use the cursor keys to highlight\n"
87"   <Help> and Press <ENTER>.\n"
88"\n"
89"   Shortcut: Press <H> or <?>.\n"
90"\n"
91"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
92"   <Help>\n"
93"\n"
94"\n"
95"Data Entry\n"
96"-----------\n"
97"o  Enter the requested information and press <ENTER>\n"
98"   If you are entering hexadecimal values, it is not necessary to\n"
99"   add the '0x' prefix to the entry.\n"
100"\n"
101"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
102"   and press <ENTER>.  You can try <TAB><H> as well.\n"
103"\n"
104"\n"
105"Text Box    (Help Window)\n"
106"--------\n"
107"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
108"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
109"   who are familiar with less and lynx.\n"
110"\n"
111"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
112"\n"
113"\n"
114"Alternate Configuration Files\n"
115"-----------------------------\n"
116"Menuconfig supports the use of alternate configuration files for\n"
117"those who, for various reasons, find it necessary to switch\n"
118"between different kernel configurations.\n"
119"\n"
120"At the end of the main menu you will find two options.  One is\n"
121"for saving the current configuration to a file of your choosing.\n"
122"The other option is for loading a previously saved alternate\n"
123"configuration.\n"
124"\n"
125"Even if you don't use alternate configuration files, but you\n"
126"find during a Menuconfig session that you have completely messed\n"
127"up your settings, you may use the \"Load Alternate...\" option to\n"
128"restore your previously saved settings from \".config\" without\n"
129"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 a xterm definition which supports color.\n"
135"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
136"display correctly in a 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 kernel options listed in a single\n"
152"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
153"with 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  => a LCD friendly version of classic. (default)\n"
176"\n"),
177menu_instructions[] = N_(
178	"Arrow keys navigate the menu.  "
179	"<Enter> selects 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[] = N_(
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[] = N_(
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[] = N_(
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[] = N_(
197	"Please enter a string value. "
198	"Use the <TAB> key to move from the input field to the buttons below it."),
199setmod_text[] = N_(
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."),
202nohelp_text[] = N_(
203	"There is no help available for this kernel option.\n"),
204load_config_text[] = N_(
205	"Enter the name of the configuration file you wish to load.  "
206	"Accept the name shown to restore the configuration you "
207	"last retrieved.  Leave blank to abort."),
208load_config_help[] = N_(
209	"\n"
210	"For various reasons, one may wish to keep several different kernel\n"
211	"configurations available on a single machine.\n"
212	"\n"
213	"If you have saved a previous configuration in a file other than the\n"
214	"kernel's default, entering the name of the file here will allow you\n"
215	"to modify that configuration.\n"
216	"\n"
217	"If you are uncertain, then you have probably never used alternate\n"
218	"configuration files.  You should therefor leave this blank to abort.\n"),
219save_config_text[] = N_(
220	"Enter a filename to which this configuration should be saved "
221	"as an alternate.  Leave blank to abort."),
222save_config_help[] = N_(
223	"\n"
224	"For various reasons, one may wish to keep different kernel\n"
225	"configurations available on a single machine.\n"
226	"\n"
227	"Entering a file name here will allow you to later retrieve, modify\n"
228	"and use the current configuration as an alternate to whatever\n"
229	"configuration options you have selected at that time.\n"
230	"\n"
231	"If you are uncertain what all this means then you should probably\n"
232	"leave this blank.\n"),
233search_help[] = N_(
234	"\n"
235	"Search for CONFIG_ symbols and display their relations.\n"
236	"Regular expressions are allowed.\n"
237	"Example: search for \"^FOO\"\n"
238	"Result:\n"
239	"-----------------------------------------------------------------\n"
240	"Symbol: FOO [=m]\n"
241	"Prompt: Foo bus is used to drive the bar HW\n"
242	"Defined at drivers/pci/Kconfig:47\n"
243	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
244	"Location:\n"
245	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
246	"    -> PCI support (PCI [=y])\n"
247	"      -> PCI access mode (<choice> [=y])\n"
248	"Selects: LIBCRC32\n"
249	"Selected by: BAR\n"
250	"-----------------------------------------------------------------\n"
251	"o The line 'Prompt:' shows the text used in the menu structure for\n"
252	"  this CONFIG_ symbol\n"
253	"o The 'Defined at' line tell at what file / line number the symbol\n"
254	"  is defined\n"
255	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
256	"  this symbol to be visible in the menu (selectable)\n"
257	"o The 'Location:' lines tell where in the menu structure this symbol\n"
258	"  is located\n"
259	"    A location followed by a [=y] indicate that this is a selectable\n"
260	"    menu item - and current value is displayed inside brackets.\n"
261	"o The 'Selects:' line tell what symbol will be automatically\n"
262	"  selected if this symbol is selected (y or m)\n"
263	"o The 'Selected by' line tell what symbol has selected this symbol\n"
264	"\n"
265	"Only relevant lines are shown.\n"
266	"\n\n"
267	"Search examples:\n"
268	"Examples: USB	=> find all CONFIG_ symbols containing USB\n"
269	"          ^USB => find all CONFIG_ symbols starting with USB\n"
270	"          USB$ => find all CONFIG_ symbols ending with USB\n"
271	"\n");
272
273static int indent;
274static struct termios ios_org;
275static int rows = 0, cols = 0;
276static struct menu *current_menu;
277static int child_count;
278static int single_menu_mode;
279
280static void conf(struct menu *menu);
281static void conf_choice(struct menu *menu);
282static void conf_string(struct menu *menu);
283static void conf_load(void);
284static void conf_save(void);
285static void show_textbox(const char *title, const char *text, int r, int c);
286static void show_helptext(const char *title, const char *text);
287static void show_help(struct menu *menu);
288
289static void init_wsize(void)
290{
291	struct winsize ws;
292	char *env;
293
294	if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) {
295		rows = ws.ws_row;
296		cols = ws.ws_col;
297	}
298
299	if (!rows) {
300		env = getenv("LINES");
301		if (env)
302			rows = atoi(env);
303		if (!rows)
304			rows = 24;
305	}
306	if (!cols) {
307		env = getenv("COLUMNS");
308		if (env)
309			cols = atoi(env);
310		if (!cols)
311			cols = 80;
312	}
313
314	if (rows < 19 || cols < 80) {
315		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
316		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
317		exit(1);
318	}
319
320	rows -= 4;
321	cols -= 5;
322}
323
324static void get_prompt_str(struct gstr *r, struct property *prop)
325{
326	int i, j;
327	struct menu *submenu[8], *menu;
328
329	str_printf(r, "Prompt: %s\n", prop->text);
330	str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
331		prop->menu->lineno);
332	if (!expr_is_yes(prop->visible.expr)) {
333		str_append(r, "  Depends on: ");
334		expr_gstr_print(prop->visible.expr, r);
335		str_append(r, "\n");
336	}
337	menu = prop->menu->parent;
338	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
339		submenu[i++] = menu;
340	if (i > 0) {
341		str_printf(r, "  Location:\n");
342		for (j = 4; --i >= 0; j += 2) {
343			menu = submenu[i];
344			str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu));
345			if (menu->sym) {
346				str_printf(r, " (%s [=%s])", menu->sym->name ?
347					menu->sym->name : "<choice>",
348					sym_get_string_value(menu->sym));
349			}
350			str_append(r, "\n");
351		}
352	}
353}
354
355static void get_symbol_str(struct gstr *r, struct symbol *sym)
356{
357	bool hit;
358	struct property *prop;
359
360	str_printf(r, "Symbol: %s [=%s]\n", sym->name,
361	                               sym_get_string_value(sym));
362	for_all_prompts(sym, prop)
363		get_prompt_str(r, prop);
364	hit = false;
365	for_all_properties(sym, prop, P_SELECT) {
366		if (!hit) {
367			str_append(r, "  Selects: ");
368			hit = true;
369		} else
370			str_printf(r, " && ");
371		expr_gstr_print(prop->expr, r);
372	}
373	if (hit)
374		str_append(r, "\n");
375	if (sym->rev_dep.expr) {
376		str_append(r, "  Selected by: ");
377		expr_gstr_print(sym->rev_dep.expr, r);
378		str_append(r, "\n");
379	}
380	str_append(r, "\n\n");
381}
382
383static struct gstr get_relations_str(struct symbol **sym_arr)
384{
385	struct symbol *sym;
386	struct gstr res = str_new();
387	int i;
388
389	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
390		get_symbol_str(&res, sym);
391	if (!i)
392		str_append(&res, "No matches found.\n");
393	return res;
394}
395
396static char filename[PATH_MAX+1];
397static void set_config_filename(const char *config_filename)
398{
399	static char menu_backtitle[PATH_MAX+128];
400	int size;
401	struct symbol *sym;
402
403	sym = sym_lookup("KERNELVERSION", 0);
404	sym_calc_value(sym);
405	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
406	                _("%s - Linux Kernel v%s Configuration"),
407		        config_filename, sym_get_string_value(sym));
408	if (size >= sizeof(menu_backtitle))
409		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
410	set_dialog_backtitle(menu_backtitle);
411
412	size = snprintf(filename, sizeof(filename), "%s", config_filename);
413	if (size >= sizeof(filename))
414		filename[sizeof(filename)-1] = '\0';
415}
416
417
418static void search_conf(void)
419{
420	struct symbol **sym_arr;
421	struct gstr res;
422	int dres;
423again:
424	dialog_clear();
425	dres = dialog_inputbox(_("Search Configuration Parameter"),
426			      _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
427			      10, 75, "");
428	switch (dres) {
429	case 0:
430		break;
431	case 1:
432		show_helptext(_("Search Configuration"), search_help);
433		goto again;
434	default:
435		return;
436	}
437
438	sym_arr = sym_re_search(dialog_input_result);
439	res = get_relations_str(sym_arr);
440	free(sym_arr);
441	show_textbox(_("Search Results"), str_get(&res), 0, 0);
442	str_free(&res);
443}
444
445static void build_conf(struct menu *menu)
446{
447	struct symbol *sym;
448	struct property *prop;
449	struct menu *child;
450	int type, tmp, doint = 2;
451	tristate val;
452	char ch;
453
454	if (!menu_is_visible(menu))
455		return;
456
457	sym = menu->sym;
458	prop = menu->prompt;
459	if (!sym) {
460		if (prop && menu != current_menu) {
461			const char *prompt = menu_get_prompt(menu);
462			switch (prop->type) {
463			case P_MENU:
464				child_count++;
465				if (single_menu_mode) {
466					item_make("%s%*c%s",
467						  menu->data ? "-->" : "++>",
468						  indent + 1, ' ', prompt);
469				} else
470					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
471
472				item_set_tag('m');
473				item_set_data(menu);
474				if (single_menu_mode && menu->data)
475					goto conf_childs;
476				return;
477			default:
478				if (prompt) {
479					child_count++;
480					item_make("---%*c%s", indent + 1, ' ', prompt);
481					item_set_tag(':');
482					item_set_data(menu);
483				}
484			}
485		} else
486			doint = 0;
487		goto conf_childs;
488	}
489
490	type = sym_get_type(sym);
491	if (sym_is_choice(sym)) {
492		struct symbol *def_sym = sym_get_choice_value(sym);
493		struct menu *def_menu = NULL;
494
495		child_count++;
496		for (child = menu->list; child; child = child->next) {
497			if (menu_is_visible(child) && child->sym == def_sym)
498				def_menu = child;
499		}
500
501		val = sym_get_tristate_value(sym);
502		if (sym_is_changable(sym)) {
503			switch (type) {
504			case S_BOOLEAN:
505				item_make("[%c]", val == no ? ' ' : '*');
506				break;
507			case S_TRISTATE:
508				switch (val) {
509				case yes: ch = '*'; break;
510				case mod: ch = 'M'; break;
511				default:  ch = ' '; break;
512				}
513				item_make("<%c>", ch);
514				break;
515			}
516			item_set_tag('t');
517			item_set_data(menu);
518		} else {
519			item_make("   ");
520			item_set_tag(def_menu ? 't' : ':');
521			item_set_data(menu);
522		}
523
524		item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
525		if (val == yes) {
526			if (def_menu) {
527				item_add_str(" (%s)", menu_get_prompt(def_menu));
528				item_add_str("  --->");
529				if (def_menu->list) {
530					indent += 2;
531					build_conf(def_menu);
532					indent -= 2;
533				}
534			}
535			return;
536		}
537	} else {
538		if (menu == current_menu) {
539			item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
540			item_set_tag(':');
541			item_set_data(menu);
542			goto conf_childs;
543		}
544		child_count++;
545		val = sym_get_tristate_value(sym);
546		if (sym_is_choice_value(sym) && val == yes) {
547			item_make("   ");
548			item_set_tag(':');
549			item_set_data(menu);
550		} else {
551			switch (type) {
552			case S_BOOLEAN:
553				if (sym_is_changable(sym))
554					item_make("[%c]", val == no ? ' ' : '*');
555				else
556					item_make("---");
557				item_set_tag('t');
558				item_set_data(menu);
559				break;
560			case S_TRISTATE:
561				switch (val) {
562				case yes: ch = '*'; break;
563				case mod: ch = 'M'; break;
564				default:  ch = ' '; break;
565				}
566				if (sym_is_changable(sym))
567					item_make("<%c>", ch);
568				else
569					item_make("---");
570				item_set_tag('t');
571				item_set_data(menu);
572				break;
573			default:
574				tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
575				item_make("(%s)", sym_get_string_value(sym));
576				tmp = indent - tmp + 4;
577				if (tmp < 0)
578					tmp = 0;
579				item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
580					     (sym_has_value(sym) || !sym_is_changable(sym)) ?
581					     "" : " (NEW)");
582				item_set_tag('s');
583				item_set_data(menu);
584				goto conf_childs;
585			}
586		}
587		item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
588			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
589			  "" : " (NEW)");
590		if (menu->prompt->type == P_MENU) {
591			item_add_str("  --->");
592			return;
593		}
594	}
595
596conf_childs:
597	indent += doint;
598	for (child = menu->list; child; child = child->next)
599		build_conf(child);
600	indent -= doint;
601}
602
603static void conf(struct menu *menu)
604{
605	struct menu *submenu;
606	const char *prompt = menu_get_prompt(menu);
607	struct symbol *sym;
608	struct menu *active_menu = NULL;
609	int res;
610	int s_scroll = 0;
611
612	while (1) {
613		item_reset();
614		current_menu = menu;
615		build_conf(menu);
616		if (!child_count)
617			break;
618		if (menu == &rootmenu) {
619			item_make("--- ");
620			item_set_tag(':');
621			item_make(_("    Load an Alternate Configuration File"));
622			item_set_tag('L');
623			item_make(_("    Save an Alternate Configuration File"));
624			item_set_tag('S');
625		}
626		dialog_clear();
627		res = dialog_menu(prompt ? prompt : _("Main Menu"),
628				  _(menu_instructions),
629				  active_menu, &s_scroll);
630		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
631			break;
632		if (!item_activate_selected())
633			continue;
634		if (!item_tag())
635			continue;
636
637		submenu = item_data();
638		active_menu = item_data();
639		if (submenu)
640			sym = submenu->sym;
641		else
642			sym = NULL;
643
644		switch (res) {
645		case 0:
646			switch (item_tag()) {
647			case 'm':
648				if (single_menu_mode)
649					submenu->data = (void *) (long) !submenu->data;
650				else
651					conf(submenu);
652				break;
653			case 't':
654				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
655					conf_choice(submenu);
656				else if (submenu->prompt->type == P_MENU)
657					conf(submenu);
658				break;
659			case 's':
660				conf_string(submenu);
661				break;
662			case 'L':
663				conf_load();
664				break;
665			case 'S':
666				conf_save();
667				break;
668			}
669			break;
670		case 2:
671			if (sym)
672				show_help(submenu);
673			else
674				show_helptext("README", _(mconf_readme));
675			break;
676		case 3:
677			if (item_is_tag('t')) {
678				if (sym_set_tristate_value(sym, yes))
679					break;
680				if (sym_set_tristate_value(sym, mod))
681					show_textbox(NULL, setmod_text, 6, 74);
682			}
683			break;
684		case 4:
685			if (item_is_tag('t'))
686				sym_set_tristate_value(sym, no);
687			break;
688		case 5:
689			if (item_is_tag('t'))
690				sym_set_tristate_value(sym, mod);
691			break;
692		case 6:
693			if (item_is_tag('t'))
694				sym_toggle_tristate_value(sym);
695			else if (item_is_tag('m'))
696				conf(submenu);
697			break;
698		case 7:
699			search_conf();
700			break;
701		}
702	}
703}
704
705static void show_textbox(const char *title, const char *text, int r, int c)
706{
707	dialog_clear();
708	dialog_textbox(title, text, r, c);
709}
710
711static void show_helptext(const char *title, const char *text)
712{
713	show_textbox(title, text, 0, 0);
714}
715
716static void show_help(struct menu *menu)
717{
718	struct gstr help = str_new();
719	struct symbol *sym = menu->sym;
720
721	if (sym->help)
722	{
723		if (sym->name) {
724			str_printf(&help, "CONFIG_%s:\n\n", sym->name);
725			str_append(&help, _(sym->help));
726			str_append(&help, "\n");
727		}
728	} else {
729		str_append(&help, nohelp_text);
730	}
731	get_symbol_str(&help, sym);
732	show_helptext(menu_get_prompt(menu), str_get(&help));
733	str_free(&help);
734}
735
736static void conf_choice(struct menu *menu)
737{
738	const char *prompt = menu_get_prompt(menu);
739	struct menu *child;
740	struct symbol *active;
741
742	active = sym_get_choice_value(menu->sym);
743	while (1) {
744		int res;
745		int selected;
746		item_reset();
747
748		current_menu = menu;
749		for (child = menu->list; child; child = child->next) {
750			if (!menu_is_visible(child))
751				continue;
752			item_make("%s", menu_get_prompt(child));
753			item_set_data(child);
754			if (child->sym == active)
755				item_set_selected(1);
756			if (child->sym == sym_get_choice_value(menu->sym))
757				item_set_tag('X');
758		}
759		dialog_clear();
760		res = dialog_checklist(prompt ? prompt : _("Main Menu"),
761					_(radiolist_instructions),
762					 15, 70, 6);
763		selected = item_activate_selected();
764		switch (res) {
765		case 0:
766			if (selected) {
767				child = item_data();
768				sym_set_tristate_value(child->sym, yes);
769			}
770			return;
771		case 1:
772			if (selected) {
773				child = item_data();
774				show_help(child);
775				active = child->sym;
776			} else
777				show_help(menu);
778			break;
779		case KEY_ESC:
780			return;
781		case -ERRDISPLAYTOOSMALL:
782			return;
783		}
784	}
785}
786
787static void conf_string(struct menu *menu)
788{
789	const char *prompt = menu_get_prompt(menu);
790
791	while (1) {
792		int res;
793		char *heading;
794
795		switch (sym_get_type(menu->sym)) {
796		case S_INT:
797			heading = _(inputbox_instructions_int);
798			break;
799		case S_HEX:
800			heading = _(inputbox_instructions_hex);
801			break;
802		case S_STRING:
803			heading = _(inputbox_instructions_string);
804			break;
805		default:
806			heading = "Internal mconf error!";
807		}
808		dialog_clear();
809		res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
810				      heading, 10, 75,
811				      sym_get_string_value(menu->sym));
812		switch (res) {
813		case 0:
814			if (sym_set_string_value(menu->sym, dialog_input_result))
815				return;
816			show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
817			break;
818		case 1:
819			show_help(menu);
820			break;
821		case KEY_ESC:
822			return;
823		}
824	}
825}
826
827static void conf_load(void)
828{
829
830	while (1) {
831		int res;
832		dialog_clear();
833		res = dialog_inputbox(NULL, load_config_text,
834				      11, 55, filename);
835		switch(res) {
836		case 0:
837			if (!dialog_input_result[0])
838				return;
839			if (!conf_read(dialog_input_result)) {
840				set_config_filename(dialog_input_result);
841				return;
842			}
843			show_textbox(NULL, _("File does not exist!"), 5, 38);
844			break;
845		case 1:
846			show_helptext(_("Load Alternate Configuration"), load_config_help);
847			break;
848		case KEY_ESC:
849			return;
850		}
851	}
852}
853
854static void conf_save(void)
855{
856	while (1) {
857		int res;
858		dialog_clear();
859		res = dialog_inputbox(NULL, save_config_text,
860				      11, 55, filename);
861		switch(res) {
862		case 0:
863			if (!dialog_input_result[0])
864				return;
865			if (!conf_write(dialog_input_result)) {
866				set_config_filename(dialog_input_result);
867				return;
868			}
869			show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
870			break;
871		case 1:
872			show_helptext(_("Save Alternate Configuration"), save_config_help);
873			break;
874		case KEY_ESC:
875			return;
876		}
877	}
878}
879
880static void conf_cleanup(void)
881{
882	tcsetattr(1, TCSAFLUSH, &ios_org);
883}
884
885int main(int ac, char **av)
886{
887	char *mode;
888	int res;
889
890	setlocale(LC_ALL, "");
891	bindtextdomain(PACKAGE, LOCALEDIR);
892	textdomain(PACKAGE);
893
894	conf_parse(av[1]);
895	conf_read(NULL);
896
897	mode = getenv("MENUCONFIG_MODE");
898	if (mode) {
899		if (!strcasecmp(mode, "single_menu"))
900			single_menu_mode = 1;
901	}
902
903	tcgetattr(1, &ios_org);
904	atexit(conf_cleanup);
905	init_wsize();
906	reset_dialog();
907	init_dialog(NULL);
908	set_config_filename(conf_get_configname());
909	do {
910		conf(&rootmenu);
911		dialog_clear();
912		if (conf_get_changed())
913			res = dialog_yesno(NULL,
914					   _("Do you wish to save your "
915					     "new kernel configuration?\n"
916					     "<ESC><ESC> to continue."),
917					   6, 60);
918		else
919			res = -1;
920	} while (res == KEY_ESC);
921	end_dialog();
922
923	switch (res) {
924	case 0:
925		if (conf_write(filename)) {
926			fprintf(stderr, _("\n\n"
927				"Error during writing of the kernel configuration.\n"
928				"Your kernel configuration changes were NOT saved."
929				"\n\n"));
930			return 1;
931		}
932	case -1:
933		printf(_("\n\n"
934			"*** End of Linux kernel configuration.\n"
935			"*** Execute 'make' to build the kernel or try 'make help'."
936			"\n\n"));
937		break;
938	default:
939		fprintf(stderr, _("\n\n"
940			"Your kernel configuration changes were NOT saved."
941			"\n\n"));
942	}
943
944	return 0;
945}
946