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