• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 static 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.\n"
49 "\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"),
132 menu_no_f_instructions[] = N_(
133 "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
134 "Submenus are designated by a trailing \"--->\".\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"),
149 menu_instructions[] = N_(
150 "Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
151 "Submenus are designated by a trailing \"--->\".\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"),
165 radiolist_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"),
170 inputbox_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."),
174 inputbox_instructions_hex[] = N_(
175 "Please enter a hexadecimal value.\n"
176 "Press <Enter> to apply, <Esc> to cancel."),
177 inputbox_instructions_string[] = N_(
178 "Please enter a string value.\n"
179 "Press <Enter> to apply, <Esc> to cancel."),
180 setmod_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."),
183 load_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."),
187 load_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"),
196 save_config_text[] = N_(
197 "Enter a filename to which this configuration should be saved\n"
198 "as an alternate.  Leave empty to abort."),
199 save_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"),
208 search_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 
247 struct mitem {
248 	char str[256];
249 	char tag;
250 	void *usrptr;
251 	int is_visible;
252 };
253 
254 #define MAX_MENU_ITEMS 4096
255 static int show_all_items;
256 static int indent;
257 static struct menu *current_menu;
258 static int child_count;
259 static int single_menu_mode;
260 /* the window in which all information appears */
261 static WINDOW *main_window;
262 /* the largest size of the menu window */
263 static int mwin_max_lines;
264 static int mwin_max_cols;
265 /* the window in which we show option buttons */
266 static MENU *curses_menu;
267 static ITEM *curses_menu_items[MAX_MENU_ITEMS];
268 static struct mitem k_menu_items[MAX_MENU_ITEMS];
269 static int items_num;
270 static int global_exit;
271 /* the currently selected button */
272 const char *current_instructions = menu_instructions;
273 
274 static char *dialog_input_result;
275 static int dialog_input_result_len;
276 
277 static void conf(struct menu *menu);
278 static void conf_choice(struct menu *menu);
279 static void conf_string(struct menu *menu);
280 static void conf_load(void);
281 static void conf_save(void);
282 static void show_help(struct menu *menu);
283 static int do_exit(void);
284 static void setup_windows(void);
285 static void search_conf(void);
286 
287 typedef void (*function_key_handler_t)(int *key, struct menu *menu);
288 static void handle_f1(int *key, struct menu *current_item);
289 static void handle_f2(int *key, struct menu *current_item);
290 static void handle_f3(int *key, struct menu *current_item);
291 static void handle_f4(int *key, struct menu *current_item);
292 static void handle_f5(int *key, struct menu *current_item);
293 static void handle_f6(int *key, struct menu *current_item);
294 static void handle_f7(int *key, struct menu *current_item);
295 static void handle_f8(int *key, struct menu *current_item);
296 static void handle_f9(int *key, struct menu *current_item);
297 
298 struct function_keys {
299 	const char *key_str;
300 	const char *func;
301 	function_key key;
302 	function_key_handler_t handler;
303 };
304 
305 static const int function_keys_num = 9;
306 struct 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 
print_function_line(void)363 static void print_function_line(void)
364 {
365 	int i;
366 	int offset = 1;
367 	const int skip = 1;
368 
369 	for (i = 0; i < function_keys_num; i++) {
370 		(void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
371 		mvwprintw(main_window, LINES-3, offset,
372 				"%s",
373 				function_keys[i].key_str);
374 		(void) wattrset(main_window, attributes[FUNCTION_TEXT]);
375 		offset += strlen(function_keys[i].key_str);
376 		mvwprintw(main_window, LINES-3,
377 				offset, "%s",
378 				function_keys[i].func);
379 		offset += strlen(function_keys[i].func) + skip;
380 	}
381 	(void) wattrset(main_window, attributes[NORMAL]);
382 }
383 
384 /* help */
handle_f1(int * key,struct menu * current_item)385 static void handle_f1(int *key, struct menu *current_item)
386 {
387 	show_scroll_win(main_window,
388 			_("Global help"), _(nconf_global_help));
389 	return;
390 }
391 
392 /* symbole help */
handle_f2(int * key,struct menu * current_item)393 static void handle_f2(int *key, struct menu *current_item)
394 {
395 	show_help(current_item);
396 	return;
397 }
398 
399 /* instructions */
handle_f3(int * key,struct menu * current_item)400 static void handle_f3(int *key, struct menu *current_item)
401 {
402 	show_scroll_win(main_window,
403 			_("Short help"),
404 			_(current_instructions));
405 	return;
406 }
407 
408 /* config */
handle_f4(int * key,struct menu * current_item)409 static void handle_f4(int *key, struct menu *current_item)
410 {
411 	int res = btn_dialog(main_window,
412 			_("Show all symbols?"),
413 			2,
414 			"   <Show All>   ",
415 			"<Don't show all>");
416 	if (res == 0)
417 		show_all_items = 1;
418 	else if (res == 1)
419 		show_all_items = 0;
420 
421 	return;
422 }
423 
424 /* back */
handle_f5(int * key,struct menu * current_item)425 static void handle_f5(int *key, struct menu *current_item)
426 {
427 	*key = KEY_LEFT;
428 	return;
429 }
430 
431 /* save */
handle_f6(int * key,struct menu * current_item)432 static void handle_f6(int *key, struct menu *current_item)
433 {
434 	conf_save();
435 	return;
436 }
437 
438 /* load */
handle_f7(int * key,struct menu * current_item)439 static void handle_f7(int *key, struct menu *current_item)
440 {
441 	conf_load();
442 	return;
443 }
444 
445 /* search */
handle_f8(int * key,struct menu * current_item)446 static void handle_f8(int *key, struct menu *current_item)
447 {
448 	search_conf();
449 	return;
450 }
451 
452 /* exit */
handle_f9(int * key,struct menu * current_item)453 static void handle_f9(int *key, struct menu *current_item)
454 {
455 	do_exit();
456 	return;
457 }
458 
459 /* return != 0 to indicate the key was handles */
process_special_keys(int * key,struct menu * menu)460 static int process_special_keys(int *key, struct menu *menu)
461 {
462 	int i;
463 
464 	if (*key == KEY_RESIZE) {
465 		setup_windows();
466 		return 1;
467 	}
468 
469 	for (i = 0; i < function_keys_num; i++) {
470 		if (*key == KEY_F(function_keys[i].key) ||
471 		    *key == '0' + function_keys[i].key){
472 			function_keys[i].handler(key, menu);
473 			return 1;
474 		}
475 	}
476 
477 	return 0;
478 }
479 
clean_items(void)480 static void clean_items(void)
481 {
482 	int i;
483 	for (i = 0; curses_menu_items[i]; i++)
484 		free_item(curses_menu_items[i]);
485 	bzero(curses_menu_items, sizeof(curses_menu_items));
486 	bzero(k_menu_items, sizeof(k_menu_items));
487 	items_num = 0;
488 }
489 
490 typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
491 	FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
492 
493 /* return the index of the matched item, or -1 if no such item exists */
get_mext_match(const char * match_str,match_f flag)494 static int get_mext_match(const char *match_str, match_f flag)
495 {
496 	int match_start = item_index(current_item(curses_menu));
497 	int index;
498 
499 	if (flag == FIND_NEXT_MATCH_DOWN)
500 		++match_start;
501 	else if (flag == FIND_NEXT_MATCH_UP)
502 		--match_start;
503 
504 	index = match_start;
505 	index = (index + items_num) % items_num;
506 	while (true) {
507 		char *str = k_menu_items[index].str;
508 		if (strcasestr(str, match_str) != 0)
509 			return index;
510 		if (flag == FIND_NEXT_MATCH_UP ||
511 		    flag == MATCH_TINKER_PATTERN_UP)
512 			--index;
513 		else
514 			++index;
515 		index = (index + items_num) % items_num;
516 		if (index == match_start)
517 			return -1;
518 	}
519 }
520 
521 /* Make a new item. */
item_make(struct menu * menu,char tag,const char * fmt,...)522 static void item_make(struct menu *menu, char tag, const char *fmt, ...)
523 {
524 	va_list ap;
525 
526 	if (items_num > MAX_MENU_ITEMS-1)
527 		return;
528 
529 	bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
530 	k_menu_items[items_num].tag = tag;
531 	k_menu_items[items_num].usrptr = menu;
532 	if (menu != NULL)
533 		k_menu_items[items_num].is_visible =
534 			menu_is_visible(menu);
535 	else
536 		k_menu_items[items_num].is_visible = 1;
537 
538 	va_start(ap, fmt);
539 	vsnprintf(k_menu_items[items_num].str,
540 		  sizeof(k_menu_items[items_num].str),
541 		  fmt, ap);
542 	va_end(ap);
543 
544 	if (!k_menu_items[items_num].is_visible)
545 		memcpy(k_menu_items[items_num].str, "XXX", 3);
546 
547 	curses_menu_items[items_num] = new_item(
548 			k_menu_items[items_num].str,
549 			k_menu_items[items_num].str);
550 	set_item_userptr(curses_menu_items[items_num],
551 			&k_menu_items[items_num]);
552 	/*
553 	if (!k_menu_items[items_num].is_visible)
554 		item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
555 	*/
556 
557 	items_num++;
558 	curses_menu_items[items_num] = NULL;
559 }
560 
561 /* very hackish. adds a string to the last item added */
item_add_str(const char * fmt,...)562 static void item_add_str(const char *fmt, ...)
563 {
564 	va_list ap;
565 	int index = items_num-1;
566 	char new_str[256];
567 	char tmp_str[256];
568 
569 	if (index < 0)
570 		return;
571 
572 	va_start(ap, fmt);
573 	vsnprintf(new_str, sizeof(new_str), fmt, ap);
574 	va_end(ap);
575 	snprintf(tmp_str, sizeof(tmp_str), "%s%s",
576 			k_menu_items[index].str, new_str);
577 	strncpy(k_menu_items[index].str,
578 		tmp_str,
579 		sizeof(k_menu_items[index].str));
580 
581 	free_item(curses_menu_items[index]);
582 	curses_menu_items[index] = new_item(
583 			k_menu_items[index].str,
584 			k_menu_items[index].str);
585 	set_item_userptr(curses_menu_items[index],
586 			&k_menu_items[index]);
587 }
588 
589 /* get the tag of the currently selected item */
item_tag(void)590 static char item_tag(void)
591 {
592 	ITEM *cur;
593 	struct mitem *mcur;
594 
595 	cur = current_item(curses_menu);
596 	if (cur == NULL)
597 		return 0;
598 	mcur = (struct mitem *) item_userptr(cur);
599 	return mcur->tag;
600 }
601 
curses_item_index(void)602 static int curses_item_index(void)
603 {
604 	return  item_index(current_item(curses_menu));
605 }
606 
item_data(void)607 static void *item_data(void)
608 {
609 	ITEM *cur;
610 	struct mitem *mcur;
611 
612 	cur = current_item(curses_menu);
613 	if (!cur)
614 		return NULL;
615 	mcur = (struct mitem *) item_userptr(cur);
616 	return mcur->usrptr;
617 
618 }
619 
item_is_tag(char tag)620 static int item_is_tag(char tag)
621 {
622 	return item_tag() == tag;
623 }
624 
625 static char filename[PATH_MAX+1];
626 static char menu_backtitle[PATH_MAX+128];
set_config_filename(const char * config_filename)627 static const char *set_config_filename(const char *config_filename)
628 {
629 	int size;
630 
631 	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
632 			"%s - %s", config_filename, rootmenu.prompt->text);
633 	if (size >= sizeof(menu_backtitle))
634 		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
635 
636 	size = snprintf(filename, sizeof(filename), "%s", config_filename);
637 	if (size >= sizeof(filename))
638 		filename[sizeof(filename)-1] = '\0';
639 	return menu_backtitle;
640 }
641 
642 /* return = 0 means we are successful.
643  * -1 means go on doing what you were doing
644  */
do_exit(void)645 static 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 		break;
675 	default:
676 		btn_dialog(
677 			main_window,
678 			_("Your configuration changes were NOT saved."),
679 			1,
680 			"<OK>");
681 		break;
682 	}
683 	global_exit = 1;
684 	return 0;
685 }
686 
687 
search_conf(void)688 static void search_conf(void)
689 {
690 	struct symbol **sym_arr;
691 	struct gstr res;
692 	struct gstr title;
693 	char *dialog_input;
694 	int dres;
695 
696 	title = str_new();
697 	str_printf( &title, _("Enter %s (sub)string to search for "
698 			      "(with or without \"%s\")"), CONFIG_, CONFIG_);
699 
700 again:
701 	dres = dialog_inputbox(main_window,
702 			_("Search Configuration Parameter"),
703 			str_get(&title),
704 			"", &dialog_input_result, &dialog_input_result_len);
705 	switch (dres) {
706 	case 0:
707 		break;
708 	case 1:
709 		show_scroll_win(main_window,
710 				_("Search Configuration"), search_help);
711 		goto again;
712 	default:
713 		str_free(&title);
714 		return;
715 	}
716 
717 	/* strip the prefix if necessary */
718 	dialog_input = dialog_input_result;
719 	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
720 		dialog_input += strlen(CONFIG_);
721 
722 	sym_arr = sym_re_search(dialog_input);
723 	res = get_relations_str(sym_arr, NULL);
724 	free(sym_arr);
725 	show_scroll_win(main_window,
726 			_("Search Results"), str_get(&res));
727 	str_free(&res);
728 	str_free(&title);
729 }
730 
731 
build_conf(struct menu * menu)732 static void build_conf(struct menu *menu)
733 {
734 	struct symbol *sym;
735 	struct property *prop;
736 	struct menu *child;
737 	int type, tmp, doint = 2;
738 	tristate val;
739 	char ch;
740 
741 	if (!menu || (!show_all_items && !menu_is_visible(menu)))
742 		return;
743 
744 	sym = menu->sym;
745 	prop = menu->prompt;
746 	if (!sym) {
747 		if (prop && menu != current_menu) {
748 			const char *prompt = menu_get_prompt(menu);
749 			enum prop_type ptype;
750 			ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
751 			switch (ptype) {
752 			case P_MENU:
753 				child_count++;
754 				prompt = _(prompt);
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  --->",
763 						indent + 1,
764 						' ', prompt);
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_changable(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_changable(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_changable(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_changable(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_changable(sym)) ?
904 				"" : _(" (NEW)"));
905 		if (menu->prompt && menu->prompt->type == P_MENU) {
906 			item_add_str("  --->");
907 			return;
908 		}
909 	}
910 
911 conf_childs:
912 	indent += doint;
913 	for (child = menu->list; child; child = child->next)
914 		build_conf(child);
915 	indent -= doint;
916 }
917 
reset_menu(void)918 static 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*/
center_item(int selected_index,int * last_top_row)926 static 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 */
show_menu(const char * prompt,const char * instructions,int selected_index,int * last_top_row)947 static 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 	(void) wattrset(main_window, attributes[NORMAL]);
957 	print_in_middle(stdscr, 1, 0, COLS,
958 			menu_backtitle,
959 			attributes[MAIN_HEADING]);
960 
961 	(void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
962 	box(main_window, 0, 0);
963 	(void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
964 	mvwprintw(main_window, 0, 3, " %s ", prompt);
965 	(void) wattrset(main_window, attributes[NORMAL]);
966 
967 	set_menu_items(curses_menu, curses_menu_items);
968 
969 	/* position the menu at the middle of the screen */
970 	scale_menu(curses_menu, &maxy, &maxx);
971 	maxx = min(maxx, mwin_max_cols-2);
972 	maxy = mwin_max_lines;
973 	menu_window = derwin(main_window,
974 			maxy,
975 			maxx,
976 			2,
977 			(mwin_max_cols-maxx)/2);
978 	keypad(menu_window, TRUE);
979 	set_menu_win(curses_menu, menu_window);
980 	set_menu_sub(curses_menu, menu_window);
981 
982 	/* must reassert this after changing items, otherwise returns to a
983 	 * default of 16
984 	 */
985 	set_menu_format(curses_menu, maxy, 1);
986 	center_item(selected_index, last_top_row);
987 	set_menu_format(curses_menu, maxy, 1);
988 
989 	print_function_line();
990 
991 	/* Post the menu */
992 	post_menu(curses_menu);
993 	refresh_all_windows(main_window);
994 }
995 
adj_match_dir(match_f * match_direction)996 static void adj_match_dir(match_f *match_direction)
997 {
998 	if (*match_direction == FIND_NEXT_MATCH_DOWN)
999 		*match_direction =
1000 			MATCH_TINKER_PATTERN_DOWN;
1001 	else if (*match_direction == FIND_NEXT_MATCH_UP)
1002 		*match_direction =
1003 			MATCH_TINKER_PATTERN_UP;
1004 	/* else, do no change.. */
1005 }
1006 
1007 struct match_state
1008 {
1009 	int in_search;
1010 	match_f match_direction;
1011 	char pattern[256];
1012 };
1013 
1014 /* Return 0 means I have handled the key. In such a case, ans should hold the
1015  * item to center, or -1 otherwise.
1016  * Else return -1 .
1017  */
do_match(int key,struct match_state * state,int * ans)1018 static int do_match(int key, struct match_state *state, int *ans)
1019 {
1020 	char c = (char) key;
1021 	int terminate_search = 0;
1022 	*ans = -1;
1023 	if (key == '/' || (state->in_search && key == 27)) {
1024 		move(0, 0);
1025 		refresh();
1026 		clrtoeol();
1027 		state->in_search = 1-state->in_search;
1028 		bzero(state->pattern, sizeof(state->pattern));
1029 		state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1030 		return 0;
1031 	} else if (!state->in_search)
1032 		return 1;
1033 
1034 	if (isalnum(c) || isgraph(c) || c == ' ') {
1035 		state->pattern[strlen(state->pattern)] = c;
1036 		state->pattern[strlen(state->pattern)] = '\0';
1037 		adj_match_dir(&state->match_direction);
1038 		*ans = get_mext_match(state->pattern,
1039 				state->match_direction);
1040 	} else if (key == KEY_DOWN) {
1041 		state->match_direction = FIND_NEXT_MATCH_DOWN;
1042 		*ans = get_mext_match(state->pattern,
1043 				state->match_direction);
1044 	} else if (key == KEY_UP) {
1045 		state->match_direction = FIND_NEXT_MATCH_UP;
1046 		*ans = get_mext_match(state->pattern,
1047 				state->match_direction);
1048 	} else if (key == KEY_BACKSPACE || key == 127) {
1049 		state->pattern[strlen(state->pattern)-1] = '\0';
1050 		adj_match_dir(&state->match_direction);
1051 	} else
1052 		terminate_search = 1;
1053 
1054 	if (terminate_search) {
1055 		state->in_search = 0;
1056 		bzero(state->pattern, sizeof(state->pattern));
1057 		move(0, 0);
1058 		refresh();
1059 		clrtoeol();
1060 		return -1;
1061 	}
1062 	return 0;
1063 }
1064 
conf(struct menu * menu)1065 static void conf(struct menu *menu)
1066 {
1067 	struct menu *submenu = 0;
1068 	const char *prompt = menu_get_prompt(menu);
1069 	struct symbol *sym;
1070 	int res;
1071 	int current_index = 0;
1072 	int last_top_row = 0;
1073 	struct match_state match_state = {
1074 		.in_search = 0,
1075 		.match_direction = MATCH_TINKER_PATTERN_DOWN,
1076 		.pattern = "",
1077 	};
1078 
1079 	while (!global_exit) {
1080 		reset_menu();
1081 		current_menu = menu;
1082 		build_conf(menu);
1083 		if (!child_count)
1084 			break;
1085 
1086 		show_menu(prompt ? _(prompt) : _("Main Menu"),
1087 				_(menu_instructions),
1088 				current_index, &last_top_row);
1089 		keypad((menu_win(curses_menu)), TRUE);
1090 		while (!global_exit) {
1091 			if (match_state.in_search) {
1092 				mvprintw(0, 0,
1093 					"searching: %s", match_state.pattern);
1094 				clrtoeol();
1095 			}
1096 			refresh_all_windows(main_window);
1097 			res = wgetch(menu_win(curses_menu));
1098 			if (!res)
1099 				break;
1100 			if (do_match(res, &match_state, &current_index) == 0) {
1101 				if (current_index != -1)
1102 					center_item(current_index,
1103 						    &last_top_row);
1104 				continue;
1105 			}
1106 			if (process_special_keys(&res,
1107 						(struct menu *) item_data()))
1108 				break;
1109 			switch (res) {
1110 			case KEY_DOWN:
1111 				menu_driver(curses_menu, REQ_DOWN_ITEM);
1112 				break;
1113 			case KEY_UP:
1114 				menu_driver(curses_menu, REQ_UP_ITEM);
1115 				break;
1116 			case KEY_NPAGE:
1117 				menu_driver(curses_menu, REQ_SCR_DPAGE);
1118 				break;
1119 			case KEY_PPAGE:
1120 				menu_driver(curses_menu, REQ_SCR_UPAGE);
1121 				break;
1122 			case KEY_HOME:
1123 				menu_driver(curses_menu, REQ_FIRST_ITEM);
1124 				break;
1125 			case KEY_END:
1126 				menu_driver(curses_menu, REQ_LAST_ITEM);
1127 				break;
1128 			case 'h':
1129 			case '?':
1130 				show_help((struct menu *) item_data());
1131 				break;
1132 			}
1133 			if (res == 10 || res == 27 ||
1134 				res == 32 || res == 'n' || res == 'y' ||
1135 				res == KEY_LEFT || res == KEY_RIGHT ||
1136 				res == 'm')
1137 				break;
1138 			refresh_all_windows(main_window);
1139 		}
1140 
1141 		refresh_all_windows(main_window);
1142 		/* if ESC or left*/
1143 		if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1144 			break;
1145 
1146 		/* remember location in the menu */
1147 		last_top_row = top_row(curses_menu);
1148 		current_index = curses_item_index();
1149 
1150 		if (!item_tag())
1151 			continue;
1152 
1153 		submenu = (struct menu *) item_data();
1154 		if (!submenu || !menu_is_visible(submenu))
1155 			continue;
1156 		sym = submenu->sym;
1157 
1158 		switch (res) {
1159 		case ' ':
1160 			if (item_is_tag('t'))
1161 				sym_toggle_tristate_value(sym);
1162 			else if (item_is_tag('m'))
1163 				conf(submenu);
1164 			break;
1165 		case KEY_RIGHT:
1166 		case 10: /* ENTER WAS PRESSED */
1167 			switch (item_tag()) {
1168 			case 'm':
1169 				if (single_menu_mode)
1170 					submenu->data =
1171 						(void *) (long) !submenu->data;
1172 				else
1173 					conf(submenu);
1174 				break;
1175 			case 't':
1176 				if (sym_is_choice(sym) &&
1177 				    sym_get_tristate_value(sym) == yes)
1178 					conf_choice(submenu);
1179 				else if (submenu->prompt &&
1180 					 submenu->prompt->type == P_MENU)
1181 					conf(submenu);
1182 				else if (res == 10)
1183 					sym_toggle_tristate_value(sym);
1184 				break;
1185 			case 's':
1186 				conf_string(submenu);
1187 				break;
1188 			}
1189 			break;
1190 		case 'y':
1191 			if (item_is_tag('t')) {
1192 				if (sym_set_tristate_value(sym, yes))
1193 					break;
1194 				if (sym_set_tristate_value(sym, mod))
1195 					btn_dialog(main_window, setmod_text, 0);
1196 			}
1197 			break;
1198 		case 'n':
1199 			if (item_is_tag('t'))
1200 				sym_set_tristate_value(sym, no);
1201 			break;
1202 		case 'm':
1203 			if (item_is_tag('t'))
1204 				sym_set_tristate_value(sym, mod);
1205 			break;
1206 		}
1207 	}
1208 }
1209 
conf_message_callback(const char * fmt,va_list ap)1210 static void conf_message_callback(const char *fmt, va_list ap)
1211 {
1212 	char buf[1024];
1213 
1214 	vsnprintf(buf, sizeof(buf), fmt, ap);
1215 	btn_dialog(main_window, buf, 1, "<OK>");
1216 }
1217 
show_help(struct menu * menu)1218 static void show_help(struct menu *menu)
1219 {
1220 	struct gstr help;
1221 
1222 	if (!menu)
1223 		return;
1224 
1225 	help = str_new();
1226 	menu_get_ext_help(menu, &help);
1227 	show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1228 	str_free(&help);
1229 }
1230 
conf_choice(struct menu * menu)1231 static void conf_choice(struct menu *menu)
1232 {
1233 	const char *prompt = _(menu_get_prompt(menu));
1234 	struct menu *child = 0;
1235 	struct symbol *active;
1236 	int selected_index = 0;
1237 	int last_top_row = 0;
1238 	int res, i = 0;
1239 	struct match_state match_state = {
1240 		.in_search = 0,
1241 		.match_direction = MATCH_TINKER_PATTERN_DOWN,
1242 		.pattern = "",
1243 	};
1244 
1245 	active = sym_get_choice_value(menu->sym);
1246 	/* this is mostly duplicated from the conf() function. */
1247 	while (!global_exit) {
1248 		reset_menu();
1249 
1250 		for (i = 0, child = menu->list; child; child = child->next) {
1251 			if (!show_all_items && !menu_is_visible(child))
1252 				continue;
1253 
1254 			if (child->sym == sym_get_choice_value(menu->sym))
1255 				item_make(child, ':', "<X> %s",
1256 						_(menu_get_prompt(child)));
1257 			else if (child->sym)
1258 				item_make(child, ':', "    %s",
1259 						_(menu_get_prompt(child)));
1260 			else
1261 				item_make(child, ':', "*** %s ***",
1262 						_(menu_get_prompt(child)));
1263 
1264 			if (child->sym == active){
1265 				last_top_row = top_row(curses_menu);
1266 				selected_index = i;
1267 			}
1268 			i++;
1269 		}
1270 		show_menu(prompt ? _(prompt) : _("Choice Menu"),
1271 				_(radiolist_instructions),
1272 				selected_index,
1273 				&last_top_row);
1274 		while (!global_exit) {
1275 			if (match_state.in_search) {
1276 				mvprintw(0, 0, "searching: %s",
1277 					 match_state.pattern);
1278 				clrtoeol();
1279 			}
1280 			refresh_all_windows(main_window);
1281 			res = wgetch(menu_win(curses_menu));
1282 			if (!res)
1283 				break;
1284 			if (do_match(res, &match_state, &selected_index) == 0) {
1285 				if (selected_index != -1)
1286 					center_item(selected_index,
1287 						    &last_top_row);
1288 				continue;
1289 			}
1290 			if (process_special_keys(
1291 						&res,
1292 						(struct menu *) item_data()))
1293 				break;
1294 			switch (res) {
1295 			case KEY_DOWN:
1296 				menu_driver(curses_menu, REQ_DOWN_ITEM);
1297 				break;
1298 			case KEY_UP:
1299 				menu_driver(curses_menu, REQ_UP_ITEM);
1300 				break;
1301 			case KEY_NPAGE:
1302 				menu_driver(curses_menu, REQ_SCR_DPAGE);
1303 				break;
1304 			case KEY_PPAGE:
1305 				menu_driver(curses_menu, REQ_SCR_UPAGE);
1306 				break;
1307 			case KEY_HOME:
1308 				menu_driver(curses_menu, REQ_FIRST_ITEM);
1309 				break;
1310 			case KEY_END:
1311 				menu_driver(curses_menu, REQ_LAST_ITEM);
1312 				break;
1313 			case 'h':
1314 			case '?':
1315 				show_help((struct menu *) item_data());
1316 				break;
1317 			}
1318 			if (res == 10 || res == 27 || res == ' ' ||
1319 					res == KEY_LEFT){
1320 				break;
1321 			}
1322 			refresh_all_windows(main_window);
1323 		}
1324 		/* if ESC or left */
1325 		if (res == 27 || res == KEY_LEFT)
1326 			break;
1327 
1328 		child = item_data();
1329 		if (!child || !menu_is_visible(child) || !child->sym)
1330 			continue;
1331 		switch (res) {
1332 		case ' ':
1333 		case  10:
1334 		case KEY_RIGHT:
1335 			sym_set_tristate_value(child->sym, yes);
1336 			return;
1337 		case 'h':
1338 		case '?':
1339 			show_help(child);
1340 			active = child->sym;
1341 			break;
1342 		case KEY_EXIT:
1343 			return;
1344 		}
1345 	}
1346 }
1347 
conf_string(struct menu * menu)1348 static void conf_string(struct menu *menu)
1349 {
1350 	const char *prompt = menu_get_prompt(menu);
1351 
1352 	while (1) {
1353 		int res;
1354 		const char *heading;
1355 
1356 		switch (sym_get_type(menu->sym)) {
1357 		case S_INT:
1358 			heading = _(inputbox_instructions_int);
1359 			break;
1360 		case S_HEX:
1361 			heading = _(inputbox_instructions_hex);
1362 			break;
1363 		case S_STRING:
1364 			heading = _(inputbox_instructions_string);
1365 			break;
1366 		default:
1367 			heading = _("Internal nconf error!");
1368 		}
1369 		res = dialog_inputbox(main_window,
1370 				prompt ? _(prompt) : _("Main Menu"),
1371 				heading,
1372 				sym_get_string_value(menu->sym),
1373 				&dialog_input_result,
1374 				&dialog_input_result_len);
1375 		switch (res) {
1376 		case 0:
1377 			if (sym_set_string_value(menu->sym,
1378 						dialog_input_result))
1379 				return;
1380 			btn_dialog(main_window,
1381 				_("You have made an invalid entry."), 0);
1382 			break;
1383 		case 1:
1384 			show_help(menu);
1385 			break;
1386 		case KEY_EXIT:
1387 			return;
1388 		}
1389 	}
1390 }
1391 
conf_load(void)1392 static void conf_load(void)
1393 {
1394 	while (1) {
1395 		int res;
1396 		res = dialog_inputbox(main_window,
1397 				NULL, load_config_text,
1398 				filename,
1399 				&dialog_input_result,
1400 				&dialog_input_result_len);
1401 		switch (res) {
1402 		case 0:
1403 			if (!dialog_input_result[0])
1404 				return;
1405 			if (!conf_read(dialog_input_result)) {
1406 				set_config_filename(dialog_input_result);
1407 				sym_set_change_count(1);
1408 				return;
1409 			}
1410 			btn_dialog(main_window, _("File does not exist!"), 0);
1411 			break;
1412 		case 1:
1413 			show_scroll_win(main_window,
1414 					_("Load Alternate Configuration"),
1415 					load_config_help);
1416 			break;
1417 		case KEY_EXIT:
1418 			return;
1419 		}
1420 	}
1421 }
1422 
conf_save(void)1423 static void conf_save(void)
1424 {
1425 	while (1) {
1426 		int res;
1427 		res = dialog_inputbox(main_window,
1428 				NULL, save_config_text,
1429 				filename,
1430 				&dialog_input_result,
1431 				&dialog_input_result_len);
1432 		switch (res) {
1433 		case 0:
1434 			if (!dialog_input_result[0])
1435 				return;
1436 			res = conf_write(dialog_input_result);
1437 			if (!res) {
1438 				set_config_filename(dialog_input_result);
1439 				return;
1440 			}
1441 			btn_dialog(main_window, _("Can't create file! "
1442 				"Probably a nonexistent directory."),
1443 				1, "<OK>");
1444 			break;
1445 		case 1:
1446 			show_scroll_win(main_window,
1447 				_("Save Alternate Configuration"),
1448 				save_config_help);
1449 			break;
1450 		case KEY_EXIT:
1451 			return;
1452 		}
1453 	}
1454 }
1455 
setup_windows(void)1456 void setup_windows(void)
1457 {
1458 	if (main_window != NULL)
1459 		delwin(main_window);
1460 
1461 	/* set up the menu and menu window */
1462 	main_window = newwin(LINES-2, COLS-2, 2, 1);
1463 	keypad(main_window, TRUE);
1464 	mwin_max_lines = LINES-7;
1465 	mwin_max_cols = COLS-6;
1466 
1467 	/* panels order is from bottom to top */
1468 	new_panel(main_window);
1469 }
1470 
main(int ac,char ** av)1471 int main(int ac, char **av)
1472 {
1473 	char *mode;
1474 
1475 	setlocale(LC_ALL, "");
1476 	bindtextdomain(PACKAGE, LOCALEDIR);
1477 	textdomain(PACKAGE);
1478 
1479 	conf_parse(av[1]);
1480 	conf_read(NULL);
1481 
1482 	mode = getenv("NCONFIG_MODE");
1483 	if (mode) {
1484 		if (!strcasecmp(mode, "single_menu"))
1485 			single_menu_mode = 1;
1486 	}
1487 
1488 	/* Initialize curses */
1489 	initscr();
1490 	/* set color theme */
1491 	set_colors();
1492 
1493 	cbreak();
1494 	noecho();
1495 	keypad(stdscr, TRUE);
1496 	curs_set(0);
1497 
1498 	if (COLS < 75 || LINES < 20) {
1499 		endwin();
1500 		printf("Your terminal should have at "
1501 			"least 20 lines and 75 columns\n");
1502 		return 1;
1503 	}
1504 
1505 	notimeout(stdscr, FALSE);
1506 #if NCURSES_REENTRANT
1507 	set_escdelay(1);
1508 #else
1509 	ESCDELAY = 1;
1510 #endif
1511 
1512 	/* set btns menu */
1513 	curses_menu = new_menu(curses_menu_items);
1514 	menu_opts_off(curses_menu, O_SHOWDESC);
1515 	menu_opts_on(curses_menu, O_SHOWMATCH);
1516 	menu_opts_on(curses_menu, O_ONEVALUE);
1517 	menu_opts_on(curses_menu, O_NONCYCLIC);
1518 	menu_opts_on(curses_menu, O_IGNORECASE);
1519 	set_menu_mark(curses_menu, " ");
1520 	set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1521 	set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1522 	set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1523 
1524 	set_config_filename(conf_get_configname());
1525 	setup_windows();
1526 
1527 	/* check for KEY_FUNC(1) */
1528 	if (has_key(KEY_F(1)) == FALSE) {
1529 		show_scroll_win(main_window,
1530 				_("Instructions"),
1531 				_(menu_no_f_instructions));
1532 	}
1533 
1534 	conf_set_message_callback(conf_message_callback);
1535 	/* do the work */
1536 	while (!global_exit) {
1537 		conf(&rootmenu);
1538 		if (!global_exit && do_exit() == 0)
1539 			break;
1540 	}
1541 	/* ok, we are done */
1542 	unpost_menu(curses_menu);
1543 	free_menu(curses_menu);
1544 	delwin(main_window);
1545 	clear();
1546 	refresh();
1547 	endwin();
1548 	return 0;
1549 }
1550 
1551