yann@2454: /* yann@2454: * Copyright (C) 2008 Nir Tzachar yann@2454: #define LKC_DIRECT_LINK yann@2454: #include "lkc.h" yann@2454: #include "nconf.h" yann@2454: #include yann@2454: yann@2454: static const char nconf_readme[] = N_( yann@2454: "Overview\n" yann@2454: "--------\n" yann@2454: "This interface let you select features and parameters for the build.\n" yann@2454: "Features can either be built-in, modularized, or ignored. Parameters\n" yann@2454: "must be entered in as decimal or hexadecimal numbers or text.\n" yann@2454: "\n" yann@2454: "Menu items beginning with following braces represent features that\n" yann@2454: " [ ] can be built in or removed\n" yann@2454: " < > can be built in, modularized or removed\n" yann@2454: " { } can be built in or modularized (selected by other feature)\n" yann@2454: " - - are selected by other feature,\n" yann@2454: " XXX cannot be selected. Use Symbol Info to find out why,\n" yann@2454: "while *, M or whitespace inside braces means to build in, build as\n" yann@2454: "a module or to exclude the feature respectively.\n" yann@2454: "\n" yann@2454: "To change any of these features, highlight it with the cursor\n" yann@2454: "keys and press to build it in, to make it a module or\n" yann@2454: " to removed it. You may also press the to cycle\n" yann@2454: "through the available options (ie. Y->N->M->Y).\n" yann@2454: "\n" yann@2454: "Some additional keyboard hints:\n" yann@2454: "\n" yann@2454: "Menus\n" yann@2454: "----------\n" yann@2454: "o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" yann@2454: " you wish to change use or . Goto submenu by \n" yann@2454: " pressing of . Use or to go back.\n" yann@2454: " Submenus are designated by \"--->\".\n" yann@2454: "\n" yann@2454: " Searching: pressing '/' triggers interactive search mode.\n" yann@2454: " nconfig performs a case insensitive search for the string\n" yann@2454: " in the menu prompts (no regex support).\n" yann@2454: " Pressing the up/down keys highlights the previous/next\n" yann@2454: " matching item. Backspace removes one character from the\n" yann@2454: " match string. Pressing either '/' again or ESC exits\n" yann@2454: " search mode. All other keys behave normally.\n" yann@2454: "\n" yann@2454: " You may also use the and keys to scroll\n" yann@2454: " unseen options into view.\n" yann@2454: "\n" yann@2454: "o To exit a menu use the just press or .\n" yann@2454: "\n" yann@2454: "o To get help with an item, press \n" yann@2454: " Shortcut: Press or .\n" yann@2454: "\n" yann@2454: "\n" yann@2454: "Radiolists (Choice lists)\n" yann@2454: "-----------\n" yann@2454: "o Use the cursor keys to select the option you wish to set and press\n" yann@2454: " or the .\n" yann@2454: "\n" yann@2454: " Shortcut: Press the first letter of the option you wish to set then\n" yann@2454: " press or .\n" yann@2454: "\n" yann@2454: "o To see available help for the item, press \n" yann@2454: " Shortcut: Press or .\n" yann@2454: "\n" yann@2454: "\n" yann@2454: "Data Entry\n" yann@2454: "-----------\n" yann@2454: "o Enter the requested information and press \n" yann@2454: " If you are entering hexadecimal values, it is not necessary to\n" yann@2454: " add the '0x' prefix to the entry.\n" yann@2454: "\n" yann@2454: "o For help, press .\n" yann@2454: "\n" yann@2454: "\n" yann@2454: "Text Box (Help Window)\n" yann@2454: "--------\n" yann@2454: "o Use the cursor keys to scroll up/down/left/right. The VI editor\n" yann@2454: " keys h,j,k,l function here as do for those\n" yann@2454: " who are familiar with less and lynx.\n" yann@2454: "\n" yann@2454: "o Press , , , or to exit.\n" yann@2454: "\n" yann@2454: "\n" yann@2454: "Alternate Configuration Files\n" yann@2454: "-----------------------------\n" yann@2454: "nconfig supports the use of alternate configuration files for\n" yann@2454: "those who, for various reasons, find it necessary to switch\n" yann@2454: "between different configurations.\n" yann@2454: "\n" yann@2454: "At the end of the main menu you will find two options. One is\n" yann@2454: "for saving the current configuration to a file of your choosing.\n" yann@2454: "The other option is for loading a previously saved alternate\n" yann@2454: "configuration.\n" yann@2454: "\n" yann@2454: "Even if you don't use alternate configuration files, but you\n" yann@2454: "find during a nconfig session that you have completely messed\n" yann@2454: "up your settings, you may use the \"Load Alternate...\" option to\n" yann@2454: "restore your previously saved settings from \".config\" without\n" yann@2454: "restarting nconfig.\n" yann@2454: "\n" yann@2454: "Other information\n" yann@2454: "-----------------\n" yann@2454: "If you use nconfig in an XTERM window make sure you have your\n" yann@2454: "$TERM variable set to point to a xterm definition which supports color.\n" yann@2454: "Otherwise, nconfig will look rather bad. nconfig will not\n" yann@2454: "display correctly in a RXVT window because rxvt displays only one\n" yann@2454: "intensity of color, bright.\n" yann@2454: "\n" yann@2454: "nconfig will display larger menus on screens or xterms which are\n" yann@2454: "set to display more than the standard 25 row by 80 column geometry.\n" yann@2454: "In order for this to work, the \"stty size\" command must be able to\n" yann@2454: "display the screen's current row and column geometry. I STRONGLY\n" yann@2454: "RECOMMEND that you make sure you do NOT have the shell variables\n" yann@2454: "LINES and COLUMNS exported into your environment. Some distributions\n" yann@2454: "export those variables via /etc/profile. Some ncurses programs can\n" yann@2454: "become confused when those variables (LINES & COLUMNS) don't reflect\n" yann@2454: "the true screen size.\n" yann@2454: "\n" yann@2454: "Optional personality available\n" yann@2454: "------------------------------\n" yann@2454: "If you prefer to have all of the options listed in a single menu, rather\n" yann@2454: "than the default multimenu hierarchy, run the nconfig with NCONFIG_MODE\n" yann@2454: "environment variable set to single_menu. Example:\n" yann@2454: "\n" yann@2454: "make NCONFIG_MODE=single_menu nconfig\n" yann@2454: "\n" yann@2454: " will then unroll the appropriate category, or enfold it if it\n" yann@2454: "is already unrolled.\n" yann@2454: "\n" yann@2454: "Note that this mode can eventually be a little more CPU expensive\n" yann@2454: "(especially with a larger number of unrolled categories) than the\n" yann@2454: "default mode.\n" yann@2454: "\n"), yann@2454: menu_no_f_instructions[] = N_( yann@2454: " You do not have function keys support. Please follow the\n" yann@2454: " following instructions:\n" yann@2454: " Arrow keys navigate the menu.\n" yann@2454: " or selects submenus --->.\n" yann@2454: " Capital Letters are hotkeys.\n" yann@2454: " Pressing includes, excludes, modularizes features.\n" yann@2454: " Pressing SpaceBar toggles between the above options.\n" yann@2454: " Press or to go back one menu,\n" yann@2454: " or for Help, for Search.\n" yann@2454: " <1> is interchangeable with , <2> with , etc.\n" yann@2454: " Legend: [*] built-in [ ] excluded module < > module capable.\n" yann@2454: " always leaves the current window.\n"), yann@2454: menu_instructions[] = N_( yann@2454: " Arrow keys navigate the menu.\n" yann@2454: " or selects submenus --->.\n" yann@2454: " Capital Letters are hotkeys.\n" yann@2454: " Pressing includes, excludes, modularizes features.\n" yann@2454: " Pressing SpaceBar toggles between the above options\n" yann@2454: " Press , or to go back one menu,\n" yann@2454: " , or for Help, for Search.\n" yann@2454: " <1> is interchangeable with , <2> with , etc.\n" yann@2454: " Legend: [*] built-in [ ] excluded module < > module capable.\n" yann@2454: " always leaves the current window\n"), yann@2454: radiolist_instructions[] = N_( yann@2454: " Use the arrow keys to navigate this window or\n" yann@2454: " press the hotkey of the item you wish to select\n" yann@2454: " followed by the .\n" yann@2454: " Press , or for additional information about this option.\n"), yann@2454: inputbox_instructions_int[] = N_( yann@2454: "Please enter a decimal value.\n" yann@2454: "Fractions will not be accepted.\n" yann@2454: "Press to accept, to cancel."), yann@2454: inputbox_instructions_hex[] = N_( yann@2454: "Please enter a hexadecimal value.\n" yann@2454: "Press to accept, to cancel."), yann@2454: inputbox_instructions_string[] = N_( yann@2454: "Please enter a string value.\n" yann@2454: "Press to accept, to cancel."), yann@2454: setmod_text[] = N_( yann@2454: "This feature depends on another which\n" yann@2454: "has been configured as a module.\n" yann@2454: "As a result, this feature will be built as a module."), yann@2454: nohelp_text[] = N_( yann@2454: "There is no help available for this option.\n"), yann@2454: load_config_text[] = N_( yann@2454: "Enter the name of the configuration file you wish to load.\n" yann@2454: "Accept the name shown to restore the configuration you\n" yann@2454: "last retrieved. Leave blank to abort."), yann@2454: load_config_help[] = N_( yann@2454: "\n" yann@2454: "For various reasons, one may wish to keep several different\n" yann@2454: "configurations available on a single machine.\n" yann@2454: "\n" yann@2454: "If you have saved a previous configuration in a file other than the\n" yann@2454: "default one, entering its name here will allow you to modify that\n" yann@2454: "configuration.\n" yann@2454: "\n" yann@2454: "If you are uncertain, then you have probably never used alternate\n" yann@2454: "configuration files. You should therefor leave this blank to abort.\n"), yann@2454: save_config_text[] = N_( yann@2454: "Enter a filename to which this configuration should be saved\n" yann@2454: "as an alternate. Leave blank to abort."), yann@2454: save_config_help[] = N_( yann@2454: "\n" yann@2454: "For various reasons, one may wish to keep different configurations\n" yann@2454: "available on a single machine.\n" yann@2454: "\n" yann@2454: "Entering a file name here will allow you to later retrieve, modify\n" yann@2454: "and use the current configuration as an alternate to whatever\n" yann@2454: "configuration options you have selected at that time.\n" yann@2454: "\n" yann@2454: "If you are uncertain what all this means then you should probably\n" yann@2454: "leave this blank.\n"), yann@2454: search_help[] = N_( yann@2454: "\n" yann@2454: "Search for symbols and display their relations. Regular expressions\n" yann@2454: "are allowed.\n" yann@2454: "Example: search for \"^FOO\"\n" yann@2454: "Result:\n" yann@2454: "-----------------------------------------------------------------\n" yann@2454: "Symbol: FOO [ = m]\n" yann@2454: "Prompt: Foo bus is used to drive the bar HW\n" yann@2454: "Defined at drivers/pci/Kconfig:47\n" yann@2454: "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" yann@2454: "Location:\n" yann@2454: " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" yann@2454: " -> PCI support (PCI [ = y])\n" yann@2454: " -> PCI access mode ( [ = y])\n" yann@2454: "Selects: LIBCRC32\n" yann@2454: "Selected by: BAR\n" yann@2454: "-----------------------------------------------------------------\n" yann@2454: "o The line 'Prompt:' shows the text used in the menu structure for\n" yann@2454: " this symbol\n" yann@2454: "o The 'Defined at' line tell at what file / line number the symbol\n" yann@2454: " is defined\n" yann@2454: "o The 'Depends on:' line tell what symbols needs to be defined for\n" yann@2454: " this symbol to be visible in the menu (selectable)\n" yann@2454: "o The 'Location:' lines tell where in the menu structure this symbol\n" yann@2454: " is located\n" yann@2454: " A location followed by a [ = y] indicate that this is a selectable\n" yann@2454: " menu item - and current value is displayed inside brackets.\n" yann@2454: "o The 'Selects:' line tell what symbol will be automatically\n" yann@2454: " selected if this symbol is selected (y or m)\n" yann@2454: "o The 'Selected by' line tell what symbol has selected this symbol\n" yann@2454: "\n" yann@2454: "Only relevant lines are shown.\n" yann@2454: "\n\n" yann@2454: "Search examples:\n" yann@2454: "Examples: USB => find all symbols containing USB\n" yann@2454: " ^USB => find all symbols starting with USB\n" yann@2454: " USB$ => find all symbols ending with USB\n" yann@2454: "\n"); yann@2454: yann@2454: struct mitem { yann@2454: char str[256]; yann@2454: char tag; yann@2454: void *usrptr; yann@2454: int is_visible; yann@2454: }; yann@2454: yann@2454: #define MAX_MENU_ITEMS 4096 yann@2454: static int show_all_items; yann@2454: static int indent; yann@2454: static struct menu *current_menu; yann@2454: static int child_count; yann@2454: static int single_menu_mode; yann@2454: /* the window in which all information appears */ yann@2454: static WINDOW *main_window; yann@2454: /* the largest size of the menu window */ yann@2454: static int mwin_max_lines; yann@2454: static int mwin_max_cols; yann@2454: /* the window in which we show option buttons */ yann@2454: static MENU *curses_menu; yann@2454: static ITEM *curses_menu_items[MAX_MENU_ITEMS]; yann@2454: static struct mitem k_menu_items[MAX_MENU_ITEMS]; yann@2454: static int items_num; yann@2454: static int global_exit; yann@2454: /* the currently selected button */ yann@2454: const char *current_instructions = menu_instructions; yann@2454: yann@2454: static void conf(struct menu *menu); yann@2454: static void conf_choice(struct menu *menu); yann@2454: static void conf_string(struct menu *menu); yann@2454: static void conf_load(void); yann@2454: static void conf_save(void); yann@2454: static void show_help(struct menu *menu); yann@2454: static int do_exit(void); yann@2454: static void setup_windows(void); yann@2454: static void search_conf(void); yann@2454: yann@2454: typedef void (*function_key_handler_t)(int *key, struct menu *menu); yann@2454: static void handle_f1(int *key, struct menu *current_item); yann@2454: static void handle_f2(int *key, struct menu *current_item); yann@2454: static void handle_f3(int *key, struct menu *current_item); yann@2454: static void handle_f4(int *key, struct menu *current_item); yann@2454: static void handle_f5(int *key, struct menu *current_item); yann@2454: static void handle_f6(int *key, struct menu *current_item); yann@2454: static void handle_f7(int *key, struct menu *current_item); yann@2454: static void handle_f8(int *key, struct menu *current_item); yann@2454: static void handle_f9(int *key, struct menu *current_item); yann@2454: yann@2454: struct function_keys { yann@2454: const char *key_str; yann@2454: const char *func; yann@2454: function_key key; yann@2454: function_key_handler_t handler; yann@2454: }; yann@2454: yann@2454: static const int function_keys_num = 9; yann@2454: struct function_keys function_keys[] = { yann@2454: { yann@2454: .key_str = "F1", yann@2454: .func = "Help", yann@2454: .key = F_HELP, yann@2454: .handler = handle_f1, yann@2454: }, yann@2454: { yann@2454: .key_str = "F2", yann@2454: .func = "Sym Info", yann@2454: .key = F_SYMBOL, yann@2454: .handler = handle_f2, yann@2454: }, yann@2454: { yann@2454: .key_str = "F3", yann@2454: .func = "Insts", yann@2454: .key = F_INSTS, yann@2454: .handler = handle_f3, yann@2454: }, yann@2454: { yann@2454: .key_str = "F4", yann@2454: .func = "Config", yann@2454: .key = F_CONF, yann@2454: .handler = handle_f4, yann@2454: }, yann@2454: { yann@2454: .key_str = "F5", yann@2454: .func = "Back", yann@2454: .key = F_BACK, yann@2454: .handler = handle_f5, yann@2454: }, yann@2454: { yann@2454: .key_str = "F6", yann@2454: .func = "Save", yann@2454: .key = F_SAVE, yann@2454: .handler = handle_f6, yann@2454: }, yann@2454: { yann@2454: .key_str = "F7", yann@2454: .func = "Load", yann@2454: .key = F_LOAD, yann@2454: .handler = handle_f7, yann@2454: }, yann@2454: { yann@2454: .key_str = "F8", yann@2454: .func = "Sym Search", yann@2454: .key = F_SEARCH, yann@2454: .handler = handle_f8, yann@2454: }, yann@2454: { yann@2454: .key_str = "F9", yann@2454: .func = "Exit", yann@2454: .key = F_EXIT, yann@2454: .handler = handle_f9, yann@2454: }, yann@2454: }; yann@2454: yann@2454: static void print_function_line(void) yann@2454: { yann@2454: int i; yann@2454: int offset = 1; yann@2454: const int skip = 1; yann@2454: yann@2454: for (i = 0; i < function_keys_num; i++) { yann@2454: (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); yann@2454: mvwprintw(main_window, LINES-3, offset, yann@2454: "%s", yann@2454: function_keys[i].key_str); yann@2454: (void) wattrset(main_window, attributes[FUNCTION_TEXT]); yann@2454: offset += strlen(function_keys[i].key_str); yann@2454: mvwprintw(main_window, LINES-3, yann@2454: offset, "%s", yann@2454: function_keys[i].func); yann@2454: offset += strlen(function_keys[i].func) + skip; yann@2454: } yann@2454: (void) wattrset(main_window, attributes[NORMAL]); yann@2454: } yann@2454: yann@2454: /* help */ yann@2454: static void handle_f1(int *key, struct menu *current_item) yann@2454: { yann@2454: show_scroll_win(main_window, yann@2454: _("README"), _(nconf_readme)); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* symbole help */ yann@2454: static void handle_f2(int *key, struct menu *current_item) yann@2454: { yann@2454: show_help(current_item); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* instructions */ yann@2454: static void handle_f3(int *key, struct menu *current_item) yann@2454: { yann@2454: show_scroll_win(main_window, yann@2454: _("Instructions"), yann@2454: _(current_instructions)); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* config */ yann@2454: static void handle_f4(int *key, struct menu *current_item) yann@2454: { yann@2454: int res = btn_dialog(main_window, yann@2454: _("Show all symbols?"), yann@2454: 2, yann@2454: " ", yann@2454: ""); yann@2454: if (res == 0) yann@2454: show_all_items = 1; yann@2454: else if (res == 1) yann@2454: show_all_items = 0; yann@2454: yann@2454: return; yann@2454: } yann@2454: yann@2454: /* back */ yann@2454: static void handle_f5(int *key, struct menu *current_item) yann@2454: { yann@2454: *key = KEY_LEFT; yann@2454: return; yann@2454: } yann@2454: yann@2454: /* save */ yann@2454: static void handle_f6(int *key, struct menu *current_item) yann@2454: { yann@2454: conf_save(); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* load */ yann@2454: static void handle_f7(int *key, struct menu *current_item) yann@2454: { yann@2454: conf_load(); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* search */ yann@2454: static void handle_f8(int *key, struct menu *current_item) yann@2454: { yann@2454: search_conf(); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* exit */ yann@2454: static void handle_f9(int *key, struct menu *current_item) yann@2454: { yann@2454: do_exit(); yann@2454: return; yann@2454: } yann@2454: yann@2454: /* return != 0 to indicate the key was handles */ yann@2454: static int process_special_keys(int *key, struct menu *menu) yann@2454: { yann@2454: int i; yann@2454: yann@2454: if (*key == KEY_RESIZE) { yann@2454: setup_windows(); yann@2454: return 1; yann@2454: } yann@2454: yann@2454: for (i = 0; i < function_keys_num; i++) { yann@2454: if (*key == KEY_F(function_keys[i].key) || yann@2454: *key == '0' + function_keys[i].key){ yann@2454: function_keys[i].handler(key, menu); yann@2454: return 1; yann@2454: } yann@2454: } yann@2454: yann@2454: return 0; yann@2454: } yann@2454: yann@2454: static void clean_items(void) yann@2454: { yann@2454: int i; yann@2454: for (i = 0; curses_menu_items[i]; i++) yann@2454: free_item(curses_menu_items[i]); yann@2454: bzero(curses_menu_items, sizeof(curses_menu_items)); yann@2454: bzero(k_menu_items, sizeof(k_menu_items)); yann@2454: items_num = 0; yann@2454: } yann@2454: yann@2454: typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN, yann@2454: FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f; yann@2454: yann@2454: /* return the index of the matched item, or -1 if no such item exists */ yann@2454: static int get_mext_match(const char *match_str, match_f flag) yann@2454: { yann@2454: int match_start = item_index(current_item(curses_menu)); yann@2454: int index; yann@2454: yann@2454: if (flag == FIND_NEXT_MATCH_DOWN) yann@2454: ++match_start; yann@2454: else if (flag == FIND_NEXT_MATCH_UP) yann@2454: --match_start; yann@2454: yann@2454: index = match_start; yann@2454: index = (index + items_num) % items_num; yann@2454: while (true) { yann@2454: char *str = k_menu_items[index].str; yann@2454: if (strcasestr(str, match_str) != 0) yann@2454: return index; yann@2454: if (flag == FIND_NEXT_MATCH_UP || yann@2454: flag == MATCH_TINKER_PATTERN_UP) yann@2454: --index; yann@2454: else yann@2454: ++index; yann@2454: index = (index + items_num) % items_num; yann@2454: if (index == match_start) yann@2454: return -1; yann@2454: } yann@2454: } yann@2454: yann@2454: /* Make a new item. */ yann@2454: static void item_make(struct menu *menu, char tag, const char *fmt, ...) yann@2454: { yann@2454: va_list ap; yann@2454: yann@2454: if (items_num > MAX_MENU_ITEMS-1) yann@2454: return; yann@2454: yann@2454: bzero(&k_menu_items[items_num], sizeof(k_menu_items[0])); yann@2454: k_menu_items[items_num].tag = tag; yann@2454: k_menu_items[items_num].usrptr = menu; yann@2454: if (menu != NULL) yann@2454: k_menu_items[items_num].is_visible = yann@2454: menu_is_visible(menu); yann@2454: else yann@2454: k_menu_items[items_num].is_visible = 1; yann@2454: yann@2454: va_start(ap, fmt); yann@2454: vsnprintf(k_menu_items[items_num].str, yann@2454: sizeof(k_menu_items[items_num].str), yann@2454: fmt, ap); yann@2454: va_end(ap); yann@2454: yann@2454: if (!k_menu_items[items_num].is_visible) yann@2454: memcpy(k_menu_items[items_num].str, "XXX", 3); yann@2454: yann@2454: curses_menu_items[items_num] = new_item( yann@2454: k_menu_items[items_num].str, yann@2454: k_menu_items[items_num].str); yann@2454: set_item_userptr(curses_menu_items[items_num], yann@2454: &k_menu_items[items_num]); yann@2454: /* yann@2454: if (!k_menu_items[items_num].is_visible) yann@2454: item_opts_off(curses_menu_items[items_num], O_SELECTABLE); yann@2454: */ yann@2454: yann@2454: items_num++; yann@2454: curses_menu_items[items_num] = NULL; yann@2454: } yann@2454: yann@2454: /* very hackish. adds a string to the last item added */ yann@2454: static void item_add_str(const char *fmt, ...) yann@2454: { yann@2454: va_list ap; yann@2454: int index = items_num-1; yann@2454: char new_str[256]; yann@2454: char tmp_str[256]; yann@2454: yann@2454: if (index < 0) yann@2454: return; yann@2454: yann@2454: va_start(ap, fmt); yann@2454: vsnprintf(new_str, sizeof(new_str), fmt, ap); yann@2454: va_end(ap); yann@2454: snprintf(tmp_str, sizeof(tmp_str), "%s%s", yann@2454: k_menu_items[index].str, new_str); yann@2454: strncpy(k_menu_items[index].str, yann@2454: tmp_str, yann@2454: sizeof(k_menu_items[index].str)); yann@2454: yann@2454: free_item(curses_menu_items[index]); yann@2454: curses_menu_items[index] = new_item( yann@2454: k_menu_items[index].str, yann@2454: k_menu_items[index].str); yann@2454: set_item_userptr(curses_menu_items[index], yann@2454: &k_menu_items[index]); yann@2454: } yann@2454: yann@2454: /* get the tag of the currently selected item */ yann@2454: static char item_tag(void) yann@2454: { yann@2454: ITEM *cur; yann@2454: struct mitem *mcur; yann@2454: yann@2454: cur = current_item(curses_menu); yann@2454: if (cur == NULL) yann@2454: return 0; yann@2454: mcur = (struct mitem *) item_userptr(cur); yann@2454: return mcur->tag; yann@2454: } yann@2454: yann@2454: static int curses_item_index(void) yann@2454: { yann@2454: return item_index(current_item(curses_menu)); yann@2454: } yann@2454: yann@2454: static void *item_data(void) yann@2454: { yann@2454: ITEM *cur; yann@2454: struct mitem *mcur; yann@2454: yann@2454: cur = current_item(curses_menu); yann@2454: if (!cur) yann@2454: return NULL; yann@2454: mcur = (struct mitem *) item_userptr(cur); yann@2454: return mcur->usrptr; yann@2454: yann@2454: } yann@2454: yann@2454: static int item_is_tag(char tag) yann@2454: { yann@2454: return item_tag() == tag; yann@2454: } yann@2454: yann@2454: static char filename[PATH_MAX+1]; yann@2454: static char menu_backtitle[PATH_MAX+128]; yann@2454: static const char *set_config_filename(const char *config_filename) yann@2454: { yann@2454: int size; yann@2454: yann@2454: size = snprintf(menu_backtitle, sizeof(menu_backtitle), yann@2454: "%s - %s", config_filename, rootmenu.prompt->text); yann@2454: if (size >= sizeof(menu_backtitle)) yann@2454: menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; yann@2454: yann@2454: size = snprintf(filename, sizeof(filename), "%s", config_filename); yann@2454: if (size >= sizeof(filename)) yann@2454: filename[sizeof(filename)-1] = '\0'; yann@2454: return menu_backtitle; yann@2454: } yann@2454: yann@2454: /* return = 0 means we are successful. yann@2454: * -1 means go on doing what you were doing yann@2454: */ yann@2454: static int do_exit(void) yann@2454: { yann@2454: int res; yann@2454: if (!conf_get_changed()) { yann@2454: global_exit = 1; yann@2454: return 0; yann@2454: } yann@2454: res = btn_dialog(main_window, yann@2454: _("Do you wish to save your new configuration?\n" yann@2454: " to cancel and resume nconfig."), yann@2454: 2, yann@2454: " ", yann@2454: ""); yann@2454: if (res == KEY_EXIT) { yann@2454: global_exit = 0; yann@2454: return -1; yann@2454: } yann@2454: yann@2454: /* if we got here, the user really wants to exit */ yann@2454: switch (res) { yann@2454: case 0: yann@2454: res = conf_write(filename); yann@2454: if (res) yann@2454: btn_dialog( yann@2454: main_window, yann@2454: _("Error during writing of configuration.\n" yann@2454: "Your configuration changes were NOT saved."), yann@2454: 1, yann@2454: ""); yann@2454: break; yann@2454: default: yann@2454: btn_dialog( yann@2454: main_window, yann@2454: _("Your configuration changes were NOT saved."), yann@2454: 1, yann@2454: ""); yann@2454: break; yann@2454: } yann@2454: global_exit = 1; yann@2454: return 0; yann@2454: } yann@2454: yann@2454: yann@2454: static void search_conf(void) yann@2454: { yann@2454: struct symbol **sym_arr; yann@2454: struct gstr res; yann@2454: char dialog_input_result[100]; yann@2454: char *dialog_input; yann@2454: int dres; yann@2454: again: yann@2454: dres = dialog_inputbox(main_window, yann@2454: _("Search Configuration Parameter"), yann@2454: _("Enter " CONFIG_ " (sub)string to search for " yann@2454: "(with or without \"" CONFIG_ "\")"), yann@2454: "", dialog_input_result, 99); yann@2454: switch (dres) { yann@2454: case 0: yann@2454: break; yann@2454: case 1: yann@2454: show_scroll_win(main_window, yann@2454: _("Search Configuration"), search_help); yann@2454: goto again; yann@2454: default: yann@2454: return; yann@2454: } yann@2454: yann@2454: /* strip the prefix if necessary */ yann@2454: dialog_input = dialog_input_result; yann@2454: if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0) yann@2454: dialog_input += strlen(CONFIG_); yann@2454: yann@2454: sym_arr = sym_re_search(dialog_input); yann@2454: res = get_relations_str(sym_arr); yann@2454: free(sym_arr); yann@2454: show_scroll_win(main_window, yann@2454: _("Search Results"), str_get(&res)); yann@2454: str_free(&res); yann@2454: } yann@2454: yann@2454: yann@2454: static void build_conf(struct menu *menu) yann@2454: { yann@2454: struct symbol *sym; yann@2454: struct property *prop; yann@2454: struct menu *child; yann@2454: int type, tmp, doint = 2; yann@2454: tristate val; yann@2454: char ch; yann@2454: yann@2454: if (!menu || (!show_all_items && !menu_is_visible(menu))) yann@2454: return; yann@2454: yann@2454: sym = menu->sym; yann@2454: prop = menu->prompt; yann@2454: if (!sym) { yann@2454: if (prop && menu != current_menu) { yann@2454: const char *prompt = menu_get_prompt(menu); yann@2454: enum prop_type ptype; yann@2454: ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; yann@2454: switch (ptype) { yann@2454: case P_MENU: yann@2454: child_count++; yann@2454: prompt = _(prompt); yann@2454: if (single_menu_mode) { yann@2454: item_make(menu, 'm', yann@2454: "%s%*c%s", yann@2454: menu->data ? "-->" : "++>", yann@2454: indent + 1, ' ', prompt); yann@2454: } else yann@2454: item_make(menu, 'm', yann@2454: " %*c%s --->", yann@2454: indent + 1, yann@2454: ' ', prompt); yann@2454: yann@2454: if (single_menu_mode && menu->data) yann@2454: goto conf_childs; yann@2454: return; yann@2454: case P_COMMENT: yann@2454: if (prompt) { yann@2454: child_count++; yann@2454: item_make(menu, ':', yann@2454: " %*c*** %s ***", yann@2454: indent + 1, ' ', yann@2454: _(prompt)); yann@2454: } yann@2454: break; yann@2454: default: yann@2454: if (prompt) { yann@2454: child_count++; yann@2454: item_make(menu, ':', "---%*c%s", yann@2454: indent + 1, ' ', yann@2454: _(prompt)); yann@2454: } yann@2454: } yann@2454: } else yann@2454: doint = 0; yann@2454: goto conf_childs; yann@2454: } yann@2454: yann@2454: type = sym_get_type(sym); yann@2454: if (sym_is_choice(sym)) { yann@2454: struct symbol *def_sym = sym_get_choice_value(sym); yann@2454: struct menu *def_menu = NULL; yann@2454: yann@2454: child_count++; yann@2454: for (child = menu->list; child; child = child->next) { yann@2454: if (menu_is_visible(child) && child->sym == def_sym) yann@2454: def_menu = child; yann@2454: } yann@2454: yann@2454: val = sym_get_tristate_value(sym); yann@2454: if (sym_is_changable(sym)) { yann@2454: switch (type) { yann@2454: case S_BOOLEAN: yann@2454: item_make(menu, 't', "[%c]", yann@2454: val == no ? ' ' : '*'); yann@2454: break; yann@2454: case S_TRISTATE: yann@2454: switch (val) { yann@2454: case yes: yann@2454: ch = '*'; yann@2454: break; yann@2454: case mod: yann@2454: ch = 'M'; yann@2454: break; yann@2454: default: yann@2454: ch = ' '; yann@2454: break; yann@2454: } yann@2454: item_make(menu, 't', "<%c>", ch); yann@2454: break; yann@2454: } yann@2454: } else { yann@2454: item_make(menu, def_menu ? 't' : ':', " "); yann@2454: } yann@2454: yann@2454: item_add_str("%*c%s", indent + 1, yann@2454: ' ', _(menu_get_prompt(menu))); yann@2454: if (val == yes) { yann@2454: if (def_menu) { yann@2454: item_add_str(" (%s)", yann@2454: _(menu_get_prompt(def_menu))); yann@2454: item_add_str(" --->"); yann@2454: if (def_menu->list) { yann@2454: indent += 2; yann@2454: build_conf(def_menu); yann@2454: indent -= 2; yann@2454: } yann@2454: } yann@2454: return; yann@2454: } yann@2454: } else { yann@2454: if (menu == current_menu) { yann@2454: item_make(menu, ':', yann@2454: "---%*c%s", indent + 1, yann@2454: ' ', _(menu_get_prompt(menu))); yann@2454: goto conf_childs; yann@2454: } yann@2454: child_count++; yann@2454: val = sym_get_tristate_value(sym); yann@2454: if (sym_is_choice_value(sym) && val == yes) { yann@2454: item_make(menu, ':', " "); yann@2454: } else { yann@2454: switch (type) { yann@2454: case S_BOOLEAN: yann@2454: if (sym_is_changable(sym)) yann@2454: item_make(menu, 't', "[%c]", yann@2454: val == no ? ' ' : '*'); yann@2454: else yann@2454: item_make(menu, 't', "-%c-", yann@2454: val == no ? ' ' : '*'); yann@2454: break; yann@2454: case S_TRISTATE: yann@2454: switch (val) { yann@2454: case yes: yann@2454: ch = '*'; yann@2454: break; yann@2454: case mod: yann@2454: ch = 'M'; yann@2454: break; yann@2454: default: yann@2454: ch = ' '; yann@2454: break; yann@2454: } yann@2454: if (sym_is_changable(sym)) { yann@2454: if (sym->rev_dep.tri == mod) yann@2454: item_make(menu, yann@2454: 't', "{%c}", ch); yann@2454: else yann@2454: item_make(menu, yann@2454: 't', "<%c>", ch); yann@2454: } else yann@2454: item_make(menu, 't', "-%c-", ch); yann@2454: break; yann@2454: default: yann@2454: tmp = 2 + strlen(sym_get_string_value(sym)); yann@2454: item_make(menu, 's', " (%s)", yann@2454: sym_get_string_value(sym)); yann@2454: tmp = indent - tmp + 4; yann@2454: if (tmp < 0) yann@2454: tmp = 0; yann@2454: item_add_str("%*c%s%s", tmp, ' ', yann@2454: _(menu_get_prompt(menu)), yann@2454: (sym_has_value(sym) || yann@2454: !sym_is_changable(sym)) ? "" : yann@2454: _(" (NEW)")); yann@2454: goto conf_childs; yann@2454: } yann@2454: } yann@2454: item_add_str("%*c%s%s", indent + 1, ' ', yann@2454: _(menu_get_prompt(menu)), yann@2454: (sym_has_value(sym) || !sym_is_changable(sym)) ? yann@2454: "" : _(" (NEW)")); yann@2454: if (menu->prompt && menu->prompt->type == P_MENU) { yann@2454: item_add_str(" --->"); yann@2454: return; yann@2454: } yann@2454: } yann@2454: yann@2454: conf_childs: yann@2454: indent += doint; yann@2454: for (child = menu->list; child; child = child->next) yann@2454: build_conf(child); yann@2454: indent -= doint; yann@2454: } yann@2454: yann@2454: static void reset_menu(void) yann@2454: { yann@2454: unpost_menu(curses_menu); yann@2454: clean_items(); yann@2454: } yann@2454: yann@2454: /* adjust the menu to show this item. yann@2454: * prefer not to scroll the menu if possible*/ yann@2454: static void center_item(int selected_index, int *last_top_row) yann@2454: { yann@2454: int toprow; yann@2454: yann@2454: set_top_row(curses_menu, *last_top_row); yann@2454: toprow = top_row(curses_menu); yann@2454: if (selected_index < toprow || yann@2454: selected_index >= toprow+mwin_max_lines) { yann@2454: toprow = max(selected_index-mwin_max_lines/2, 0); yann@2454: if (toprow >= item_count(curses_menu)-mwin_max_lines) yann@2454: toprow = item_count(curses_menu)-mwin_max_lines; yann@2454: set_top_row(curses_menu, toprow); yann@2454: } yann@2454: set_current_item(curses_menu, yann@2454: curses_menu_items[selected_index]); yann@2454: *last_top_row = toprow; yann@2454: post_menu(curses_menu); yann@2454: refresh_all_windows(main_window); yann@2454: } yann@2454: yann@2454: /* this function assumes reset_menu has been called before */ yann@2454: static void show_menu(const char *prompt, const char *instructions, yann@2454: int selected_index, int *last_top_row) yann@2454: { yann@2454: int maxx, maxy; yann@2454: WINDOW *menu_window; yann@2454: yann@2454: current_instructions = instructions; yann@2454: yann@2454: clear(); yann@2454: (void) wattrset(main_window, attributes[NORMAL]); yann@2454: print_in_middle(stdscr, 1, 0, COLS, yann@2454: menu_backtitle, yann@2454: attributes[MAIN_HEADING]); yann@2454: yann@2454: (void) wattrset(main_window, attributes[MAIN_MENU_BOX]); yann@2454: box(main_window, 0, 0); yann@2454: (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]); yann@2454: mvwprintw(main_window, 0, 3, " %s ", prompt); yann@2454: (void) wattrset(main_window, attributes[NORMAL]); yann@2454: yann@2454: set_menu_items(curses_menu, curses_menu_items); yann@2454: yann@2454: /* position the menu at the middle of the screen */ yann@2454: scale_menu(curses_menu, &maxy, &maxx); yann@2454: maxx = min(maxx, mwin_max_cols-2); yann@2454: maxy = mwin_max_lines; yann@2454: menu_window = derwin(main_window, yann@2454: maxy, yann@2454: maxx, yann@2454: 2, yann@2454: (mwin_max_cols-maxx)/2); yann@2454: keypad(menu_window, TRUE); yann@2454: set_menu_win(curses_menu, menu_window); yann@2454: set_menu_sub(curses_menu, menu_window); yann@2454: yann@2454: /* must reassert this after changing items, otherwise returns to a yann@2454: * default of 16 yann@2454: */ yann@2454: set_menu_format(curses_menu, maxy, 1); yann@2454: center_item(selected_index, last_top_row); yann@2454: set_menu_format(curses_menu, maxy, 1); yann@2454: yann@2454: print_function_line(); yann@2454: yann@2454: /* Post the menu */ yann@2454: post_menu(curses_menu); yann@2454: refresh_all_windows(main_window); yann@2454: } yann@2454: yann@2454: static void adj_match_dir(match_f *match_direction) yann@2454: { yann@2454: if (*match_direction == FIND_NEXT_MATCH_DOWN) yann@2454: *match_direction = yann@2454: MATCH_TINKER_PATTERN_DOWN; yann@2454: else if (*match_direction == FIND_NEXT_MATCH_UP) yann@2454: *match_direction = yann@2454: MATCH_TINKER_PATTERN_UP; yann@2454: /* else, do no change.. */ yann@2454: } yann@2454: yann@2454: struct match_state yann@2454: { yann@2454: int in_search; yann@2454: match_f match_direction; yann@2454: char pattern[256]; yann@2454: }; yann@2454: yann@2454: /* Return 0 means I have handled the key. In such a case, ans should hold the yann@2454: * item to center, or -1 otherwise. yann@2454: * Else return -1 . yann@2454: */ yann@2454: static int do_match(int key, struct match_state *state, int *ans) yann@2454: { yann@2454: char c = (char) key; yann@2454: int terminate_search = 0; yann@2454: *ans = -1; yann@2454: if (key == '/' || (state->in_search && key == 27)) { yann@2454: move(0, 0); yann@2454: refresh(); yann@2454: clrtoeol(); yann@2454: state->in_search = 1-state->in_search; yann@2454: bzero(state->pattern, sizeof(state->pattern)); yann@2454: state->match_direction = MATCH_TINKER_PATTERN_DOWN; yann@2454: return 0; yann@2454: } else if (!state->in_search) yann@2454: return 1; yann@2454: yann@2454: if (isalnum(c) || isgraph(c) || c == ' ') { yann@2454: state->pattern[strlen(state->pattern)] = c; yann@2454: state->pattern[strlen(state->pattern)] = '\0'; yann@2454: adj_match_dir(&state->match_direction); yann@2454: *ans = get_mext_match(state->pattern, yann@2454: state->match_direction); yann@2454: } else if (key == KEY_DOWN) { yann@2454: state->match_direction = FIND_NEXT_MATCH_DOWN; yann@2454: *ans = get_mext_match(state->pattern, yann@2454: state->match_direction); yann@2454: } else if (key == KEY_UP) { yann@2454: state->match_direction = FIND_NEXT_MATCH_UP; yann@2454: *ans = get_mext_match(state->pattern, yann@2454: state->match_direction); yann@2454: } else if (key == KEY_BACKSPACE || key == 127) { yann@2454: state->pattern[strlen(state->pattern)-1] = '\0'; yann@2454: adj_match_dir(&state->match_direction); yann@2454: } else yann@2454: terminate_search = 1; yann@2454: yann@2454: if (terminate_search) { yann@2454: state->in_search = 0; yann@2454: bzero(state->pattern, sizeof(state->pattern)); yann@2454: move(0, 0); yann@2454: refresh(); yann@2454: clrtoeol(); yann@2454: return -1; yann@2454: } yann@2454: return 0; yann@2454: } yann@2454: yann@2454: static void conf(struct menu *menu) yann@2454: { yann@2454: struct menu *submenu = 0; yann@2454: const char *prompt = menu_get_prompt(menu); yann@2454: struct symbol *sym; yann@2454: struct menu *active_menu = NULL; yann@2454: int res; yann@2454: int current_index = 0; yann@2454: int last_top_row = 0; yann@2454: struct match_state match_state = { yann@2454: .in_search = 0, yann@2454: .match_direction = MATCH_TINKER_PATTERN_DOWN, yann@2454: .pattern = "", yann@2454: }; yann@2454: yann@2454: while (!global_exit) { yann@2454: reset_menu(); yann@2454: current_menu = menu; yann@2454: build_conf(menu); yann@2454: if (!child_count) yann@2454: break; yann@2454: yann@2454: show_menu(prompt ? _(prompt) : _("Main Menu"), yann@2454: _(menu_instructions), yann@2454: current_index, &last_top_row); yann@2454: keypad((menu_win(curses_menu)), TRUE); yann@2454: while (!global_exit) { yann@2454: if (match_state.in_search) { yann@2454: mvprintw(0, 0, yann@2454: "searching: %s", match_state.pattern); yann@2454: clrtoeol(); yann@2454: } yann@2454: refresh_all_windows(main_window); yann@2454: res = wgetch(menu_win(curses_menu)); yann@2454: if (!res) yann@2454: break; yann@2454: if (do_match(res, &match_state, ¤t_index) == 0) { yann@2454: if (current_index != -1) yann@2454: center_item(current_index, yann@2454: &last_top_row); yann@2454: continue; yann@2454: } yann@2454: if (process_special_keys(&res, yann@2454: (struct menu *) item_data())) yann@2454: break; yann@2454: switch (res) { yann@2454: case KEY_DOWN: yann@2454: menu_driver(curses_menu, REQ_DOWN_ITEM); yann@2454: break; yann@2454: case KEY_UP: yann@2454: menu_driver(curses_menu, REQ_UP_ITEM); yann@2454: break; yann@2454: case KEY_NPAGE: yann@2454: menu_driver(curses_menu, REQ_SCR_DPAGE); yann@2454: break; yann@2454: case KEY_PPAGE: yann@2454: menu_driver(curses_menu, REQ_SCR_UPAGE); yann@2454: break; yann@2454: case KEY_HOME: yann@2454: menu_driver(curses_menu, REQ_FIRST_ITEM); yann@2454: break; yann@2454: case KEY_END: yann@2454: menu_driver(curses_menu, REQ_LAST_ITEM); yann@2454: break; yann@2454: case 'h': yann@2454: case '?': yann@2454: show_help((struct menu *) item_data()); yann@2454: break; yann@2454: } yann@2454: if (res == 10 || res == 27 || yann@2454: res == 32 || res == 'n' || res == 'y' || yann@2454: res == KEY_LEFT || res == KEY_RIGHT || yann@2454: res == 'm') yann@2454: break; yann@2454: refresh_all_windows(main_window); yann@2454: } yann@2454: yann@2454: refresh_all_windows(main_window); yann@2454: /* if ESC or left*/ yann@2454: if (res == 27 || (menu != &rootmenu && res == KEY_LEFT)) yann@2454: break; yann@2454: yann@2454: /* remember location in the menu */ yann@2454: last_top_row = top_row(curses_menu); yann@2454: current_index = curses_item_index(); yann@2454: yann@2454: if (!item_tag()) yann@2454: continue; yann@2454: yann@2454: submenu = (struct menu *) item_data(); yann@2454: active_menu = (struct menu *)item_data(); yann@2454: if (!submenu || !menu_is_visible(submenu)) yann@2454: continue; yann@2454: if (submenu) yann@2454: sym = submenu->sym; yann@2454: else yann@2454: sym = NULL; yann@2454: yann@2454: switch (res) { yann@2454: case ' ': yann@2454: if (item_is_tag('t')) yann@2454: sym_toggle_tristate_value(sym); yann@2454: else if (item_is_tag('m')) yann@2454: conf(submenu); yann@2454: break; yann@2454: case KEY_RIGHT: yann@2454: case 10: /* ENTER WAS PRESSED */ yann@2454: switch (item_tag()) { yann@2454: case 'm': yann@2454: if (single_menu_mode) yann@2454: submenu->data = yann@2454: (void *) (long) !submenu->data; yann@2454: else yann@2454: conf(submenu); yann@2454: break; yann@2454: case 't': yann@2454: if (sym_is_choice(sym) && yann@2454: sym_get_tristate_value(sym) == yes) yann@2454: conf_choice(submenu); yann@2454: else if (submenu->prompt && yann@2454: submenu->prompt->type == P_MENU) yann@2454: conf(submenu); yann@2454: else if (res == 10) yann@2454: sym_toggle_tristate_value(sym); yann@2454: break; yann@2454: case 's': yann@2454: conf_string(submenu); yann@2454: break; yann@2454: } yann@2454: break; yann@2454: case 'y': yann@2454: if (item_is_tag('t')) { yann@2454: if (sym_set_tristate_value(sym, yes)) yann@2454: break; yann@2454: if (sym_set_tristate_value(sym, mod)) yann@2454: btn_dialog(main_window, setmod_text, 0); yann@2454: } yann@2454: break; yann@2454: case 'n': yann@2454: if (item_is_tag('t')) yann@2454: sym_set_tristate_value(sym, no); yann@2454: break; yann@2454: case 'm': yann@2454: if (item_is_tag('t')) yann@2454: sym_set_tristate_value(sym, mod); yann@2454: break; yann@2454: } yann@2454: } yann@2454: } yann@2454: yann@2454: static void conf_message_callback(const char *fmt, va_list ap) yann@2454: { yann@2454: char buf[1024]; yann@2454: yann@2454: vsnprintf(buf, sizeof(buf), fmt, ap); yann@2454: btn_dialog(main_window, buf, 1, ""); yann@2454: } yann@2454: yann@2454: static void show_help(struct menu *menu) yann@2454: { yann@2454: struct gstr help = str_new(); yann@2454: yann@2454: if (menu && menu->sym && menu_has_help(menu)) { yann@2454: if (menu->sym->name) { yann@2454: str_printf(&help, "%s%s:\n\n", CONFIG_, menu->sym->name); yann@2454: str_append(&help, _(menu_get_help(menu))); yann@2454: str_append(&help, "\n"); yann@2454: get_symbol_str(&help, menu->sym); yann@2454: } else { yann@2454: str_append(&help, _(menu_get_help(menu))); yann@2454: } yann@2454: } else { yann@2454: str_append(&help, nohelp_text); yann@2454: } yann@2454: show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help)); yann@2454: str_free(&help); yann@2454: } yann@2454: yann@2454: static void conf_choice(struct menu *menu) yann@2454: { yann@2454: const char *prompt = _(menu_get_prompt(menu)); yann@2454: struct menu *child = 0; yann@2454: struct symbol *active; yann@2454: int selected_index = 0; yann@2454: int last_top_row = 0; yann@2454: int res, i = 0; yann@2454: struct match_state match_state = { yann@2454: .in_search = 0, yann@2454: .match_direction = MATCH_TINKER_PATTERN_DOWN, yann@2454: .pattern = "", yann@2454: }; yann@2454: yann@2454: active = sym_get_choice_value(menu->sym); yann@2454: /* this is mostly duplicated from the conf() function. */ yann@2454: while (!global_exit) { yann@2454: reset_menu(); yann@2454: yann@2454: for (i = 0, child = menu->list; child; child = child->next) { yann@2454: if (!show_all_items && !menu_is_visible(child)) yann@2454: continue; yann@2454: yann@2454: if (child->sym == sym_get_choice_value(menu->sym)) yann@2454: item_make(child, ':', " %s", yann@2454: _(menu_get_prompt(child))); yann@2454: else if (child->sym) yann@2454: item_make(child, ':', " %s", yann@2454: _(menu_get_prompt(child))); yann@2454: else yann@2454: item_make(child, ':', "*** %s ***", yann@2454: _(menu_get_prompt(child))); yann@2454: yann@2454: if (child->sym == active){ yann@2454: last_top_row = top_row(curses_menu); yann@2454: selected_index = i; yann@2454: } yann@2454: i++; yann@2454: } yann@2454: show_menu(prompt ? _(prompt) : _("Choice Menu"), yann@2454: _(radiolist_instructions), yann@2454: selected_index, yann@2454: &last_top_row); yann@2454: while (!global_exit) { yann@2454: if (match_state.in_search) { yann@2454: mvprintw(0, 0, "searching: %s", yann@2454: match_state.pattern); yann@2454: clrtoeol(); yann@2454: } yann@2454: refresh_all_windows(main_window); yann@2454: res = wgetch(menu_win(curses_menu)); yann@2454: if (!res) yann@2454: break; yann@2454: if (do_match(res, &match_state, &selected_index) == 0) { yann@2454: if (selected_index != -1) yann@2454: center_item(selected_index, yann@2454: &last_top_row); yann@2454: continue; yann@2454: } yann@2454: if (process_special_keys( yann@2454: &res, yann@2454: (struct menu *) item_data())) yann@2454: break; yann@2454: switch (res) { yann@2454: case KEY_DOWN: yann@2454: menu_driver(curses_menu, REQ_DOWN_ITEM); yann@2454: break; yann@2454: case KEY_UP: yann@2454: menu_driver(curses_menu, REQ_UP_ITEM); yann@2454: break; yann@2454: case KEY_NPAGE: yann@2454: menu_driver(curses_menu, REQ_SCR_DPAGE); yann@2454: break; yann@2454: case KEY_PPAGE: yann@2454: menu_driver(curses_menu, REQ_SCR_UPAGE); yann@2454: break; yann@2454: case KEY_HOME: yann@2454: menu_driver(curses_menu, REQ_FIRST_ITEM); yann@2454: break; yann@2454: case KEY_END: yann@2454: menu_driver(curses_menu, REQ_LAST_ITEM); yann@2454: break; yann@2454: case 'h': yann@2454: case '?': yann@2454: show_help((struct menu *) item_data()); yann@2454: break; yann@2454: } yann@2454: if (res == 10 || res == 27 || res == ' ' || yann@2454: res == KEY_LEFT){ yann@2454: break; yann@2454: } yann@2454: refresh_all_windows(main_window); yann@2454: } yann@2454: /* if ESC or left */ yann@2454: if (res == 27 || res == KEY_LEFT) yann@2454: break; yann@2454: yann@2454: child = item_data(); yann@2454: if (!child || !menu_is_visible(child) || !child->sym) yann@2454: continue; yann@2454: switch (res) { yann@2454: case ' ': yann@2454: case 10: yann@2454: case KEY_RIGHT: yann@2454: sym_set_tristate_value(child->sym, yes); yann@2454: return; yann@2454: case 'h': yann@2454: case '?': yann@2454: show_help(child); yann@2454: active = child->sym; yann@2454: break; yann@2454: case KEY_EXIT: yann@2454: return; yann@2454: } yann@2454: } yann@2454: } yann@2454: yann@2454: static void conf_string(struct menu *menu) yann@2454: { yann@2454: const char *prompt = menu_get_prompt(menu); yann@2454: char dialog_input_result[256]; yann@2454: yann@2454: while (1) { yann@2454: int res; yann@2454: const char *heading; yann@2454: yann@2454: switch (sym_get_type(menu->sym)) { yann@2454: case S_INT: yann@2454: heading = _(inputbox_instructions_int); yann@2454: break; yann@2454: case S_HEX: yann@2454: heading = _(inputbox_instructions_hex); yann@2454: break; yann@2454: case S_STRING: yann@2454: heading = _(inputbox_instructions_string); yann@2454: break; yann@2454: default: yann@2454: heading = _("Internal nconf error!"); yann@2454: } yann@2454: res = dialog_inputbox(main_window, yann@2454: prompt ? _(prompt) : _("Main Menu"), yann@2454: heading, yann@2454: sym_get_string_value(menu->sym), yann@2454: dialog_input_result, yann@2454: sizeof(dialog_input_result)); yann@2454: switch (res) { yann@2454: case 0: yann@2454: if (sym_set_string_value(menu->sym, yann@2454: dialog_input_result)) yann@2454: return; yann@2454: btn_dialog(main_window, yann@2454: _("You have made an invalid entry."), 0); yann@2454: break; yann@2454: case 1: yann@2454: show_help(menu); yann@2454: break; yann@2454: case KEY_EXIT: yann@2454: return; yann@2454: } yann@2454: } yann@2454: } yann@2454: yann@2454: static void conf_load(void) yann@2454: { yann@2454: char dialog_input_result[256]; yann@2454: while (1) { yann@2454: int res; yann@2454: res = dialog_inputbox(main_window, yann@2454: NULL, load_config_text, yann@2454: filename, yann@2454: dialog_input_result, yann@2454: sizeof(dialog_input_result)); yann@2454: switch (res) { yann@2454: case 0: yann@2454: if (!dialog_input_result[0]) yann@2454: return; yann@2454: if (!conf_read(dialog_input_result)) { yann@2454: set_config_filename(dialog_input_result); yann@2454: sym_set_change_count(1); yann@2454: return; yann@2454: } yann@2454: btn_dialog(main_window, _("File does not exist!"), 0); yann@2454: break; yann@2454: case 1: yann@2454: show_scroll_win(main_window, yann@2454: _("Load Alternate Configuration"), yann@2454: load_config_help); yann@2454: break; yann@2454: case KEY_EXIT: yann@2454: return; yann@2454: } yann@2454: } yann@2454: } yann@2454: yann@2454: static void conf_save(void) yann@2454: { yann@2454: char dialog_input_result[256]; yann@2454: while (1) { yann@2454: int res; yann@2454: res = dialog_inputbox(main_window, yann@2454: NULL, save_config_text, yann@2454: filename, yann@2454: dialog_input_result, yann@2454: sizeof(dialog_input_result)); yann@2454: switch (res) { yann@2454: case 0: yann@2454: if (!dialog_input_result[0]) yann@2454: return; yann@2454: res = conf_write(dialog_input_result); yann@2454: if (!res) { yann@2454: set_config_filename(dialog_input_result); yann@2454: return; yann@2454: } yann@2454: btn_dialog(main_window, _("Can't create file! " yann@2454: "Probably a nonexistent directory."), yann@2454: 1, ""); yann@2454: break; yann@2454: case 1: yann@2454: show_scroll_win(main_window, yann@2454: _("Save Alternate Configuration"), yann@2454: save_config_help); yann@2454: break; yann@2454: case KEY_EXIT: yann@2454: return; yann@2454: } yann@2454: } yann@2454: } yann@2454: yann@2454: void setup_windows(void) yann@2454: { yann@2454: if (main_window != NULL) yann@2454: delwin(main_window); yann@2454: yann@2454: /* set up the menu and menu window */ yann@2454: main_window = newwin(LINES-2, COLS-2, 2, 1); yann@2454: keypad(main_window, TRUE); yann@2454: mwin_max_lines = LINES-7; yann@2454: mwin_max_cols = COLS-6; yann@2454: yann@2454: /* panels order is from bottom to top */ yann@2454: new_panel(main_window); yann@2454: } yann@2454: yann@2454: int main(int ac, char **av) yann@2454: { yann@2454: char *mode; yann@2454: yann@2454: setlocale(LC_ALL, ""); yann@2454: bindtextdomain(PACKAGE, LOCALEDIR); yann@2454: textdomain(PACKAGE); yann@2454: yann@2454: conf_parse(av[1]); yann@2454: conf_read(NULL); yann@2454: yann@2454: mode = getenv("NCONFIG_MODE"); yann@2454: if (mode) { yann@2454: if (!strcasecmp(mode, "single_menu")) yann@2454: single_menu_mode = 1; yann@2454: } yann@2454: yann@2454: /* Initialize curses */ yann@2454: initscr(); yann@2454: /* set color theme */ yann@2454: set_colors(); yann@2454: yann@2454: cbreak(); yann@2454: noecho(); yann@2454: keypad(stdscr, TRUE); yann@2454: curs_set(0); yann@2454: yann@2454: if (COLS < 75 || LINES < 20) { yann@2454: endwin(); yann@2454: printf("Your terminal should have at " yann@2454: "least 20 lines and 75 columns\n"); yann@2454: return 1; yann@2454: } yann@2454: yann@2454: notimeout(stdscr, FALSE); yann@2454: ESCDELAY = 1; yann@2454: yann@2454: /* set btns menu */ yann@2454: curses_menu = new_menu(curses_menu_items); yann@2454: menu_opts_off(curses_menu, O_SHOWDESC); yann@2454: menu_opts_on(curses_menu, O_SHOWMATCH); yann@2454: menu_opts_on(curses_menu, O_ONEVALUE); yann@2454: menu_opts_on(curses_menu, O_NONCYCLIC); yann@2454: menu_opts_on(curses_menu, O_IGNORECASE); yann@2454: set_menu_mark(curses_menu, " "); yann@2454: set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); yann@2454: set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); yann@2454: set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); yann@2454: yann@2454: set_config_filename(conf_get_configname()); yann@2454: setup_windows(); yann@2454: yann@2454: /* check for KEY_FUNC(1) */ yann@2454: if (has_key(KEY_F(1)) == FALSE) { yann@2454: show_scroll_win(main_window, yann@2454: _("Instructions"), yann@2454: _(menu_no_f_instructions)); yann@2454: } yann@2454: yann@2454: conf_set_message_callback(conf_message_callback); yann@2454: /* do the work */ yann@2454: while (!global_exit) { yann@2454: conf(&rootmenu); yann@2454: if (!global_exit && do_exit() == 0) yann@2454: break; yann@2454: } yann@2454: /* ok, we are done */ yann@2454: unpost_menu(curses_menu); yann@2454: free_menu(curses_menu); yann@2454: delwin(main_window); yann@2454: clear(); yann@2454: refresh(); yann@2454: endwin(); yann@2454: return 0; yann@2454: } yann@2454: