cachepc-linux

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

nconf.c (38823B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
      4 *
      5 * Derived from menuconfig.
      6 */
      7#ifndef _GNU_SOURCE
      8#define _GNU_SOURCE
      9#endif
     10#include <string.h>
     11#include <strings.h>
     12#include <stdlib.h>
     13
     14#include "lkc.h"
     15#include "nconf.h"
     16#include <ctype.h>
     17
     18static const char nconf_global_help[] =
     19"Help windows\n"
     20"------------\n"
     21"o  Global help:  Unless in a data entry window, pressing <F1> will give \n"
     22"   you the global help window, which you are just reading.\n"
     23"\n"
     24"o  A short version of the global help is available by pressing <F3>.\n"
     25"\n"
     26"o  Local help:  To get help related to the current menu entry, use any\n"
     27"   of <?> <h>, or if in a data entry window then press <F1>.\n"
     28"\n"
     29"\n"
     30"Menu entries\n"
     31"------------\n"
     32"This interface lets you select features and parameters for the kernel\n"
     33"build.  Kernel features can either be built-in, modularized, or removed.\n"
     34"Parameters must be entered as text or decimal or hexadecimal numbers.\n"
     35"\n"
     36"Menu entries beginning with following braces represent features that\n"
     37"  [ ]  can be built in or removed\n"
     38"  < >  can be built in, modularized or removed\n"
     39"  { }  can be built in or modularized, are selected by another feature\n"
     40"  - -  are selected by another feature\n"
     41"  XXX  cannot be selected.  Symbol Info <F2> tells you why.\n"
     42"*, M or whitespace inside braces means to build in, build as a module\n"
     43"or to exclude the feature respectively.\n"
     44"\n"
     45"To change any of these features, highlight it with the movement keys\n"
     46"listed below and press <y> to build it in, <m> to make it a module or\n"
     47"<n> to remove it.  You may press the <Space> key to cycle through the\n"
     48"available options.\n"
     49"\n"
     50"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
     51"empty submenu.\n"
     52"\n"
     53"Menu navigation keys\n"
     54"----------------------------------------------------------------------\n"
     55"Linewise up                 <Up>    <k>\n"
     56"Linewise down               <Down>  <j>\n"
     57"Pagewise up                 <Page Up>\n"
     58"Pagewise down               <Page Down>\n"
     59"First entry                 <Home>\n"
     60"Last entry                  <End>\n"
     61"Enter a submenu             <Right>  <Enter>\n"
     62"Go back to parent menu      <Left>   <Esc>  <F5>\n"
     63"Close a help window         <Enter>  <Esc>  <F5>\n"
     64"Close entry window, apply   <Enter>\n"
     65"Close entry window, forget  <Esc>  <F5>\n"
     66"Start incremental, case-insensitive search for STRING in menu entries,\n"
     67"    no regex support, STRING is displayed in upper left corner\n"
     68"                            </>STRING\n"
     69"    Remove last character   <Backspace>\n"
     70"    Jump to next hit        <Down>\n"
     71"    Jump to previous hit    <Up>\n"
     72"Exit menu search mode       </>  <Esc>\n"
     73"Search for configuration variables with or without leading CONFIG_\n"
     74"                            <F8>RegExpr<Enter>\n"
     75"Verbose search help         <F8><F1>\n"
     76"----------------------------------------------------------------------\n"
     77"\n"
     78"Unless in a data entry window, key <1> may be used instead of <F1>,\n"
     79"<2> instead of <F2>, etc.\n"
     80"\n"
     81"\n"
     82"Radiolist (Choice list)\n"
     83"-----------------------\n"
     84"Use the movement keys listed above to select the option you wish to set\n"
     85"and press <Space>.\n"
     86"\n"
     87"\n"
     88"Data entry\n"
     89"----------\n"
     90"Enter the requested information and press <Enter>.  Hexadecimal values\n"
     91"may be entered without the \"0x\" prefix.\n"
     92"\n"
     93"\n"
     94"Text Box (Help Window)\n"
     95"----------------------\n"
     96"Use movement keys as listed in table above.\n"
     97"\n"
     98"Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
     99"\n"
    100"\n"
    101"Alternate configuration files\n"
    102"-----------------------------\n"
    103"nconfig supports switching between different configurations.\n"
    104"Press <F6> to save your current configuration.  Press <F7> and enter\n"
    105"a file name to load a previously saved configuration.\n"
    106"\n"
    107"\n"
    108"Terminal configuration\n"
    109"----------------------\n"
    110"If you use nconfig in a xterm window, make sure your TERM environment\n"
    111"variable specifies a terminal configuration which supports at least\n"
    112"16 colors.  Otherwise nconfig will look rather bad.\n"
    113"\n"
    114"If the \"stty size\" command reports the current terminalsize correctly,\n"
    115"nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n"
    116"and display longer menus properly.\n"
    117"\n"
    118"\n"
    119"Single menu mode\n"
    120"----------------\n"
    121"If you prefer to have all of the menu entries listed in a single menu,\n"
    122"rather than the default multimenu hierarchy, run nconfig with\n"
    123"NCONFIG_MODE environment variable set to single_menu.  Example:\n"
    124"\n"
    125"make NCONFIG_MODE=single_menu nconfig\n"
    126"\n"
    127"<Enter> will then unfold the appropriate category, or fold it if it\n"
    128"is already unfolded.  Folded menu entries will be designated by a\n"
    129"leading \"++>\" and unfolded entries by a leading \"-->\".\n"
    130"\n"
    131"Note that this mode can eventually be a little more CPU expensive than\n"
    132"the default mode, especially with a larger number of unfolded submenus.\n"
    133"\n",
    134menu_no_f_instructions[] =
    135"Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
    136"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
    137"\n"
    138"Use the following keys to navigate the menus:\n"
    139"Move up or down with <Up> and <Down>.\n"
    140"Enter a submenu with <Enter> or <Right>.\n"
    141"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
    142"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
    143"Pressing <Space> cycles through the available options.\n"
    144"To search for menu entries press </>.\n"
    145"<Esc> always leaves the current window.\n"
    146"\n"
    147"You do not have function keys support.\n"
    148"Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
    149"For verbose global help use key <1>.\n"
    150"For help related to the current menu entry press <?> or <h>.\n",
    151menu_instructions[] =
    152"Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
    153"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
    154"\n"
    155"Use the following keys to navigate the menus:\n"
    156"Move up or down with <Up> or <Down>.\n"
    157"Enter a submenu with <Enter> or <Right>.\n"
    158"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
    159"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
    160"Pressing <Space> cycles through the available options.\n"
    161"To search for menu entries press </>.\n"
    162"<Esc> always leaves the current window.\n"
    163"\n"
    164"Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
    165"For verbose global help press <F1>.\n"
    166"For help related to the current menu entry press <?> or <h>.\n",
    167radiolist_instructions[] =
    168"Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
    169"with <Space>.\n"
    170"For help related to the current entry press <?> or <h>.\n"
    171"For global help press <F1>.\n",
    172inputbox_instructions_int[] =
    173"Please enter a decimal value.\n"
    174"Fractions will not be accepted.\n"
    175"Press <Enter> to apply, <Esc> to cancel.",
    176inputbox_instructions_hex[] =
    177"Please enter a hexadecimal value.\n"
    178"Press <Enter> to apply, <Esc> to cancel.",
    179inputbox_instructions_string[] =
    180"Please enter a string value.\n"
    181"Press <Enter> to apply, <Esc> to cancel.",
    182setmod_text[] =
    183"This feature depends on another feature which has been configured as a\n"
    184"module.  As a result, the current feature will be built as a module too.",
    185load_config_text[] =
    186"Enter the name of the configuration file you wish to load.\n"
    187"Accept the name shown to restore the configuration you last\n"
    188"retrieved.  Leave empty to abort.",
    189load_config_help[] =
    190"For various reasons, one may wish to keep several different\n"
    191"configurations available on a single machine.\n"
    192"\n"
    193"If you have saved a previous configuration in a file other than the\n"
    194"default one, entering its name here will allow you to load and modify\n"
    195"that configuration.\n"
    196"\n"
    197"Leave empty to abort.\n",
    198save_config_text[] =
    199"Enter a filename to which this configuration should be saved\n"
    200"as an alternate.  Leave empty to abort.",
    201save_config_help[] =
    202"For various reasons, one may wish to keep several different\n"
    203"configurations available on a single machine.\n"
    204"\n"
    205"Entering a file name here will allow you to later retrieve, modify\n"
    206"and use the current configuration as an alternate to whatever\n"
    207"configuration options you have selected at that time.\n"
    208"\n"
    209"Leave empty to abort.\n",
    210search_help[] =
    211"Search for symbols (configuration variable names CONFIG_*) and display\n"
    212"their relations.  Regular expressions are supported.\n"
    213"Example:  Search for \"^FOO\".\n"
    214"Result:\n"
    215"-----------------------------------------------------------------\n"
    216"Symbol: FOO [ = m]\n"
    217"Prompt: Foo bus is used to drive the bar HW\n"
    218"Defined at drivers/pci/Kconfig:47\n"
    219"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
    220"Location:\n"
    221"  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
    222"    -> PCI support (PCI [ = y])\n"
    223"      -> PCI access mode (<choice> [ = y])\n"
    224"Selects: LIBCRC32\n"
    225"Selected by: BAR\n"
    226"-----------------------------------------------------------------\n"
    227"o  The line 'Prompt:' shows the text displayed for this symbol in\n"
    228"   the menu hierarchy.\n"
    229"o  The 'Defined at' line tells at what file / line number the symbol is\n"
    230"   defined.\n"
    231"o  The 'Depends on:' line lists symbols that need to be defined for\n"
    232"   this symbol to be visible and selectable in the menu.\n"
    233"o  The 'Location:' lines tell, where in the menu structure this symbol\n"
    234"   is located.  A location followed by a [ = y] indicates that this is\n"
    235"   a selectable menu item, and the current value is displayed inside\n"
    236"   brackets.\n"
    237"o  The 'Selects:' line tells, what symbol will be automatically selected\n"
    238"   if this symbol is selected (y or m).\n"
    239"o  The 'Selected by' line tells what symbol has selected this symbol.\n"
    240"\n"
    241"Only relevant lines are shown.\n"
    242"\n\n"
    243"Search examples:\n"
    244"USB  => find all symbols containing USB\n"
    245"^USB => find all symbols starting with USB\n"
    246"USB$ => find all symbols ending with USB\n"
    247"\n";
    248
    249struct mitem {
    250	char str[256];
    251	char tag;
    252	void *usrptr;
    253	int is_visible;
    254};
    255
    256#define MAX_MENU_ITEMS 4096
    257static int show_all_items;
    258static int indent;
    259static struct menu *current_menu;
    260static int child_count;
    261static int single_menu_mode;
    262/* the window in which all information appears */
    263static WINDOW *main_window;
    264/* the largest size of the menu window */
    265static int mwin_max_lines;
    266static int mwin_max_cols;
    267/* the window in which we show option buttons */
    268static MENU *curses_menu;
    269static ITEM *curses_menu_items[MAX_MENU_ITEMS];
    270static struct mitem k_menu_items[MAX_MENU_ITEMS];
    271static unsigned int items_num;
    272static int global_exit;
    273/* the currently selected button */
    274static const char *current_instructions = menu_instructions;
    275
    276static char *dialog_input_result;
    277static int dialog_input_result_len;
    278
    279static void conf(struct menu *menu);
    280static void conf_choice(struct menu *menu);
    281static void conf_string(struct menu *menu);
    282static void conf_load(void);
    283static void conf_save(void);
    284static void show_help(struct menu *menu);
    285static int do_exit(void);
    286static void setup_windows(void);
    287static void search_conf(void);
    288
    289typedef void (*function_key_handler_t)(int *key, struct menu *menu);
    290static void handle_f1(int *key, struct menu *current_item);
    291static void handle_f2(int *key, struct menu *current_item);
    292static void handle_f3(int *key, struct menu *current_item);
    293static void handle_f4(int *key, struct menu *current_item);
    294static void handle_f5(int *key, struct menu *current_item);
    295static void handle_f6(int *key, struct menu *current_item);
    296static void handle_f7(int *key, struct menu *current_item);
    297static void handle_f8(int *key, struct menu *current_item);
    298static void handle_f9(int *key, struct menu *current_item);
    299
    300struct function_keys {
    301	const char *key_str;
    302	const char *func;
    303	function_key key;
    304	function_key_handler_t handler;
    305};
    306
    307static const int function_keys_num = 9;
    308static struct function_keys function_keys[] = {
    309	{
    310		.key_str = "F1",
    311		.func = "Help",
    312		.key = F_HELP,
    313		.handler = handle_f1,
    314	},
    315	{
    316		.key_str = "F2",
    317		.func = "SymInfo",
    318		.key = F_SYMBOL,
    319		.handler = handle_f2,
    320	},
    321	{
    322		.key_str = "F3",
    323		.func = "Help 2",
    324		.key = F_INSTS,
    325		.handler = handle_f3,
    326	},
    327	{
    328		.key_str = "F4",
    329		.func = "ShowAll",
    330		.key = F_CONF,
    331		.handler = handle_f4,
    332	},
    333	{
    334		.key_str = "F5",
    335		.func = "Back",
    336		.key = F_BACK,
    337		.handler = handle_f5,
    338	},
    339	{
    340		.key_str = "F6",
    341		.func = "Save",
    342		.key = F_SAVE,
    343		.handler = handle_f6,
    344	},
    345	{
    346		.key_str = "F7",
    347		.func = "Load",
    348		.key = F_LOAD,
    349		.handler = handle_f7,
    350	},
    351	{
    352		.key_str = "F8",
    353		.func = "SymSearch",
    354		.key = F_SEARCH,
    355		.handler = handle_f8,
    356	},
    357	{
    358		.key_str = "F9",
    359		.func = "Exit",
    360		.key = F_EXIT,
    361		.handler = handle_f9,
    362	},
    363};
    364
    365static void print_function_line(void)
    366{
    367	int i;
    368	int offset = 1;
    369	const int skip = 1;
    370	int lines = getmaxy(stdscr);
    371
    372	for (i = 0; i < function_keys_num; i++) {
    373		wattrset(main_window, attr_function_highlight);
    374		mvwprintw(main_window, lines-3, offset,
    375				"%s",
    376				function_keys[i].key_str);
    377		wattrset(main_window, attr_function_text);
    378		offset += strlen(function_keys[i].key_str);
    379		mvwprintw(main_window, lines-3,
    380				offset, "%s",
    381				function_keys[i].func);
    382		offset += strlen(function_keys[i].func) + skip;
    383	}
    384	wattrset(main_window, attr_normal);
    385}
    386
    387/* help */
    388static void handle_f1(int *key, struct menu *current_item)
    389{
    390	show_scroll_win(main_window,
    391			"Global help", nconf_global_help);
    392	return;
    393}
    394
    395/* symbole help */
    396static void handle_f2(int *key, struct menu *current_item)
    397{
    398	show_help(current_item);
    399	return;
    400}
    401
    402/* instructions */
    403static void handle_f3(int *key, struct menu *current_item)
    404{
    405	show_scroll_win(main_window,
    406			"Short help",
    407			current_instructions);
    408	return;
    409}
    410
    411/* config */
    412static void handle_f4(int *key, struct menu *current_item)
    413{
    414	int res = btn_dialog(main_window,
    415			"Show all symbols?",
    416			2,
    417			"   <Show All>   ",
    418			"<Don't show all>");
    419	if (res == 0)
    420		show_all_items = 1;
    421	else if (res == 1)
    422		show_all_items = 0;
    423
    424	return;
    425}
    426
    427/* back */
    428static void handle_f5(int *key, struct menu *current_item)
    429{
    430	*key = KEY_LEFT;
    431	return;
    432}
    433
    434/* save */
    435static void handle_f6(int *key, struct menu *current_item)
    436{
    437	conf_save();
    438	return;
    439}
    440
    441/* load */
    442static void handle_f7(int *key, struct menu *current_item)
    443{
    444	conf_load();
    445	return;
    446}
    447
    448/* search */
    449static void handle_f8(int *key, struct menu *current_item)
    450{
    451	search_conf();
    452	return;
    453}
    454
    455/* exit */
    456static void handle_f9(int *key, struct menu *current_item)
    457{
    458	do_exit();
    459	return;
    460}
    461
    462/* return != 0 to indicate the key was handles */
    463static int process_special_keys(int *key, struct menu *menu)
    464{
    465	int i;
    466
    467	if (*key == KEY_RESIZE) {
    468		setup_windows();
    469		return 1;
    470	}
    471
    472	for (i = 0; i < function_keys_num; i++) {
    473		if (*key == KEY_F(function_keys[i].key) ||
    474		    *key == '0' + function_keys[i].key){
    475			function_keys[i].handler(key, menu);
    476			return 1;
    477		}
    478	}
    479
    480	return 0;
    481}
    482
    483static void clean_items(void)
    484{
    485	int i;
    486	for (i = 0; curses_menu_items[i]; i++)
    487		free_item(curses_menu_items[i]);
    488	bzero(curses_menu_items, sizeof(curses_menu_items));
    489	bzero(k_menu_items, sizeof(k_menu_items));
    490	items_num = 0;
    491}
    492
    493typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
    494	FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
    495
    496/* return the index of the matched item, or -1 if no such item exists */
    497static int get_mext_match(const char *match_str, match_f flag)
    498{
    499	int match_start, index;
    500
    501	/* Do not search if the menu is empty (i.e. items_num == 0) */
    502	match_start = item_index(current_item(curses_menu));
    503	if (match_start == ERR)
    504		return -1;
    505
    506	if (flag == FIND_NEXT_MATCH_DOWN)
    507		++match_start;
    508	else if (flag == FIND_NEXT_MATCH_UP)
    509		--match_start;
    510
    511	match_start = (match_start + items_num) % items_num;
    512	index = match_start;
    513	while (true) {
    514		char *str = k_menu_items[index].str;
    515		if (strcasestr(str, match_str) != NULL)
    516			return index;
    517		if (flag == FIND_NEXT_MATCH_UP ||
    518		    flag == MATCH_TINKER_PATTERN_UP)
    519			--index;
    520		else
    521			++index;
    522		index = (index + items_num) % items_num;
    523		if (index == match_start)
    524			return -1;
    525	}
    526}
    527
    528/* Make a new item. */
    529static void item_make(struct menu *menu, char tag, const char *fmt, ...)
    530{
    531	va_list ap;
    532
    533	if (items_num > MAX_MENU_ITEMS-1)
    534		return;
    535
    536	bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
    537	k_menu_items[items_num].tag = tag;
    538	k_menu_items[items_num].usrptr = menu;
    539	if (menu != NULL)
    540		k_menu_items[items_num].is_visible =
    541			menu_is_visible(menu);
    542	else
    543		k_menu_items[items_num].is_visible = 1;
    544
    545	va_start(ap, fmt);
    546	vsnprintf(k_menu_items[items_num].str,
    547		  sizeof(k_menu_items[items_num].str),
    548		  fmt, ap);
    549	va_end(ap);
    550
    551	if (!k_menu_items[items_num].is_visible)
    552		memcpy(k_menu_items[items_num].str, "XXX", 3);
    553
    554	curses_menu_items[items_num] = new_item(
    555			k_menu_items[items_num].str,
    556			k_menu_items[items_num].str);
    557	set_item_userptr(curses_menu_items[items_num],
    558			&k_menu_items[items_num]);
    559	/*
    560	if (!k_menu_items[items_num].is_visible)
    561		item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
    562	*/
    563
    564	items_num++;
    565	curses_menu_items[items_num] = NULL;
    566}
    567
    568/* very hackish. adds a string to the last item added */
    569static void item_add_str(const char *fmt, ...)
    570{
    571	va_list ap;
    572	int index = items_num-1;
    573	char new_str[256];
    574	char tmp_str[256];
    575
    576	if (index < 0)
    577		return;
    578
    579	va_start(ap, fmt);
    580	vsnprintf(new_str, sizeof(new_str), fmt, ap);
    581	va_end(ap);
    582	snprintf(tmp_str, sizeof(tmp_str), "%s%s",
    583			k_menu_items[index].str, new_str);
    584	strncpy(k_menu_items[index].str,
    585		tmp_str,
    586		sizeof(k_menu_items[index].str));
    587
    588	free_item(curses_menu_items[index]);
    589	curses_menu_items[index] = new_item(
    590			k_menu_items[index].str,
    591			k_menu_items[index].str);
    592	set_item_userptr(curses_menu_items[index],
    593			&k_menu_items[index]);
    594}
    595
    596/* get the tag of the currently selected item */
    597static char item_tag(void)
    598{
    599	ITEM *cur;
    600	struct mitem *mcur;
    601
    602	cur = current_item(curses_menu);
    603	if (cur == NULL)
    604		return 0;
    605	mcur = (struct mitem *) item_userptr(cur);
    606	return mcur->tag;
    607}
    608
    609static int curses_item_index(void)
    610{
    611	return  item_index(current_item(curses_menu));
    612}
    613
    614static void *item_data(void)
    615{
    616	ITEM *cur;
    617	struct mitem *mcur;
    618
    619	cur = current_item(curses_menu);
    620	if (!cur)
    621		return NULL;
    622	mcur = (struct mitem *) item_userptr(cur);
    623	return mcur->usrptr;
    624
    625}
    626
    627static int item_is_tag(char tag)
    628{
    629	return item_tag() == tag;
    630}
    631
    632static char filename[PATH_MAX+1];
    633static char menu_backtitle[PATH_MAX+128];
    634static void set_config_filename(const char *config_filename)
    635{
    636	snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
    637		 config_filename, rootmenu.prompt->text);
    638
    639	snprintf(filename, sizeof(filename), "%s", config_filename);
    640}
    641
    642/* return = 0 means we are successful.
    643 * -1 means go on doing what you were doing
    644 */
    645static int do_exit(void)
    646{
    647	int res;
    648	if (!conf_get_changed()) {
    649		global_exit = 1;
    650		return 0;
    651	}
    652	res = btn_dialog(main_window,
    653			"Do you wish to save your new configuration?\n"
    654				"<ESC> to cancel and resume nconfig.",
    655			2,
    656			"   <save>   ",
    657			"<don't save>");
    658	if (res == KEY_EXIT) {
    659		global_exit = 0;
    660		return -1;
    661	}
    662
    663	/* if we got here, the user really wants to exit */
    664	switch (res) {
    665	case 0:
    666		res = conf_write(filename);
    667		if (res)
    668			btn_dialog(
    669				main_window,
    670				"Error during writing of configuration.\n"
    671				  "Your configuration changes were NOT saved.",
    672				  1,
    673				  "<OK>");
    674		conf_write_autoconf(0);
    675		break;
    676	default:
    677		btn_dialog(
    678			main_window,
    679			"Your configuration changes were NOT saved.",
    680			1,
    681			"<OK>");
    682		break;
    683	}
    684	global_exit = 1;
    685	return 0;
    686}
    687
    688
    689static void search_conf(void)
    690{
    691	struct symbol **sym_arr;
    692	struct gstr res;
    693	struct gstr title;
    694	char *dialog_input;
    695	int dres;
    696
    697	title = str_new();
    698	str_printf( &title, "Enter (sub)string or regexp to search for "
    699			      "(with or without \"%s\")", CONFIG_);
    700
    701again:
    702	dres = dialog_inputbox(main_window,
    703			"Search Configuration Parameter",
    704			str_get(&title),
    705			"", &dialog_input_result, &dialog_input_result_len);
    706	switch (dres) {
    707	case 0:
    708		break;
    709	case 1:
    710		show_scroll_win(main_window,
    711				"Search Configuration", search_help);
    712		goto again;
    713	default:
    714		str_free(&title);
    715		return;
    716	}
    717
    718	/* strip the prefix if necessary */
    719	dialog_input = dialog_input_result;
    720	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
    721		dialog_input += strlen(CONFIG_);
    722
    723	sym_arr = sym_re_search(dialog_input);
    724	res = get_relations_str(sym_arr, NULL);
    725	free(sym_arr);
    726	show_scroll_win(main_window,
    727			"Search Results", str_get(&res));
    728	str_free(&res);
    729	str_free(&title);
    730}
    731
    732
    733static void build_conf(struct menu *menu)
    734{
    735	struct symbol *sym;
    736	struct property *prop;
    737	struct menu *child;
    738	int type, tmp, doint = 2;
    739	tristate val;
    740	char ch;
    741
    742	if (!menu || (!show_all_items && !menu_is_visible(menu)))
    743		return;
    744
    745	sym = menu->sym;
    746	prop = menu->prompt;
    747	if (!sym) {
    748		if (prop && menu != current_menu) {
    749			const char *prompt = menu_get_prompt(menu);
    750			enum prop_type ptype;
    751			ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
    752			switch (ptype) {
    753			case P_MENU:
    754				child_count++;
    755				if (single_menu_mode) {
    756					item_make(menu, 'm',
    757						"%s%*c%s",
    758						menu->data ? "-->" : "++>",
    759						indent + 1, ' ', prompt);
    760				} else
    761					item_make(menu, 'm',
    762						  "   %*c%s  %s",
    763						  indent + 1, ' ', prompt,
    764						  menu_is_empty(menu) ? "----" : "--->");
    765
    766				if (single_menu_mode && menu->data)
    767					goto conf_childs;
    768				return;
    769			case P_COMMENT:
    770				if (prompt) {
    771					child_count++;
    772					item_make(menu, ':',
    773						"   %*c*** %s ***",
    774						indent + 1, ' ',
    775						prompt);
    776				}
    777				break;
    778			default:
    779				if (prompt) {
    780					child_count++;
    781					item_make(menu, ':', "---%*c%s",
    782						indent + 1, ' ',
    783						prompt);
    784				}
    785			}
    786		} else
    787			doint = 0;
    788		goto conf_childs;
    789	}
    790
    791	type = sym_get_type(sym);
    792	if (sym_is_choice(sym)) {
    793		struct symbol *def_sym = sym_get_choice_value(sym);
    794		struct menu *def_menu = NULL;
    795
    796		child_count++;
    797		for (child = menu->list; child; child = child->next) {
    798			if (menu_is_visible(child) && child->sym == def_sym)
    799				def_menu = child;
    800		}
    801
    802		val = sym_get_tristate_value(sym);
    803		if (sym_is_changeable(sym)) {
    804			switch (type) {
    805			case S_BOOLEAN:
    806				item_make(menu, 't', "[%c]",
    807						val == no ? ' ' : '*');
    808				break;
    809			case S_TRISTATE:
    810				switch (val) {
    811				case yes:
    812					ch = '*';
    813					break;
    814				case mod:
    815					ch = 'M';
    816					break;
    817				default:
    818					ch = ' ';
    819					break;
    820				}
    821				item_make(menu, 't', "<%c>", ch);
    822				break;
    823			}
    824		} else {
    825			item_make(menu, def_menu ? 't' : ':', "   ");
    826		}
    827
    828		item_add_str("%*c%s", indent + 1,
    829				' ', menu_get_prompt(menu));
    830		if (val == yes) {
    831			if (def_menu) {
    832				item_add_str(" (%s)",
    833					menu_get_prompt(def_menu));
    834				item_add_str("  --->");
    835				if (def_menu->list) {
    836					indent += 2;
    837					build_conf(def_menu);
    838					indent -= 2;
    839				}
    840			}
    841			return;
    842		}
    843	} else {
    844		if (menu == current_menu) {
    845			item_make(menu, ':',
    846				"---%*c%s", indent + 1,
    847				' ', menu_get_prompt(menu));
    848			goto conf_childs;
    849		}
    850		child_count++;
    851		val = sym_get_tristate_value(sym);
    852		if (sym_is_choice_value(sym) && val == yes) {
    853			item_make(menu, ':', "   ");
    854		} else {
    855			switch (type) {
    856			case S_BOOLEAN:
    857				if (sym_is_changeable(sym))
    858					item_make(menu, 't', "[%c]",
    859						val == no ? ' ' : '*');
    860				else
    861					item_make(menu, 't', "-%c-",
    862						val == no ? ' ' : '*');
    863				break;
    864			case S_TRISTATE:
    865				switch (val) {
    866				case yes:
    867					ch = '*';
    868					break;
    869				case mod:
    870					ch = 'M';
    871					break;
    872				default:
    873					ch = ' ';
    874					break;
    875				}
    876				if (sym_is_changeable(sym)) {
    877					if (sym->rev_dep.tri == mod)
    878						item_make(menu,
    879							't', "{%c}", ch);
    880					else
    881						item_make(menu,
    882							't', "<%c>", ch);
    883				} else
    884					item_make(menu, 't', "-%c-", ch);
    885				break;
    886			default:
    887				tmp = 2 + strlen(sym_get_string_value(sym));
    888				item_make(menu, 's', "    (%s)",
    889						sym_get_string_value(sym));
    890				tmp = indent - tmp + 4;
    891				if (tmp < 0)
    892					tmp = 0;
    893				item_add_str("%*c%s%s", tmp, ' ',
    894						menu_get_prompt(menu),
    895						(sym_has_value(sym) ||
    896						 !sym_is_changeable(sym)) ? "" :
    897						" (NEW)");
    898				goto conf_childs;
    899			}
    900		}
    901		item_add_str("%*c%s%s", indent + 1, ' ',
    902				menu_get_prompt(menu),
    903				(sym_has_value(sym) || !sym_is_changeable(sym)) ?
    904				"" : " (NEW)");
    905		if (menu->prompt && menu->prompt->type == P_MENU) {
    906			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
    907			return;
    908		}
    909	}
    910
    911conf_childs:
    912	indent += doint;
    913	for (child = menu->list; child; child = child->next)
    914		build_conf(child);
    915	indent -= doint;
    916}
    917
    918static void reset_menu(void)
    919{
    920	unpost_menu(curses_menu);
    921	clean_items();
    922}
    923
    924/* adjust the menu to show this item.
    925 * prefer not to scroll the menu if possible*/
    926static void center_item(int selected_index, int *last_top_row)
    927{
    928	int toprow;
    929
    930	set_top_row(curses_menu, *last_top_row);
    931	toprow = top_row(curses_menu);
    932	if (selected_index < toprow ||
    933	    selected_index >= toprow+mwin_max_lines) {
    934		toprow = max(selected_index-mwin_max_lines/2, 0);
    935		if (toprow >= item_count(curses_menu)-mwin_max_lines)
    936			toprow = item_count(curses_menu)-mwin_max_lines;
    937		set_top_row(curses_menu, toprow);
    938	}
    939	set_current_item(curses_menu,
    940			curses_menu_items[selected_index]);
    941	*last_top_row = toprow;
    942	post_menu(curses_menu);
    943	refresh_all_windows(main_window);
    944}
    945
    946/* this function assumes reset_menu has been called before */
    947static void show_menu(const char *prompt, const char *instructions,
    948		int selected_index, int *last_top_row)
    949{
    950	int maxx, maxy;
    951	WINDOW *menu_window;
    952
    953	current_instructions = instructions;
    954
    955	clear();
    956	print_in_middle(stdscr, 1, getmaxx(stdscr),
    957			menu_backtitle,
    958			attr_main_heading);
    959
    960	wattrset(main_window, attr_main_menu_box);
    961	box(main_window, 0, 0);
    962	wattrset(main_window, attr_main_menu_heading);
    963	mvwprintw(main_window, 0, 3, " %s ", prompt);
    964	wattrset(main_window, attr_normal);
    965
    966	set_menu_items(curses_menu, curses_menu_items);
    967
    968	/* position the menu at the middle of the screen */
    969	scale_menu(curses_menu, &maxy, &maxx);
    970	maxx = min(maxx, mwin_max_cols-2);
    971	maxy = mwin_max_lines;
    972	menu_window = derwin(main_window,
    973			maxy,
    974			maxx,
    975			2,
    976			(mwin_max_cols-maxx)/2);
    977	keypad(menu_window, TRUE);
    978	set_menu_win(curses_menu, menu_window);
    979	set_menu_sub(curses_menu, menu_window);
    980
    981	/* must reassert this after changing items, otherwise returns to a
    982	 * default of 16
    983	 */
    984	set_menu_format(curses_menu, maxy, 1);
    985	center_item(selected_index, last_top_row);
    986	set_menu_format(curses_menu, maxy, 1);
    987
    988	print_function_line();
    989
    990	/* Post the menu */
    991	post_menu(curses_menu);
    992	refresh_all_windows(main_window);
    993}
    994
    995static void adj_match_dir(match_f *match_direction)
    996{
    997	if (*match_direction == FIND_NEXT_MATCH_DOWN)
    998		*match_direction =
    999			MATCH_TINKER_PATTERN_DOWN;
   1000	else if (*match_direction == FIND_NEXT_MATCH_UP)
   1001		*match_direction =
   1002			MATCH_TINKER_PATTERN_UP;
   1003	/* else, do no change.. */
   1004}
   1005
   1006struct match_state
   1007{
   1008	int in_search;
   1009	match_f match_direction;
   1010	char pattern[256];
   1011};
   1012
   1013/* Return 0 means I have handled the key. In such a case, ans should hold the
   1014 * item to center, or -1 otherwise.
   1015 * Else return -1 .
   1016 */
   1017static int do_match(int key, struct match_state *state, int *ans)
   1018{
   1019	char c = (char) key;
   1020	int terminate_search = 0;
   1021	*ans = -1;
   1022	if (key == '/' || (state->in_search && key == 27)) {
   1023		move(0, 0);
   1024		refresh();
   1025		clrtoeol();
   1026		state->in_search = 1-state->in_search;
   1027		bzero(state->pattern, sizeof(state->pattern));
   1028		state->match_direction = MATCH_TINKER_PATTERN_DOWN;
   1029		return 0;
   1030	} else if (!state->in_search)
   1031		return 1;
   1032
   1033	if (isalnum(c) || isgraph(c) || c == ' ') {
   1034		state->pattern[strlen(state->pattern)] = c;
   1035		state->pattern[strlen(state->pattern)] = '\0';
   1036		adj_match_dir(&state->match_direction);
   1037		*ans = get_mext_match(state->pattern,
   1038				state->match_direction);
   1039	} else if (key == KEY_DOWN) {
   1040		state->match_direction = FIND_NEXT_MATCH_DOWN;
   1041		*ans = get_mext_match(state->pattern,
   1042				state->match_direction);
   1043	} else if (key == KEY_UP) {
   1044		state->match_direction = FIND_NEXT_MATCH_UP;
   1045		*ans = get_mext_match(state->pattern,
   1046				state->match_direction);
   1047	} else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
   1048		state->pattern[strlen(state->pattern)-1] = '\0';
   1049		adj_match_dir(&state->match_direction);
   1050	} else
   1051		terminate_search = 1;
   1052
   1053	if (terminate_search) {
   1054		state->in_search = 0;
   1055		bzero(state->pattern, sizeof(state->pattern));
   1056		move(0, 0);
   1057		refresh();
   1058		clrtoeol();
   1059		return -1;
   1060	}
   1061	return 0;
   1062}
   1063
   1064static void conf(struct menu *menu)
   1065{
   1066	struct menu *submenu = NULL;
   1067	struct symbol *sym;
   1068	int res;
   1069	int current_index = 0;
   1070	int last_top_row = 0;
   1071	struct match_state match_state = {
   1072		.in_search = 0,
   1073		.match_direction = MATCH_TINKER_PATTERN_DOWN,
   1074		.pattern = "",
   1075	};
   1076
   1077	while (!global_exit) {
   1078		reset_menu();
   1079		current_menu = menu;
   1080		build_conf(menu);
   1081		if (!child_count)
   1082			break;
   1083
   1084		show_menu(menu_get_prompt(menu), menu_instructions,
   1085			  current_index, &last_top_row);
   1086		keypad((menu_win(curses_menu)), TRUE);
   1087		while (!global_exit) {
   1088			if (match_state.in_search) {
   1089				mvprintw(0, 0,
   1090					"searching: %s", match_state.pattern);
   1091				clrtoeol();
   1092			}
   1093			refresh_all_windows(main_window);
   1094			res = wgetch(menu_win(curses_menu));
   1095			if (!res)
   1096				break;
   1097			if (do_match(res, &match_state, &current_index) == 0) {
   1098				if (current_index != -1)
   1099					center_item(current_index,
   1100						    &last_top_row);
   1101				continue;
   1102			}
   1103			if (process_special_keys(&res,
   1104						(struct menu *) item_data()))
   1105				break;
   1106			switch (res) {
   1107			case KEY_DOWN:
   1108			case 'j':
   1109				menu_driver(curses_menu, REQ_DOWN_ITEM);
   1110				break;
   1111			case KEY_UP:
   1112			case 'k':
   1113				menu_driver(curses_menu, REQ_UP_ITEM);
   1114				break;
   1115			case KEY_NPAGE:
   1116				menu_driver(curses_menu, REQ_SCR_DPAGE);
   1117				break;
   1118			case KEY_PPAGE:
   1119				menu_driver(curses_menu, REQ_SCR_UPAGE);
   1120				break;
   1121			case KEY_HOME:
   1122				menu_driver(curses_menu, REQ_FIRST_ITEM);
   1123				break;
   1124			case KEY_END:
   1125				menu_driver(curses_menu, REQ_LAST_ITEM);
   1126				break;
   1127			case 'h':
   1128			case '?':
   1129				show_help((struct menu *) item_data());
   1130				break;
   1131			}
   1132			if (res == 10 || res == 27 ||
   1133				res == 32 || res == 'n' || res == 'y' ||
   1134				res == KEY_LEFT || res == KEY_RIGHT ||
   1135				res == 'm')
   1136				break;
   1137			refresh_all_windows(main_window);
   1138		}
   1139
   1140		refresh_all_windows(main_window);
   1141		/* if ESC or left*/
   1142		if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
   1143			break;
   1144
   1145		/* remember location in the menu */
   1146		last_top_row = top_row(curses_menu);
   1147		current_index = curses_item_index();
   1148
   1149		if (!item_tag())
   1150			continue;
   1151
   1152		submenu = (struct menu *) item_data();
   1153		if (!submenu || !menu_is_visible(submenu))
   1154			continue;
   1155		sym = submenu->sym;
   1156
   1157		switch (res) {
   1158		case ' ':
   1159			if (item_is_tag('t'))
   1160				sym_toggle_tristate_value(sym);
   1161			else if (item_is_tag('m'))
   1162				conf(submenu);
   1163			break;
   1164		case KEY_RIGHT:
   1165		case 10: /* ENTER WAS PRESSED */
   1166			switch (item_tag()) {
   1167			case 'm':
   1168				if (single_menu_mode)
   1169					submenu->data =
   1170						(void *) (long) !submenu->data;
   1171				else
   1172					conf(submenu);
   1173				break;
   1174			case 't':
   1175				if (sym_is_choice(sym) &&
   1176				    sym_get_tristate_value(sym) == yes)
   1177					conf_choice(submenu);
   1178				else if (submenu->prompt &&
   1179					 submenu->prompt->type == P_MENU)
   1180					conf(submenu);
   1181				else if (res == 10)
   1182					sym_toggle_tristate_value(sym);
   1183				break;
   1184			case 's':
   1185				conf_string(submenu);
   1186				break;
   1187			}
   1188			break;
   1189		case 'y':
   1190			if (item_is_tag('t')) {
   1191				if (sym_set_tristate_value(sym, yes))
   1192					break;
   1193				if (sym_set_tristate_value(sym, mod))
   1194					btn_dialog(main_window, setmod_text, 0);
   1195			}
   1196			break;
   1197		case 'n':
   1198			if (item_is_tag('t'))
   1199				sym_set_tristate_value(sym, no);
   1200			break;
   1201		case 'm':
   1202			if (item_is_tag('t'))
   1203				sym_set_tristate_value(sym, mod);
   1204			break;
   1205		}
   1206	}
   1207}
   1208
   1209static void conf_message_callback(const char *s)
   1210{
   1211	btn_dialog(main_window, s, 1, "<OK>");
   1212}
   1213
   1214static void show_help(struct menu *menu)
   1215{
   1216	struct gstr help;
   1217
   1218	if (!menu)
   1219		return;
   1220
   1221	help = str_new();
   1222	menu_get_ext_help(menu, &help);
   1223	show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help));
   1224	str_free(&help);
   1225}
   1226
   1227static void conf_choice(struct menu *menu)
   1228{
   1229	const char *prompt = menu_get_prompt(menu);
   1230	struct menu *child = NULL;
   1231	struct symbol *active;
   1232	int selected_index = 0;
   1233	int last_top_row = 0;
   1234	int res, i = 0;
   1235	struct match_state match_state = {
   1236		.in_search = 0,
   1237		.match_direction = MATCH_TINKER_PATTERN_DOWN,
   1238		.pattern = "",
   1239	};
   1240
   1241	active = sym_get_choice_value(menu->sym);
   1242	/* this is mostly duplicated from the conf() function. */
   1243	while (!global_exit) {
   1244		reset_menu();
   1245
   1246		for (i = 0, child = menu->list; child; child = child->next) {
   1247			if (!show_all_items && !menu_is_visible(child))
   1248				continue;
   1249
   1250			if (child->sym == sym_get_choice_value(menu->sym))
   1251				item_make(child, ':', "<X> %s",
   1252						menu_get_prompt(child));
   1253			else if (child->sym)
   1254				item_make(child, ':', "    %s",
   1255						menu_get_prompt(child));
   1256			else
   1257				item_make(child, ':', "*** %s ***",
   1258						menu_get_prompt(child));
   1259
   1260			if (child->sym == active){
   1261				last_top_row = top_row(curses_menu);
   1262				selected_index = i;
   1263			}
   1264			i++;
   1265		}
   1266		show_menu(prompt ? prompt : "Choice Menu",
   1267				radiolist_instructions,
   1268				selected_index,
   1269				&last_top_row);
   1270		while (!global_exit) {
   1271			if (match_state.in_search) {
   1272				mvprintw(0, 0, "searching: %s",
   1273					 match_state.pattern);
   1274				clrtoeol();
   1275			}
   1276			refresh_all_windows(main_window);
   1277			res = wgetch(menu_win(curses_menu));
   1278			if (!res)
   1279				break;
   1280			if (do_match(res, &match_state, &selected_index) == 0) {
   1281				if (selected_index != -1)
   1282					center_item(selected_index,
   1283						    &last_top_row);
   1284				continue;
   1285			}
   1286			if (process_special_keys(
   1287						&res,
   1288						(struct menu *) item_data()))
   1289				break;
   1290			switch (res) {
   1291			case KEY_DOWN:
   1292			case 'j':
   1293				menu_driver(curses_menu, REQ_DOWN_ITEM);
   1294				break;
   1295			case KEY_UP:
   1296			case 'k':
   1297				menu_driver(curses_menu, REQ_UP_ITEM);
   1298				break;
   1299			case KEY_NPAGE:
   1300				menu_driver(curses_menu, REQ_SCR_DPAGE);
   1301				break;
   1302			case KEY_PPAGE:
   1303				menu_driver(curses_menu, REQ_SCR_UPAGE);
   1304				break;
   1305			case KEY_HOME:
   1306				menu_driver(curses_menu, REQ_FIRST_ITEM);
   1307				break;
   1308			case KEY_END:
   1309				menu_driver(curses_menu, REQ_LAST_ITEM);
   1310				break;
   1311			case 'h':
   1312			case '?':
   1313				show_help((struct menu *) item_data());
   1314				break;
   1315			}
   1316			if (res == 10 || res == 27 || res == ' ' ||
   1317					res == KEY_LEFT){
   1318				break;
   1319			}
   1320			refresh_all_windows(main_window);
   1321		}
   1322		/* if ESC or left */
   1323		if (res == 27 || res == KEY_LEFT)
   1324			break;
   1325
   1326		child = item_data();
   1327		if (!child || !menu_is_visible(child) || !child->sym)
   1328			continue;
   1329		switch (res) {
   1330		case ' ':
   1331		case  10:
   1332		case KEY_RIGHT:
   1333			sym_set_tristate_value(child->sym, yes);
   1334			return;
   1335		case 'h':
   1336		case '?':
   1337			show_help(child);
   1338			active = child->sym;
   1339			break;
   1340		case KEY_EXIT:
   1341			return;
   1342		}
   1343	}
   1344}
   1345
   1346static void conf_string(struct menu *menu)
   1347{
   1348	const char *prompt = menu_get_prompt(menu);
   1349
   1350	while (1) {
   1351		int res;
   1352		const char *heading;
   1353
   1354		switch (sym_get_type(menu->sym)) {
   1355		case S_INT:
   1356			heading = inputbox_instructions_int;
   1357			break;
   1358		case S_HEX:
   1359			heading = inputbox_instructions_hex;
   1360			break;
   1361		case S_STRING:
   1362			heading = inputbox_instructions_string;
   1363			break;
   1364		default:
   1365			heading = "Internal nconf error!";
   1366		}
   1367		res = dialog_inputbox(main_window,
   1368				prompt ? prompt : "Main Menu",
   1369				heading,
   1370				sym_get_string_value(menu->sym),
   1371				&dialog_input_result,
   1372				&dialog_input_result_len);
   1373		switch (res) {
   1374		case 0:
   1375			if (sym_set_string_value(menu->sym,
   1376						dialog_input_result))
   1377				return;
   1378			btn_dialog(main_window,
   1379				"You have made an invalid entry.", 0);
   1380			break;
   1381		case 1:
   1382			show_help(menu);
   1383			break;
   1384		case KEY_EXIT:
   1385			return;
   1386		}
   1387	}
   1388}
   1389
   1390static void conf_load(void)
   1391{
   1392	while (1) {
   1393		int res;
   1394		res = dialog_inputbox(main_window,
   1395				NULL, load_config_text,
   1396				filename,
   1397				&dialog_input_result,
   1398				&dialog_input_result_len);
   1399		switch (res) {
   1400		case 0:
   1401			if (!dialog_input_result[0])
   1402				return;
   1403			if (!conf_read(dialog_input_result)) {
   1404				set_config_filename(dialog_input_result);
   1405				conf_set_changed(true);
   1406				return;
   1407			}
   1408			btn_dialog(main_window, "File does not exist!", 0);
   1409			break;
   1410		case 1:
   1411			show_scroll_win(main_window,
   1412					"Load Alternate Configuration",
   1413					load_config_help);
   1414			break;
   1415		case KEY_EXIT:
   1416			return;
   1417		}
   1418	}
   1419}
   1420
   1421static void conf_save(void)
   1422{
   1423	while (1) {
   1424		int res;
   1425		res = dialog_inputbox(main_window,
   1426				NULL, save_config_text,
   1427				filename,
   1428				&dialog_input_result,
   1429				&dialog_input_result_len);
   1430		switch (res) {
   1431		case 0:
   1432			if (!dialog_input_result[0])
   1433				return;
   1434			res = conf_write(dialog_input_result);
   1435			if (!res) {
   1436				set_config_filename(dialog_input_result);
   1437				return;
   1438			}
   1439			btn_dialog(main_window, "Can't create file!",
   1440				1, "<OK>");
   1441			break;
   1442		case 1:
   1443			show_scroll_win(main_window,
   1444				"Save Alternate Configuration",
   1445				save_config_help);
   1446			break;
   1447		case KEY_EXIT:
   1448			return;
   1449		}
   1450	}
   1451}
   1452
   1453static void setup_windows(void)
   1454{
   1455	int lines, columns;
   1456
   1457	getmaxyx(stdscr, lines, columns);
   1458
   1459	if (main_window != NULL)
   1460		delwin(main_window);
   1461
   1462	/* set up the menu and menu window */
   1463	main_window = newwin(lines-2, columns-2, 2, 1);
   1464	keypad(main_window, TRUE);
   1465	mwin_max_lines = lines-7;
   1466	mwin_max_cols = columns-6;
   1467
   1468	/* panels order is from bottom to top */
   1469	new_panel(main_window);
   1470}
   1471
   1472int main(int ac, char **av)
   1473{
   1474	int lines, columns;
   1475	char *mode;
   1476
   1477	if (ac > 1 && strcmp(av[1], "-s") == 0) {
   1478		/* Silence conf_read() until the real callback is set up */
   1479		conf_set_message_callback(NULL);
   1480		av++;
   1481	}
   1482	conf_parse(av[1]);
   1483	conf_read(NULL);
   1484
   1485	mode = getenv("NCONFIG_MODE");
   1486	if (mode) {
   1487		if (!strcasecmp(mode, "single_menu"))
   1488			single_menu_mode = 1;
   1489	}
   1490
   1491	/* Initialize curses */
   1492	initscr();
   1493	/* set color theme */
   1494	set_colors();
   1495
   1496	cbreak();
   1497	noecho();
   1498	keypad(stdscr, TRUE);
   1499	curs_set(0);
   1500
   1501	getmaxyx(stdscr, lines, columns);
   1502	if (columns < 75 || lines < 20) {
   1503		endwin();
   1504		printf("Your terminal should have at "
   1505			"least 20 lines and 75 columns\n");
   1506		return 1;
   1507	}
   1508
   1509	notimeout(stdscr, FALSE);
   1510#if NCURSES_REENTRANT
   1511	set_escdelay(1);
   1512#else
   1513	ESCDELAY = 1;
   1514#endif
   1515
   1516	/* set btns menu */
   1517	curses_menu = new_menu(curses_menu_items);
   1518	menu_opts_off(curses_menu, O_SHOWDESC);
   1519	menu_opts_on(curses_menu, O_SHOWMATCH);
   1520	menu_opts_on(curses_menu, O_ONEVALUE);
   1521	menu_opts_on(curses_menu, O_NONCYCLIC);
   1522	menu_opts_on(curses_menu, O_IGNORECASE);
   1523	set_menu_mark(curses_menu, " ");
   1524	set_menu_fore(curses_menu, attr_main_menu_fore);
   1525	set_menu_back(curses_menu, attr_main_menu_back);
   1526	set_menu_grey(curses_menu, attr_main_menu_grey);
   1527
   1528	set_config_filename(conf_get_configname());
   1529	setup_windows();
   1530
   1531	/* check for KEY_FUNC(1) */
   1532	if (has_key(KEY_F(1)) == FALSE) {
   1533		show_scroll_win(main_window,
   1534				"Instructions",
   1535				menu_no_f_instructions);
   1536	}
   1537
   1538	conf_set_message_callback(conf_message_callback);
   1539	/* do the work */
   1540	while (!global_exit) {
   1541		conf(&rootmenu);
   1542		if (!global_exit && do_exit() == 0)
   1543			break;
   1544	}
   1545	/* ok, we are done */
   1546	unpost_menu(curses_menu);
   1547	free_menu(curses_menu);
   1548	delwin(main_window);
   1549	clear();
   1550	refresh();
   1551	endwin();
   1552	return 0;
   1553}