linux/scripts/kconfig/nconf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com>
   4 *
   5 * Derived from menuconfig.
   6 */
   7#ifndef _GNU_SOURCE
   8#define _GNU_SOURCE
   9#endif
  10#include <string.h>
  11#include <strings.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[] =
  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[] =
 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[] =
 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[] =
 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[] =
 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[] =
 177"Please enter a hexadecimal value.\n"
 178"Press <Enter> to apply, <Esc> to cancel.",
 179inputbox_instructions_string[] =
 180"Please enter a string value.\n"
 181"Press <Enter> to apply, <Esc> to cancel.",
 182setmod_text[] =
 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[] =
 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[] =
 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[] =
 199"Enter a filename to which this configuration should be saved\n"
 200"as an alternate.  Leave empty to abort.",
 201save_config_help[] =
 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[] =
 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                conf_write_autoconf(0);
 678                break;
 679        default:
 680                btn_dialog(
 681                        main_window,
 682                        "Your configuration changes were NOT saved.",
 683                        1,
 684                        "<OK>");
 685                break;
 686        }
 687        global_exit = 1;
 688        return 0;
 689}
 690
 691
 692static void search_conf(void)
 693{
 694        struct symbol **sym_arr;
 695        struct gstr res;
 696        struct gstr title;
 697        char *dialog_input;
 698        int dres;
 699
 700        title = str_new();
 701        str_printf( &title, "Enter (sub)string or regexp to search for "
 702                              "(with or without \"%s\")", CONFIG_);
 703
 704again:
 705        dres = dialog_inputbox(main_window,
 706                        "Search Configuration Parameter",
 707                        str_get(&title),
 708                        "", &dialog_input_result, &dialog_input_result_len);
 709        switch (dres) {
 710        case 0:
 711                break;
 712        case 1:
 713                show_scroll_win(main_window,
 714                                "Search Configuration", search_help);
 715                goto again;
 716        default:
 717                str_free(&title);
 718                return;
 719        }
 720
 721        /* strip the prefix if necessary */
 722        dialog_input = dialog_input_result;
 723        if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
 724                dialog_input += strlen(CONFIG_);
 725
 726        sym_arr = sym_re_search(dialog_input);
 727        res = get_relations_str(sym_arr, NULL);
 728        free(sym_arr);
 729        show_scroll_win(main_window,
 730                        "Search Results", str_get(&res));
 731        str_free(&res);
 732        str_free(&title);
 733}
 734
 735
 736static void build_conf(struct menu *menu)
 737{
 738        struct symbol *sym;
 739        struct property *prop;
 740        struct menu *child;
 741        int type, tmp, doint = 2;
 742        tristate val;
 743        char ch;
 744
 745        if (!menu || (!show_all_items && !menu_is_visible(menu)))
 746                return;
 747
 748        sym = menu->sym;
 749        prop = menu->prompt;
 750        if (!sym) {
 751                if (prop && menu != current_menu) {
 752                        const char *prompt = menu_get_prompt(menu);
 753                        enum prop_type ptype;
 754                        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 755                        switch (ptype) {
 756                        case P_MENU:
 757                                child_count++;
 758                                prompt = prompt;
 759                                if (single_menu_mode) {
 760                                        item_make(menu, 'm',
 761                                                "%s%*c%s",
 762                                                menu->data ? "-->" : "++>",
 763                                                indent + 1, ' ', prompt);
 764                                } else
 765                                        item_make(menu, 'm',
 766                                                  "   %*c%s  %s",
 767                                                  indent + 1, ' ', prompt,
 768                                                  menu_is_empty(menu) ? "----" : "--->");
 769
 770                                if (single_menu_mode && menu->data)
 771                                        goto conf_childs;
 772                                return;
 773                        case P_COMMENT:
 774                                if (prompt) {
 775                                        child_count++;
 776                                        item_make(menu, ':',
 777                                                "   %*c*** %s ***",
 778                                                indent + 1, ' ',
 779                                                prompt);
 780                                }
 781                                break;
 782                        default:
 783                                if (prompt) {
 784                                        child_count++;
 785                                        item_make(menu, ':', "---%*c%s",
 786                                                indent + 1, ' ',
 787                                                prompt);
 788                                }
 789                        }
 790                } else
 791                        doint = 0;
 792                goto conf_childs;
 793        }
 794
 795        type = sym_get_type(sym);
 796        if (sym_is_choice(sym)) {
 797                struct symbol *def_sym = sym_get_choice_value(sym);
 798                struct menu *def_menu = NULL;
 799
 800                child_count++;
 801                for (child = menu->list; child; child = child->next) {
 802                        if (menu_is_visible(child) && child->sym == def_sym)
 803                                def_menu = child;
 804                }
 805
 806                val = sym_get_tristate_value(sym);
 807                if (sym_is_changeable(sym)) {
 808                        switch (type) {
 809                        case S_BOOLEAN:
 810                                item_make(menu, 't', "[%c]",
 811                                                val == no ? ' ' : '*');
 812                                break;
 813                        case S_TRISTATE:
 814                                switch (val) {
 815                                case yes:
 816                                        ch = '*';
 817                                        break;
 818                                case mod:
 819                                        ch = 'M';
 820                                        break;
 821                                default:
 822                                        ch = ' ';
 823                                        break;
 824                                }
 825                                item_make(menu, 't', "<%c>", ch);
 826                                break;
 827                        }
 828                } else {
 829                        item_make(menu, def_menu ? 't' : ':', "   ");
 830                }
 831
 832                item_add_str("%*c%s", indent + 1,
 833                                ' ', menu_get_prompt(menu));
 834                if (val == yes) {
 835                        if (def_menu) {
 836                                item_add_str(" (%s)",
 837                                        menu_get_prompt(def_menu));
 838                                item_add_str("  --->");
 839                                if (def_menu->list) {
 840                                        indent += 2;
 841                                        build_conf(def_menu);
 842                                        indent -= 2;
 843                                }
 844                        }
 845                        return;
 846                }
 847        } else {
 848                if (menu == current_menu) {
 849                        item_make(menu, ':',
 850                                "---%*c%s", indent + 1,
 851                                ' ', menu_get_prompt(menu));
 852                        goto conf_childs;
 853                }
 854                child_count++;
 855                val = sym_get_tristate_value(sym);
 856                if (sym_is_choice_value(sym) && val == yes) {
 857                        item_make(menu, ':', "   ");
 858                } else {
 859                        switch (type) {
 860                        case S_BOOLEAN:
 861                                if (sym_is_changeable(sym))
 862                                        item_make(menu, 't', "[%c]",
 863                                                val == no ? ' ' : '*');
 864                                else
 865                                        item_make(menu, 't', "-%c-",
 866                                                val == no ? ' ' : '*');
 867                                break;
 868                        case S_TRISTATE:
 869                                switch (val) {
 870                                case yes:
 871                                        ch = '*';
 872                                        break;
 873                                case mod:
 874                                        ch = 'M';
 875                                        break;
 876                                default:
 877                                        ch = ' ';
 878                                        break;
 879                                }
 880                                if (sym_is_changeable(sym)) {
 881                                        if (sym->rev_dep.tri == mod)
 882                                                item_make(menu,
 883                                                        't', "{%c}", ch);
 884                                        else
 885                                                item_make(menu,
 886                                                        't', "<%c>", ch);
 887                                } else
 888                                        item_make(menu, 't', "-%c-", ch);
 889                                break;
 890                        default:
 891                                tmp = 2 + strlen(sym_get_string_value(sym));
 892                                item_make(menu, 's', "    (%s)",
 893                                                sym_get_string_value(sym));
 894                                tmp = indent - tmp + 4;
 895                                if (tmp < 0)
 896                                        tmp = 0;
 897                                item_add_str("%*c%s%s", tmp, ' ',
 898                                                menu_get_prompt(menu),
 899                                                (sym_has_value(sym) ||
 900                                                 !sym_is_changeable(sym)) ? "" :
 901                                                " (NEW)");
 902                                goto conf_childs;
 903                        }
 904                }
 905                item_add_str("%*c%s%s", indent + 1, ' ',
 906                                menu_get_prompt(menu),
 907                                (sym_has_value(sym) || !sym_is_changeable(sym)) ?
 908                                "" : " (NEW)");
 909                if (menu->prompt && menu->prompt->type == P_MENU) {
 910                        item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
 911                        return;
 912                }
 913        }
 914
 915conf_childs:
 916        indent += doint;
 917        for (child = menu->list; child; child = child->next)
 918                build_conf(child);
 919        indent -= doint;
 920}
 921
 922static void reset_menu(void)
 923{
 924        unpost_menu(curses_menu);
 925        clean_items();
 926}
 927
 928/* adjust the menu to show this item.
 929 * prefer not to scroll the menu if possible*/
 930static void center_item(int selected_index, int *last_top_row)
 931{
 932        int toprow;
 933
 934        set_top_row(curses_menu, *last_top_row);
 935        toprow = top_row(curses_menu);
 936        if (selected_index < toprow ||
 937            selected_index >= toprow+mwin_max_lines) {
 938                toprow = max(selected_index-mwin_max_lines/2, 0);
 939                if (toprow >= item_count(curses_menu)-mwin_max_lines)
 940                        toprow = item_count(curses_menu)-mwin_max_lines;
 941                set_top_row(curses_menu, toprow);
 942        }
 943        set_current_item(curses_menu,
 944                        curses_menu_items[selected_index]);
 945        *last_top_row = toprow;
 946        post_menu(curses_menu);
 947        refresh_all_windows(main_window);
 948}
 949
 950/* this function assumes reset_menu has been called before */
 951static void show_menu(const char *prompt, const char *instructions,
 952                int selected_index, int *last_top_row)
 953{
 954        int maxx, maxy;
 955        WINDOW *menu_window;
 956
 957        current_instructions = instructions;
 958
 959        clear();
 960        (void) wattrset(main_window, attributes[NORMAL]);
 961        print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
 962                        menu_backtitle,
 963                        attributes[MAIN_HEADING]);
 964
 965        (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
 966        box(main_window, 0, 0);
 967        (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
 968        mvwprintw(main_window, 0, 3, " %s ", prompt);
 969        (void) wattrset(main_window, attributes[NORMAL]);
 970
 971        set_menu_items(curses_menu, curses_menu_items);
 972
 973        /* position the menu at the middle of the screen */
 974        scale_menu(curses_menu, &maxy, &maxx);
 975        maxx = min(maxx, mwin_max_cols-2);
 976        maxy = mwin_max_lines;
 977        menu_window = derwin(main_window,
 978                        maxy,
 979                        maxx,
 980                        2,
 981                        (mwin_max_cols-maxx)/2);
 982        keypad(menu_window, TRUE);
 983        set_menu_win(curses_menu, menu_window);
 984        set_menu_sub(curses_menu, menu_window);
 985
 986        /* must reassert this after changing items, otherwise returns to a
 987         * default of 16
 988         */
 989        set_menu_format(curses_menu, maxy, 1);
 990        center_item(selected_index, last_top_row);
 991        set_menu_format(curses_menu, maxy, 1);
 992
 993        print_function_line();
 994
 995        /* Post the menu */
 996        post_menu(curses_menu);
 997        refresh_all_windows(main_window);
 998}
 999
1000static void adj_match_dir(match_f *match_direction)
1001{
1002        if (*match_direction == FIND_NEXT_MATCH_DOWN)
1003                *match_direction =
1004                        MATCH_TINKER_PATTERN_DOWN;
1005        else if (*match_direction == FIND_NEXT_MATCH_UP)
1006                *match_direction =
1007                        MATCH_TINKER_PATTERN_UP;
1008        /* else, do no change.. */
1009}
1010
1011struct match_state
1012{
1013        int in_search;
1014        match_f match_direction;
1015        char pattern[256];
1016};
1017
1018/* Return 0 means I have handled the key. In such a case, ans should hold the
1019 * item to center, or -1 otherwise.
1020 * Else return -1 .
1021 */
1022static int do_match(int key, struct match_state *state, int *ans)
1023{
1024        char c = (char) key;
1025        int terminate_search = 0;
1026        *ans = -1;
1027        if (key == '/' || (state->in_search && key == 27)) {
1028                move(0, 0);
1029                refresh();
1030                clrtoeol();
1031                state->in_search = 1-state->in_search;
1032                bzero(state->pattern, sizeof(state->pattern));
1033                state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1034                return 0;
1035        } else if (!state->in_search)
1036                return 1;
1037
1038        if (isalnum(c) || isgraph(c) || c == ' ') {
1039                state->pattern[strlen(state->pattern)] = c;
1040                state->pattern[strlen(state->pattern)] = '\0';
1041                adj_match_dir(&state->match_direction);
1042                *ans = get_mext_match(state->pattern,
1043                                state->match_direction);
1044        } else if (key == KEY_DOWN) {
1045                state->match_direction = FIND_NEXT_MATCH_DOWN;
1046                *ans = get_mext_match(state->pattern,
1047                                state->match_direction);
1048        } else if (key == KEY_UP) {
1049                state->match_direction = FIND_NEXT_MATCH_UP;
1050                *ans = get_mext_match(state->pattern,
1051                                state->match_direction);
1052        } else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
1053                state->pattern[strlen(state->pattern)-1] = '\0';
1054                adj_match_dir(&state->match_direction);
1055        } else
1056                terminate_search = 1;
1057
1058        if (terminate_search) {
1059                state->in_search = 0;
1060                bzero(state->pattern, sizeof(state->pattern));
1061                move(0, 0);
1062                refresh();
1063                clrtoeol();
1064                return -1;
1065        }
1066        return 0;
1067}
1068
1069static void conf(struct menu *menu)
1070{
1071        struct menu *submenu = NULL;
1072        const char *prompt = menu_get_prompt(menu);
1073        struct symbol *sym;
1074        int res;
1075        int current_index = 0;
1076        int last_top_row = 0;
1077        struct match_state match_state = {
1078                .in_search = 0,
1079                .match_direction = MATCH_TINKER_PATTERN_DOWN,
1080                .pattern = "",
1081        };
1082
1083        while (!global_exit) {
1084                reset_menu();
1085                current_menu = menu;
1086                build_conf(menu);
1087                if (!child_count)
1088                        break;
1089
1090                show_menu(prompt ? prompt : "Main Menu",
1091                                menu_instructions,
1092                                current_index, &last_top_row);
1093                keypad((menu_win(curses_menu)), TRUE);
1094                while (!global_exit) {
1095                        if (match_state.in_search) {
1096                                mvprintw(0, 0,
1097                                        "searching: %s", match_state.pattern);
1098                                clrtoeol();
1099                        }
1100                        refresh_all_windows(main_window);
1101                        res = wgetch(menu_win(curses_menu));
1102                        if (!res)
1103                                break;
1104                        if (do_match(res, &match_state, &current_index) == 0) {
1105                                if (current_index != -1)
1106                                        center_item(current_index,
1107                                                    &last_top_row);
1108                                continue;
1109                        }
1110                        if (process_special_keys(&res,
1111                                                (struct menu *) item_data()))
1112                                break;
1113                        switch (res) {
1114                        case KEY_DOWN:
1115                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1116                                break;
1117                        case KEY_UP:
1118                                menu_driver(curses_menu, REQ_UP_ITEM);
1119                                break;
1120                        case KEY_NPAGE:
1121                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1122                                break;
1123                        case KEY_PPAGE:
1124                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1125                                break;
1126                        case KEY_HOME:
1127                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1128                                break;
1129                        case KEY_END:
1130                                menu_driver(curses_menu, REQ_LAST_ITEM);
1131                                break;
1132                        case 'h':
1133                        case '?':
1134                                show_help((struct menu *) item_data());
1135                                break;
1136                        }
1137                        if (res == 10 || res == 27 ||
1138                                res == 32 || res == 'n' || res == 'y' ||
1139                                res == KEY_LEFT || res == KEY_RIGHT ||
1140                                res == 'm')
1141                                break;
1142                        refresh_all_windows(main_window);
1143                }
1144
1145                refresh_all_windows(main_window);
1146                /* if ESC or left*/
1147                if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1148                        break;
1149
1150                /* remember location in the menu */
1151                last_top_row = top_row(curses_menu);
1152                current_index = curses_item_index();
1153
1154                if (!item_tag())
1155                        continue;
1156
1157                submenu = (struct menu *) item_data();
1158                if (!submenu || !menu_is_visible(submenu))
1159                        continue;
1160                sym = submenu->sym;
1161
1162                switch (res) {
1163                case ' ':
1164                        if (item_is_tag('t'))
1165                                sym_toggle_tristate_value(sym);
1166                        else if (item_is_tag('m'))
1167                                conf(submenu);
1168                        break;
1169                case KEY_RIGHT:
1170                case 10: /* ENTER WAS PRESSED */
1171                        switch (item_tag()) {
1172                        case 'm':
1173                                if (single_menu_mode)
1174                                        submenu->data =
1175                                                (void *) (long) !submenu->data;
1176                                else
1177                                        conf(submenu);
1178                                break;
1179                        case 't':
1180                                if (sym_is_choice(sym) &&
1181                                    sym_get_tristate_value(sym) == yes)
1182                                        conf_choice(submenu);
1183                                else if (submenu->prompt &&
1184                                         submenu->prompt->type == P_MENU)
1185                                        conf(submenu);
1186                                else if (res == 10)
1187                                        sym_toggle_tristate_value(sym);
1188                                break;
1189                        case 's':
1190                                conf_string(submenu);
1191                                break;
1192                        }
1193                        break;
1194                case 'y':
1195                        if (item_is_tag('t')) {
1196                                if (sym_set_tristate_value(sym, yes))
1197                                        break;
1198                                if (sym_set_tristate_value(sym, mod))
1199                                        btn_dialog(main_window, setmod_text, 0);
1200                        }
1201                        break;
1202                case 'n':
1203                        if (item_is_tag('t'))
1204                                sym_set_tristate_value(sym, no);
1205                        break;
1206                case 'm':
1207                        if (item_is_tag('t'))
1208                                sym_set_tristate_value(sym, mod);
1209                        break;
1210                }
1211        }
1212}
1213
1214static void conf_message_callback(const char *s)
1215{
1216        btn_dialog(main_window, s, 1, "<OK>");
1217}
1218
1219static void show_help(struct menu *menu)
1220{
1221        struct gstr help;
1222
1223        if (!menu)
1224                return;
1225
1226        help = str_new();
1227        menu_get_ext_help(menu, &help);
1228        show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help));
1229        str_free(&help);
1230}
1231
1232static void conf_choice(struct menu *menu)
1233{
1234        const char *prompt = menu_get_prompt(menu);
1235        struct menu *child = NULL;
1236        struct symbol *active;
1237        int selected_index = 0;
1238        int last_top_row = 0;
1239        int res, i = 0;
1240        struct match_state match_state = {
1241                .in_search = 0,
1242                .match_direction = MATCH_TINKER_PATTERN_DOWN,
1243                .pattern = "",
1244        };
1245
1246        active = sym_get_choice_value(menu->sym);
1247        /* this is mostly duplicated from the conf() function. */
1248        while (!global_exit) {
1249                reset_menu();
1250
1251                for (i = 0, child = menu->list; child; child = child->next) {
1252                        if (!show_all_items && !menu_is_visible(child))
1253                                continue;
1254
1255                        if (child->sym == sym_get_choice_value(menu->sym))
1256                                item_make(child, ':', "<X> %s",
1257                                                menu_get_prompt(child));
1258                        else if (child->sym)
1259                                item_make(child, ':', "    %s",
1260                                                menu_get_prompt(child));
1261                        else
1262                                item_make(child, ':', "*** %s ***",
1263                                                menu_get_prompt(child));
1264
1265                        if (child->sym == active){
1266                                last_top_row = top_row(curses_menu);
1267                                selected_index = i;
1268                        }
1269                        i++;
1270                }
1271                show_menu(prompt ? prompt : "Choice Menu",
1272                                radiolist_instructions,
1273                                selected_index,
1274                                &last_top_row);
1275                while (!global_exit) {
1276                        if (match_state.in_search) {
1277                                mvprintw(0, 0, "searching: %s",
1278                                         match_state.pattern);
1279                                clrtoeol();
1280                        }
1281                        refresh_all_windows(main_window);
1282                        res = wgetch(menu_win(curses_menu));
1283                        if (!res)
1284                                break;
1285                        if (do_match(res, &match_state, &selected_index) == 0) {
1286                                if (selected_index != -1)
1287                                        center_item(selected_index,
1288                                                    &last_top_row);
1289                                continue;
1290                        }
1291                        if (process_special_keys(
1292                                                &res,
1293                                                (struct menu *) item_data()))
1294                                break;
1295                        switch (res) {
1296                        case KEY_DOWN:
1297                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1298                                break;
1299                        case KEY_UP:
1300                                menu_driver(curses_menu, REQ_UP_ITEM);
1301                                break;
1302                        case KEY_NPAGE:
1303                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1304                                break;
1305                        case KEY_PPAGE:
1306                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1307                                break;
1308                        case KEY_HOME:
1309                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1310                                break;
1311                        case KEY_END:
1312                                menu_driver(curses_menu, REQ_LAST_ITEM);
1313                                break;
1314                        case 'h':
1315                        case '?':
1316                                show_help((struct menu *) item_data());
1317                                break;
1318                        }
1319                        if (res == 10 || res == 27 || res == ' ' ||
1320                                        res == KEY_LEFT){
1321                                break;
1322                        }
1323                        refresh_all_windows(main_window);
1324                }
1325                /* if ESC or left */
1326                if (res == 27 || res == KEY_LEFT)
1327                        break;
1328
1329                child = item_data();
1330                if (!child || !menu_is_visible(child) || !child->sym)
1331                        continue;
1332                switch (res) {
1333                case ' ':
1334                case  10:
1335                case KEY_RIGHT:
1336                        sym_set_tristate_value(child->sym, yes);
1337                        return;
1338                case 'h':
1339                case '?':
1340                        show_help(child);
1341                        active = child->sym;
1342                        break;
1343                case KEY_EXIT:
1344                        return;
1345                }
1346        }
1347}
1348
1349static void conf_string(struct menu *menu)
1350{
1351        const char *prompt = menu_get_prompt(menu);
1352
1353        while (1) {
1354                int res;
1355                const char *heading;
1356
1357                switch (sym_get_type(menu->sym)) {
1358                case S_INT:
1359                        heading = inputbox_instructions_int;
1360                        break;
1361                case S_HEX:
1362                        heading = inputbox_instructions_hex;
1363                        break;
1364                case S_STRING:
1365                        heading = inputbox_instructions_string;
1366                        break;
1367                default:
1368                        heading = "Internal nconf error!";
1369                }
1370                res = dialog_inputbox(main_window,
1371                                prompt ? prompt : "Main Menu",
1372                                heading,
1373                                sym_get_string_value(menu->sym),
1374                                &dialog_input_result,
1375                                &dialog_input_result_len);
1376                switch (res) {
1377                case 0:
1378                        if (sym_set_string_value(menu->sym,
1379                                                dialog_input_result))
1380                                return;
1381                        btn_dialog(main_window,
1382                                "You have made an invalid entry.", 0);
1383                        break;
1384                case 1:
1385                        show_help(menu);
1386                        break;
1387                case KEY_EXIT:
1388                        return;
1389                }
1390        }
1391}
1392
1393static void conf_load(void)
1394{
1395        while (1) {
1396                int res;
1397                res = dialog_inputbox(main_window,
1398                                NULL, load_config_text,
1399                                filename,
1400                                &dialog_input_result,
1401                                &dialog_input_result_len);
1402                switch (res) {
1403                case 0:
1404                        if (!dialog_input_result[0])
1405                                return;
1406                        if (!conf_read(dialog_input_result)) {
1407                                set_config_filename(dialog_input_result);
1408                                sym_set_change_count(1);
1409                                return;
1410                        }
1411                        btn_dialog(main_window, "File does not exist!", 0);
1412                        break;
1413                case 1:
1414                        show_scroll_win(main_window,
1415                                        "Load Alternate Configuration",
1416                                        load_config_help);
1417                        break;
1418                case KEY_EXIT:
1419                        return;
1420                }
1421        }
1422}
1423
1424static void conf_save(void)
1425{
1426        while (1) {
1427                int res;
1428                res = dialog_inputbox(main_window,
1429                                NULL, save_config_text,
1430                                filename,
1431                                &dialog_input_result,
1432                                &dialog_input_result_len);
1433                switch (res) {
1434                case 0:
1435                        if (!dialog_input_result[0])
1436                                return;
1437                        res = conf_write(dialog_input_result);
1438                        if (!res) {
1439                                set_config_filename(dialog_input_result);
1440                                return;
1441                        }
1442                        btn_dialog(main_window, "Can't create file!",
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
1456static void setup_windows(void)
1457{
1458        int lines, columns;
1459
1460        getmaxyx(stdscr, lines, columns);
1461
1462        if (main_window != NULL)
1463                delwin(main_window);
1464
1465        /* set up the menu and menu window */
1466        main_window = newwin(lines-2, columns-2, 2, 1);
1467        keypad(main_window, TRUE);
1468        mwin_max_lines = lines-7;
1469        mwin_max_cols = columns-6;
1470
1471        /* panels order is from bottom to top */
1472        new_panel(main_window);
1473}
1474
1475int main(int ac, char **av)
1476{
1477        int lines, columns;
1478        char *mode;
1479
1480        if (ac > 1 && strcmp(av[1], "-s") == 0) {
1481                /* Silence conf_read() until the real callback is set up */
1482                conf_set_message_callback(NULL);
1483                av++;
1484        }
1485        conf_parse(av[1]);
1486        conf_read(NULL);
1487
1488        mode = getenv("NCONFIG_MODE");
1489        if (mode) {
1490                if (!strcasecmp(mode, "single_menu"))
1491                        single_menu_mode = 1;
1492        }
1493
1494        /* Initialize curses */
1495        initscr();
1496        /* set color theme */
1497        set_colors();
1498
1499        cbreak();
1500        noecho();
1501        keypad(stdscr, TRUE);
1502        curs_set(0);
1503
1504        getmaxyx(stdscr, lines, columns);
1505        if (columns < 75 || lines < 20) {
1506                endwin();
1507                printf("Your terminal should have at "
1508                        "least 20 lines and 75 columns\n");
1509                return 1;
1510        }
1511
1512        notimeout(stdscr, FALSE);
1513#if NCURSES_REENTRANT
1514        set_escdelay(1);
1515#else
1516        ESCDELAY = 1;
1517#endif
1518
1519        /* set btns menu */
1520        curses_menu = new_menu(curses_menu_items);
1521        menu_opts_off(curses_menu, O_SHOWDESC);
1522        menu_opts_on(curses_menu, O_SHOWMATCH);
1523        menu_opts_on(curses_menu, O_ONEVALUE);
1524        menu_opts_on(curses_menu, O_NONCYCLIC);
1525        menu_opts_on(curses_menu, O_IGNORECASE);
1526        set_menu_mark(curses_menu, " ");
1527        set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
1528        set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
1529        set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
1530
1531        set_config_filename(conf_get_configname());
1532        setup_windows();
1533
1534        /* check for KEY_FUNC(1) */
1535        if (has_key(KEY_F(1)) == FALSE) {
1536                show_scroll_win(main_window,
1537                                "Instructions",
1538                                menu_no_f_instructions);
1539        }
1540
1541        conf_set_message_callback(conf_message_callback);
1542        /* do the work */
1543        while (!global_exit) {
1544                conf(&rootmenu);
1545                if (!global_exit && do_exit() == 0)
1546                        break;
1547        }
1548        /* ok, we are done */
1549        unpost_menu(curses_menu);
1550        free_menu(curses_menu);
1551        delwin(main_window);
1552        clear();
1553        refresh();
1554        endwin();
1555        return 0;
1556}
1557