Linux Audio

Check our new training course

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