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