diff options
Diffstat (limited to 'scripts/kconfig/nconf.c')
| -rw-r--r-- | scripts/kconfig/nconf.c | 1568 | 
1 files changed, 1568 insertions, 0 deletions
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c new file mode 100644 index 00000000000..762caf80ce3 --- /dev/null +++ b/scripts/kconfig/nconf.c @@ -0,0 +1,1568 @@ +/* + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com? + * Released under the terms of the GNU GPL v2.0. + * + * Derived from menuconfig. + * + */ +#define LKC_DIRECT_LINK +#include "lkc.h" +#include "nconf.h" + +static const char nconf_readme[] = N_( +"Overview\n" +"--------\n" +"Some kernel features may be built directly into the kernel.\n" +"Some may be made into loadable runtime modules.  Some features\n" +"may be completely removed altogether.  There are also certain\n" +"kernel parameters which are not really features, but must be\n" +"entered in as decimal or hexadecimal numbers or possibly text.\n" +"\n" +"Menu items beginning with following braces represent features that\n" +"  [ ] can be built in or removed\n" +"  < > can be built in, modularized or removed\n" +"  { } can be built in or modularized (selected by other feature)\n" +"  - - are selected by other feature,\n" +"  XXX cannot be selected. use Symbol Info to find out why,\n" +"while *, M or whitespace inside braces means to build in, build as\n" +"a module or to exclude the feature respectively.\n" +"\n" +"To change any of these features, highlight it with the cursor\n" +"keys and press <Y> to build it in, <M> to make it a module or\n" +"<N> to removed it.  You may also press the <Space Bar> to cycle\n" +"through the available options (ie. Y->N->M->Y).\n" +"\n" +"Some additional keyboard hints:\n" +"\n" +"Menus\n" +"----------\n" +"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n" +"   you wish to change use <Enter> or <Space>. Goto submenu by \n" +"   pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n" +"   Submenus are designated by \"--->\".\n" +"\n" +"   Shortcut: Press the option's highlighted letter (hotkey).\n" +"             Pressing a hotkey more than once will sequence\n" +"             through all visible items which use that hotkey.\n" +"\n" +"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n" +"   unseen options into view.\n" +"\n" +"o  To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n" +"\n" +"o  To get help with an item, press <F1>\n" +"   Shortcut: Press <h> or <?>.\n" +"\n" +"\n" +"Radiolists  (Choice lists)\n" +"-----------\n" +"o  Use the cursor keys to select the option you wish to set and press\n" +"   <S> or the <SPACE BAR>.\n" +"\n" +"   Shortcut: Press the first letter of the option you wish to set then\n" +"             press <S> or <SPACE BAR>.\n" +"\n" +"o  To see available help for the item, press <F1>\n" +"   Shortcut: Press <H> or <?>.\n" +"\n" +"\n" +"Data Entry\n" +"-----------\n" +"o  Enter the requested information and press <ENTER>\n" +"   If you are entering hexadecimal values, it is not necessary to\n" +"   add the '0x' prefix to the entry.\n" +"\n" +"o  For help, press <F1>.\n" +"\n" +"\n" +"Text Box    (Help Window)\n" +"--------\n" +"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n" +"   keys h,j,k,l function here as do <SPACE BAR> for those\n" +"   who are familiar with less and lynx.\n" +"\n" +"o  Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n" +"\n" +"\n" +"Alternate Configuration Files\n" +"-----------------------------\n" +"nconfig supports the use of alternate configuration files for\n" +"those who, for various reasons, find it necessary to switch\n" +"between different kernel configurations.\n" +"\n" +"At the end of the main menu you will find two options.  One is\n" +"for saving the current configuration to a file of your choosing.\n" +"The other option is for loading a previously saved alternate\n" +"configuration.\n" +"\n" +"Even if you don't use alternate configuration files, but you\n" +"find during a nconfig session that you have completely messed\n" +"up your settings, you may use the \"Load Alternate...\" option to\n" +"restore your previously saved settings from \".config\" without\n" +"restarting nconfig.\n" +"\n" +"Other information\n" +"-----------------\n" +"If you use nconfig in an XTERM window make sure you have your\n" +"$TERM variable set to point to a xterm definition which supports color.\n" +"Otherwise, nconfig will look rather bad.  nconfig will not\n" +"display correctly in a RXVT window because rxvt displays only one\n" +"intensity of color, bright.\n" +"\n" +"nconfig will display larger menus on screens or xterms which are\n" +"set to display more than the standard 25 row by 80 column geometry.\n" +"In order for this to work, the \"stty size\" command must be able to\n" +"display the screen's current row and column geometry.  I STRONGLY\n" +"RECOMMEND that you make sure you do NOT have the shell variables\n" +"LINES and COLUMNS exported into your environment.  Some distributions\n" +"export those variables via /etc/profile.  Some ncurses programs can\n" +"become confused when those variables (LINES & COLUMNS) don't reflect\n" +"the true screen size.\n" +"\n" +"Optional personality available\n" +"------------------------------\n" +"If you prefer to have all of the kernel options listed in a single\n" +"menu, rather than the default multimenu hierarchy, run the nconfig\n" +"with NCONFIG_MODE environment variable set to single_menu. Example:\n" +"\n" +"make NCONFIG_MODE=single_menu nconfig\n" +"\n" +"<Enter> will then unroll the appropriate category, or enfold it if it\n" +"is already unrolled.\n" +"\n" +"Note that this mode can eventually be a little more CPU expensive\n" +"(especially with a larger number of unrolled categories) than the\n" +"default mode.\n" +"\n"), +menu_no_f_instructions[] = N_( +" You do not have function keys support. Please follow the\n" +" following instructions:\n" +" Arrow keys navigate the menu.\n" +" <Enter> or <right-arrow> selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press <Esc> or <left-arrow> to go back one menu, \n" +" <?> or <h> for Help, </> for Search.\n" +" <1> is interchangable with <F1>, <2> with <F2>, etc.\n" +" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n" +" <Esc> always leaves the current window\n"), +menu_instructions[] = N_( +" Arrow keys navigate the menu.\n" +" <Enter> or <right-arrow> selects submenus --->.\n" +" Capital Letters are hotkeys.\n" +" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n" +" Pressing SpaceBar toggles between the above options\n" +" Press <Esc>, <F3> or <left-arrow> to go back one menu, \n" +" <?>, <F1> or <h> for Help, </> for Search.\n" +" <1> is interchangable with <F1>, <2> with <F2>, etc.\n" +" Legend: [*] built-in  [ ] excluded  <M> module  < > module capable.\n" +" <Esc> always leaves the current window\n"), +radiolist_instructions[] = N_( +" Use the arrow keys to navigate this window or\n" +" press the hotkey of the item you wish to select\n" +" followed by the <SPACE BAR>.\n" +" Press <?>, <F1> or <h> for additional information about this option.\n"), +inputbox_instructions_int[] = N_( +"Please enter a decimal value.\n" +"Fractions will not be accepted.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +inputbox_instructions_hex[] = N_( +"Please enter a hexadecimal value.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +inputbox_instructions_string[] = N_( +"Please enter a string value.\n" +"Press <RETURN> to accept, <ESC> to cancel."), +setmod_text[] = N_( +"This feature depends on another which\n" +"has been configured as a module.\n" +"As a result, this feature will be built as a module."), +nohelp_text[] = N_( +"There is no help available for this kernel option.\n"), +load_config_text[] = N_( +"Enter the name of the configuration file you wish to load.\n" +"Accept the name shown to restore the configuration you\n" +"last retrieved.  Leave blank to abort."), +load_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep several different kernel\n" +"configurations available on a single machine.\n" +"\n" +"If you have saved a previous configuration in a file other than the\n" +"kernel's default, entering the name of the file here will allow you\n" +"to modify that configuration.\n" +"\n" +"If you are uncertain, then you have probably never used alternate\n" +"configuration files.  You should therefor leave this blank to abort.\n"), +save_config_text[] = N_( +"Enter a filename to which this configuration should be saved\n" +"as an alternate.  Leave blank to abort."), +save_config_help[] = N_( +"\n" +"For various reasons, one may wish to keep different kernel\n" +"configurations available on a single machine.\n" +"\n" +"Entering a file name here will allow you to later retrieve, modify\n" +"and use the current configuration as an alternate to whatever\n" +"configuration options you have selected at that time.\n" +"\n" +"If you are uncertain what all this means then you should probably\n" +"leave this blank.\n"), +search_help[] = N_( +"\n" +"Search for CONFIG_ symbols and display their relations.\n" +"Regular expressions are allowed.\n" +"Example: search for \"^FOO\"\n" +"Result:\n" +"-----------------------------------------------------------------\n" +"Symbol: FOO [ = m]\n" +"Prompt: Foo bus is used to drive the bar HW\n" +"Defined at drivers/pci/Kconfig:47\n" +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" +"Location:\n" +"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" +"    -> PCI support (PCI [ = y])\n" +"      -> PCI access mode (<choice> [ = y])\n" +"Selects: LIBCRC32\n" +"Selected by: BAR\n" +"-----------------------------------------------------------------\n" +"o The line 'Prompt:' shows the text used in the menu structure for\n" +"  this CONFIG_ symbol\n" +"o The 'Defined at' line tell at what file / line number the symbol\n" +"  is defined\n" +"o The 'Depends on:' line tell what symbols needs to be defined for\n" +"  this symbol to be visible in the menu (selectable)\n" +"o The 'Location:' lines tell where in the menu structure this symbol\n" +"  is located\n" +"    A location followed by a [ = y] indicate that this is a selectable\n" +"    menu item - and current value is displayed inside brackets.\n" +"o The 'Selects:' line tell what symbol will be automatically\n" +"  selected if this symbol is selected (y or m)\n" +"o The 'Selected by' line tell what symbol has selected this symbol\n" +"\n" +"Only relevant lines are shown.\n" +"\n\n" +"Search examples:\n" +"Examples: USB   = > find all CONFIG_ symbols containing USB\n" +"          ^USB => find all CONFIG_ symbols starting with USB\n" +"          USB$ => find all CONFIG_ symbols ending with USB\n" +"\n"); + +struct mitem { +	char str[256]; +	char tag; +	void *usrptr; +	int is_hot; +	int is_visible; +}; + +#define MAX_MENU_ITEMS 4096 +static int show_all_items; +static int indent; +static struct menu *current_menu; +static int child_count; +static int single_menu_mode; +/* the window in which all information appears */ +static WINDOW *main_window; +/* the largest size of the menu window */ +static int mwin_max_lines; +static int mwin_max_cols; +/* the window in which we show option buttons */ +static MENU *curses_menu; +static ITEM *curses_menu_items[MAX_MENU_ITEMS]; +static struct mitem k_menu_items[MAX_MENU_ITEMS]; +static int items_num; +static int global_exit; +/* the currently selected button */ +const char *current_instructions = menu_instructions; +/* this array is used to implement hot keys. it is updated in item_make and + * resetted in clean_items. It would be better to use a hash, but lets keep it + * simple... */ +#define MAX_SAME_KEY MAX_MENU_ITEMS +struct { +	int count; +	int ptrs[MAX_MENU_ITEMS]; +} hotkeys[1<<(sizeof(char)*8)]; + +static void conf(struct menu *menu); +static void conf_choice(struct menu *menu); +static void conf_string(struct menu *menu); +static void conf_load(void); +static void conf_save(void); +static void show_help(struct menu *menu); +static int do_exit(void); +static void setup_windows(void); + +typedef void (*function_key_handler_t)(int *key, struct menu *menu); +static void handle_f1(int *key, struct menu *current_item); +static void handle_f2(int *key, struct menu *current_item); +static void handle_f3(int *key, struct menu *current_item); +static void handle_f4(int *key, struct menu *current_item); +static void handle_f5(int *key, struct menu *current_item); +static void handle_f6(int *key, struct menu *current_item); +static void handle_f7(int *key, struct menu *current_item); +static void handle_f8(int *key, struct menu *current_item); + +struct function_keys { +	const char *key_str; +	const char *func; +	function_key key; +	function_key_handler_t handler; +}; + +static const int function_keys_num = 8; +struct function_keys function_keys[] = { +	{ +		.key_str = "F1", +		.func = "Help", +		.key = F_HELP, +		.handler = handle_f1, +	}, +	{ +		.key_str = "F2", +		.func = "Symbol Info", +		.key = F_SYMBOL, +		.handler = handle_f2, +	}, +	{ +		.key_str = "F3", +		.func = "Instructions", +		.key = F_INSTS, +		.handler = handle_f3, +	}, +	{ +		.key_str = "F4", +		.func = "Config", +		.key = F_CONF, +		.handler = handle_f4, +	}, +	{ +		.key_str = "F5", +		.func = "Back", +		.key = F_BACK, +		.handler = handle_f5, +	}, +	{ +		.key_str = "F6", +		.func = "Save", +		.key = F_SAVE, +		.handler = handle_f6, +	}, +	{ +		.key_str = "F7", +		.func = "Load", +		.key = F_LOAD, +		.handler = handle_f7, +	}, +	{ +		.key_str = "F8", +		.func = "Exit", +		.key = F_EXIT, +		.handler = handle_f8, +	}, +}; + +static void print_function_line(void) +{ +	int i; +	int offset = 1; +	const int skip = 1; + +	for (i = 0; i < function_keys_num; i++) { +		wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); +		mvwprintw(main_window, LINES-3, offset, +				"%s", +				function_keys[i].key_str); +		wattrset(main_window, attributes[FUNCTION_TEXT]); +		offset += strlen(function_keys[i].key_str); +		mvwprintw(main_window, LINES-3, +				offset, "%s", +				function_keys[i].func); +		offset += strlen(function_keys[i].func) + skip; +	} +	wattrset(main_window, attributes[NORMAL]); +} + +/* help */ +static void handle_f1(int *key, struct menu *current_item) +{ +	show_scroll_win(main_window, +			_("README"), _(nconf_readme)); +	return; +} + +/* symbole help */ +static void handle_f2(int *key, struct menu *current_item) +{ +	show_help(current_item); +	return; +} + +/* instructions */ +static void handle_f3(int *key, struct menu *current_item) +{ +	show_scroll_win(main_window, +			_("Instructions"), +			_(current_instructions)); +	return; +} + +/* config */ +static void handle_f4(int *key, struct menu *current_item) +{ +	int res = btn_dialog(main_window, +			_("Show all symbols?"), +			2, +			"   <Show All>   ", +			"<Don't show all>"); +	if (res == 0) +		show_all_items = 1; +	else if (res == 1) +		show_all_items = 0; + +	return; +} + +/* back */ +static void handle_f5(int *key, struct menu *current_item) +{ +	*key = KEY_LEFT; +	return; +} + +/* save */ +static void handle_f6(int *key, struct menu *current_item) +{ +	conf_save(); +	return; +} + +/* load */ +static void handle_f7(int *key, struct menu *current_item) +{ +	conf_load(); +	return; +} + +/* exit */ +static void handle_f8(int *key, struct menu *current_item) +{ +	do_exit(); +	return; +} + +/* return != 0 to indicate the key was handles */ +static int process_special_keys(int *key, struct menu *menu) +{ +	int i; + +	if (*key == KEY_RESIZE) { +		setup_windows(); +		return 1; +	} + +	for (i = 0; i < function_keys_num; i++) { +		if (*key == KEY_F(function_keys[i].key) || +		    *key == '0' + function_keys[i].key){ +			function_keys[i].handler(key, menu); +			return 1; +		} +	} + +	return 0; +} + +static void clean_items(void) +{ +	int i; +	for (i = 0; curses_menu_items[i]; i++) +		free_item(curses_menu_items[i]); +	bzero(curses_menu_items, sizeof(curses_menu_items)); +	bzero(k_menu_items, sizeof(k_menu_items)); +	bzero(hotkeys, sizeof(hotkeys)); +	items_num = 0; +} + +/* return the index of the next hot item, or -1 if no such item exists */ +static int get_next_hot(int c) +{ +	static int hot_index; +	static int hot_char; + +	if (c < 0 || c > 255 || hotkeys[c].count <= 0) +		return -1; + +	if (hot_char == c) { +		hot_index = (hot_index+1)%hotkeys[c].count; +		return hotkeys[c].ptrs[hot_index]; +	} else { +		hot_char = c; +		hot_index = 0; +		return hotkeys[c].ptrs[0]; +	} +} + +/* can the char c be a hot key? no, if c is a common shortcut used elsewhere */ +static int canbhot(char c) +{ +	c = tolower(c); +	return isalnum(c) && c != 'y' && c != 'm' && c != 'h' && +		c != 'n' && c != '?'; +} + +/* check if str already contains a hot key. */ +static int is_hot(int index) +{ +	return k_menu_items[index].is_hot; +} + +/* find the first possible hot key, and mark it. + * index is the index of the item in the menu + * return 0 on success*/ +static int make_hot(char *dest, int len, const char *org, int index) +{ +	int position = -1; +	int i; +	int tmp; +	int c; +	int org_len = strlen(org); + +	if (org == NULL || is_hot(index)) +		return 1; + +	/* make sure not to make hot keys out of markers. +	 * find where to start looking for a hot key +	 */ +	i = 0; +	/* skip white space */ +	while (i < org_len && org[i] == ' ') +		i++; +	if (i == org_len) +		return -1; +	/* if encountering '(' or '<' or '[', find the match and look from there +	 **/ +	if (org[i] == '[' || org[i] == '<' || org[i] == '(') { +		i++; +		for (; i < org_len; i++) +			if (org[i] == ']' || org[i] == '>' || org[i] == ')') +				break; +	} +	if (i == org_len) +		return -1; +	for (; i < org_len; i++) { +		if (canbhot(org[i]) && org[i-1] != '<' && org[i-1] != '(') { +			position = i; +			break; +		} +	} +	if (position == -1) +		return 1; + +	/* ok, char at org[position] should be a hot key to this item */ +	c = tolower(org[position]); +	tmp = hotkeys[c].count; +	hotkeys[c].ptrs[tmp] = index; +	hotkeys[c].count++; +	/* +	   snprintf(dest, len, "%.*s(%c)%s", position, org, org[position], +	   &org[position+1]); +	   */ +	/* make org[position] uppercase, and all leading letter small case */ +	strncpy(dest, org, len); +	for (i = 0; i < position; i++) +		dest[i] = tolower(dest[i]); +	dest[position] = toupper(dest[position]); +	k_menu_items[index].is_hot = 1; +	return 0; +} + +/* Make a new item. Add a hotkey mark in the first possible letter. + * As ncurses does not allow any attributes inside menue item, we mark the + * hot key as the first capitalized letter in the string */ +static void item_make(struct menu *menu, char tag, const char *fmt, ...) +{ +	va_list ap; +	char tmp_str[256]; + +	if (items_num > MAX_MENU_ITEMS-1) +		return; + +	bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); +	k_menu_items[items_num].tag = tag; +	k_menu_items[items_num].usrptr = menu; +	if (menu != NULL) +		k_menu_items[items_num].is_visible = +			menu_is_visible(menu); +	else +		k_menu_items[items_num].is_visible = 1; + +	va_start(ap, fmt); +	vsnprintf(tmp_str, sizeof(tmp_str), fmt, ap); +	if (!k_menu_items[items_num].is_visible) +		memcpy(tmp_str, "XXX", 3); +	va_end(ap); +	if (make_hot( +		k_menu_items[items_num].str, +		sizeof(k_menu_items[items_num].str), tmp_str, items_num) != 0) +		strncpy(k_menu_items[items_num].str, +			tmp_str, +			sizeof(k_menu_items[items_num].str)); + +	curses_menu_items[items_num] = new_item( +			k_menu_items[items_num].str, +			k_menu_items[items_num].str); +	set_item_userptr(curses_menu_items[items_num], +			&k_menu_items[items_num]); +	/* +	if (!k_menu_items[items_num].is_visible) +		item_opts_off(curses_menu_items[items_num], O_SELECTABLE); +	*/ + +	items_num++; +	curses_menu_items[items_num] = NULL; +} + +/* very hackish. adds a string to the last item added */ +static void item_add_str(const char *fmt, ...) +{ +	va_list ap; +	int index = items_num-1; +	char new_str[256]; +	char tmp_str[256]; + +	if (index < 0) +		return; + +	va_start(ap, fmt); +	vsnprintf(new_str, sizeof(new_str), fmt, ap); +	va_end(ap); +	snprintf(tmp_str, sizeof(tmp_str), "%s%s", +			k_menu_items[index].str, new_str); +	if (make_hot(k_menu_items[index].str, +			sizeof(k_menu_items[index].str), tmp_str, index) != 0) +		strncpy(k_menu_items[index].str, +			tmp_str, +			sizeof(k_menu_items[index].str)); + +	free_item(curses_menu_items[index]); +	curses_menu_items[index] = new_item( +			k_menu_items[index].str, +			k_menu_items[index].str); +	set_item_userptr(curses_menu_items[index], +			&k_menu_items[index]); +} + +/* get the tag of the currently selected item */ +static char item_tag(void) +{ +	ITEM *cur; +	struct mitem *mcur; + +	cur = current_item(curses_menu); +	if (cur == NULL) +		return 0; +	mcur = (struct mitem *) item_userptr(cur); +	return mcur->tag; +} + +static int curses_item_index(void) +{ +	return  item_index(current_item(curses_menu)); +} + +static void *item_data(void) +{ +	ITEM *cur; +	struct mitem *mcur; + +	cur = current_item(curses_menu); +	mcur = (struct mitem *) item_userptr(cur); +	return mcur->usrptr; + +} + +static int item_is_tag(char tag) +{ +	return item_tag() == tag; +} + +static char filename[PATH_MAX+1]; +static char menu_backtitle[PATH_MAX+128]; +static const char *set_config_filename(const char *config_filename) +{ +	int size; +	struct symbol *sym; + +	sym = sym_lookup("KERNELVERSION", 0); +	sym_calc_value(sym); +	size = snprintf(menu_backtitle, sizeof(menu_backtitle), +			_("%s - Linux Kernel v%s Configuration"), +			config_filename, sym_get_string_value(sym)); +	if (size >= sizeof(menu_backtitle)) +		menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + +	size = snprintf(filename, sizeof(filename), "%s", config_filename); +	if (size >= sizeof(filename)) +		filename[sizeof(filename)-1] = '\0'; +	return menu_backtitle; +} + +/* command = 0 is supress, 1 is restore */ +static void supress_stdout(int command) +{ +	static FILE *org_stdout; +	static FILE *org_stderr; + +	if (command == 0) { +		org_stdout = stdout; +		org_stderr = stderr; +		stdout = fopen("/dev/null", "a"); +		stderr = fopen("/dev/null", "a"); +	} else { +		fclose(stdout); +		fclose(stderr); +		stdout = org_stdout; +		stderr = org_stderr; +	} +} + +/* return = 0 means we are successful. + * -1 means go on doing what you were doing + */ +static int do_exit(void) +{ +	int res; +	if (!conf_get_changed()) { +		global_exit = 1; +		return 0; +	} +	res = btn_dialog(main_window, +			_("Do you wish to save your " +				"new kernel configuration?\n" +				"<ESC> to cancel and resume nconfig."), +			2, +			"   <save>   ", +			"<don't save>"); +	if (res == KEY_EXIT) { +		global_exit = 0; +		return -1; +	} + +	/* if we got here, the user really wants to exit */ +	switch (res) { +	case 0: +		supress_stdout(0); +		res = conf_write(filename); +		supress_stdout(1); +		if (res) +			btn_dialog( +				main_window, +				_("Error during writing of the kernel " +				  "configuration.\n" +				  "Your kernel configuration " +				  "changes were NOT saved."), +				  1, +				  "<OK>"); +		else { +			char buf[1024]; +			snprintf(buf, 1024, +				_("Configuration written to %s\n" +				  "End of Linux kernel configuration.\n" +				  "Execute 'make' to build the kernel or try" +				  " 'make help'."), filename); +			btn_dialog( +				main_window, +				buf, +				1, +				"<OK>"); +		} +		break; +	default: +		btn_dialog( +			main_window, +			_("Your kernel configuration changes were NOT saved."), +			1, +			"<OK>"); +		break; +	} +	global_exit = 1; +	return 0; +} + + +static void search_conf(void) +{ +	struct symbol **sym_arr; +	struct gstr res; +	char dialog_input_result[100]; +	char *dialog_input; +	int dres; +again: +	dres = dialog_inputbox(main_window, +			_("Search Configuration Parameter"), +			_("Enter CONFIG_ (sub)string to search for " +				"(with or without \"CONFIG\")"), +			"", dialog_input_result, 99); +	switch (dres) { +	case 0: +		break; +	case 1: +		show_scroll_win(main_window, +				_("Search Configuration"), search_help); +		goto again; +	default: +		return; +	} + +	/* strip CONFIG_ if necessary */ +	dialog_input = dialog_input_result; +	if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0) +		dialog_input += 7; + +	sym_arr = sym_re_search(dialog_input); +	res = get_relations_str(sym_arr); +	free(sym_arr); +	show_scroll_win(main_window, +			_("Search Results"), str_get(&res)); +	str_free(&res); +} + + +static void build_conf(struct menu *menu) +{ +	struct symbol *sym; +	struct property *prop; +	struct menu *child; +	int type, tmp, doint = 2; +	tristate val; +	char ch; + +	if (!menu || (!show_all_items && !menu_is_visible(menu))) +		return; + +	sym = menu->sym; +	prop = menu->prompt; +	if (!sym) { +		if (prop && menu != current_menu) { +			const char *prompt = menu_get_prompt(menu); +			enum prop_type ptype; +			ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; +			switch (ptype) { +			case P_MENU: +				child_count++; +				prompt = _(prompt); +				if (single_menu_mode) { +					item_make(menu, 'm', +						"%s%*c%s", +						menu->data ? "-->" : "++>", +						indent + 1, ' ', prompt); +				} else +					item_make(menu, 'm', +						"   %*c%s  --->", +						indent + 1, +						' ', prompt); + +				if (single_menu_mode && menu->data) +					goto conf_childs; +				return; +			case P_COMMENT: +				if (prompt) { +					child_count++; +					item_make(menu, ':', +						"   %*c*** %s ***", +						indent + 1, ' ', +						_(prompt)); +				} +				break; +			default: +				if (prompt) { +					child_count++; +					item_make(menu, ':', "---%*c%s", +						indent + 1, ' ', +						_(prompt)); +				} +			} +		} else +			doint = 0; +		goto conf_childs; +	} + +	type = sym_get_type(sym); +	if (sym_is_choice(sym)) { +		struct symbol *def_sym = sym_get_choice_value(sym); +		struct menu *def_menu = NULL; + +		child_count++; +		for (child = menu->list; child; child = child->next) { +			if (menu_is_visible(child) && child->sym == def_sym) +				def_menu = child; +		} + +		val = sym_get_tristate_value(sym); +		if (sym_is_changable(sym)) { +			switch (type) { +			case S_BOOLEAN: +				item_make(menu, 't', "[%c]", +						val == no ? ' ' : '*'); +				break; +			case S_TRISTATE: +				switch (val) { +				case yes: +					ch = '*'; +					break; +				case mod: +					ch = 'M'; +					break; +				default: +					ch = ' '; +					break; +				} +				item_make(menu, 't', "<%c>", ch); +				break; +			} +		} else { +			item_make(menu, def_menu ? 't' : ':', "   "); +		} + +		item_add_str("%*c%s", indent + 1, +				' ', _(menu_get_prompt(menu))); +		if (val == yes) { +			if (def_menu) { +				item_add_str(" (%s)", +					_(menu_get_prompt(def_menu))); +				item_add_str("  --->"); +				if (def_menu->list) { +					indent += 2; +					build_conf(def_menu); +					indent -= 2; +				} +			} +			return; +		} +	} else { +		if (menu == current_menu) { +			item_make(menu, ':', +				"---%*c%s", indent + 1, +				' ', _(menu_get_prompt(menu))); +			goto conf_childs; +		} +		child_count++; +		val = sym_get_tristate_value(sym); +		if (sym_is_choice_value(sym) && val == yes) { +			item_make(menu, ':', "   "); +		} else { +			switch (type) { +			case S_BOOLEAN: +				if (sym_is_changable(sym)) +					item_make(menu, 't', "[%c]", +						val == no ? ' ' : '*'); +				else +					item_make(menu, 't', "-%c-", +						val == no ? ' ' : '*'); +				break; +			case S_TRISTATE: +				switch (val) { +				case yes: +					ch = '*'; +					break; +				case mod: +					ch = 'M'; +					break; +				default: +					ch = ' '; +					break; +				} +				if (sym_is_changable(sym)) { +					if (sym->rev_dep.tri == mod) +						item_make(menu, +							't', "{%c}", ch); +					else +						item_make(menu, +							't', "<%c>", ch); +				} else +					item_make(menu, 't', "-%c-", ch); +				break; +			default: +				tmp = 2 + strlen(sym_get_string_value(sym)); +				item_make(menu, 's', "    (%s)", +						sym_get_string_value(sym)); +				tmp = indent - tmp + 4; +				if (tmp < 0) +					tmp = 0; +				item_add_str("%*c%s%s", tmp, ' ', +						_(menu_get_prompt(menu)), +						(sym_has_value(sym) || +						 !sym_is_changable(sym)) ? "" : +						_(" (NEW)")); +				goto conf_childs; +			} +		} +		item_add_str("%*c%s%s", indent + 1, ' ', +				_(menu_get_prompt(menu)), +				(sym_has_value(sym) || !sym_is_changable(sym)) ? +				"" : _(" (NEW)")); +		if (menu->prompt && menu->prompt->type == P_MENU) { +			item_add_str("  --->"); +			return; +		} +	} + +conf_childs: +	indent += doint; +	for (child = menu->list; child; child = child->next) +		build_conf(child); +	indent -= doint; +} + +static void reset_menu(void) +{ +	unpost_menu(curses_menu); +	clean_items(); +} + +/* adjust the menu to show this item. + * prefer not to scroll the menu if possible*/ +static void center_item(int selected_index, int *last_top_row) +{ +	int toprow; +	int maxy, maxx; + +	scale_menu(curses_menu, &maxy, &maxx); +	set_top_row(curses_menu, *last_top_row); +	toprow = top_row(curses_menu); +	if (selected_index >= toprow && selected_index < toprow+maxy) { +		/* we can only move the selected item. no need to scroll */ +		set_current_item(curses_menu, +				curses_menu_items[selected_index]); +	} else { +		toprow = max(selected_index-maxy/2, 0); +		if (toprow >= item_count(curses_menu)-maxy) +			toprow = item_count(curses_menu)-mwin_max_lines; +		set_top_row(curses_menu, toprow); +		set_current_item(curses_menu, +				curses_menu_items[selected_index]); +	} +	*last_top_row = toprow; +	post_menu(curses_menu); +	refresh_all_windows(main_window); +} + +/* this function assumes reset_menu has been called before */ +static void show_menu(const char *prompt, const char *instructions, +		int selected_index, int *last_top_row) +{ +	int maxx, maxy; +	WINDOW *menu_window; + +	current_instructions = instructions; + +	clear(); +	wattrset(main_window, attributes[NORMAL]); +	print_in_middle(stdscr, 1, 0, COLS, +			menu_backtitle, +			attributes[MAIN_HEADING]); + +	wattrset(main_window, attributes[MAIN_MENU_BOX]); +	box(main_window, 0, 0); +	wattrset(main_window, attributes[MAIN_MENU_HEADING]); +	mvwprintw(main_window, 0, 3, " %s ", prompt); +	wattrset(main_window, attributes[NORMAL]); + +	set_menu_items(curses_menu, curses_menu_items); + +	/* position the menu at the middle of the screen */ +	scale_menu(curses_menu, &maxy, &maxx); +	maxx = min(maxx, mwin_max_cols-2); +	maxy = mwin_max_lines-2; +	menu_window = derwin(main_window, +			maxy, +			maxx, +			2, +			(mwin_max_cols-maxx)/2); +	keypad(menu_window, TRUE); +	set_menu_win(curses_menu, menu_window); +	set_menu_sub(curses_menu, menu_window); + +	/* must reassert this after changing items, otherwise returns to a +	 * default of 16 +	 */ +	set_menu_format(curses_menu, maxy, 1); +	center_item(selected_index, last_top_row); +	set_menu_format(curses_menu, maxy, 1); + +	print_function_line(); + +	/* Post the menu */ +	post_menu(curses_menu); +	refresh_all_windows(main_window); +} + + +static void conf(struct menu *menu) +{ +	char pattern[256]; +	struct menu *submenu = 0; +	const char *prompt = menu_get_prompt(menu); +	struct symbol *sym; +	struct menu *active_menu = NULL; +	int res; +	int current_index = 0; +	int last_top_row = 0; + +	bzero(pattern, sizeof(pattern)); + +	while (!global_exit) { +		reset_menu(); +		current_menu = menu; +		build_conf(menu); +		if (!child_count) +			break; + +		show_menu(prompt ? _(prompt) : _("Main Menu"), +				_(menu_instructions), +				current_index, &last_top_row); +		keypad((menu_win(curses_menu)), TRUE); +		while (!global_exit && (res = wgetch(menu_win(curses_menu)))) { +			if (process_special_keys(&res, +						(struct menu *) item_data())) +				break; +			switch (res) { +			case KEY_DOWN: +				menu_driver(curses_menu, REQ_DOWN_ITEM); +				break; +			case KEY_UP: +				menu_driver(curses_menu, REQ_UP_ITEM); +				break; +			case KEY_NPAGE: +				menu_driver(curses_menu, REQ_SCR_DPAGE); +				break; +			case KEY_PPAGE: +				menu_driver(curses_menu, REQ_SCR_UPAGE); +				break; +			case KEY_HOME: +				menu_driver(curses_menu, REQ_FIRST_ITEM); +				break; +			case KEY_END: +				menu_driver(curses_menu, REQ_LAST_ITEM); +				break; +			case 'h': +			case '?': +				show_help((struct menu *) item_data()); +				break; +			} +			if (res == 10 || res == 27 || +				res == 32 || res == 'n' || res == 'y' || +				res == KEY_LEFT || res == KEY_RIGHT || +				res == 'm' || res == '/') +				break; +			else if (canbhot(res)) { +				/* check for hot keys: */ +				int tmp = get_next_hot(res); +				if (tmp != -1) +					center_item(tmp, &last_top_row); +			} +			refresh_all_windows(main_window); +		} + +		refresh_all_windows(main_window); +		/* if ESC  or left*/ +		if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) +			break; + +		/* remember location in the menu */ +		last_top_row = top_row(curses_menu); +		current_index = curses_item_index(); + +		if (!item_tag()) +			continue; + +		submenu = (struct menu *) item_data(); +		active_menu = (struct menu *)item_data(); +		if (!submenu || !menu_is_visible(submenu)) +			continue; +		if (submenu) +			sym = submenu->sym; +		else +			sym = NULL; + +		switch (res) { +		case ' ': +			if (item_is_tag('t')) +				sym_toggle_tristate_value(sym); +			else if (item_is_tag('m')) +				conf(submenu); +			break; +		case KEY_RIGHT: +		case 10: /* ENTER WAS PRESSED */ +			switch (item_tag()) { +			case 'm': +				if (single_menu_mode) +					submenu->data = +						(void *) (long) !submenu->data; +				else +					conf(submenu); +				break; +			case 't': +				if (sym_is_choice(sym) && +				    sym_get_tristate_value(sym) == yes) +					conf_choice(submenu); +				else if (submenu->prompt && +					 submenu->prompt->type == P_MENU) +					conf(submenu); +				else if (res == 10) +					sym_toggle_tristate_value(sym); +				break; +			case 's': +				conf_string(submenu); +				break; +			} +			break; +		case 'y': +			if (item_is_tag('t')) { +				if (sym_set_tristate_value(sym, yes)) +					break; +				if (sym_set_tristate_value(sym, mod)) +					btn_dialog(main_window, setmod_text, 0); +			} +			break; +		case 'n': +			if (item_is_tag('t')) +				sym_set_tristate_value(sym, no); +			break; +		case 'm': +			if (item_is_tag('t')) +				sym_set_tristate_value(sym, mod); +			break; +		case '/': +			search_conf(); +			break; +		} +	} +} + +static void show_help(struct menu *menu) +{ +	struct gstr help = str_new(); + +	if (menu && menu->sym && menu_has_help(menu)) { +		if (menu->sym->name) { +			str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name); +			str_append(&help, _(menu_get_help(menu))); +			str_append(&help, "\n"); +			get_symbol_str(&help, menu->sym); +		} +	} else { +		str_append(&help, nohelp_text); +	} +	show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); +	str_free(&help); +} + +static void conf_choice(struct menu *menu) +{ +	const char *prompt = _(menu_get_prompt(menu)); +	struct menu *child = 0; +	struct symbol *active; +	int selected_index = 0; +	int last_top_row = 0; +	int res, i = 0; + +	active = sym_get_choice_value(menu->sym); +	/* this is mostly duplicated from the conf() function. */ +	while (!global_exit) { +		reset_menu(); + +		for (i = 0, child = menu->list; child; child = child->next) { +			if (!show_all_items && !menu_is_visible(child)) +				continue; + +			if (child->sym == sym_get_choice_value(menu->sym)) +				item_make(child, ':', "<X> %s", +						_(menu_get_prompt(child))); +			else +				item_make(child, ':', "    %s", +						_(menu_get_prompt(child))); +			if (child->sym == active){ +				last_top_row = top_row(curses_menu); +				selected_index = i; +			} +			i++; +		} +		show_menu(prompt ? _(prompt) : _("Choice Menu"), +				_(radiolist_instructions), +				selected_index, +				&last_top_row); +		while (!global_exit && (res = wgetch(menu_win(curses_menu)))) { +			if (process_special_keys( +						&res, +						(struct menu *) item_data())) +				break; +			switch (res) { +			case KEY_DOWN: +				menu_driver(curses_menu, REQ_DOWN_ITEM); +				break; +			case KEY_UP: +				menu_driver(curses_menu, REQ_UP_ITEM); +				break; +			case KEY_NPAGE: +				menu_driver(curses_menu, REQ_SCR_DPAGE); +				break; +			case KEY_PPAGE: +				menu_driver(curses_menu, REQ_SCR_UPAGE); +				break; +			case KEY_HOME: +				menu_driver(curses_menu, REQ_FIRST_ITEM); +				break; +			case KEY_END: +				menu_driver(curses_menu, REQ_LAST_ITEM); +				break; +			case 'h': +			case '?': +				show_help((struct menu *) item_data()); +				break; +			} +			if (res == 10 || res == 27 || res == ' ' || +				res == KEY_LEFT) +				break; +			else if (canbhot(res)) { +				/* check for hot keys: */ +				int tmp = get_next_hot(res); +				if (tmp != -1) +					center_item(tmp, &last_top_row); +			} +			refresh_all_windows(main_window); +		} +		/* if ESC or left */ +		if (res == 27 || res == KEY_LEFT) +			break; + +		child = item_data(); +		if (!child || !menu_is_visible(child)) +			continue; +		switch (res) { +		case ' ': +		case  10: +		case KEY_RIGHT: +			sym_set_tristate_value(child->sym, yes); +			return; +		case 'h': +		case '?': +			show_help(child); +			active = child->sym; +			break; +		case KEY_EXIT: +			return; +		} +	} +} + +static void conf_string(struct menu *menu) +{ +	const char *prompt = menu_get_prompt(menu); +	char dialog_input_result[256]; + +	while (1) { +		int res; +		const char *heading; + +		switch (sym_get_type(menu->sym)) { +		case S_INT: +			heading = _(inputbox_instructions_int); +			break; +		case S_HEX: +			heading = _(inputbox_instructions_hex); +			break; +		case S_STRING: +			heading = _(inputbox_instructions_string); +			break; +		default: +			heading = _("Internal nconf error!"); +		} +		res = dialog_inputbox(main_window, +				prompt ? _(prompt) : _("Main Menu"), +				heading, +				sym_get_string_value(menu->sym), +				dialog_input_result, +				sizeof(dialog_input_result)); +		switch (res) { +		case 0: +			if (sym_set_string_value(menu->sym, +						dialog_input_result)) +				return; +			btn_dialog(main_window, +				_("You have made an invalid entry."), 0); +			break; +		case 1: +			show_help(menu); +			break; +		case KEY_EXIT: +			return; +		} +	} +} + +static void conf_load(void) +{ +	char dialog_input_result[256]; +	while (1) { +		int res; +		res = dialog_inputbox(main_window, +				NULL, load_config_text, +				filename, +				dialog_input_result, +				sizeof(dialog_input_result)); +		switch (res) { +		case 0: +			if (!dialog_input_result[0]) +				return; +			if (!conf_read(dialog_input_result)) { +				set_config_filename(dialog_input_result); +				sym_set_change_count(1); +				return; +			} +			btn_dialog(main_window, _("File does not exist!"), 0); +			break; +		case 1: +			show_scroll_win(main_window, +					_("Load Alternate Configuration"), +					load_config_help); +			break; +		case KEY_EXIT: +			return; +		} +	} +} + +static void conf_save(void) +{ +	char dialog_input_result[256]; +	while (1) { +		int res; +		res = dialog_inputbox(main_window, +				NULL, save_config_text, +				filename, +				dialog_input_result, +				sizeof(dialog_input_result)); +		switch (res) { +		case 0: +			if (!dialog_input_result[0]) +				return; +			supress_stdout(0); +			res = conf_write(dialog_input_result); +			supress_stdout(1); +			if (!res) { +				char buf[1024]; +				sprintf(buf, "%s %s", +					_("configuration file saved to: "), +					dialog_input_result); +				btn_dialog(main_window, +					   buf, 1, "<OK>"); +				set_config_filename(dialog_input_result); +				return; +			} +			btn_dialog(main_window, _("Can't create file! " +				"Probably a nonexistent directory."), +				1, "<OK>"); +			break; +		case 1: +			show_scroll_win(main_window, +				_("Save Alternate Configuration"), +				save_config_help); +			break; +		case KEY_EXIT: +			return; +		} +	} +} + +void setup_windows(void) +{ +	if (main_window != NULL) +		delwin(main_window); + +	/* set up the menu and menu window */ +	main_window = newwin(LINES-2, COLS-2, 2, 1); +	keypad(main_window, TRUE); +	mwin_max_lines = LINES-6; +	mwin_max_cols = COLS-6; + +	/* panels order is from bottom to top */ +	new_panel(main_window); +} + +int main(int ac, char **av) +{ +	char *mode; + +	setlocale(LC_ALL, ""); +	bindtextdomain(PACKAGE, LOCALEDIR); +	textdomain(PACKAGE); + +	conf_parse(av[1]); +	conf_read(NULL); + +	mode = getenv("NCONFIG_MODE"); +	if (mode) { +		if (!strcasecmp(mode, "single_menu")) +			single_menu_mode = 1; +	} + +	/* Initialize curses */ +	initscr(); +	/* set color theme */ +	set_colors(); + +	cbreak(); +	noecho(); +	keypad(stdscr, TRUE); +	curs_set(0); + +	if (COLS < 75 || LINES < 20) { +		endwin(); +		printf("Your terminal should have at " +			"least 20 lines and 75 columns\n"); +		return 1; +	} + +	notimeout(stdscr, FALSE); +	ESCDELAY = 1; + +	/* set btns menu */ +	curses_menu = new_menu(curses_menu_items); +	menu_opts_off(curses_menu, O_SHOWDESC); +	menu_opts_off(curses_menu, O_SHOWMATCH); +	menu_opts_on(curses_menu, O_ONEVALUE); +	menu_opts_on(curses_menu, O_NONCYCLIC); +	set_menu_mark(curses_menu, " "); +	set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); +	set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); +	set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); + +	set_config_filename(conf_get_configname()); +	setup_windows(); + +	/* check for KEY_FUNC(1) */ +	if (has_key(KEY_F(1)) == FALSE) { +		show_scroll_win(main_window, +				_("Instructions"), +				_(menu_no_f_instructions)); +	} + + + +	/* do the work */ +	while (!global_exit) { +		conf(&rootmenu); +		if (!global_exit && do_exit() == 0) +			break; +	} +	/* ok, we are done */ +	unpost_menu(curses_menu); +	free_menu(curses_menu); +	delwin(main_window); +	clear(); +	refresh(); +	endwin(); +	return 0; +} +  |