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