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
  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."),
 185load_config_text[] = N_(
 186"Enter the name of the configuration file you wish to load.\n"
 187"Accept the name shown to restore the configuration you\n"
 188"last retrieved.  Leave blank to abort."),
 189load_config_help[] = N_(
 190"\n"
 191"For various reasons, one may wish to keep several different\n"
 192"configurations available on a single machine.\n"
 193"\n"
 194"If you have saved a previous configuration in a file other than the\n"
 195"default one, entering its name here will allow you to modify that\n"
 196"configuration.\n"
 197"\n"
 198"If you are uncertain, then you have probably never used alternate\n"
 199"configuration files.  You should therefor leave this blank to abort.\n"),
 200save_config_text[] = N_(
 201"Enter a filename to which this configuration should be saved\n"
 202"as an alternate.  Leave blank to abort."),
 203save_config_help[] = N_(
 204"\n"
 205"For various reasons, one may wish to keep different configurations\n"
 206"available on a single machine.\n"
 207"\n"
 208"Entering a file name here will allow you to later retrieve, modify\n"
 209"and use the current configuration as an alternate to whatever\n"
 210"configuration options you have selected at that time.\n"
 211"\n"
 212"If you are uncertain what all this means then you should probably\n"
 213"leave this blank.\n"),
 214search_help[] = N_(
 215"\n"
 216"Search for symbols and display their relations. Regular expressions\n"
 217"are allowed.\n"
 218"Example: search for \"^FOO\"\n"
 219"Result:\n"
 220"-----------------------------------------------------------------\n"
 221"Symbol: FOO [ = m]\n"
 222"Prompt: Foo bus is used to drive the bar HW\n"
 223"Defined at drivers/pci/Kconfig:47\n"
 224"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
 225"Location:\n"
 226"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
 227"    -> PCI support (PCI [ = y])\n"
 228"      -> PCI access mode (<choice> [ = y])\n"
 229"Selects: LIBCRC32\n"
 230"Selected by: BAR\n"
 231"-----------------------------------------------------------------\n"
 232"o The line 'Prompt:' shows the text used in the menu structure for\n"
 233"  this symbol\n"
 234"o The 'Defined at' line tell at what file / line number the symbol\n"
 235"  is defined\n"
 236"o The 'Depends on:' line tell what symbols needs to be defined for\n"
 237"  this symbol to be visible in the menu (selectable)\n"
 238"o The 'Location:' lines tell where in the menu structure this symbol\n"
 239"  is located\n"
 240"    A location followed by a [ = y] indicate that this is a selectable\n"
 241"    menu item - and current value is displayed inside brackets.\n"
 242"o The 'Selects:' line tell what symbol will be automatically\n"
 243"  selected if this symbol is selected (y or m)\n"
 244"o The 'Selected by' line tell what symbol has selected this symbol\n"
 245"\n"
 246"Only relevant lines are shown.\n"
 247"\n\n"
 248"Search examples:\n"
 249"Examples: USB  => find all symbols containing USB\n"
 250"          ^USB => find all symbols starting with USB\n"
 251"          USB$ => find all symbols ending with USB\n"
 252"\n");
 253
 254struct mitem {
 255        char str[256];
 256        char tag;
 257        void *usrptr;
 258        int is_visible;
 259};
 260
 261#define MAX_MENU_ITEMS 4096
 262static int show_all_items;
 263static int indent;
 264static struct menu *current_menu;
 265static int child_count;
 266static int single_menu_mode;
 267/* the window in which all information appears */
 268static WINDOW *main_window;
 269/* the largest size of the menu window */
 270static int mwin_max_lines;
 271static int mwin_max_cols;
 272/* the window in which we show option buttons */
 273static MENU *curses_menu;
 274static ITEM *curses_menu_items[MAX_MENU_ITEMS];
 275static struct mitem k_menu_items[MAX_MENU_ITEMS];
 276static int items_num;
 277static int global_exit;
 278/* the currently selected button */
 279const char *current_instructions = menu_instructions;
 280
 281static char *dialog_input_result;
 282static int dialog_input_result_len;
 283
 284static void conf(struct menu *menu);
 285static void conf_choice(struct menu *menu);
 286static void conf_string(struct menu *menu);
 287static void conf_load(void);
 288static void conf_save(void);
 289static void show_help(struct menu *menu);
 290static int do_exit(void);
 291static void setup_windows(void);
 292static void search_conf(void);
 293
 294typedef void (*function_key_handler_t)(int *key, struct menu *menu);
 295static void handle_f1(int *key, struct menu *current_item);
 296static void handle_f2(int *key, struct menu *current_item);
 297static void handle_f3(int *key, struct menu *current_item);
 298static void handle_f4(int *key, struct menu *current_item);
 299static void handle_f5(int *key, struct menu *current_item);
 300static void handle_f6(int *key, struct menu *current_item);
 301static void handle_f7(int *key, struct menu *current_item);
 302static void handle_f8(int *key, struct menu *current_item);
 303static void handle_f9(int *key, struct menu *current_item);
 304
 305struct function_keys {
 306        const char *key_str;
 307        const char *func;
 308        function_key key;
 309        function_key_handler_t handler;
 310};
 311
 312static const int function_keys_num = 9;
 313struct function_keys function_keys[] = {
 314        {
 315                .key_str = "F1",
 316                .func = "Help",
 317                .key = F_HELP,
 318                .handler = handle_f1,
 319        },
 320        {
 321                .key_str = "F2",
 322                .func = "Sym Info",
 323                .key = F_SYMBOL,
 324                .handler = handle_f2,
 325        },
 326        {
 327                .key_str = "F3",
 328                .func = "Insts",
 329                .key = F_INSTS,
 330                .handler = handle_f3,
 331        },
 332        {
 333                .key_str = "F4",
 334                .func = "Config",
 335                .key = F_CONF,
 336                .handler = handle_f4,
 337        },
 338        {
 339                .key_str = "F5",
 340                .func = "Back",
 341                .key = F_BACK,
 342                .handler = handle_f5,
 343        },
 344        {
 345                .key_str = "F6",
 346                .func = "Save",
 347                .key = F_SAVE,
 348                .handler = handle_f6,
 349        },
 350        {
 351                .key_str = "F7",
 352                .func = "Load",
 353                .key = F_LOAD,
 354                .handler = handle_f7,
 355        },
 356        {
 357                .key_str = "F8",
 358                .func = "Sym Search",
 359                .key = F_SEARCH,
 360                .handler = handle_f8,
 361        },
 362        {
 363                .key_str = "F9",
 364                .func = "Exit",
 365                .key = F_EXIT,
 366                .handler = handle_f9,
 367        },
 368};
 369
 370static void print_function_line(void)
 371{
 372        int i;
 373        int offset = 1;
 374        const int skip = 1;
 375
 376        for (i = 0; i < function_keys_num; i++) {
 377                (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
 378                mvwprintw(main_window, LINES-3, offset,
 379                                "%s",
 380                                function_keys[i].key_str);
 381                (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
 382                offset += strlen(function_keys[i].key_str);
 383                mvwprintw(main_window, LINES-3,
 384                                offset, "%s",
 385                                function_keys[i].func);
 386                offset += strlen(function_keys[i].func) + skip;
 387        }
 388        (void) wattrset(main_window, attributes[NORMAL]);
 389}
 390
 391/* help */
 392static void handle_f1(int *key, struct menu *current_item)
 393{
 394        show_scroll_win(main_window,
 395                        _("README"), _(nconf_readme));
 396        return;
 397}
 398
 399/* symbole help */
 400static void handle_f2(int *key, struct menu *current_item)
 401{
 402        show_help(current_item);
 403        return;
 404}
 405
 406/* instructions */
 407static void handle_f3(int *key, struct menu *current_item)
 408{
 409        show_scroll_win(main_window,
 410                        _("Instructions"),
 411                        _(current_instructions));
 412        return;
 413}
 414
 415/* config */
 416static void handle_f4(int *key, struct menu *current_item)
 417{
 418        int res = btn_dialog(main_window,
 419                        _("Show all symbols?"),
 420                        2,
 421                        "   <Show All>   ",
 422                        "<Don't show all>");
 423        if (res == 0)
 424                show_all_items = 1;
 425        else if (res == 1)
 426                show_all_items = 0;
 427
 428        return;
 429}
 430
 431/* back */
 432static void handle_f5(int *key, struct menu *current_item)
 433{
 434        *key = KEY_LEFT;
 435        return;
 436}
 437
 438/* save */
 439static void handle_f6(int *key, struct menu *current_item)
 440{
 441        conf_save();
 442        return;
 443}
 444
 445/* load */
 446static void handle_f7(int *key, struct menu *current_item)
 447{
 448        conf_load();
 449        return;
 450}
 451
 452/* search */
 453static void handle_f8(int *key, struct menu *current_item)
 454{
 455        search_conf();
 456        return;
 457}
 458
 459/* exit */
 460static void handle_f9(int *key, struct menu *current_item)
 461{
 462        do_exit();
 463        return;
 464}
 465
 466/* return != 0 to indicate the key was handles */
 467static int process_special_keys(int *key, struct menu *menu)
 468{
 469        int i;
 470
 471        if (*key == KEY_RESIZE) {
 472                setup_windows();
 473                return 1;
 474        }
 475
 476        for (i = 0; i < function_keys_num; i++) {
 477                if (*key == KEY_F(function_keys[i].key) ||
 478                    *key == '0' + function_keys[i].key){
 479                        function_keys[i].handler(key, menu);
 480                        return 1;
 481                }
 482        }
 483
 484        return 0;
 485}
 486
 487static void clean_items(void)
 488{
 489        int i;
 490        for (i = 0; curses_menu_items[i]; i++)
 491                free_item(curses_menu_items[i]);
 492        bzero(curses_menu_items, sizeof(curses_menu_items));
 493        bzero(k_menu_items, sizeof(k_menu_items));
 494        items_num = 0;
 495}
 496
 497typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
 498        FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
 499
 500/* return the index of the matched item, or -1 if no such item exists */
 501static int get_mext_match(const char *match_str, match_f flag)
 502{
 503        int match_start = item_index(current_item(curses_menu));
 504        int index;
 505
 506        if (flag == FIND_NEXT_MATCH_DOWN)
 507                ++match_start;
 508        else if (flag == FIND_NEXT_MATCH_UP)
 509                --match_start;
 510
 511        index = match_start;
 512        index = (index + items_num) % items_num;
 513        while (true) {
 514                char *str = k_menu_items[index].str;
 515                if (strcasestr(str, match_str) != 0)
 516                        return index;
 517                if (flag == FIND_NEXT_MATCH_UP ||
 518                    flag == MATCH_TINKER_PATTERN_UP)
 519                        --index;
 520                else
 521                        ++index;
 522                index = (index + items_num) % items_num;
 523                if (index == match_start)
 524                        return -1;
 525        }
 526}
 527
 528/* Make a new item. */
 529static void item_make(struct menu *menu, char tag, const char *fmt, ...)
 530{
 531        va_list ap;
 532
 533        if (items_num > MAX_MENU_ITEMS-1)
 534                return;
 535
 536        bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
 537        k_menu_items[items_num].tag = tag;
 538        k_menu_items[items_num].usrptr = menu;
 539        if (menu != NULL)
 540                k_menu_items[items_num].is_visible =
 541                        menu_is_visible(menu);
 542        else
 543                k_menu_items[items_num].is_visible = 1;
 544
 545        va_start(ap, fmt);
 546        vsnprintf(k_menu_items[items_num].str,
 547                  sizeof(k_menu_items[items_num].str),
 548                  fmt, ap);
 549        va_end(ap);
 550
 551        if (!k_menu_items[items_num].is_visible)
 552                memcpy(k_menu_items[items_num].str, "XXX", 3);
 553
 554        curses_menu_items[items_num] = new_item(
 555                        k_menu_items[items_num].str,
 556                        k_menu_items[items_num].str);
 557        set_item_userptr(curses_menu_items[items_num],
 558                        &k_menu_items[items_num]);
 559        /*
 560        if (!k_menu_items[items_num].is_visible)
 561                item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
 562        */
 563
 564        items_num++;
 565        curses_menu_items[items_num] = NULL;
 566}
 567
 568/* very hackish. adds a string to the last item added */
 569static void item_add_str(const char *fmt, ...)
 570{
 571        va_list ap;
 572        int index = items_num-1;
 573        char new_str[256];
 574        char tmp_str[256];
 575
 576        if (index < 0)
 577                return;
 578
 579        va_start(ap, fmt);
 580        vsnprintf(new_str, sizeof(new_str), fmt, ap);
 581        va_end(ap);
 582        snprintf(tmp_str, sizeof(tmp_str), "%s%s",
 583                        k_menu_items[index].str, new_str);
 584        strncpy(k_menu_items[index].str,
 585                tmp_str,
 586                sizeof(k_menu_items[index].str));
 587
 588        free_item(curses_menu_items[index]);
 589        curses_menu_items[index] = new_item(
 590                        k_menu_items[index].str,
 591                        k_menu_items[index].str);
 592        set_item_userptr(curses_menu_items[index],
 593                        &k_menu_items[index]);
 594}
 595
 596/* get the tag of the currently selected item */
 597static char item_tag(void)
 598{
 599        ITEM *cur;
 600        struct mitem *mcur;
 601
 602        cur = current_item(curses_menu);
 603        if (cur == NULL)
 604                return 0;
 605        mcur = (struct mitem *) item_userptr(cur);
 606        return mcur->tag;
 607}
 608
 609static int curses_item_index(void)
 610{
 611        return  item_index(current_item(curses_menu));
 612}
 613
 614static void *item_data(void)
 615{
 616        ITEM *cur;
 617        struct mitem *mcur;
 618
 619        cur = current_item(curses_menu);
 620        if (!cur)
 621                return NULL;
 622        mcur = (struct mitem *) item_userptr(cur);
 623        return mcur->usrptr;
 624
 625}
 626
 627static int item_is_tag(char tag)
 628{
 629        return item_tag() == tag;
 630}
 631
 632static char filename[PATH_MAX+1];
 633static char menu_backtitle[PATH_MAX+128];
 634static const char *set_config_filename(const char *config_filename)
 635{
 636        int size;
 637
 638        size = snprintf(menu_backtitle, sizeof(menu_backtitle),
 639                        "%s - %s", config_filename, rootmenu.prompt->text);
 640        if (size >= sizeof(menu_backtitle))
 641                menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
 642
 643        size = snprintf(filename, sizeof(filename), "%s", config_filename);
 644        if (size >= sizeof(filename))
 645                filename[sizeof(filename)-1] = '\0';
 646        return menu_backtitle;
 647}
 648
 649/* return = 0 means we are successful.
 650 * -1 means go on doing what you were doing
 651 */
 652static int do_exit(void)
 653{
 654        int res;
 655        if (!conf_get_changed()) {
 656                global_exit = 1;
 657                return 0;
 658        }
 659        res = btn_dialog(main_window,
 660                        _("Do you wish to save your new configuration?\n"
 661                                "<ESC> to cancel and resume nconfig."),
 662                        2,
 663                        "   <save>   ",
 664                        "<don't save>");
 665        if (res == KEY_EXIT) {
 666                global_exit = 0;
 667                return -1;
 668        }
 669
 670        /* if we got here, the user really wants to exit */
 671        switch (res) {
 672        case 0:
 673                res = conf_write(filename);
 674                if (res)
 675                        btn_dialog(
 676                                main_window,
 677                                _("Error during writing of configuration.\n"
 678                                  "Your configuration changes were NOT saved."),
 679                                  1,
 680                                  "<OK>");
 681                break;
 682        default:
 683                btn_dialog(
 684                        main_window,
 685                        _("Your configuration changes were NOT saved."),
 686                        1,
 687                        "<OK>");
 688                break;
 689        }
 690        global_exit = 1;
 691        return 0;
 692}
 693
 694
 695static void search_conf(void)
 696{
 697        struct symbol **sym_arr;
 698        struct gstr res;
 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, &dialog_input_result_len);
 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        (void) wattrset(main_window, attributes[NORMAL]);
 957        print_in_middle(stdscr, 1, 0, COLS,
 958                        menu_backtitle,
 959                        attributes[MAIN_HEADING]);
 960
 961        (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
 962        box(main_window, 0, 0);
 963        (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
 964        mvwprintw(main_window, 0, 3, " %s ", prompt);
 965        (void) 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        int res;
1071        int current_index = 0;
1072        int last_top_row = 0;
1073        struct match_state match_state = {
1074                .in_search = 0,
1075                .match_direction = MATCH_TINKER_PATTERN_DOWN,
1076                .pattern = "",
1077        };
1078
1079        while (!global_exit) {
1080                reset_menu();
1081                current_menu = menu;
1082                build_conf(menu);
1083                if (!child_count)
1084                        break;
1085
1086                show_menu(prompt ? _(prompt) : _("Main Menu"),
1087                                _(menu_instructions),
1088                                current_index, &last_top_row);
1089                keypad((menu_win(curses_menu)), TRUE);
1090                while (!global_exit) {
1091                        if (match_state.in_search) {
1092                                mvprintw(0, 0,
1093                                        "searching: %s", match_state.pattern);
1094                                clrtoeol();
1095                        }
1096                        refresh_all_windows(main_window);
1097                        res = wgetch(menu_win(curses_menu));
1098                        if (!res)
1099                                break;
1100                        if (do_match(res, &match_state, &current_index) == 0) {
1101                                if (current_index != -1)
1102                                        center_item(current_index,
1103                                                    &last_top_row);
1104                                continue;
1105                        }
1106                        if (process_special_keys(&res,
1107                                                (struct menu *) item_data()))
1108                                break;
1109                        switch (res) {
1110                        case KEY_DOWN:
1111                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1112                                break;
1113                        case KEY_UP:
1114                                menu_driver(curses_menu, REQ_UP_ITEM);
1115                                break;
1116                        case KEY_NPAGE:
1117                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1118                                break;
1119                        case KEY_PPAGE:
1120                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1121                                break;
1122                        case KEY_HOME:
1123                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1124                                break;
1125                        case KEY_END:
1126                                menu_driver(curses_menu, REQ_LAST_ITEM);
1127                                break;
1128                        case 'h':
1129                        case '?':
1130                                show_help((struct menu *) item_data());
1131                                break;
1132                        }
1133                        if (res == 10 || res == 27 ||
1134                                res == 32 || res == 'n' || res == 'y' ||
1135                                res == KEY_LEFT || res == KEY_RIGHT ||
1136                                res == 'm')
1137                                break;
1138                        refresh_all_windows(main_window);
1139                }
1140
1141                refresh_all_windows(main_window);
1142                /* if ESC or left*/
1143                if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1144                        break;
1145
1146                /* remember location in the menu */
1147                last_top_row = top_row(curses_menu);
1148                current_index = curses_item_index();
1149
1150                if (!item_tag())
1151                        continue;
1152
1153                submenu = (struct menu *) item_data();
1154                if (!submenu || !menu_is_visible(submenu))
1155                        continue;
1156                sym = submenu->sym;
1157
1158                switch (res) {
1159                case ' ':
1160                        if (item_is_tag('t'))
1161                                sym_toggle_tristate_value(sym);
1162                        else if (item_is_tag('m'))
1163                                conf(submenu);
1164                        break;
1165                case KEY_RIGHT:
1166                case 10: /* ENTER WAS PRESSED */
1167                        switch (item_tag()) {
1168                        case 'm':
1169                                if (single_menu_mode)
1170                                        submenu->data =
1171                                                (void *) (long) !submenu->data;
1172                                else
1173                                        conf(submenu);
1174                                break;
1175                        case 't':
1176                                if (sym_is_choice(sym) &&
1177                                    sym_get_tristate_value(sym) == yes)
1178                                        conf_choice(submenu);
1179                                else if (submenu->prompt &&
1180                                         submenu->prompt->type == P_MENU)
1181                                        conf(submenu);
1182                                else if (res == 10)
1183                                        sym_toggle_tristate_value(sym);
1184                                break;
1185                        case 's':
1186                                conf_string(submenu);
1187                                break;
1188                        }
1189                        break;
1190                case 'y':
1191                        if (item_is_tag('t')) {
1192                                if (sym_set_tristate_value(sym, yes))
1193                                        break;
1194                                if (sym_set_tristate_value(sym, mod))
1195                                        btn_dialog(main_window, setmod_text, 0);
1196                        }
1197                        break;
1198                case 'n':
1199                        if (item_is_tag('t'))
1200                                sym_set_tristate_value(sym, no);
1201                        break;
1202                case 'm':
1203                        if (item_is_tag('t'))
1204                                sym_set_tristate_value(sym, mod);
1205                        break;
1206                }
1207        }
1208}
1209
1210static void conf_message_callback(const char *fmt, va_list ap)
1211{
1212        char buf[1024];
1213
1214        vsnprintf(buf, sizeof(buf), fmt, ap);
1215        btn_dialog(main_window, buf, 1, "<OK>");
1216}
1217
1218static void show_help(struct menu *menu)
1219{
1220        struct gstr help;
1221
1222        if (!menu)
1223                return;
1224
1225        help = str_new();
1226        menu_get_ext_help(menu, &help);
1227        show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
1228        str_free(&help);
1229}
1230
1231static void conf_choice(struct menu *menu)
1232{
1233        const char *prompt = _(menu_get_prompt(menu));
1234        struct menu *child = 0;
1235        struct symbol *active;
1236        int selected_index = 0;
1237        int last_top_row = 0;
1238        int res, i = 0;
1239        struct match_state match_state = {
1240                .in_search = 0,
1241                .match_direction = MATCH_TINKER_PATTERN_DOWN,
1242                .pattern = "",
1243        };
1244
1245        active = sym_get_choice_value(menu->sym);
1246        /* this is mostly duplicated from the conf() function. */
1247        while (!global_exit) {
1248                reset_menu();
1249
1250                for (i = 0, child = menu->list; child; child = child->next) {
1251                        if (!show_all_items && !menu_is_visible(child))
1252                                continue;
1253
1254                        if (child->sym == sym_get_choice_value(menu->sym))
1255                                item_make(child, ':', "<X> %s",
1256                                                _(menu_get_prompt(child)));
1257                        else if (child->sym)
1258                                item_make(child, ':', "    %s",
1259                                                _(menu_get_prompt(child)));
1260                        else
1261                                item_make(child, ':', "*** %s ***",
1262                                                _(menu_get_prompt(child)));
1263
1264                        if (child->sym == active){
1265                                last_top_row = top_row(curses_menu);
1266                                selected_index = i;
1267                        }
1268                        i++;
1269                }
1270                show_menu(prompt ? _(prompt) : _("Choice Menu"),
1271                                _(radiolist_instructions),
1272                                selected_index,
1273                                &last_top_row);
1274                while (!global_exit) {
1275                        if (match_state.in_search) {
1276                                mvprintw(0, 0, "searching: %s",
1277                                         match_state.pattern);
1278                                clrtoeol();
1279                        }
1280                        refresh_all_windows(main_window);
1281                        res = wgetch(menu_win(curses_menu));
1282                        if (!res)
1283                                break;
1284                        if (do_match(res, &match_state, &selected_index) == 0) {
1285                                if (selected_index != -1)
1286                                        center_item(selected_index,
1287                                                    &last_top_row);
1288                                continue;
1289                        }
1290                        if (process_special_keys(
1291                                                &res,
1292                                                (struct menu *) item_data()))
1293                                break;
1294                        switch (res) {
1295                        case KEY_DOWN:
1296                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1297                                break;
1298                        case KEY_UP:
1299                                menu_driver(curses_menu, REQ_UP_ITEM);
1300                                break;
1301                        case KEY_NPAGE:
1302                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1303                                break;
1304                        case KEY_PPAGE:
1305                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1306                                break;
1307                        case KEY_HOME:
1308                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1309                                break;
1310                        case KEY_END:
1311                                menu_driver(curses_menu, REQ_LAST_ITEM);
1312                                break;
1313                        case 'h':
1314                        case '?':
1315                                show_help((struct menu *) item_data());
1316                                break;
1317                        }
1318                        if (res == 10 || res == 27 || res == ' ' ||
1319                                        res == KEY_LEFT){
1320                                break;
1321                        }
1322                        refresh_all_windows(main_window);
1323                }
1324                /* if ESC or left */
1325                if (res == 27 || res == KEY_LEFT)
1326                        break;
1327
1328                child = item_data();
1329                if (!child || !menu_is_visible(child) || !child->sym)
1330                        continue;
1331                switch (res) {
1332                case ' ':
1333                case  10:
1334                case KEY_RIGHT:
1335                        sym_set_tristate_value(child->sym, yes);
1336                        return;
1337                case 'h':
1338                case '?':
1339                        show_help(child);
1340                        active = child->sym;
1341                        break;
1342                case KEY_EXIT:
1343                        return;
1344                }
1345        }
1346}
1347
1348static void conf_string(struct menu *menu)
1349{
1350        const char *prompt = menu_get_prompt(menu);
1351
1352        while (1) {
1353                int res;
1354                const char *heading;
1355
1356                switch (sym_get_type(menu->sym)) {
1357                case S_INT:
1358                        heading = _(inputbox_instructions_int);
1359                        break;
1360                case S_HEX:
1361                        heading = _(inputbox_instructions_hex);
1362                        break;
1363                case S_STRING:
1364                        heading = _(inputbox_instructions_string);
1365                        break;
1366                default:
1367                        heading = _("Internal nconf error!");
1368                }
1369                res = dialog_inputbox(main_window,
1370                                prompt ? _(prompt) : _("Main Menu"),
1371                                heading,
1372                                sym_get_string_value(menu->sym),
1373                                &dialog_input_result,
1374                                &dialog_input_result_len);
1375                switch (res) {
1376                case 0:
1377                        if (sym_set_string_value(menu->sym,
1378                                                dialog_input_result))
1379                                return;
1380                        btn_dialog(main_window,
1381                                _("You have made an invalid entry."), 0);
1382                        break;
1383                case 1:
1384                        show_help(menu);
1385                        break;
1386                case KEY_EXIT:
1387                        return;
1388                }
1389        }
1390}
1391
1392static void conf_load(void)
1393{
1394        while (1) {
1395                int res;
1396                res = dialog_inputbox(main_window,
1397                                NULL, load_config_text,
1398                                filename,
1399                                &dialog_input_result,
1400                                &dialog_input_result_len);
1401                switch (res) {
1402                case 0:
1403                        if (!dialog_input_result[0])
1404                                return;
1405                        if (!conf_read(dialog_input_result)) {
1406                                set_config_filename(dialog_input_result);
1407                                sym_set_change_count(1);
1408                                return;
1409                        }
1410                        btn_dialog(main_window, _("File does not exist!"), 0);
1411                        break;
1412                case 1:
1413                        show_scroll_win(main_window,
1414                                        _("Load Alternate Configuration"),
1415                                        load_config_help);
1416                        break;
1417                case KEY_EXIT:
1418                        return;
1419                }
1420        }
1421}
1422
1423static void conf_save(void)
1424{
1425        while (1) {
1426                int res;
1427                res = dialog_inputbox(main_window,
1428                                NULL, save_config_text,
1429                                filename,
1430                                &dialog_input_result,
1431                                &dialog_input_result_len);
1432                switch (res) {
1433                case 0:
1434                        if (!dialog_input_result[0])
1435                                return;
1436                        res = conf_write(dialog_input_result);
1437                        if (!res) {
1438                                set_config_filename(dialog_input_result);
1439                                return;
1440                        }
1441                        btn_dialog(main_window, _("Can't create file! "
1442                                "Probably a nonexistent directory."),
1443                                1, "<OK>");
1444                        break;
1445                case 1:
1446                        show_scroll_win(main_window,
1447                                _("Save Alternate Configuration"),
1448                                save_config_help);
1449                        break;
1450                case KEY_EXIT:
1451                        return;
1452                }
1453        }
1454}
1455
1456void setup_windows(void)
1457{
1458        if (main_window != NULL)
1459                delwin(main_window);
1460
1461        /* set up the menu and menu window */
1462        main_window = newwin(LINES-2, COLS-2, 2, 1);
1463        keypad(main_window, TRUE);
1464        mwin_max_lines = LINES-7;
1465        mwin_max_cols = COLS-6;
1466
1467        /* panels order is from bottom to top */
1468        new_panel(main_window);
1469}
1470
1471int main(int ac, char **av)
1472{
1473        char *mode;
1474
1475        setlocale(LC_ALL, "");
1476        bindtextdomain(PACKAGE, LOCALEDIR);
1477        textdomain(PACKAGE);
1478
1479        conf_parse(av[1]);
1480        conf_read(NULL);
1481
1482        mode = getenv("NCONFIG_MODE");
1483        if (mode) {
1484                if (!strcasecmp(mode, "single_menu"))
1485                        single_menu_mode = 1;
1486        }
1487
1488        /* Initialize curses */
1489        initscr();
1490        /* set color theme */
1491        set_colors();
1492
1493        cbreak();
1494        noecho();
1495        keypad(stdscr, TRUE);
1496        curs_set(0);
1497
1498        if (COLS < 75 || LINES < 20) {
1499                endwin();
1500                printf("Your terminal should have at "
1501                        "least 20 lines and 75 columns\n");
1502                return 1;
1503        }
1504
1505        notimeout(stdscr, FALSE);
1506        ESCDELAY = 1;
1507
1508        /* set btns menu */
1509        curses_menu = new_menu(curses_menu_items);
1510        menu_opts_off(curses_menu, O_SHOWDESC);
1511        menu_opts_on(curses_menu, O_SHOWMATCH);
1512        menu_opts_on(curses_menu, O_ONEVALUE);
1513        menu_opts_on(curses_menu, O_NONCYCLIC);
1514        menu_opts_on(curses_menu, O_IGNORECASE);
1515        set_menu_mark(curses_menu, " ");
1516        set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1517        set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1518        set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1519
1520        set_config_filename(conf_get_configname());
1521        setup_windows();
1522
1523        /* check for KEY_FUNC(1) */
1524        if (has_key(KEY_F(1)) == FALSE) {
1525                show_scroll_win(main_window,
1526                                _("Instructions"),
1527                                _(menu_no_f_instructions));
1528        }
1529
1530        conf_set_message_callback(conf_message_callback);
1531        /* do the work */
1532        while (!global_exit) {
1533                conf(&rootmenu);
1534                if (!global_exit && do_exit() == 0)
1535                        break;
1536        }
1537        /* ok, we are done */
1538        unpost_menu(curses_menu);
1539        free_menu(curses_menu);
1540        delwin(main_window);
1541        clear();
1542        refresh();
1543        endwin();
1544        return 0;
1545}
1546
1547