yann@1: /* yann@1: * Copyright (C) 2002 Roman Zippel yann@1: * Released under the terms of the GNU GPL v2.0. yann@1: * yann@1: * Introduced single menu mode (show all sub-menus in one large tree). yann@1: * 2002-11-06 Petr Baudis yann@1: * yann@1: * i18n, 2005, Arnaldo Carvalho de Melo yann@1: */ yann@1: yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: #include yann@1: yann@1: #define LKC_DIRECT_LINK yann@1: #include "lkc.h" yann@1: #include "lxdialog/dialog.h" yann@1: yann@1: static char menu_backtitle[128]; yann@1: static const char mconf_readme[] = N_( yann@1: "Overview\n" yann@1: "--------\n" yann@1: "Some kernel features may be built directly into the kernel.\n" yann@1: "Some may be made into loadable runtime modules. Some features\n" yann@1: "may be completely removed altogether. There are also certain\n" yann@1: "kernel parameters which are not really features, but must be\n" yann@1: "entered in as decimal or hexadecimal numbers or possibly text.\n" yann@1: "\n" yann@1: "Menu items beginning with [*], or [ ] represent features\n" yann@1: "configured to be built in, modularized or removed respectively.\n" yann@1: "Pointed brackets <> represent module capable features.\n" yann@1: "\n" yann@1: "To change any of these features, highlight it with the cursor\n" yann@1: "keys and press to build it in, to make it a module or\n" yann@1: " to removed it. You may also press the to cycle\n" yann@1: "through the available options (ie. Y->N->M->Y).\n" yann@1: "\n" yann@1: "Some additional keyboard hints:\n" yann@1: "\n" yann@1: "Menus\n" yann@1: "----------\n" yann@1: "o Use the Up/Down arrow keys (cursor keys) to highlight the item\n" yann@1: " you wish to change or submenu wish to select and press .\n" yann@1: " Submenus are designated by \"--->\".\n" yann@1: "\n" yann@1: " Shortcut: Press the option's highlighted letter (hotkey).\n" yann@1: " Pressing a hotkey more than once will sequence\n" yann@1: " through all visible items which use that hotkey.\n" yann@1: "\n" yann@1: " You may also use the and keys to scroll\n" yann@1: " unseen options into view.\n" yann@1: "\n" yann@1: "o To exit a menu use the cursor keys to highlight the button\n" yann@1: " and press .\n" yann@1: "\n" yann@1: " Shortcut: Press or or if there is no hotkey\n" yann@1: " using those letters. You may press a single , but\n" yann@1: " there is a delayed response which you may find annoying.\n" yann@1: "\n" yann@1: " Also, the and cursor keys will cycle between and\n" yann@1: " \n" yann@1: "\n" yann@1: "\n" yann@1: "Data Entry\n" yann@1: "-----------\n" yann@1: "o Enter the requested information and press \n" yann@1: " If you are entering hexadecimal values, it is not necessary to\n" yann@1: " add the '0x' prefix to the entry.\n" yann@1: "\n" yann@1: "o For help, use the or cursor keys to highlight the help option\n" yann@1: " and press . You can try as well.\n" yann@1: "\n" yann@1: "\n" yann@1: "Text Box (Help Window)\n" yann@1: "--------\n" yann@1: "o Use the cursor keys to scroll up/down/left/right. The VI editor\n" yann@1: " keys h,j,k,l function here as do and for those\n" yann@1: " who are familiar with less and lynx.\n" yann@1: "\n" yann@1: "o Press , , or to exit.\n" yann@1: "\n" yann@1: "\n" yann@1: "Alternate Configuration Files\n" yann@1: "-----------------------------\n" yann@1: "Menuconfig supports the use of alternate configuration files for\n" yann@1: "those who, for various reasons, find it necessary to switch\n" yann@1: "between different kernel configurations.\n" yann@1: "\n" yann@1: "At the end of the main menu you will find two options. One is\n" yann@1: "for saving the current configuration to a file of your choosing.\n" yann@1: "The other option is for loading a previously saved alternate\n" yann@1: "configuration.\n" yann@1: "\n" yann@1: "Even if you don't use alternate configuration files, but you\n" yann@1: "find during a Menuconfig session that you have completely messed\n" yann@1: "up your settings, you may use the \"Load Alternate...\" option to\n" yann@1: "restore your previously saved settings from \".config\" without\n" yann@1: "restarting Menuconfig.\n" yann@1: "\n" yann@1: "Other information\n" yann@1: "-----------------\n" yann@1: "If you use Menuconfig in an XTERM window make sure you have your\n" yann@1: "$TERM variable set to point to a xterm definition which supports color.\n" yann@1: "Otherwise, Menuconfig will look rather bad. Menuconfig will not\n" yann@1: "display correctly in a RXVT window because rxvt displays only one\n" yann@1: "intensity of color, bright.\n" yann@1: "\n" yann@1: "Menuconfig will display larger menus on screens or xterms which are\n" yann@1: "set to display more than the standard 25 row by 80 column geometry.\n" yann@1: "In order for this to work, the \"stty size\" command must be able to\n" yann@1: "display the screen's current row and column geometry. I STRONGLY\n" yann@1: "RECOMMEND that you make sure you do NOT have the shell variables\n" yann@1: "LINES and COLUMNS exported into your environment. Some distributions\n" yann@1: "export those variables via /etc/profile. Some ncurses programs can\n" yann@1: "become confused when those variables (LINES & COLUMNS) don't reflect\n" yann@1: "the true screen size.\n" yann@1: "\n" yann@1: "Optional personality available\n" yann@1: "------------------------------\n" yann@1: "If you prefer to have all of the kernel options listed in a single\n" yann@1: "menu, rather than the default multimenu hierarchy, run the menuconfig\n" yann@1: "with MENUCONFIG_MODE environment variable set to single_menu. Example:\n" yann@1: "\n" yann@1: "make MENUCONFIG_MODE=single_menu menuconfig\n" yann@1: "\n" yann@1: " will then unroll the appropriate category, or enfold it if it\n" yann@1: "is already unrolled.\n" yann@1: "\n" yann@1: "Note that this mode can eventually be a little more CPU expensive\n" yann@1: "(especially with a larger number of unrolled categories) than the\n" yann@1: "default mode.\n" yann@1: "\n" yann@1: "Different color themes available\n" yann@1: "--------------------------------\n" yann@1: "It is possible to select different color themes using the variable\n" yann@1: "MENUCONFIG_COLOR. To select a theme use:\n" yann@1: "\n" yann@1: "make MENUCONFIG_COLOR= menuconfig\n" yann@1: "\n" yann@1: "Available themes are\n" yann@1: " mono => selects colors suitable for monochrome displays\n" yann@1: " blackbg => selects a color scheme with black background\n" yann@1: " classic => theme with blue background. The classic look\n" yann@1: " bluetitle => a LCD friendly version of classic. (default)\n" yann@1: "\n"), yann@1: menu_instructions[] = N_( yann@1: "Arrow keys navigate the menu. " yann@1: " selects submenus --->. " yann@1: "Highlighted letters are hotkeys. " yann@1: "Pressing includes, excludes, modularizes features. " yann@1: "Press to exit, for Help, for Search. " yann@1: "Legend: [*] built-in [ ] excluded module < > module capable"), yann@1: radiolist_instructions[] = N_( yann@1: "Use the arrow keys to navigate this window or " yann@1: "press the hotkey of the item you wish to select " yann@1: "followed by the . " yann@1: "Press for additional information about this option."), yann@1: inputbox_instructions_int[] = N_( yann@1: "Please enter a decimal value. " yann@1: "Fractions will not be accepted. " yann@1: "Use the key to move from the input field to the buttons below it."), yann@1: inputbox_instructions_hex[] = N_( yann@1: "Please enter a hexadecimal value. " yann@1: "Use the key to move from the input field to the buttons below it."), yann@1: inputbox_instructions_string[] = N_( yann@1: "Please enter a string value. " yann@1: "Use the key to move from the input field to the buttons below it."), yann@1: setmod_text[] = N_( yann@1: "This feature depends on another which has been configured as a module.\n" yann@1: "As a result, this feature will be built as a module."), yann@1: nohelp_text[] = N_( yann@1: "There is no help available for this kernel option.\n"), yann@1: load_config_text[] = N_( yann@1: "Enter the name of the configuration file you wish to load. " yann@1: "Accept the name shown to restore the configuration you " yann@1: "last retrieved. Leave blank to abort."), yann@1: load_config_help[] = N_( yann@1: "\n" yann@1: "For various reasons, one may wish to keep several different kernel\n" yann@1: "configurations available on a single machine.\n" yann@1: "\n" yann@1: "If you have saved a previous configuration in a file other than the\n" yann@1: "kernel's default, entering the name of the file here will allow you\n" yann@1: "to modify that configuration.\n" yann@1: "\n" yann@1: "If you are uncertain, then you have probably never used alternate\n" yann@1: "configuration files. You should therefor leave this blank to abort.\n"), yann@1: save_config_text[] = N_( yann@1: "Enter a filename to which this configuration should be saved " yann@1: "as an alternate. Leave blank to abort."), yann@1: save_config_help[] = N_( yann@1: "\n" yann@1: "For various reasons, one may wish to keep different kernel\n" yann@1: "configurations available on a single machine.\n" yann@1: "\n" yann@1: "Entering a file name here will allow you to later retrieve, modify\n" yann@1: "and use the current configuration as an alternate to whatever\n" yann@1: "configuration options you have selected at that time.\n" yann@1: "\n" yann@1: "If you are uncertain what all this means then you should probably\n" yann@1: "leave this blank.\n"), yann@1: search_help[] = N_( yann@1: "\n" yann@1: "Search for CT_ symbols and display their relations.\n" yann@1: "Regular expressions are allowed.\n" yann@1: "Example: search for \"^FOO\"\n" yann@1: "Result:\n" yann@1: "-----------------------------------------------------------------\n" yann@1: "Symbol: FOO [=m]\n" yann@1: "Prompt: Foo bus is used to drive the bar HW\n" yann@1: "Defined at drivers/pci/Kconfig:47\n" yann@1: "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n" yann@1: "Location:\n" yann@1: " -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n" yann@1: " -> PCI support (PCI [=y])\n" yann@1: " -> PCI access mode ( [=y])\n" yann@1: "Selects: LIBCRC32\n" yann@1: "Selected by: BAR\n" yann@1: "-----------------------------------------------------------------\n" yann@1: "o The line 'Prompt:' shows the text used in the menu structure for\n" yann@1: " this CT_ symbol\n" yann@1: "o The 'Defined at' line tell at what file / line number the symbol\n" yann@1: " is defined\n" yann@1: "o The 'Depends on:' line tell what symbols needs to be defined for\n" yann@1: " this symbol to be visible in the menu (selectable)\n" yann@1: "o The 'Location:' lines tell where in the menu structure this symbol\n" yann@1: " is located\n" yann@1: " A location followed by a [=y] indicate that this is a selectable\n" yann@1: " menu item - and current value is displayed inside brackets.\n" yann@1: "o The 'Selects:' line tell what symbol will be automatically\n" yann@1: " selected if this symbol is selected (y or m)\n" yann@1: "o The 'Selected by' line tell what symbol has selected this symbol\n" yann@1: "\n" yann@1: "Only relevant lines are shown.\n" yann@1: "\n\n" yann@1: "Search examples:\n" yann@1: "Examples: USB => find all CT_ symbols containing USB\n" yann@1: " ^USB => find all CT_ symbols starting with USB\n" yann@1: " USB$ => find all CT_ symbols ending with USB\n" yann@1: "\n"); yann@1: yann@1: static char filename[PATH_MAX+1] = ".config"; yann@1: static int indent; yann@1: static struct termios ios_org; yann@1: static int rows = 0, cols = 0; yann@1: static struct menu *current_menu; yann@1: static int child_count; yann@1: static int single_menu_mode; yann@1: yann@1: static void conf(struct menu *menu); yann@1: static void conf_choice(struct menu *menu); yann@1: static void conf_string(struct menu *menu); yann@1: static void conf_load(void); yann@1: static void conf_save(void); yann@1: static void show_textbox(const char *title, const char *text, int r, int c); yann@1: static void show_helptext(const char *title, const char *text); yann@1: static void show_help(struct menu *menu); yann@1: yann@1: static void init_wsize(void) yann@1: { yann@1: struct winsize ws; yann@1: char *env; yann@1: yann@1: if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)) { yann@1: rows = ws.ws_row; yann@1: cols = ws.ws_col; yann@1: } yann@1: yann@1: if (!rows) { yann@1: env = getenv("LINES"); yann@1: if (env) yann@1: rows = atoi(env); yann@1: if (!rows) yann@1: rows = 24; yann@1: } yann@1: if (!cols) { yann@1: env = getenv("COLUMNS"); yann@1: if (env) yann@1: cols = atoi(env); yann@1: if (!cols) yann@1: cols = 80; yann@1: } yann@1: yann@1: if (rows < 19 || cols < 80) { yann@1: fprintf(stderr, N_("Your display is too small to run Menuconfig!\n")); yann@1: fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n")); yann@1: exit(1); yann@1: } yann@1: yann@1: rows -= 4; yann@1: cols -= 5; yann@1: } yann@1: yann@1: static void get_prompt_str(struct gstr *r, struct property *prop) yann@1: { yann@1: int i, j; yann@1: struct menu *submenu[8], *menu; yann@1: yann@1: str_printf(r, "Prompt: %s\n", prop->text); yann@1: str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, yann@1: prop->menu->lineno); yann@1: if (!expr_is_yes(prop->visible.expr)) { yann@1: str_append(r, " Depends on: "); yann@1: expr_gstr_print(prop->visible.expr, r); yann@1: str_append(r, "\n"); yann@1: } yann@1: menu = prop->menu->parent; yann@1: for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) yann@1: submenu[i++] = menu; yann@1: if (i > 0) { yann@1: str_printf(r, " Location:\n"); yann@1: for (j = 4; --i >= 0; j += 2) { yann@1: menu = submenu[i]; yann@1: str_printf(r, "%*c-> %s", j, ' ', menu_get_prompt(menu)); yann@1: if (menu->sym) { yann@1: str_printf(r, " (%s [=%s])", menu->sym->name ? yann@1: menu->sym->name : "", yann@1: sym_get_string_value(menu->sym)); yann@1: } yann@1: str_append(r, "\n"); yann@1: } yann@1: } yann@1: } yann@1: yann@1: static void get_symbol_str(struct gstr *r, struct symbol *sym) yann@1: { yann@1: bool hit; yann@1: struct property *prop; yann@1: yann@1: str_printf(r, "Symbol: %s [=%s]\n", sym->name, yann@1: sym_get_string_value(sym)); yann@1: for_all_prompts(sym, prop) yann@1: get_prompt_str(r, prop); yann@1: hit = false; yann@1: for_all_properties(sym, prop, P_SELECT) { yann@1: if (!hit) { yann@1: str_append(r, " Selects: "); yann@1: hit = true; yann@1: } else yann@1: str_printf(r, " && "); yann@1: expr_gstr_print(prop->expr, r); yann@1: } yann@1: if (hit) yann@1: str_append(r, "\n"); yann@1: if (sym->rev_dep.expr) { yann@1: str_append(r, " Selected by: "); yann@1: expr_gstr_print(sym->rev_dep.expr, r); yann@1: str_append(r, "\n"); yann@1: } yann@1: str_append(r, "\n\n"); yann@1: } yann@1: yann@1: static struct gstr get_relations_str(struct symbol **sym_arr) yann@1: { yann@1: struct symbol *sym; yann@1: struct gstr res = str_new(); yann@1: int i; yann@1: yann@1: for (i = 0; sym_arr && (sym = sym_arr[i]); i++) yann@1: get_symbol_str(&res, sym); yann@1: if (!i) yann@1: str_append(&res, "No matches found.\n"); yann@1: return res; yann@1: } yann@1: yann@1: static void search_conf(void) yann@1: { yann@1: struct symbol **sym_arr; yann@1: struct gstr res; yann@1: int dres; yann@1: again: yann@1: dialog_clear(); yann@1: dres = dialog_inputbox(_("Search Configuration Parameter"), yann@1: _("Enter CT_ (sub)string to search for (omit CT_)"), yann@1: 10, 75, ""); yann@1: switch (dres) { yann@1: case 0: yann@1: break; yann@1: case 1: yann@1: show_helptext(_("Search Configuration"), search_help); yann@1: goto again; yann@1: default: yann@1: return; yann@1: } yann@1: yann@1: sym_arr = sym_re_search(dialog_input_result); yann@1: res = get_relations_str(sym_arr); yann@1: free(sym_arr); yann@1: show_textbox(_("Search Results"), str_get(&res), 0, 0); yann@1: str_free(&res); yann@1: } yann@1: yann@1: static void build_conf(struct menu *menu) yann@1: { yann@1: struct symbol *sym; yann@1: struct property *prop; yann@1: struct menu *child; yann@1: int type, tmp, doint = 2; yann@1: tristate val; yann@1: char ch; yann@1: yann@1: if (!menu_is_visible(menu)) yann@1: return; yann@1: yann@1: sym = menu->sym; yann@1: prop = menu->prompt; yann@1: if (!sym) { yann@1: if (prop && menu != current_menu) { yann@1: const char *prompt = menu_get_prompt(menu); yann@1: switch (prop->type) { yann@1: case P_MENU: yann@1: child_count++; yann@1: if (single_menu_mode) { yann@1: item_make("%s%*c%s", yann@1: menu->data ? "-->" : "++>", yann@1: indent + 1, ' ', prompt); yann@1: } else yann@1: item_make(" %*c%s --->", indent + 1, ' ', prompt); yann@1: yann@1: item_set_tag('m'); yann@1: item_set_data(menu); yann@1: if (single_menu_mode && menu->data) yann@1: goto conf_childs; yann@1: return; yann@1: default: yann@1: if (prompt) { yann@1: child_count++; yann@1: item_make("---%*c%s", indent + 1, ' ', prompt); yann@1: item_set_tag(':'); yann@1: item_set_data(menu); yann@1: } yann@1: } yann@1: } else yann@1: doint = 0; yann@1: goto conf_childs; yann@1: } yann@1: yann@1: type = sym_get_type(sym); yann@1: if (sym_is_choice(sym)) { yann@1: struct symbol *def_sym = sym_get_choice_value(sym); yann@1: struct menu *def_menu = NULL; yann@1: yann@1: child_count++; yann@1: for (child = menu->list; child; child = child->next) { yann@1: if (menu_is_visible(child) && child->sym == def_sym) yann@1: def_menu = child; yann@1: } yann@1: yann@1: val = sym_get_tristate_value(sym); yann@1: if (sym_is_changable(sym)) { yann@1: switch (type) { yann@1: case S_BOOLEAN: yann@1: item_make("[%c]", val == no ? ' ' : '*'); yann@1: break; yann@1: case S_TRISTATE: yann@1: switch (val) { yann@1: case yes: ch = '*'; break; yann@1: case mod: ch = 'M'; break; yann@1: default: ch = ' '; break; yann@1: } yann@1: item_make("<%c>", ch); yann@1: break; yann@1: } yann@1: item_set_tag('t'); yann@1: item_set_data(menu); yann@1: } else { yann@1: item_make(" "); yann@1: item_set_tag(def_menu ? 't' : ':'); yann@1: item_set_data(menu); yann@1: } yann@1: yann@1: item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); yann@1: if (val == yes) { yann@1: if (def_menu) { yann@1: item_add_str(" (%s)", menu_get_prompt(def_menu)); yann@1: item_add_str(" --->"); yann@1: if (def_menu->list) { yann@1: indent += 2; yann@1: build_conf(def_menu); yann@1: indent -= 2; yann@1: } yann@1: } yann@1: return; yann@1: } yann@1: } else { yann@1: if (menu == current_menu) { yann@1: item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu)); yann@1: item_set_tag(':'); yann@1: item_set_data(menu); yann@1: goto conf_childs; yann@1: } yann@1: child_count++; yann@1: val = sym_get_tristate_value(sym); yann@1: if (sym_is_choice_value(sym) && val == yes) { yann@1: item_make(" "); yann@1: item_set_tag(':'); yann@1: item_set_data(menu); yann@1: } else { yann@1: switch (type) { yann@1: case S_BOOLEAN: yann@1: if (sym_is_changable(sym)) yann@1: item_make("[%c]", val == no ? ' ' : '*'); yann@1: else yann@1: item_make("---"); yann@1: item_set_tag('t'); yann@1: item_set_data(menu); yann@1: break; yann@1: case S_TRISTATE: yann@1: switch (val) { yann@1: case yes: ch = '*'; break; yann@1: case mod: ch = 'M'; break; yann@1: default: ch = ' '; break; yann@1: } yann@1: if (sym_is_changable(sym)) yann@1: item_make("<%c>", ch); yann@1: else yann@1: item_make("---"); yann@1: item_set_tag('t'); yann@1: item_set_data(menu); yann@1: break; yann@1: default: yann@1: tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */ yann@1: item_make("(%s)", sym_get_string_value(sym)); yann@1: tmp = indent - tmp + 4; yann@1: if (tmp < 0) yann@1: tmp = 0; yann@1: item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu), yann@1: (sym_has_value(sym) || !sym_is_changable(sym)) ? yann@1: "" : " (NEW)"); yann@1: item_set_tag('s'); yann@1: item_set_data(menu); yann@1: goto conf_childs; yann@1: } yann@1: } yann@1: item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), yann@1: (sym_has_value(sym) || !sym_is_changable(sym)) ? yann@1: "" : " (NEW)"); yann@1: if (menu->prompt->type == P_MENU) { yann@1: item_add_str(" --->"); yann@1: return; yann@1: } yann@1: } yann@1: yann@1: conf_childs: yann@1: indent += doint; yann@1: for (child = menu->list; child; child = child->next) yann@1: build_conf(child); yann@1: indent -= doint; yann@1: } yann@1: yann@1: static void conf(struct menu *menu) yann@1: { yann@1: struct menu *submenu; yann@1: const char *prompt = menu_get_prompt(menu); yann@1: struct symbol *sym; yann@1: struct menu *active_menu = NULL; yann@1: int res; yann@1: int s_scroll = 0; yann@1: yann@1: while (1) { yann@1: item_reset(); yann@1: current_menu = menu; yann@1: build_conf(menu); yann@1: if (!child_count) yann@1: break; yann@1: if (menu == &rootmenu) { yann@1: item_make("--- "); yann@1: item_set_tag(':'); yann@1: item_make(_(" Load an Alternate Configuration File")); yann@1: item_set_tag('L'); yann@1: item_make(_(" Save an Alternate Configuration File")); yann@1: item_set_tag('S'); yann@1: } yann@1: dialog_clear(); yann@1: res = dialog_menu(prompt ? prompt : _("Main Menu"), yann@1: _(menu_instructions), yann@1: active_menu, &s_scroll); yann@1: if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL) yann@1: break; yann@1: if (!item_activate_selected()) yann@1: continue; yann@1: if (!item_tag()) yann@1: continue; yann@1: yann@1: submenu = item_data(); yann@1: active_menu = item_data(); yann@1: if (submenu) yann@1: sym = submenu->sym; yann@1: else yann@1: sym = NULL; yann@1: yann@1: switch (res) { yann@1: case 0: yann@1: switch (item_tag()) { yann@1: case 'm': yann@1: if (single_menu_mode) yann@1: submenu->data = (void *) (long) !submenu->data; yann@1: else yann@1: conf(submenu); yann@1: break; yann@1: case 't': yann@1: if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) yann@1: conf_choice(submenu); yann@1: else if (submenu->prompt->type == P_MENU) yann@1: conf(submenu); yann@1: break; yann@1: case 's': yann@1: conf_string(submenu); yann@1: break; yann@1: case 'L': yann@1: conf_load(); yann@1: break; yann@1: case 'S': yann@1: conf_save(); yann@1: break; yann@1: } yann@1: break; yann@1: case 2: yann@1: if (sym) yann@1: show_help(submenu); yann@1: else yann@1: show_helptext("README", _(mconf_readme)); yann@1: break; yann@1: case 3: yann@1: if (item_is_tag('t')) { yann@1: if (sym_set_tristate_value(sym, yes)) yann@1: break; yann@1: if (sym_set_tristate_value(sym, mod)) yann@1: show_textbox(NULL, setmod_text, 6, 74); yann@1: } yann@1: break; yann@1: case 4: yann@1: if (item_is_tag('t')) yann@1: sym_set_tristate_value(sym, no); yann@1: break; yann@1: case 5: yann@1: if (item_is_tag('t')) yann@1: sym_set_tristate_value(sym, mod); yann@1: break; yann@1: case 6: yann@1: if (item_is_tag('t')) yann@1: sym_toggle_tristate_value(sym); yann@1: else if (item_is_tag('m')) yann@1: conf(submenu); yann@1: break; yann@1: case 7: yann@1: search_conf(); yann@1: break; yann@1: } yann@1: } yann@1: } yann@1: yann@1: static void show_textbox(const char *title, const char *text, int r, int c) yann@1: { yann@1: dialog_clear(); yann@1: dialog_textbox(title, text, r, c); yann@1: } yann@1: yann@1: static void show_helptext(const char *title, const char *text) yann@1: { yann@1: show_textbox(title, text, 0, 0); yann@1: } yann@1: yann@1: static void show_help(struct menu *menu) yann@1: { yann@1: struct gstr help = str_new(); yann@1: struct symbol *sym = menu->sym; yann@1: yann@1: if (sym->help) yann@1: { yann@1: if (sym->name) { yann@1: str_printf(&help, "CT_%s:\n\n", sym->name); yann@1: str_append(&help, _(sym->help)); yann@1: str_append(&help, "\n"); yann@1: } yann@1: } else { yann@1: str_append(&help, nohelp_text); yann@1: } yann@1: get_symbol_str(&help, sym); yann@1: show_helptext(menu_get_prompt(menu), str_get(&help)); yann@1: str_free(&help); yann@1: } yann@1: yann@1: static void conf_choice(struct menu *menu) yann@1: { yann@1: const char *prompt = menu_get_prompt(menu); yann@1: struct menu *child; yann@1: struct symbol *active; yann@1: yann@1: active = sym_get_choice_value(menu->sym); yann@1: while (1) { yann@1: int res; yann@1: int selected; yann@1: item_reset(); yann@1: yann@1: current_menu = menu; yann@1: for (child = menu->list; child; child = child->next) { yann@1: if (!menu_is_visible(child)) yann@1: continue; yann@1: item_make("%s", menu_get_prompt(child)); yann@1: item_set_data(child); yann@1: if (child->sym == active) yann@1: item_set_selected(1); yann@1: if (child->sym == sym_get_choice_value(menu->sym)) yann@1: item_set_tag('X'); yann@1: } yann@1: dialog_clear(); yann@1: res = dialog_checklist(prompt ? prompt : _("Main Menu"), yann@1: _(radiolist_instructions), yann@1: 15, 70, 6); yann@1: selected = item_activate_selected(); yann@1: switch (res) { yann@1: case 0: yann@1: if (selected) { yann@1: child = item_data(); yann@1: sym_set_tristate_value(child->sym, yes); yann@1: } yann@1: return; yann@1: case 1: yann@1: if (selected) { yann@1: child = item_data(); yann@1: show_help(child); yann@1: active = child->sym; yann@1: } else yann@1: show_help(menu); yann@1: break; yann@1: case KEY_ESC: yann@1: return; yann@1: case -ERRDISPLAYTOOSMALL: yann@1: return; yann@1: } yann@1: } yann@1: } yann@1: yann@1: static void conf_string(struct menu *menu) yann@1: { yann@1: const char *prompt = menu_get_prompt(menu); yann@1: yann@1: while (1) { yann@1: int res; yann@1: char *heading; yann@1: yann@1: switch (sym_get_type(menu->sym)) { yann@1: case S_INT: yann@1: heading = _(inputbox_instructions_int); yann@1: break; yann@1: case S_HEX: yann@1: heading = _(inputbox_instructions_hex); yann@1: break; yann@1: case S_STRING: yann@1: heading = _(inputbox_instructions_string); yann@1: break; yann@1: default: yann@1: heading = "Internal mconf error!"; yann@1: } yann@1: dialog_clear(); yann@1: res = dialog_inputbox(prompt ? prompt : _("Main Menu"), yann@1: heading, 10, 75, yann@1: sym_get_string_value(menu->sym)); yann@1: switch (res) { yann@1: case 0: yann@1: if (sym_set_string_value(menu->sym, dialog_input_result)) yann@1: return; yann@1: show_textbox(NULL, _("You have made an invalid entry."), 5, 43); yann@1: break; yann@1: case 1: yann@1: show_help(menu); yann@1: break; yann@1: case KEY_ESC: yann@1: return; yann@1: } yann@1: } yann@1: } yann@1: yann@1: static void conf_load(void) yann@1: { yann@1: yann@1: while (1) { yann@1: int res; yann@1: dialog_clear(); yann@1: res = dialog_inputbox(NULL, load_config_text, yann@1: 11, 55, filename); yann@1: switch(res) { yann@1: case 0: yann@1: if (!dialog_input_result[0]) yann@1: return; yann@1: if (!conf_read(dialog_input_result)) yann@1: return; yann@1: show_textbox(NULL, _("File does not exist!"), 5, 38); yann@1: break; yann@1: case 1: yann@1: show_helptext(_("Load Alternate Configuration"), load_config_help); yann@1: break; yann@1: case KEY_ESC: yann@1: return; yann@1: } yann@1: } yann@1: } yann@1: yann@1: static void conf_save(void) yann@1: { yann@1: while (1) { yann@1: int res; yann@1: dialog_clear(); yann@1: res = dialog_inputbox(NULL, save_config_text, yann@1: 11, 55, filename); yann@1: switch(res) { yann@1: case 0: yann@1: if (!dialog_input_result[0]) yann@1: return; yann@1: if (!conf_write(dialog_input_result)) yann@1: return; yann@1: show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60); yann@1: break; yann@1: case 1: yann@1: show_helptext(_("Save Alternate Configuration"), save_config_help); yann@1: break; yann@1: case KEY_ESC: yann@1: return; yann@1: } yann@1: } yann@1: } yann@1: yann@1: static void conf_cleanup(void) yann@1: { yann@1: tcsetattr(1, TCSAFLUSH, &ios_org); yann@1: } yann@1: yann@1: int main(int ac, char **av) yann@1: { yann@1: struct symbol *sym; yann@1: char *mode; yann@1: int res; yann@1: yann@1: setlocale(LC_ALL, ""); yann@1: bindtextdomain(PACKAGE, LOCALEDIR); yann@1: textdomain(PACKAGE); yann@1: yann@39: conf_parse(av[1]); yann@1: conf_read(NULL); yann@1: yann@1: sym = sym_lookup("PROJECTVERSION", 0); yann@1: sym_calc_value(sym); yann@1: sprintf(menu_backtitle, _(PROJECT_NAME" v%s Configuration"), yann@1: sym_get_string_value(sym)); yann@1: yann@1: mode = getenv("MENUCONFIG_MODE"); yann@1: if (mode) { yann@1: if (!strcasecmp(mode, "single_menu")) yann@1: single_menu_mode = 1; yann@1: } yann@1: yann@1: tcgetattr(1, &ios_org); yann@1: atexit(conf_cleanup); yann@1: init_wsize(); yann@1: reset_dialog(); yann@1: init_dialog(menu_backtitle); yann@1: do { yann@1: conf(&rootmenu); yann@1: dialog_clear(); yann@39: if (conf_get_changed()) yann@39: res = dialog_yesno(NULL, yann@39: _("Do you wish to save your " yann@39: "new "PROJECT_NAME" configuration?\n" yann@39: " to continue."), yann@39: 6, 60); yann@39: else yann@39: res = -1; yann@1: } while (res == KEY_ESC); yann@1: end_dialog(); yann@39: yann@39: switch (res) { yann@39: case 0: yann@1: if (conf_write(NULL)) { yann@94: fprintf(stderr, yann@94: _( "Error during writing of "PROJECT_NAME" configuration.\n" yann@94: "Your configuration changes were NOT saved.\n")); yann@1: return 1; yann@1: } yann@39: case -1: yann@39: break; yann@39: default: yann@94: fprintf(stderr, _( "Your configuration changes were NOT saved.\n")); yann@1: } yann@1: yann@1: return 0; yann@1: }