mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-25 18:18:19 +01:00 
			
		
		
		
	Import - scripts/kconfig/* - include/linux/kconfig.h from Linux 3.16-rc7. Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com> Reviewed-by: Simon Glass <sjg@chromium.org>
		
			
				
	
	
		
			1557 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1557 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
 | |
|  * Released under the terms of the GNU GPL v2.0.
 | |
|  *
 | |
|  * Derived from menuconfig.
 | |
|  *
 | |
|  */
 | |
| #define _GNU_SOURCE
 | |
| #include <string.h>
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "lkc.h"
 | |
| #include "nconf.h"
 | |
| #include <ctype.h>
 | |
| 
 | |
| static const char nconf_global_help[] = N_(
 | |
| "Help windows\n"
 | |
| "------------\n"
 | |
| "o  Global help:  Unless in a data entry window, pressing <F1> will give \n"
 | |
| "   you the global help window, which you are just reading.\n"
 | |
| "\n"
 | |
| "o  A short version of the global help is available by pressing <F3>.\n"
 | |
| "\n"
 | |
| "o  Local help:  To get help related to the current menu entry, use any\n"
 | |
| "   of <?> <h>, or if in a data entry window then press <F1>.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Menu entries\n"
 | |
| "------------\n"
 | |
| "This interface lets you select features and parameters for the kernel\n"
 | |
| "build.  Kernel features can either be built-in, modularized, or removed.\n"
 | |
| "Parameters must be entered as text or decimal or hexadecimal numbers.\n"
 | |
| "\n"
 | |
| "Menu entries 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, are selected by another feature\n"
 | |
| "  - -  are selected by another feature\n"
 | |
| "  XXX  cannot be selected.  Symbol Info <F2> tells you why.\n"
 | |
| "*, M or whitespace inside braces means to build in, build as a module\n"
 | |
| "or to exclude the feature respectively.\n"
 | |
| "\n"
 | |
| "To change any of these features, highlight it with the movement keys\n"
 | |
| "listed below and press <y> to build it in, <m> to make it a module or\n"
 | |
| "<n> to remove it.  You may press the <Space> key to cycle through the\n"
 | |
| "available options.\n"
 | |
| "\n"
 | |
| "A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
 | |
| "empty submenu.\n"
 | |
| "\n"
 | |
| "Menu navigation keys\n"
 | |
| "----------------------------------------------------------------------\n"
 | |
| "Linewise up                 <Up>\n"
 | |
| "Linewise down               <Down>\n"
 | |
| "Pagewise up                 <Page Up>\n"
 | |
| "Pagewise down               <Page Down>\n"
 | |
| "First entry                 <Home>\n"
 | |
| "Last entry                  <End>\n"
 | |
| "Enter a submenu             <Right>  <Enter>\n"
 | |
| "Go back to parent menu      <Left>   <Esc>  <F5>\n"
 | |
| "Close a help window         <Enter>  <Esc>  <F5>\n"
 | |
| "Close entry window, apply   <Enter>\n"
 | |
| "Close entry window, forget  <Esc>  <F5>\n"
 | |
| "Start incremental, case-insensitive search for STRING in menu entries,\n"
 | |
| "    no regex support, STRING is displayed in upper left corner\n"
 | |
| "                            </>STRING\n"
 | |
| "    Remove last character   <Backspace>\n"
 | |
| "    Jump to next hit        <Down>\n"
 | |
| "    Jump to previous hit    <Up>\n"
 | |
| "Exit menu search mode       </>  <Esc>\n"
 | |
| "Search for configuration variables with or without leading CONFIG_\n"
 | |
| "                            <F8>RegExpr<Enter>\n"
 | |
| "Verbose search help         <F8><F1>\n"
 | |
| "----------------------------------------------------------------------\n"
 | |
| "\n"
 | |
| "Unless in a data entry window, key <1> may be used instead of <F1>,\n"
 | |
| "<2> instead of <F2>, etc.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Radiolist (Choice list)\n"
 | |
| "-----------------------\n"
 | |
| "Use the movement keys listed above to select the option you wish to set\n"
 | |
| "and press <Space>.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Data entry\n"
 | |
| "----------\n"
 | |
| "Enter the requested information and press <Enter>.  Hexadecimal values\n"
 | |
| "may be entered without the \"0x\" prefix.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Text Box (Help Window)\n"
 | |
| "----------------------\n"
 | |
| "Use movement keys as listed in table above.\n"
 | |
| "\n"
 | |
| "Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Alternate configuration files\n"
 | |
| "-----------------------------\n"
 | |
| "nconfig supports switching between different configurations.\n"
 | |
| "Press <F6> to save your current configuration.  Press <F7> and enter\n"
 | |
| "a file name to load a previously saved configuration.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Terminal configuration\n"
 | |
| "----------------------\n"
 | |
| "If you use nconfig in a xterm window, make sure your TERM environment\n"
 | |
| "variable specifies a terminal configuration which supports at least\n"
 | |
| "16 colors.  Otherwise nconfig will look rather bad.\n"
 | |
| "\n"
 | |
| "If the \"stty size\" command reports the current terminalsize correctly,\n"
 | |
| "nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n"
 | |
| "and display longer menus properly.\n"
 | |
| "\n"
 | |
| "\n"
 | |
| "Single menu mode\n"
 | |
| "----------------\n"
 | |
| "If you prefer to have all of the menu entries listed in a single menu,\n"
 | |
| "rather than the default multimenu hierarchy, run nconfig with\n"
 | |
| "NCONFIG_MODE environment variable set to single_menu.  Example:\n"
 | |
| "\n"
 | |
| "make NCONFIG_MODE=single_menu nconfig\n"
 | |
| "\n"
 | |
| "<Enter> will then unfold the appropriate category, or fold it if it\n"
 | |
| "is already unfolded.  Folded menu entries will be designated by a\n"
 | |
| "leading \"++>\" and unfolded entries by a leading \"-->\".\n"
 | |
| "\n"
 | |
| "Note that this mode can eventually be a little more CPU expensive than\n"
 | |
| "the default mode, especially with a larger number of unfolded submenus.\n"
 | |
| "\n"),
 | |
| menu_no_f_instructions[] = N_(
 | |
| "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
 | |
| "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
 | |
| "\n"
 | |
| "Use the following keys to navigate the menus:\n"
 | |
| "Move up or down with <Up> and <Down>.\n"
 | |
| "Enter a submenu with <Enter> or <Right>.\n"
 | |
| "Exit a submenu to its parent menu with <Esc> or <Left>.\n"
 | |
| "Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
 | |
| "Pressing <Space> cycles through the available options.\n"
 | |
| "To search for menu entries press </>.\n"
 | |
| "<Esc> always leaves the current window.\n"
 | |
| "\n"
 | |
| "You do not have function keys support.\n"
 | |
| "Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
 | |
| "For verbose global help use key <1>.\n"
 | |
| "For help related to the current menu entry press <?> or <h>.\n"),
 | |
| menu_instructions[] = N_(
 | |
| "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
 | |
| "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
 | |
| "\n"
 | |
| "Use the following keys to navigate the menus:\n"
 | |
| "Move up or down with <Up> or <Down>.\n"
 | |
| "Enter a submenu with <Enter> or <Right>.\n"
 | |
| "Exit a submenu to its parent menu with <Esc> or <Left>.\n"
 | |
| "Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
 | |
| "Pressing <Space> cycles through the available options.\n"
 | |
| "To search for menu entries press </>.\n"
 | |
| "<Esc> always leaves the current window.\n"
 | |
| "\n"
 | |
| "Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
 | |
| "For verbose global help press <F1>.\n"
 | |
| "For help related to the current menu entry press <?> or <h>.\n"),
 | |
| radiolist_instructions[] = N_(
 | |
| "Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
 | |
| "with <Space>.\n"
 | |
| "For help related to the current entry press <?> or <h>.\n"
 | |
| "For global help press <F1>.\n"),
 | |
| inputbox_instructions_int[] = N_(
 | |
| "Please enter a decimal value.\n"
 | |
| "Fractions will not be accepted.\n"
 | |
| "Press <Enter> to apply, <Esc> to cancel."),
 | |
| inputbox_instructions_hex[] = N_(
 | |
| "Please enter a hexadecimal value.\n"
 | |
| "Press <Enter> to apply, <Esc> to cancel."),
 | |
| inputbox_instructions_string[] = N_(
 | |
| "Please enter a string value.\n"
 | |
| "Press <Enter> to apply, <Esc> to cancel."),
 | |
| setmod_text[] = N_(
 | |
| "This feature depends on another feature which has been configured as a\n"
 | |
| "module.  As a result, the current feature will be built as a module too."),
 | |
| 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 last\n"
 | |
| "retrieved.  Leave empty to abort."),
 | |
| load_config_help[] = N_(
 | |
| "For various reasons, one may wish to keep several different\n"
 | |
| "configurations available on a single machine.\n"
 | |
| "\n"
 | |
| "If you have saved a previous configuration in a file other than the\n"
 | |
| "default one, entering its name here will allow you to load and modify\n"
 | |
| "that configuration.\n"
 | |
| "\n"
 | |
| "Leave empty to abort.\n"),
 | |
| save_config_text[] = N_(
 | |
| "Enter a filename to which this configuration should be saved\n"
 | |
| "as an alternate.  Leave empty to abort."),
 | |
| save_config_help[] = N_(
 | |
| "For various reasons, one may wish to keep several different\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"
 | |
| "Leave empty to abort.\n"),
 | |
| search_help[] = N_(
 | |
| "Search for symbols (configuration variable names CONFIG_*) and display\n"
 | |
| "their relations.  Regular expressions are supported.\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, 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 displayed for this symbol in\n"
 | |
| "   the menu hierarchy.\n"
 | |
| "o  The 'Defined at' line tells at what file / line number the symbol is\n"
 | |
| "   defined.\n"
 | |
| "o  The 'Depends on:' line lists symbols that need to be defined for\n"
 | |
| "   this symbol to be visible and selectable in the menu.\n"
 | |
| "o  The 'Location:' lines tell, where in the menu structure this symbol\n"
 | |
| "   is located.  A location followed by a [ = y] indicates that this is\n"
 | |
| "   a selectable menu item, and the current value is displayed inside\n"
 | |
| "   brackets.\n"
 | |
| "o  The 'Selects:' line tells, what symbol will be automatically selected\n"
 | |
| "   if this symbol is selected (y or m).\n"
 | |
| "o  The 'Selected by' line tells what symbol has selected this symbol.\n"
 | |
| "\n"
 | |
| "Only relevant lines are shown.\n"
 | |
| "\n\n"
 | |
| "Search examples:\n"
 | |
| "USB  => find all symbols containing USB\n"
 | |
| "^USB => find all symbols starting with USB\n"
 | |
| "USB$ => find all symbols ending with USB\n"
 | |
| "\n");
 | |
| 
 | |
| struct mitem {
 | |
| 	char str[256];
 | |
| 	char tag;
 | |
| 	void *usrptr;
 | |
| 	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;
 | |
| 
 | |
| static char *dialog_input_result;
 | |
| static int dialog_input_result_len;
 | |
| 
 | |
| 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);
 | |
| static void search_conf(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);
 | |
| static void handle_f9(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 = 9;
 | |
| struct function_keys function_keys[] = {
 | |
| 	{
 | |
| 		.key_str = "F1",
 | |
| 		.func = "Help",
 | |
| 		.key = F_HELP,
 | |
| 		.handler = handle_f1,
 | |
| 	},
 | |
| 	{
 | |
| 		.key_str = "F2",
 | |
| 		.func = "SymInfo",
 | |
| 		.key = F_SYMBOL,
 | |
| 		.handler = handle_f2,
 | |
| 	},
 | |
| 	{
 | |
| 		.key_str = "F3",
 | |
| 		.func = "Help 2",
 | |
| 		.key = F_INSTS,
 | |
| 		.handler = handle_f3,
 | |
| 	},
 | |
| 	{
 | |
| 		.key_str = "F4",
 | |
| 		.func = "ShowAll",
 | |
| 		.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 = "SymSearch",
 | |
| 		.key = F_SEARCH,
 | |
| 		.handler = handle_f8,
 | |
| 	},
 | |
| 	{
 | |
| 		.key_str = "F9",
 | |
| 		.func = "Exit",
 | |
| 		.key = F_EXIT,
 | |
| 		.handler = handle_f9,
 | |
| 	},
 | |
| };
 | |
| 
 | |
| static void print_function_line(void)
 | |
| {
 | |
| 	int i;
 | |
| 	int offset = 1;
 | |
| 	const int skip = 1;
 | |
| 	int lines = getmaxy(stdscr);
 | |
| 
 | |
| 	for (i = 0; i < function_keys_num; i++) {
 | |
| 		(void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
 | |
| 		mvwprintw(main_window, lines-3, offset,
 | |
| 				"%s",
 | |
| 				function_keys[i].key_str);
 | |
| 		(void) 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;
 | |
| 	}
 | |
| 	(void) wattrset(main_window, attributes[NORMAL]);
 | |
| }
 | |
| 
 | |
| /* help */
 | |
| static void handle_f1(int *key, struct menu *current_item)
 | |
| {
 | |
| 	show_scroll_win(main_window,
 | |
| 			_("Global help"), _(nconf_global_help));
 | |
| 	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,
 | |
| 			_("Short help"),
 | |
| 			_(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;
 | |
| }
 | |
| 
 | |
| /* search */
 | |
| static void handle_f8(int *key, struct menu *current_item)
 | |
| {
 | |
| 	search_conf();
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| /* exit */
 | |
| static void handle_f9(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));
 | |
| 	items_num = 0;
 | |
| }
 | |
| 
 | |
| typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
 | |
| 	FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
 | |
| 
 | |
| /* return the index of the matched item, or -1 if no such item exists */
 | |
| static int get_mext_match(const char *match_str, match_f flag)
 | |
| {
 | |
| 	int match_start = item_index(current_item(curses_menu));
 | |
| 	int index;
 | |
| 
 | |
| 	if (flag == FIND_NEXT_MATCH_DOWN)
 | |
| 		++match_start;
 | |
| 	else if (flag == FIND_NEXT_MATCH_UP)
 | |
| 		--match_start;
 | |
| 
 | |
| 	index = match_start;
 | |
| 	index = (index + items_num) % items_num;
 | |
| 	while (true) {
 | |
| 		char *str = k_menu_items[index].str;
 | |
| 		if (strcasestr(str, match_str) != 0)
 | |
| 			return index;
 | |
| 		if (flag == FIND_NEXT_MATCH_UP ||
 | |
| 		    flag == MATCH_TINKER_PATTERN_UP)
 | |
| 			--index;
 | |
| 		else
 | |
| 			++index;
 | |
| 		index = (index + items_num) % items_num;
 | |
| 		if (index == match_start)
 | |
| 			return -1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* Make a new item. */
 | |
| static void item_make(struct menu *menu, char tag, const char *fmt, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 
 | |
| 	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(k_menu_items[items_num].str,
 | |
| 		  sizeof(k_menu_items[items_num].str),
 | |
| 		  fmt, ap);
 | |
| 	va_end(ap);
 | |
| 
 | |
| 	if (!k_menu_items[items_num].is_visible)
 | |
| 		memcpy(k_menu_items[items_num].str, "XXX", 3);
 | |
| 
 | |
| 	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);
 | |
| 	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);
 | |
| 	if (!cur)
 | |
| 		return NULL;
 | |
| 	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;
 | |
| 
 | |
| 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
 | |
| 			"%s - %s", config_filename, rootmenu.prompt->text);
 | |
| 	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;
 | |
| }
 | |
| 
 | |
| /* 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 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:
 | |
| 		res = conf_write(filename);
 | |
| 		if (res)
 | |
| 			btn_dialog(
 | |
| 				main_window,
 | |
| 				_("Error during writing of configuration.\n"
 | |
| 				  "Your configuration changes were NOT saved."),
 | |
| 				  1,
 | |
| 				  "<OK>");
 | |
| 		break;
 | |
| 	default:
 | |
| 		btn_dialog(
 | |
| 			main_window,
 | |
| 			_("Your 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;
 | |
| 	struct gstr title;
 | |
| 	char *dialog_input;
 | |
| 	int dres;
 | |
| 
 | |
| 	title = str_new();
 | |
| 	str_printf( &title, _("Enter (sub)string or regexp to search for "
 | |
| 			      "(with or without \"%s\")"), CONFIG_);
 | |
| 
 | |
| again:
 | |
| 	dres = dialog_inputbox(main_window,
 | |
| 			_("Search Configuration Parameter"),
 | |
| 			str_get(&title),
 | |
| 			"", &dialog_input_result, &dialog_input_result_len);
 | |
| 	switch (dres) {
 | |
| 	case 0:
 | |
| 		break;
 | |
| 	case 1:
 | |
| 		show_scroll_win(main_window,
 | |
| 				_("Search Configuration"), search_help);
 | |
| 		goto again;
 | |
| 	default:
 | |
| 		str_free(&title);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	/* strip the prefix if necessary */
 | |
| 	dialog_input = dialog_input_result;
 | |
| 	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
 | |
| 		dialog_input += strlen(CONFIG_);
 | |
| 
 | |
| 	sym_arr = sym_re_search(dialog_input);
 | |
| 	res = get_relations_str(sym_arr, NULL);
 | |
| 	free(sym_arr);
 | |
| 	show_scroll_win(main_window,
 | |
| 			_("Search Results"), str_get(&res));
 | |
| 	str_free(&res);
 | |
| 	str_free(&title);
 | |
| }
 | |
| 
 | |
| 
 | |
| 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  %s",
 | |
| 						  indent + 1, ' ', prompt,
 | |
| 						  menu_is_empty(menu) ? "----" : "--->");
 | |
| 
 | |
| 				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("  %s", menu_is_empty(menu) ? "----" : "--->");
 | |
| 			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;
 | |
| 
 | |
| 	set_top_row(curses_menu, *last_top_row);
 | |
| 	toprow = top_row(curses_menu);
 | |
| 	if (selected_index < toprow ||
 | |
| 	    selected_index >= toprow+mwin_max_lines) {
 | |
| 		toprow = max(selected_index-mwin_max_lines/2, 0);
 | |
| 		if (toprow >= item_count(curses_menu)-mwin_max_lines)
 | |
| 			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();
 | |
| 	(void) wattrset(main_window, attributes[NORMAL]);
 | |
| 	print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
 | |
| 			menu_backtitle,
 | |
| 			attributes[MAIN_HEADING]);
 | |
| 
 | |
| 	(void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
 | |
| 	box(main_window, 0, 0);
 | |
| 	(void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
 | |
| 	mvwprintw(main_window, 0, 3, " %s ", prompt);
 | |
| 	(void) 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;
 | |
| 	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 adj_match_dir(match_f *match_direction)
 | |
| {
 | |
| 	if (*match_direction == FIND_NEXT_MATCH_DOWN)
 | |
| 		*match_direction =
 | |
| 			MATCH_TINKER_PATTERN_DOWN;
 | |
| 	else if (*match_direction == FIND_NEXT_MATCH_UP)
 | |
| 		*match_direction =
 | |
| 			MATCH_TINKER_PATTERN_UP;
 | |
| 	/* else, do no change.. */
 | |
| }
 | |
| 
 | |
| struct match_state
 | |
| {
 | |
| 	int in_search;
 | |
| 	match_f match_direction;
 | |
| 	char pattern[256];
 | |
| };
 | |
| 
 | |
| /* Return 0 means I have handled the key. In such a case, ans should hold the
 | |
|  * item to center, or -1 otherwise.
 | |
|  * Else return -1 .
 | |
|  */
 | |
| static int do_match(int key, struct match_state *state, int *ans)
 | |
| {
 | |
| 	char c = (char) key;
 | |
| 	int terminate_search = 0;
 | |
| 	*ans = -1;
 | |
| 	if (key == '/' || (state->in_search && key == 27)) {
 | |
| 		move(0, 0);
 | |
| 		refresh();
 | |
| 		clrtoeol();
 | |
| 		state->in_search = 1-state->in_search;
 | |
| 		bzero(state->pattern, sizeof(state->pattern));
 | |
| 		state->match_direction = MATCH_TINKER_PATTERN_DOWN;
 | |
| 		return 0;
 | |
| 	} else if (!state->in_search)
 | |
| 		return 1;
 | |
| 
 | |
| 	if (isalnum(c) || isgraph(c) || c == ' ') {
 | |
| 		state->pattern[strlen(state->pattern)] = c;
 | |
| 		state->pattern[strlen(state->pattern)] = '\0';
 | |
| 		adj_match_dir(&state->match_direction);
 | |
| 		*ans = get_mext_match(state->pattern,
 | |
| 				state->match_direction);
 | |
| 	} else if (key == KEY_DOWN) {
 | |
| 		state->match_direction = FIND_NEXT_MATCH_DOWN;
 | |
| 		*ans = get_mext_match(state->pattern,
 | |
| 				state->match_direction);
 | |
| 	} else if (key == KEY_UP) {
 | |
| 		state->match_direction = FIND_NEXT_MATCH_UP;
 | |
| 		*ans = get_mext_match(state->pattern,
 | |
| 				state->match_direction);
 | |
| 	} else if (key == KEY_BACKSPACE || key == 127) {
 | |
| 		state->pattern[strlen(state->pattern)-1] = '\0';
 | |
| 		adj_match_dir(&state->match_direction);
 | |
| 	} else
 | |
| 		terminate_search = 1;
 | |
| 
 | |
| 	if (terminate_search) {
 | |
| 		state->in_search = 0;
 | |
| 		bzero(state->pattern, sizeof(state->pattern));
 | |
| 		move(0, 0);
 | |
| 		refresh();
 | |
| 		clrtoeol();
 | |
| 		return -1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void conf(struct menu *menu)
 | |
| {
 | |
| 	struct menu *submenu = 0;
 | |
| 	const char *prompt = menu_get_prompt(menu);
 | |
| 	struct symbol *sym;
 | |
| 	int res;
 | |
| 	int current_index = 0;
 | |
| 	int last_top_row = 0;
 | |
| 	struct match_state match_state = {
 | |
| 		.in_search = 0,
 | |
| 		.match_direction = MATCH_TINKER_PATTERN_DOWN,
 | |
| 		.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) {
 | |
| 			if (match_state.in_search) {
 | |
| 				mvprintw(0, 0,
 | |
| 					"searching: %s", match_state.pattern);
 | |
| 				clrtoeol();
 | |
| 			}
 | |
| 			refresh_all_windows(main_window);
 | |
| 			res = wgetch(menu_win(curses_menu));
 | |
| 			if (!res)
 | |
| 				break;
 | |
| 			if (do_match(res, &match_state, ¤t_index) == 0) {
 | |
| 				if (current_index != -1)
 | |
| 					center_item(current_index,
 | |
| 						    &last_top_row);
 | |
| 				continue;
 | |
| 			}
 | |
| 			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')
 | |
| 				break;
 | |
| 			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();
 | |
| 		if (!submenu || !menu_is_visible(submenu))
 | |
| 			continue;
 | |
| 		sym = submenu->sym;
 | |
| 
 | |
| 		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;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void conf_message_callback(const char *fmt, va_list ap)
 | |
| {
 | |
| 	char buf[1024];
 | |
| 
 | |
| 	vsnprintf(buf, sizeof(buf), fmt, ap);
 | |
| 	btn_dialog(main_window, buf, 1, "<OK>");
 | |
| }
 | |
| 
 | |
| static void show_help(struct menu *menu)
 | |
| {
 | |
| 	struct gstr help;
 | |
| 
 | |
| 	if (!menu)
 | |
| 		return;
 | |
| 
 | |
| 	help = str_new();
 | |
| 	menu_get_ext_help(menu, &help);
 | |
| 	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;
 | |
| 	struct match_state match_state = {
 | |
| 		.in_search = 0,
 | |
| 		.match_direction = MATCH_TINKER_PATTERN_DOWN,
 | |
| 		.pattern = "",
 | |
| 	};
 | |
| 
 | |
| 	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 if (child->sym)
 | |
| 				item_make(child, ':', "    %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) {
 | |
| 			if (match_state.in_search) {
 | |
| 				mvprintw(0, 0, "searching: %s",
 | |
| 					 match_state.pattern);
 | |
| 				clrtoeol();
 | |
| 			}
 | |
| 			refresh_all_windows(main_window);
 | |
| 			res = wgetch(menu_win(curses_menu));
 | |
| 			if (!res)
 | |
| 				break;
 | |
| 			if (do_match(res, &match_state, &selected_index) == 0) {
 | |
| 				if (selected_index != -1)
 | |
| 					center_item(selected_index,
 | |
| 						    &last_top_row);
 | |
| 				continue;
 | |
| 			}
 | |
| 			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;
 | |
| 			}
 | |
| 			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) || !child->sym)
 | |
| 			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);
 | |
| 
 | |
| 	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,
 | |
| 				&dialog_input_result_len);
 | |
| 		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)
 | |
| {
 | |
| 	while (1) {
 | |
| 		int res;
 | |
| 		res = dialog_inputbox(main_window,
 | |
| 				NULL, load_config_text,
 | |
| 				filename,
 | |
| 				&dialog_input_result,
 | |
| 				&dialog_input_result_len);
 | |
| 		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)
 | |
| {
 | |
| 	while (1) {
 | |
| 		int res;
 | |
| 		res = dialog_inputbox(main_window,
 | |
| 				NULL, save_config_text,
 | |
| 				filename,
 | |
| 				&dialog_input_result,
 | |
| 				&dialog_input_result_len);
 | |
| 		switch (res) {
 | |
| 		case 0:
 | |
| 			if (!dialog_input_result[0])
 | |
| 				return;
 | |
| 			res = conf_write(dialog_input_result);
 | |
| 			if (!res) {
 | |
| 				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)
 | |
| {
 | |
| 	int lines, columns;
 | |
| 
 | |
| 	getmaxyx(stdscr, lines, columns);
 | |
| 
 | |
| 	if (main_window != NULL)
 | |
| 		delwin(main_window);
 | |
| 
 | |
| 	/* set up the menu and menu window */
 | |
| 	main_window = newwin(lines-2, columns-2, 2, 1);
 | |
| 	keypad(main_window, TRUE);
 | |
| 	mwin_max_lines = lines-7;
 | |
| 	mwin_max_cols = columns-6;
 | |
| 
 | |
| 	/* panels order is from bottom to top */
 | |
| 	new_panel(main_window);
 | |
| }
 | |
| 
 | |
| int main(int ac, char **av)
 | |
| {
 | |
| 	int lines, columns;
 | |
| 	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);
 | |
| 
 | |
| 	getmaxyx(stdscr, lines, columns);
 | |
| 	if (columns < 75 || lines < 20) {
 | |
| 		endwin();
 | |
| 		printf("Your terminal should have at "
 | |
| 			"least 20 lines and 75 columns\n");
 | |
| 		return 1;
 | |
| 	}
 | |
| 
 | |
| 	notimeout(stdscr, FALSE);
 | |
| #if NCURSES_REENTRANT
 | |
| 	set_escdelay(1);
 | |
| #else
 | |
| 	ESCDELAY = 1;
 | |
| #endif
 | |
| 
 | |
| 	/* set btns menu */
 | |
| 	curses_menu = new_menu(curses_menu_items);
 | |
| 	menu_opts_off(curses_menu, O_SHOWDESC);
 | |
| 	menu_opts_on(curses_menu, O_SHOWMATCH);
 | |
| 	menu_opts_on(curses_menu, O_ONEVALUE);
 | |
| 	menu_opts_on(curses_menu, O_NONCYCLIC);
 | |
| 	menu_opts_on(curses_menu, O_IGNORECASE);
 | |
| 	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));
 | |
| 	}
 | |
| 
 | |
| 	conf_set_message_callback(conf_message_callback);
 | |
| 	/* 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;
 | |
| }
 |