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