• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/scripts/kconfig/
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
12static 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"),
137menu_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"),
150menu_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"),
161radiolist_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"),
166inputbox_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."),
170inputbox_instructions_hex[] = N_(
171"Please enter a hexadecimal value.\n"
172"Press <RETURN> to accept, <ESC> to cancel."),
173inputbox_instructions_string[] = N_(
174"Please enter a string value.\n"
175"Press <RETURN> to accept, <ESC> to cancel."),
176setmod_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."),
180nohelp_text[] = N_(
181"There is no help available for this kernel option.\n"),
182load_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."),
186load_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"),
197save_config_text[] = N_(
198"Enter a filename to which this configuration should be saved\n"
199"as an alternate.  Leave blank to abort."),
200save_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"),
211search_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
251struct 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
260static int show_all_items;
261static int indent;
262static struct menu *current_menu;
263static int child_count;
264static int single_menu_mode;
265/* the window in which all information appears */
266static WINDOW *main_window;
267/* the largest size of the menu window */
268static int mwin_max_lines;
269static int mwin_max_cols;
270/* the window in which we show option buttons */
271static MENU *curses_menu;
272static ITEM *curses_menu_items[MAX_MENU_ITEMS];
273static struct mitem k_menu_items[MAX_MENU_ITEMS];
274static int items_num;
275static int global_exit;
276/* the currently selected button */
277const 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
282struct {
283	int count;
284	int ptrs[MAX_MENU_ITEMS];
285} hotkeys[1<<(sizeof(char)*8)];
286
287static void conf(struct menu *menu);
288static void conf_choice(struct menu *menu);
289static void conf_string(struct menu *menu);
290static void conf_load(void);
291static void conf_save(void);
292static void show_help(struct menu *menu);
293static int do_exit(void);
294static void setup_windows(void);
295
296typedef void (*function_key_handler_t)(int *key, struct menu *menu);
297static void handle_f1(int *key, struct menu *current_item);
298static void handle_f2(int *key, struct menu *current_item);
299static void handle_f3(int *key, struct menu *current_item);
300static void handle_f4(int *key, struct menu *current_item);
301static void handle_f5(int *key, struct menu *current_item);
302static void handle_f6(int *key, struct menu *current_item);
303static void handle_f7(int *key, struct menu *current_item);
304static void handle_f8(int *key, struct menu *current_item);
305
306struct function_keys {
307	const char *key_str;
308	const char *func;
309	function_key key;
310	function_key_handler_t handler;
311};
312
313static const int function_keys_num = 8;
314struct 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
365static 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 */
387static 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 */
395static void handle_f2(int *key, struct menu *current_item)
396{
397	show_help(current_item);
398	return;
399}
400
401/* instructions */
402static 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 */
411static 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 */
427static void handle_f5(int *key, struct menu *current_item)
428{
429	*key = KEY_LEFT;
430	return;
431}
432
433/* save */
434static void handle_f6(int *key, struct menu *current_item)
435{
436	conf_save();
437	return;
438}
439
440/* load */
441static void handle_f7(int *key, struct menu *current_item)
442{
443	conf_load();
444	return;
445}
446
447/* exit */
448static 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 */
455static 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
475static 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 */
487static 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 */
506static 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. */
514static 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*/
522static 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 */
582static 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 */
626static 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 */
656static 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
668static int curses_item_index(void)
669{
670	return  item_index(current_item(curses_menu));
671}
672
673static 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
686static int item_is_tag(char tag)
687{
688	return item_tag() == tag;
689}
690
691static char filename[PATH_MAX+1];
692static char menu_backtitle[PATH_MAX+128];
693static 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 */
713static 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 */
734static 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
795static 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;
802again:
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
833static 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
1012conf_childs:
1013	indent += doint;
1014	for (child = menu->list; child; child = child->next)
1015		build_conf(child);
1016	indent -= doint;
1017}
1018
1019static 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*/
1027static 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 */
1053static 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
1103static 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
1245static 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
1263static 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
1361static 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
1406static 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
1438static 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
1480void 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
1495int 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