123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557 |
- /*
- * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
- * Released under the terms of the GNU GPL v2.0.
- *
- * Derived from menuconfig.
- *
- */
- #define _GNU_SOURCE
- #include <string.h>
- #include <stdlib.h>
- #include "lkc.h"
- #include "nconf.h"
- #include <ctype.h>
- static const char nconf_global_help[] = N_(
- "Help windows\n"
- "------------\n"
- "o Global help: Unless in a data entry window, pressing <F1> will give \n"
- " you the global help window, which you are just reading.\n"
- "\n"
- "o A short version of the global help is available by pressing <F3>.\n"
- "\n"
- "o Local help: To get help related to the current menu entry, use any\n"
- " of <?> <h>, or if in a data entry window then press <F1>.\n"
- "\n"
- "\n"
- "Menu entries\n"
- "------------\n"
- "This interface lets you select features and parameters for the \n"
- "build. Features can either be built-in, modularized, or removed.\n"
- "Parameters must be entered as text or decimal or hexadecimal numbers.\n"
- "\n"
- "Menu entries beginning with following braces represent features that\n"
- " [ ] can be built in or removed\n"
- " < > can be built in, modularized or removed\n"
- " { } can be built in or modularized, are selected by another feature\n"
- " - - are selected by another feature\n"
- " XXX cannot be selected. Symbol Info <F2> tells you why.\n"
- "*, M or whitespace inside braces means to build in, build as a module\n"
- "or to exclude the feature respectively.\n"
- "\n"
- "To change any of these features, highlight it with the movement keys\n"
- "listed below and press <y> to build it in, <m> to make it a module or\n"
- "<n> to remove it. You may press the <Space> key to cycle through the\n"
- "available options.\n"
- "\n"
- "A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
- "empty submenu.\n"
- "\n"
- "Menu navigation keys\n"
- "----------------------------------------------------------------------\n"
- "Linewise up <Up>\n"
- "Linewise down <Down>\n"
- "Pagewise up <Page Up>\n"
- "Pagewise down <Page Down>\n"
- "First entry <Home>\n"
- "Last entry <End>\n"
- "Enter a submenu <Right> <Enter>\n"
- "Go back to parent menu <Left> <Esc> <F5>\n"
- "Close a help window <Enter> <Esc> <F5>\n"
- "Close entry window, apply <Enter>\n"
- "Close entry window, forget <Esc> <F5>\n"
- "Start incremental, case-insensitive search for STRING in menu entries,\n"
- " no regex support, STRING is displayed in upper left corner\n"
- " </>STRING\n"
- " Remove last character <Backspace>\n"
- " Jump to next hit <Down>\n"
- " Jump to previous hit <Up>\n"
- "Exit menu search mode </> <Esc>\n"
- "Search for configuration variables with or without leading CONFIG_\n"
- " <F8>RegExpr<Enter>\n"
- "Verbose search help <F8><F1>\n"
- "----------------------------------------------------------------------\n"
- "\n"
- "Unless in a data entry window, key <1> may be used instead of <F1>,\n"
- "<2> instead of <F2>, etc.\n"
- "\n"
- "\n"
- "Radiolist (Choice list)\n"
- "-----------------------\n"
- "Use the movement keys listed above to select the option you wish to set\n"
- "and press <Space>.\n"
- "\n"
- "\n"
- "Data entry\n"
- "----------\n"
- "Enter the requested information and press <Enter>. Hexadecimal values\n"
- "may be entered without the \"0x\" prefix.\n"
- "\n"
- "\n"
- "Text Box (Help Window)\n"
- "----------------------\n"
- "Use movement keys as listed in table above.\n"
- "\n"
- "Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
- "\n"
- "\n"
- "Alternate configuration files\n"
- "-----------------------------\n"
- "nconfig supports switching between different configurations.\n"
- "Press <F6> to save your current configuration. Press <F7> and enter\n"
- "a file name to load a previously saved configuration.\n"
- "\n"
- "\n"
- "Terminal configuration\n"
- "----------------------\n"
- "If you use nconfig in a xterm window, make sure your TERM environment\n"
- "variable specifies a terminal configuration which supports at least\n"
- "16 colors. Otherwise nconfig will look rather bad.\n"
- "\n"
- "If the \"stty size\" command reports the current terminalsize correctly,\n"
- "nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n"
- "and display longer menus properly.\n"
- "\n"
- "\n"
- "Single menu mode\n"
- "----------------\n"
- "If you prefer to have all of the menu entries listed in a single menu,\n"
- "rather than the default multimenu hierarchy, run nconfig with\n"
- "NCONFIG_MODE environment variable set to single_menu. Example:\n"
- "\n"
- "make NCONFIG_MODE=single_menu nconfig\n"
- "\n"
- "<Enter> will then unfold the appropriate category, or fold it if it\n"
- "is already unfolded. Folded menu entries will be designated by a\n"
- "leading \"++>\" and unfolded entries by a leading \"-->\".\n"
- "\n"
- "Note that this mode can eventually be a little more CPU expensive than\n"
- "the default mode, especially with a larger number of unfolded submenus.\n"
- "\n"),
- menu_no_f_instructions[] = N_(
- "Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
- "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
- "\n"
- "Use the following keys to navigate the menus:\n"
- "Move up or down with <Up> and <Down>.\n"
- "Enter a submenu with <Enter> or <Right>.\n"
- "Exit a submenu to its parent menu with <Esc> or <Left>.\n"
- "Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
- "Pressing <Space> cycles through the available options.\n"
- "To search for menu entries press </>.\n"
- "<Esc> always leaves the current window.\n"
- "\n"
- "You do not have function keys support.\n"
- "Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
- "For verbose global help use key <1>.\n"
- "For help related to the current menu entry press <?> or <h>.\n"),
- menu_instructions[] = N_(
- "Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
- "Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
- "\n"
- "Use the following keys to navigate the menus:\n"
- "Move up or down with <Up> or <Down>.\n"
- "Enter a submenu with <Enter> or <Right>.\n"
- "Exit a submenu to its parent menu with <Esc> or <Left>.\n"
- "Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
- "Pressing <Space> cycles through the available options.\n"
- "To search for menu entries press </>.\n"
- "<Esc> always leaves the current window.\n"
- "\n"
- "Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
- "For verbose global help press <F1>.\n"
- "For help related to the current menu entry press <?> or <h>.\n"),
- radiolist_instructions[] = N_(
- "Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
- "with <Space>.\n"
- "For help related to the current entry press <?> or <h>.\n"
- "For global help press <F1>.\n"),
- inputbox_instructions_int[] = N_(
- "Please enter a decimal value.\n"
- "Fractions will not be accepted.\n"
- "Press <Enter> to apply, <Esc> to cancel."),
- inputbox_instructions_hex[] = N_(
- "Please enter a hexadecimal value.\n"
- "Press <Enter> to apply, <Esc> to cancel."),
- inputbox_instructions_string[] = N_(
- "Please enter a string value.\n"
- "Press <Enter> to apply, <Esc> to cancel."),
- setmod_text[] = N_(
- "This feature depends on another feature which has been configured as a\n"
- "module. As a result, the current feature will be built as a module too."),
- load_config_text[] = N_(
- "Enter the name of the configuration file you wish to load.\n"
- "Accept the name shown to restore the configuration you last\n"
- "retrieved. Leave empty to abort."),
- load_config_help[] = N_(
- "For various reasons, one may wish to keep several different\n"
- "configurations available on a single machine.\n"
- "\n"
- "If you have saved a previous configuration in a file other than the\n"
- "default one, entering its name here will allow you to load and modify\n"
- "that configuration.\n"
- "\n"
- "Leave empty to abort.\n"),
- save_config_text[] = N_(
- "Enter a filename to which this configuration should be saved\n"
- "as an alternate. Leave empty to abort."),
- save_config_help[] = N_(
- "For various reasons, one may wish to keep several different\n"
- "configurations available on a single machine.\n"
- "\n"
- "Entering a file name here will allow you to later retrieve, modify\n"
- "and use the current configuration as an alternate to whatever\n"
- "configuration options you have selected at that time.\n"
- "\n"
- "Leave empty to abort.\n"),
- search_help[] = N_(
- "Search for symbols (configuration variable names CONFIG_*) and display\n"
- "their relations. Regular expressions are supported.\n"
- "Example: Search for \"^FOO\".\n"
- "Result:\n"
- "-----------------------------------------------------------------\n"
- "Symbol: FOO [ = m]\n"
- "Prompt: Foo bus is used to drive the bar HW\n"
- "Defined at drivers/pci/Kconfig:47\n"
- "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
- "Location:\n"
- " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
- " -> PCI support (PCI [ = y])\n"
- " -> PCI access mode (<choice> [ = y])\n"
- "Selects: LIBCRC32\n"
- "Selected by: BAR\n"
- "-----------------------------------------------------------------\n"
- "o The line 'Prompt:' shows the text displayed for this symbol in\n"
- " the menu hierarchy.\n"
- "o The 'Defined at' line tells at what file / line number the symbol is\n"
- " defined.\n"
- "o The 'Depends on:' line lists symbols that need to be defined for\n"
- " this symbol to be visible and selectable in the menu.\n"
- "o The 'Location:' lines tell, where in the menu structure this symbol\n"
- " is located. A location followed by a [ = y] indicates that this is\n"
- " a selectable menu item, and the current value is displayed inside\n"
- " brackets.\n"
- "o The 'Selects:' line tells, what symbol will be automatically selected\n"
- " if this symbol is selected (y or m).\n"
- "o The 'Selected by' line tells what symbol has selected this symbol.\n"
- "\n"
- "Only relevant lines are shown.\n"
- "\n\n"
- "Search examples:\n"
- "USB => find all symbols containing USB\n"
- "^USB => find all symbols starting with USB\n"
- "USB$ => find all symbols ending with USB\n"
- "\n");
- struct mitem {
- char str[256];
- char tag;
- void *usrptr;
- int is_visible;
- };
- #define MAX_MENU_ITEMS 4096
- static int show_all_items;
- static int indent;
- static struct menu *current_menu;
- static int child_count;
- static int single_menu_mode;
- /* the window in which all information appears */
- static WINDOW *main_window;
- /* the largest size of the menu window */
- static int mwin_max_lines;
- static int mwin_max_cols;
- /* the window in which we show option buttons */
- static MENU *curses_menu;
- static ITEM *curses_menu_items[MAX_MENU_ITEMS];
- static struct mitem k_menu_items[MAX_MENU_ITEMS];
- static int items_num;
- static int global_exit;
- /* the currently selected button */
- const char *current_instructions = menu_instructions;
- static char *dialog_input_result;
- static int dialog_input_result_len;
- static void conf(struct menu *menu);
- static void conf_choice(struct menu *menu);
- static void conf_string(struct menu *menu);
- static void conf_load(void);
- static void conf_save(void);
- static void show_help(struct menu *menu);
- static int do_exit(void);
- static void setup_windows(void);
- static void search_conf(void);
- typedef void (*function_key_handler_t)(int *key, struct menu *menu);
- static void handle_f1(int *key, struct menu *current_item);
- static void handle_f2(int *key, struct menu *current_item);
- static void handle_f3(int *key, struct menu *current_item);
- static void handle_f4(int *key, struct menu *current_item);
- static void handle_f5(int *key, struct menu *current_item);
- static void handle_f6(int *key, struct menu *current_item);
- static void handle_f7(int *key, struct menu *current_item);
- static void handle_f8(int *key, struct menu *current_item);
- static void handle_f9(int *key, struct menu *current_item);
- struct function_keys {
- const char *key_str;
- const char *func;
- function_key key;
- function_key_handler_t handler;
- };
- static const int function_keys_num = 9;
- struct function_keys function_keys[] = {
- {
- .key_str = "F1",
- .func = "Help",
- .key = F_HELP,
- .handler = handle_f1,
- },
- {
- .key_str = "F2",
- .func = "SymInfo",
- .key = F_SYMBOL,
- .handler = handle_f2,
- },
- {
- .key_str = "F3",
- .func = "Help 2",
- .key = F_INSTS,
- .handler = handle_f3,
- },
- {
- .key_str = "F4",
- .func = "ShowAll",
- .key = F_CONF,
- .handler = handle_f4,
- },
- {
- .key_str = "F5",
- .func = "Back",
- .key = F_BACK,
- .handler = handle_f5,
- },
- {
- .key_str = "F6",
- .func = "Save",
- .key = F_SAVE,
- .handler = handle_f6,
- },
- {
- .key_str = "F7",
- .func = "Load",
- .key = F_LOAD,
- .handler = handle_f7,
- },
- {
- .key_str = "F8",
- .func = "SymSearch",
- .key = F_SEARCH,
- .handler = handle_f8,
- },
- {
- .key_str = "F9",
- .func = "Exit",
- .key = F_EXIT,
- .handler = handle_f9,
- },
- };
- static void print_function_line(void)
- {
- int i;
- int offset = 1;
- const int skip = 1;
- int lines = getmaxy(stdscr);
- for (i = 0; i < function_keys_num; i++) {
- (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
- mvwprintw(main_window, lines-3, offset,
- "%s",
- function_keys[i].key_str);
- (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
- offset += strlen(function_keys[i].key_str);
- mvwprintw(main_window, lines-3,
- offset, "%s",
- function_keys[i].func);
- offset += strlen(function_keys[i].func) + skip;
- }
- (void) wattrset(main_window, attributes[NORMAL]);
- }
- /* help */
- static void handle_f1(int *key, struct menu *current_item)
- {
- show_scroll_win(main_window,
- _("Global help"), _(nconf_global_help));
- return;
- }
- /* symbole help */
- static void handle_f2(int *key, struct menu *current_item)
- {
- show_help(current_item);
- return;
- }
- /* instructions */
- static void handle_f3(int *key, struct menu *current_item)
- {
- show_scroll_win(main_window,
- _("Short help"),
- _(current_instructions));
- return;
- }
- /* config */
- static void handle_f4(int *key, struct menu *current_item)
- {
- int res = btn_dialog(main_window,
- _("Show all symbols?"),
- 2,
- " <Show All> ",
- "<Don't show all>");
- if (res == 0)
- show_all_items = 1;
- else if (res == 1)
- show_all_items = 0;
- return;
- }
- /* back */
- static void handle_f5(int *key, struct menu *current_item)
- {
- *key = KEY_LEFT;
- return;
- }
- /* save */
- static void handle_f6(int *key, struct menu *current_item)
- {
- conf_save();
- return;
- }
- /* load */
- static void handle_f7(int *key, struct menu *current_item)
- {
- conf_load();
- return;
- }
- /* search */
- static void handle_f8(int *key, struct menu *current_item)
- {
- search_conf();
- return;
- }
- /* exit */
- static void handle_f9(int *key, struct menu *current_item)
- {
- do_exit();
- return;
- }
- /* return != 0 to indicate the key was handles */
- static int process_special_keys(int *key, struct menu *menu)
- {
- int i;
- if (*key == KEY_RESIZE) {
- setup_windows();
- return 1;
- }
- for (i = 0; i < function_keys_num; i++) {
- if (*key == KEY_F(function_keys[i].key) ||
- *key == '0' + function_keys[i].key){
- function_keys[i].handler(key, menu);
- return 1;
- }
- }
- return 0;
- }
- static void clean_items(void)
- {
- int i;
- for (i = 0; curses_menu_items[i]; i++)
- free_item(curses_menu_items[i]);
- bzero(curses_menu_items, sizeof(curses_menu_items));
- bzero(k_menu_items, sizeof(k_menu_items));
- items_num = 0;
- }
- typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
- FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
- /* return the index of the matched item, or -1 if no such item exists */
- static int get_mext_match(const char *match_str, match_f flag)
- {
- int match_start = item_index(current_item(curses_menu));
- int index;
- if (flag == FIND_NEXT_MATCH_DOWN)
- ++match_start;
- else if (flag == FIND_NEXT_MATCH_UP)
- --match_start;
- index = match_start;
- index = (index + items_num) % items_num;
- while (true) {
- char *str = k_menu_items[index].str;
- if (strcasestr(str, match_str) != 0)
- return index;
- if (flag == FIND_NEXT_MATCH_UP ||
- flag == MATCH_TINKER_PATTERN_UP)
- --index;
- else
- ++index;
- index = (index + items_num) % items_num;
- if (index == match_start)
- return -1;
- }
- }
- /* Make a new item. */
- static void item_make(struct menu *menu, char tag, const char *fmt, ...)
- {
- va_list ap;
- if (items_num > MAX_MENU_ITEMS-1)
- return;
- bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
- k_menu_items[items_num].tag = tag;
- k_menu_items[items_num].usrptr = menu;
- if (menu != NULL)
- k_menu_items[items_num].is_visible =
- menu_is_visible(menu);
- else
- k_menu_items[items_num].is_visible = 1;
- va_start(ap, fmt);
- vsnprintf(k_menu_items[items_num].str,
- sizeof(k_menu_items[items_num].str),
- fmt, ap);
- va_end(ap);
- if (!k_menu_items[items_num].is_visible)
- memcpy(k_menu_items[items_num].str, "XXX", 3);
- curses_menu_items[items_num] = new_item(
- k_menu_items[items_num].str,
- k_menu_items[items_num].str);
- set_item_userptr(curses_menu_items[items_num],
- &k_menu_items[items_num]);
- /*
- if (!k_menu_items[items_num].is_visible)
- item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
- */
- items_num++;
- curses_menu_items[items_num] = NULL;
- }
- /* very hackish. adds a string to the last item added */
- static void item_add_str(const char *fmt, ...)
- {
- va_list ap;
- int index = items_num-1;
- char new_str[256];
- char tmp_str[256];
- if (index < 0)
- return;
- va_start(ap, fmt);
- vsnprintf(new_str, sizeof(new_str), fmt, ap);
- va_end(ap);
- snprintf(tmp_str, sizeof(tmp_str), "%s%s",
- k_menu_items[index].str, new_str);
- strncpy(k_menu_items[index].str,
- tmp_str,
- sizeof(k_menu_items[index].str));
- free_item(curses_menu_items[index]);
- curses_menu_items[index] = new_item(
- k_menu_items[index].str,
- k_menu_items[index].str);
- set_item_userptr(curses_menu_items[index],
- &k_menu_items[index]);
- }
- /* get the tag of the currently selected item */
- static char item_tag(void)
- {
- ITEM *cur;
- struct mitem *mcur;
- cur = current_item(curses_menu);
- if (cur == NULL)
- return 0;
- mcur = (struct mitem *) item_userptr(cur);
- return mcur->tag;
- }
- static int curses_item_index(void)
- {
- return item_index(current_item(curses_menu));
- }
- static void *item_data(void)
- {
- ITEM *cur;
- struct mitem *mcur;
- cur = current_item(curses_menu);
- if (!cur)
- return NULL;
- mcur = (struct mitem *) item_userptr(cur);
- return mcur->usrptr;
- }
- static int item_is_tag(char tag)
- {
- return item_tag() == tag;
- }
- static char filename[PATH_MAX+1];
- static char menu_backtitle[PATH_MAX+128];
- static const char *set_config_filename(const char *config_filename)
- {
- int size;
- size = snprintf(menu_backtitle, sizeof(menu_backtitle),
- "%s - %s", config_filename, rootmenu.prompt->text);
- if (size >= sizeof(menu_backtitle))
- menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
- size = snprintf(filename, sizeof(filename), "%s", config_filename);
- if (size >= sizeof(filename))
- filename[sizeof(filename)-1] = '\0';
- return menu_backtitle;
- }
- /* return = 0 means we are successful.
- * -1 means go on doing what you were doing
- */
- static int do_exit(void)
- {
- int res;
- if (!conf_get_changed()) {
- global_exit = 1;
- return 0;
- }
- res = btn_dialog(main_window,
- _("Do you wish to save your new configuration?\n"
- "<ESC> to cancel and resume nconfig."),
- 2,
- " <save> ",
- "<don't save>");
- if (res == KEY_EXIT) {
- global_exit = 0;
- return -1;
- }
- /* if we got here, the user really wants to exit */
- switch (res) {
- case 0:
- res = conf_write(filename);
- if (res)
- btn_dialog(
- main_window,
- _("Error during writing of configuration.\n"
- "Your configuration changes were NOT saved."),
- 1,
- "<OK>");
- break;
- default:
- btn_dialog(
- main_window,
- _("Your configuration changes were NOT saved."),
- 1,
- "<OK>");
- break;
- }
- global_exit = 1;
- return 0;
- }
- static void search_conf(void)
- {
- struct symbol **sym_arr;
- struct gstr res;
- struct gstr title;
- char *dialog_input;
- int dres;
- title = str_new();
- str_printf( &title, _("Enter %s (sub)string or regexp to search for "
- "(with or without \"%s\")"), CONFIG_, CONFIG_);
- again:
- dres = dialog_inputbox(main_window,
- _("Search Configuration Parameter"),
- str_get(&title),
- "", &dialog_input_result, &dialog_input_result_len);
- switch (dres) {
- case 0:
- break;
- case 1:
- show_scroll_win(main_window,
- _("Search Configuration"), search_help);
- goto again;
- default:
- str_free(&title);
- return;
- }
- /* strip the prefix if necessary */
- dialog_input = dialog_input_result;
- if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
- dialog_input += strlen(CONFIG_);
- sym_arr = sym_re_search(dialog_input);
- res = get_relations_str(sym_arr, NULL);
- free(sym_arr);
- show_scroll_win(main_window,
- _("Search Results"), str_get(&res));
- str_free(&res);
- str_free(&title);
- }
- static void build_conf(struct menu *menu)
- {
- struct symbol *sym;
- struct property *prop;
- struct menu *child;
- int type, tmp, doint = 2;
- tristate val;
- char ch;
- if (!menu || (!show_all_items && !menu_is_visible(menu)))
- return;
- sym = menu->sym;
- prop = menu->prompt;
- if (!sym) {
- if (prop && menu != current_menu) {
- const char *prompt = menu_get_prompt(menu);
- enum prop_type ptype;
- ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
- switch (ptype) {
- case P_MENU:
- child_count++;
- prompt = _(prompt);
- if (single_menu_mode) {
- item_make(menu, 'm',
- "%s%*c%s",
- menu->data ? "-->" : "++>",
- indent + 1, ' ', prompt);
- } else
- item_make(menu, 'm',
- " %*c%s %s",
- indent + 1, ' ', prompt,
- menu_is_empty(menu) ? "----" : "--->");
- if (single_menu_mode && menu->data)
- goto conf_childs;
- return;
- case P_COMMENT:
- if (prompt) {
- child_count++;
- item_make(menu, ':',
- " %*c*** %s ***",
- indent + 1, ' ',
- _(prompt));
- }
- break;
- default:
- if (prompt) {
- child_count++;
- item_make(menu, ':', "---%*c%s",
- indent + 1, ' ',
- _(prompt));
- }
- }
- } else
- doint = 0;
- goto conf_childs;
- }
- type = sym_get_type(sym);
- if (sym_is_choice(sym)) {
- struct symbol *def_sym = sym_get_choice_value(sym);
- struct menu *def_menu = NULL;
- child_count++;
- for (child = menu->list; child; child = child->next) {
- if (menu_is_visible(child) && child->sym == def_sym)
- def_menu = child;
- }
- val = sym_get_tristate_value(sym);
- if (sym_is_changable(sym)) {
- switch (type) {
- case S_BOOLEAN:
- item_make(menu, 't', "[%c]",
- val == no ? ' ' : '*');
- break;
- case S_TRISTATE:
- switch (val) {
- case yes:
- ch = '*';
- break;
- case mod:
- ch = 'M';
- break;
- default:
- ch = ' ';
- break;
- }
- item_make(menu, 't', "<%c>", ch);
- break;
- }
- } else {
- item_make(menu, def_menu ? 't' : ':', " ");
- }
- item_add_str("%*c%s", indent + 1,
- ' ', _(menu_get_prompt(menu)));
- if (val == yes) {
- if (def_menu) {
- item_add_str(" (%s)",
- _(menu_get_prompt(def_menu)));
- item_add_str(" --->");
- if (def_menu->list) {
- indent += 2;
- build_conf(def_menu);
- indent -= 2;
- }
- }
- return;
- }
- } else {
- if (menu == current_menu) {
- item_make(menu, ':',
- "---%*c%s", indent + 1,
- ' ', _(menu_get_prompt(menu)));
- goto conf_childs;
- }
- child_count++;
- val = sym_get_tristate_value(sym);
- if (sym_is_choice_value(sym) && val == yes) {
- item_make(menu, ':', " ");
- } else {
- switch (type) {
- case S_BOOLEAN:
- if (sym_is_changable(sym))
- item_make(menu, 't', "[%c]",
- val == no ? ' ' : '*');
- else
- item_make(menu, 't', "-%c-",
- val == no ? ' ' : '*');
- break;
- case S_TRISTATE:
- switch (val) {
- case yes:
- ch = '*';
- break;
- case mod:
- ch = 'M';
- break;
- default:
- ch = ' ';
- break;
- }
- if (sym_is_changable(sym)) {
- if (sym->rev_dep.tri == mod)
- item_make(menu,
- 't', "{%c}", ch);
- else
- item_make(menu,
- 't', "<%c>", ch);
- } else
- item_make(menu, 't', "-%c-", ch);
- break;
- default:
- tmp = 2 + strlen(sym_get_string_value(sym));
- item_make(menu, 's', " (%s)",
- sym_get_string_value(sym));
- tmp = indent - tmp + 4;
- if (tmp < 0)
- tmp = 0;
- item_add_str("%*c%s%s", tmp, ' ',
- _(menu_get_prompt(menu)),
- (sym_has_value(sym) ||
- !sym_is_changable(sym)) ? "" :
- _(" (NEW)"));
- goto conf_childs;
- }
- }
- item_add_str("%*c%s%s", indent + 1, ' ',
- _(menu_get_prompt(menu)),
- (sym_has_value(sym) || !sym_is_changable(sym)) ?
- "" : _(" (NEW)"));
- if (menu->prompt && menu->prompt->type == P_MENU) {
- item_add_str(" %s", menu_is_empty(menu) ? "----" : "--->");
- return;
- }
- }
- conf_childs:
- indent += doint;
- for (child = menu->list; child; child = child->next)
- build_conf(child);
- indent -= doint;
- }
- static void reset_menu(void)
- {
- unpost_menu(curses_menu);
- clean_items();
- }
- /* adjust the menu to show this item.
- * prefer not to scroll the menu if possible*/
- static void center_item(int selected_index, int *last_top_row)
- {
- int toprow;
- set_top_row(curses_menu, *last_top_row);
- toprow = top_row(curses_menu);
- if (selected_index < toprow ||
- selected_index >= toprow+mwin_max_lines) {
- toprow = max(selected_index-mwin_max_lines/2, 0);
- if (toprow >= item_count(curses_menu)-mwin_max_lines)
- toprow = item_count(curses_menu)-mwin_max_lines;
- set_top_row(curses_menu, toprow);
- }
- set_current_item(curses_menu,
- curses_menu_items[selected_index]);
- *last_top_row = toprow;
- post_menu(curses_menu);
- refresh_all_windows(main_window);
- }
- /* this function assumes reset_menu has been called before */
- static void show_menu(const char *prompt, const char *instructions,
- int selected_index, int *last_top_row)
- {
- int maxx, maxy;
- WINDOW *menu_window;
- current_instructions = instructions;
- clear();
- (void) wattrset(main_window, attributes[NORMAL]);
- print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
- menu_backtitle,
- attributes[MAIN_HEADING]);
- (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
- box(main_window, 0, 0);
- (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
- mvwprintw(main_window, 0, 3, " %s ", prompt);
- (void) wattrset(main_window, attributes[NORMAL]);
- set_menu_items(curses_menu, curses_menu_items);
- /* position the menu at the middle of the screen */
- scale_menu(curses_menu, &maxy, &maxx);
- maxx = min(maxx, mwin_max_cols-2);
- maxy = mwin_max_lines;
- menu_window = derwin(main_window,
- maxy,
- maxx,
- 2,
- (mwin_max_cols-maxx)/2);
- keypad(menu_window, TRUE);
- set_menu_win(curses_menu, menu_window);
- set_menu_sub(curses_menu, menu_window);
- /* must reassert this after changing items, otherwise returns to a
- * default of 16
- */
- set_menu_format(curses_menu, maxy, 1);
- center_item(selected_index, last_top_row);
- set_menu_format(curses_menu, maxy, 1);
- print_function_line();
- /* Post the menu */
- post_menu(curses_menu);
- refresh_all_windows(main_window);
- }
- static void adj_match_dir(match_f *match_direction)
- {
- if (*match_direction == FIND_NEXT_MATCH_DOWN)
- *match_direction =
- MATCH_TINKER_PATTERN_DOWN;
- else if (*match_direction == FIND_NEXT_MATCH_UP)
- *match_direction =
- MATCH_TINKER_PATTERN_UP;
- /* else, do no change.. */
- }
- struct match_state
- {
- int in_search;
- match_f match_direction;
- char pattern[256];
- };
- /* Return 0 means I have handled the key. In such a case, ans should hold the
- * item to center, or -1 otherwise.
- * Else return -1 .
- */
- static int do_match(int key, struct match_state *state, int *ans)
- {
- char c = (char) key;
- int terminate_search = 0;
- *ans = -1;
- if (key == '/' || (state->in_search && key == 27)) {
- move(0, 0);
- refresh();
- clrtoeol();
- state->in_search = 1-state->in_search;
- bzero(state->pattern, sizeof(state->pattern));
- state->match_direction = MATCH_TINKER_PATTERN_DOWN;
- return 0;
- } else if (!state->in_search)
- return 1;
- if (isalnum(c) || isgraph(c) || c == ' ') {
- state->pattern[strlen(state->pattern)] = c;
- state->pattern[strlen(state->pattern)] = '\0';
- adj_match_dir(&state->match_direction);
- *ans = get_mext_match(state->pattern,
- state->match_direction);
- } else if (key == KEY_DOWN) {
- state->match_direction = FIND_NEXT_MATCH_DOWN;
- *ans = get_mext_match(state->pattern,
- state->match_direction);
- } else if (key == KEY_UP) {
- state->match_direction = FIND_NEXT_MATCH_UP;
- *ans = get_mext_match(state->pattern,
- state->match_direction);
- } else if (key == KEY_BACKSPACE || key == 127) {
- state->pattern[strlen(state->pattern)-1] = '\0';
- adj_match_dir(&state->match_direction);
- } else
- terminate_search = 1;
- if (terminate_search) {
- state->in_search = 0;
- bzero(state->pattern, sizeof(state->pattern));
- move(0, 0);
- refresh();
- clrtoeol();
- return -1;
- }
- return 0;
- }
- static void conf(struct menu *menu)
- {
- struct menu *submenu = 0;
- const char *prompt = menu_get_prompt(menu);
- struct symbol *sym;
- int res;
- int current_index = 0;
- int last_top_row = 0;
- struct match_state match_state = {
- .in_search = 0,
- .match_direction = MATCH_TINKER_PATTERN_DOWN,
- .pattern = "",
- };
- while (!global_exit) {
- reset_menu();
- current_menu = menu;
- build_conf(menu);
- if (!child_count)
- break;
- show_menu(prompt ? _(prompt) : _("Main Menu"),
- _(menu_instructions),
- current_index, &last_top_row);
- keypad((menu_win(curses_menu)), TRUE);
- while (!global_exit) {
- if (match_state.in_search) {
- mvprintw(0, 0,
- "searching: %s", match_state.pattern);
- clrtoeol();
- }
- refresh_all_windows(main_window);
- res = wgetch(menu_win(curses_menu));
- if (!res)
- break;
- if (do_match(res, &match_state, ¤t_index) == 0) {
- if (current_index != -1)
- center_item(current_index,
- &last_top_row);
- continue;
- }
- if (process_special_keys(&res,
- (struct menu *) item_data()))
- break;
- switch (res) {
- case KEY_DOWN:
- menu_driver(curses_menu, REQ_DOWN_ITEM);
- break;
- case KEY_UP:
- menu_driver(curses_menu, REQ_UP_ITEM);
- break;
- case KEY_NPAGE:
- menu_driver(curses_menu, REQ_SCR_DPAGE);
- break;
- case KEY_PPAGE:
- menu_driver(curses_menu, REQ_SCR_UPAGE);
- break;
- case KEY_HOME:
- menu_driver(curses_menu, REQ_FIRST_ITEM);
- break;
- case KEY_END:
- menu_driver(curses_menu, REQ_LAST_ITEM);
- break;
- case 'h':
- case '?':
- show_help((struct menu *) item_data());
- break;
- }
- if (res == 10 || res == 27 ||
- res == 32 || res == 'n' || res == 'y' ||
- res == KEY_LEFT || res == KEY_RIGHT ||
- res == 'm')
- break;
- refresh_all_windows(main_window);
- }
- refresh_all_windows(main_window);
- /* if ESC or left*/
- if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
- break;
- /* remember location in the menu */
- last_top_row = top_row(curses_menu);
- current_index = curses_item_index();
- if (!item_tag())
- continue;
- submenu = (struct menu *) item_data();
- if (!submenu || !menu_is_visible(submenu))
- continue;
- sym = submenu->sym;
- switch (res) {
- case ' ':
- if (item_is_tag('t'))
- sym_toggle_tristate_value(sym);
- else if (item_is_tag('m'))
- conf(submenu);
- break;
- case KEY_RIGHT:
- case 10: /* ENTER WAS PRESSED */
- switch (item_tag()) {
- case 'm':
- if (single_menu_mode)
- submenu->data =
- (void *) (long) !submenu->data;
- else
- conf(submenu);
- break;
- case 't':
- if (sym_is_choice(sym) &&
- sym_get_tristate_value(sym) == yes)
- conf_choice(submenu);
- else if (submenu->prompt &&
- submenu->prompt->type == P_MENU)
- conf(submenu);
- else if (res == 10)
- sym_toggle_tristate_value(sym);
- break;
- case 's':
- conf_string(submenu);
- break;
- }
- break;
- case 'y':
- if (item_is_tag('t')) {
- if (sym_set_tristate_value(sym, yes))
- break;
- if (sym_set_tristate_value(sym, mod))
- btn_dialog(main_window, setmod_text, 0);
- }
- break;
- case 'n':
- if (item_is_tag('t'))
- sym_set_tristate_value(sym, no);
- break;
- case 'm':
- if (item_is_tag('t'))
- sym_set_tristate_value(sym, mod);
- break;
- }
- }
- }
- static void conf_message_callback(const char *fmt, va_list ap)
- {
- char buf[1024];
- vsnprintf(buf, sizeof(buf), fmt, ap);
- btn_dialog(main_window, buf, 1, "<OK>");
- }
- static void show_help(struct menu *menu)
- {
- struct gstr help;
- if (!menu)
- return;
- help = str_new();
- menu_get_ext_help(menu, &help);
- show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
- str_free(&help);
- }
- static void conf_choice(struct menu *menu)
- {
- const char *prompt = _(menu_get_prompt(menu));
- struct menu *child = 0;
- struct symbol *active;
- int selected_index = 0;
- int last_top_row = 0;
- int res, i = 0;
- struct match_state match_state = {
- .in_search = 0,
- .match_direction = MATCH_TINKER_PATTERN_DOWN,
- .pattern = "",
- };
- active = sym_get_choice_value(menu->sym);
- /* this is mostly duplicated from the conf() function. */
- while (!global_exit) {
- reset_menu();
- for (i = 0, child = menu->list; child; child = child->next) {
- if (!show_all_items && !menu_is_visible(child))
- continue;
- if (child->sym == sym_get_choice_value(menu->sym))
- item_make(child, ':', "<X> %s",
- _(menu_get_prompt(child)));
- else if (child->sym)
- item_make(child, ':', " %s",
- _(menu_get_prompt(child)));
- else
- item_make(child, ':', "*** %s ***",
- _(menu_get_prompt(child)));
- if (child->sym == active){
- last_top_row = top_row(curses_menu);
- selected_index = i;
- }
- i++;
- }
- show_menu(prompt ? _(prompt) : _("Choice Menu"),
- _(radiolist_instructions),
- selected_index,
- &last_top_row);
- while (!global_exit) {
- if (match_state.in_search) {
- mvprintw(0, 0, "searching: %s",
- match_state.pattern);
- clrtoeol();
- }
- refresh_all_windows(main_window);
- res = wgetch(menu_win(curses_menu));
- if (!res)
- break;
- if (do_match(res, &match_state, &selected_index) == 0) {
- if (selected_index != -1)
- center_item(selected_index,
- &last_top_row);
- continue;
- }
- if (process_special_keys(
- &res,
- (struct menu *) item_data()))
- break;
- switch (res) {
- case KEY_DOWN:
- menu_driver(curses_menu, REQ_DOWN_ITEM);
- break;
- case KEY_UP:
- menu_driver(curses_menu, REQ_UP_ITEM);
- break;
- case KEY_NPAGE:
- menu_driver(curses_menu, REQ_SCR_DPAGE);
- break;
- case KEY_PPAGE:
- menu_driver(curses_menu, REQ_SCR_UPAGE);
- break;
- case KEY_HOME:
- menu_driver(curses_menu, REQ_FIRST_ITEM);
- break;
- case KEY_END:
- menu_driver(curses_menu, REQ_LAST_ITEM);
- break;
- case 'h':
- case '?':
- show_help((struct menu *) item_data());
- break;
- }
- if (res == 10 || res == 27 || res == ' ' ||
- res == KEY_LEFT){
- break;
- }
- refresh_all_windows(main_window);
- }
- /* if ESC or left */
- if (res == 27 || res == KEY_LEFT)
- break;
- child = item_data();
- if (!child || !menu_is_visible(child) || !child->sym)
- continue;
- switch (res) {
- case ' ':
- case 10:
- case KEY_RIGHT:
- sym_set_tristate_value(child->sym, yes);
- return;
- case 'h':
- case '?':
- show_help(child);
- active = child->sym;
- break;
- case KEY_EXIT:
- return;
- }
- }
- }
- static void conf_string(struct menu *menu)
- {
- const char *prompt = menu_get_prompt(menu);
- while (1) {
- int res;
- const char *heading;
- switch (sym_get_type(menu->sym)) {
- case S_INT:
- heading = _(inputbox_instructions_int);
- break;
- case S_HEX:
- heading = _(inputbox_instructions_hex);
- break;
- case S_STRING:
- heading = _(inputbox_instructions_string);
- break;
- default:
- heading = _("Internal nconf error!");
- }
- res = dialog_inputbox(main_window,
- prompt ? _(prompt) : _("Main Menu"),
- heading,
- sym_get_string_value(menu->sym),
- &dialog_input_result,
- &dialog_input_result_len);
- switch (res) {
- case 0:
- if (sym_set_string_value(menu->sym,
- dialog_input_result))
- return;
- btn_dialog(main_window,
- _("You have made an invalid entry."), 0);
- break;
- case 1:
- show_help(menu);
- break;
- case KEY_EXIT:
- return;
- }
- }
- }
- static void conf_load(void)
- {
- while (1) {
- int res;
- res = dialog_inputbox(main_window,
- NULL, load_config_text,
- filename,
- &dialog_input_result,
- &dialog_input_result_len);
- switch (res) {
- case 0:
- if (!dialog_input_result[0])
- return;
- if (!conf_read(dialog_input_result)) {
- set_config_filename(dialog_input_result);
- sym_set_change_count(1);
- return;
- }
- btn_dialog(main_window, _("File does not exist!"), 0);
- break;
- case 1:
- show_scroll_win(main_window,
- _("Load Alternate Configuration"),
- load_config_help);
- break;
- case KEY_EXIT:
- return;
- }
- }
- }
- static void conf_save(void)
- {
- while (1) {
- int res;
- res = dialog_inputbox(main_window,
- NULL, save_config_text,
- filename,
- &dialog_input_result,
- &dialog_input_result_len);
- switch (res) {
- case 0:
- if (!dialog_input_result[0])
- return;
- res = conf_write(dialog_input_result);
- if (!res) {
- set_config_filename(dialog_input_result);
- return;
- }
- btn_dialog(main_window, _("Can't create file! "
- "Probably a nonexistent directory."),
- 1, "<OK>");
- break;
- case 1:
- show_scroll_win(main_window,
- _("Save Alternate Configuration"),
- save_config_help);
- break;
- case KEY_EXIT:
- return;
- }
- }
- }
- void setup_windows(void)
- {
- int lines, columns;
- getmaxyx(stdscr, lines, columns);
- if (main_window != NULL)
- delwin(main_window);
- /* set up the menu and menu window */
- main_window = newwin(lines-2, columns-2, 2, 1);
- keypad(main_window, TRUE);
- mwin_max_lines = lines-7;
- mwin_max_cols = columns-6;
- /* panels order is from bottom to top */
- new_panel(main_window);
- }
- int main(int ac, char **av)
- {
- int lines, columns;
- char *mode;
- setlocale(LC_ALL, "");
- bindtextdomain(PACKAGE, LOCALEDIR);
- textdomain(PACKAGE);
- conf_parse(av[1]);
- conf_read(NULL);
- mode = getenv("NCONFIG_MODE");
- if (mode) {
- if (!strcasecmp(mode, "single_menu"))
- single_menu_mode = 1;
- }
- /* Initialize curses */
- initscr();
- /* set color theme */
- set_colors();
- cbreak();
- noecho();
- keypad(stdscr, TRUE);
- curs_set(0);
- getmaxyx(stdscr, lines, columns);
- if (columns < 75 || lines < 20) {
- endwin();
- printf("Your terminal should have at "
- "least 20 lines and 75 columns\n");
- return 1;
- }
- notimeout(stdscr, FALSE);
- #if NCURSES_REENTRANT
- set_escdelay(1);
- #else
- ESCDELAY = 1;
- #endif
- /* set btns menu */
- curses_menu = new_menu(curses_menu_items);
- menu_opts_off(curses_menu, O_SHOWDESC);
- menu_opts_on(curses_menu, O_SHOWMATCH);
- menu_opts_on(curses_menu, O_ONEVALUE);
- menu_opts_on(curses_menu, O_NONCYCLIC);
- menu_opts_on(curses_menu, O_IGNORECASE);
- set_menu_mark(curses_menu, " ");
- set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
- set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
- set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
- set_config_filename(conf_get_configname());
- setup_windows();
- /* check for KEY_FUNC(1) */
- if (has_key(KEY_F(1)) == FALSE) {
- show_scroll_win(main_window,
- _("Instructions"),
- _(menu_no_f_instructions));
- }
- conf_set_message_callback(conf_message_callback);
- /* do the work */
- while (!global_exit) {
- conf(&rootmenu);
- if (!global_exit && do_exit() == 0)
- break;
- }
- /* ok, we are done */
- unpost_menu(curses_menu);
- free_menu(curses_menu);
- delwin(main_window);
- clear();
- refresh();
- endwin();
- return 0;
- }
|