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>    <k>\n"
  56"Linewise down               <Down>  <j>\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 unsigned 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                wattrset(main_window, attr_function_highlight);
 374                mvwprintw(main_window, lines-3, offset,
 375                                "%s",
 376                                function_keys[i].key_str);
 377                wattrset(main_window, attr_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        wattrset(main_window, attr_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, index;
 500
 501        /* Do not search if the menu is empty (i.e. items_num == 0) */
 502        match_start = item_index(current_item(curses_menu));
 503        if (match_start == ERR)
 504                return -1;
 505
 506        if (flag == FIND_NEXT_MATCH_DOWN)
 507                ++match_start;
 508        else if (flag == FIND_NEXT_MATCH_UP)
 509                --match_start;
 510
 511        match_start = (match_start + items_num) % items_num;
 512        index = match_start;
 513        while (true) {
 514                char *str = k_menu_items[index].str;
 515                if (strcasestr(str, match_str) != NULL)
 516                        return index;
 517                if (flag == FIND_NEXT_MATCH_UP ||
 518                    flag == MATCH_TINKER_PATTERN_UP)
 519                        --index;
 520                else
 521                        ++index;
 522                index = (index + items_num) % items_num;
 523                if (index == match_start)
 524                        return -1;
 525        }
 526}
 527
 528/* Make a new item. */
 529static void item_make(struct menu *menu, char tag, const char *fmt, ...)
 530{
 531        va_list ap;
 532
 533        if (items_num > MAX_MENU_ITEMS-1)
 534                return;
 535
 536        bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
 537        k_menu_items[items_num].tag = tag;
 538        k_menu_items[items_num].usrptr = menu;
 539        if (menu != NULL)
 540                k_menu_items[items_num].is_visible =
 541                        menu_is_visible(menu);
 542        else
 543                k_menu_items[items_num].is_visible = 1;
 544
 545        va_start(ap, fmt);
 546        vsnprintf(k_menu_items[items_num].str,
 547                  sizeof(k_menu_items[items_num].str),
 548                  fmt, ap);
 549        va_end(ap);
 550
 551        if (!k_menu_items[items_num].is_visible)
 552                memcpy(k_menu_items[items_num].str, "XXX", 3);
 553
 554        curses_menu_items[items_num] = new_item(
 555                        k_menu_items[items_num].str,
 556                        k_menu_items[items_num].str);
 557        set_item_userptr(curses_menu_items[items_num],
 558                        &k_menu_items[items_num]);
 559        /*
 560        if (!k_menu_items[items_num].is_visible)
 561                item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
 562        */
 563
 564        items_num++;
 565        curses_menu_items[items_num] = NULL;
 566}
 567
 568/* very hackish. adds a string to the last item added */
 569static void item_add_str(const char *fmt, ...)
 570{
 571        va_list ap;
 572        int index = items_num-1;
 573        char new_str[256];
 574        char tmp_str[256];
 575
 576        if (index < 0)
 577                return;
 578
 579        va_start(ap, fmt);
 580        vsnprintf(new_str, sizeof(new_str), fmt, ap);
 581        va_end(ap);
 582        snprintf(tmp_str, sizeof(tmp_str), "%s%s",
 583                        k_menu_items[index].str, new_str);
 584        strncpy(k_menu_items[index].str,
 585                tmp_str,
 586                sizeof(k_menu_items[index].str));
 587
 588        free_item(curses_menu_items[index]);
 589        curses_menu_items[index] = new_item(
 590                        k_menu_items[index].str,
 591                        k_menu_items[index].str);
 592        set_item_userptr(curses_menu_items[index],
 593                        &k_menu_items[index]);
 594}
 595
 596/* get the tag of the currently selected item */
 597static char item_tag(void)
 598{
 599        ITEM *cur;
 600        struct mitem *mcur;
 601
 602        cur = current_item(curses_menu);
 603        if (cur == NULL)
 604                return 0;
 605        mcur = (struct mitem *) item_userptr(cur);
 606        return mcur->tag;
 607}
 608
 609static int curses_item_index(void)
 610{
 611        return  item_index(current_item(curses_menu));
 612}
 613
 614static void *item_data(void)
 615{
 616        ITEM *cur;
 617        struct mitem *mcur;
 618
 619        cur = current_item(curses_menu);
 620        if (!cur)
 621                return NULL;
 622        mcur = (struct mitem *) item_userptr(cur);
 623        return mcur->usrptr;
 624
 625}
 626
 627static int item_is_tag(char tag)
 628{
 629        return item_tag() == tag;
 630}
 631
 632static char filename[PATH_MAX+1];
 633static char menu_backtitle[PATH_MAX+128];
 634static void set_config_filename(const char *config_filename)
 635{
 636        snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s",
 637                 config_filename, rootmenu.prompt->text);
 638
 639        snprintf(filename, sizeof(filename), "%s", config_filename);
 640}
 641
 642/* return = 0 means we are successful.
 643 * -1 means go on doing what you were doing
 644 */
 645static int do_exit(void)
 646{
 647        int res;
 648        if (!conf_get_changed()) {
 649                global_exit = 1;
 650                return 0;
 651        }
 652        res = btn_dialog(main_window,
 653                        "Do you wish to save your new configuration?\n"
 654                                "<ESC> to cancel and resume nconfig.",
 655                        2,
 656                        "   <save>   ",
 657                        "<don't save>");
 658        if (res == KEY_EXIT) {
 659                global_exit = 0;
 660                return -1;
 661        }
 662
 663        /* if we got here, the user really wants to exit */
 664        switch (res) {
 665        case 0:
 666                res = conf_write(filename);
 667                if (res)
 668                        btn_dialog(
 669                                main_window,
 670                                "Error during writing of configuration.\n"
 671                                  "Your configuration changes were NOT saved.",
 672                                  1,
 673                                  "<OK>");
 674                conf_write_autoconf(0);
 675                break;
 676        default:
 677                btn_dialog(
 678                        main_window,
 679                        "Your configuration changes were NOT saved.",
 680                        1,
 681                        "<OK>");
 682                break;
 683        }
 684        global_exit = 1;
 685        return 0;
 686}
 687
 688
 689static void search_conf(void)
 690{
 691        struct symbol **sym_arr;
 692        struct gstr res;
 693        struct gstr title;
 694        char *dialog_input;
 695        int dres;
 696
 697        title = str_new();
 698        str_printf( &title, "Enter (sub)string or regexp to search for "
 699                              "(with or without \"%s\")", CONFIG_);
 700
 701again:
 702        dres = dialog_inputbox(main_window,
 703                        "Search Configuration Parameter",
 704                        str_get(&title),
 705                        "", &dialog_input_result, &dialog_input_result_len);
 706        switch (dres) {
 707        case 0:
 708                break;
 709        case 1:
 710                show_scroll_win(main_window,
 711                                "Search Configuration", search_help);
 712                goto again;
 713        default:
 714                str_free(&title);
 715                return;
 716        }
 717
 718        /* strip the prefix if necessary */
 719        dialog_input = dialog_input_result;
 720        if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
 721                dialog_input += strlen(CONFIG_);
 722
 723        sym_arr = sym_re_search(dialog_input);
 724        res = get_relations_str(sym_arr, NULL);
 725        free(sym_arr);
 726        show_scroll_win(main_window,
 727                        "Search Results", str_get(&res));
 728        str_free(&res);
 729        str_free(&title);
 730}
 731
 732
 733static void build_conf(struct menu *menu)
 734{
 735        struct symbol *sym;
 736        struct property *prop;
 737        struct menu *child;
 738        int type, tmp, doint = 2;
 739        tristate val;
 740        char ch;
 741
 742        if (!menu || (!show_all_items && !menu_is_visible(menu)))
 743                return;
 744
 745        sym = menu->sym;
 746        prop = menu->prompt;
 747        if (!sym) {
 748                if (prop && menu != current_menu) {
 749                        const char *prompt = menu_get_prompt(menu);
 750                        enum prop_type ptype;
 751                        ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
 752                        switch (ptype) {
 753                        case P_MENU:
 754                                child_count++;
 755                                if (single_menu_mode) {
 756                                        item_make(menu, 'm',
 757                                                "%s%*c%s",
 758                                                menu->data ? "-->" : "++>",
 759                                                indent + 1, ' ', prompt);
 760                                } else
 761                                        item_make(menu, 'm',
 762                                                  "   %*c%s  %s",
 763                                                  indent + 1, ' ', prompt,
 764                                                  menu_is_empty(menu) ? "----" : "--->");
 765
 766                                if (single_menu_mode && menu->data)
 767                                        goto conf_childs;
 768                                return;
 769                        case P_COMMENT:
 770                                if (prompt) {
 771                                        child_count++;
 772                                        item_make(menu, ':',
 773                                                "   %*c*** %s ***",
 774                                                indent + 1, ' ',
 775                                                prompt);
 776                                }
 777                                break;
 778                        default:
 779                                if (prompt) {
 780                                        child_count++;
 781                                        item_make(menu, ':', "---%*c%s",
 782                                                indent + 1, ' ',
 783                                                prompt);
 784                                }
 785                        }
 786                } else
 787                        doint = 0;
 788                goto conf_childs;
 789        }
 790
 791        type = sym_get_type(sym);
 792        if (sym_is_choice(sym)) {
 793                struct symbol *def_sym = sym_get_choice_value(sym);
 794                struct menu *def_menu = NULL;
 795
 796                child_count++;
 797                for (child = menu->list; child; child = child->next) {
 798                        if (menu_is_visible(child) && child->sym == def_sym)
 799                                def_menu = child;
 800                }
 801
 802                val = sym_get_tristate_value(sym);
 803                if (sym_is_changeable(sym)) {
 804                        switch (type) {
 805                        case S_BOOLEAN:
 806                                item_make(menu, 't', "[%c]",
 807                                                val == no ? ' ' : '*');
 808                                break;
 809                        case S_TRISTATE:
 810                                switch (val) {
 811                                case yes:
 812                                        ch = '*';
 813                                        break;
 814                                case mod:
 815                                        ch = 'M';
 816                                        break;
 817                                default:
 818                                        ch = ' ';
 819                                        break;
 820                                }
 821                                item_make(menu, 't', "<%c>", ch);
 822                                break;
 823                        }
 824                } else {
 825                        item_make(menu, def_menu ? 't' : ':', "   ");
 826                }
 827
 828                item_add_str("%*c%s", indent + 1,
 829                                ' ', menu_get_prompt(menu));
 830                if (val == yes) {
 831                        if (def_menu) {
 832                                item_add_str(" (%s)",
 833                                        menu_get_prompt(def_menu));
 834                                item_add_str("  --->");
 835                                if (def_menu->list) {
 836                                        indent += 2;
 837                                        build_conf(def_menu);
 838                                        indent -= 2;
 839                                }
 840                        }
 841                        return;
 842                }
 843        } else {
 844                if (menu == current_menu) {
 845                        item_make(menu, ':',
 846                                "---%*c%s", indent + 1,
 847                                ' ', menu_get_prompt(menu));
 848                        goto conf_childs;
 849                }
 850                child_count++;
 851                val = sym_get_tristate_value(sym);
 852                if (sym_is_choice_value(sym) && val == yes) {
 853                        item_make(menu, ':', "   ");
 854                } else {
 855                        switch (type) {
 856                        case S_BOOLEAN:
 857                                if (sym_is_changeable(sym))
 858                                        item_make(menu, 't', "[%c]",
 859                                                val == no ? ' ' : '*');
 860                                else
 861                                        item_make(menu, 't', "-%c-",
 862                                                val == no ? ' ' : '*');
 863                                break;
 864                        case S_TRISTATE:
 865                                switch (val) {
 866                                case yes:
 867                                        ch = '*';
 868                                        break;
 869                                case mod:
 870                                        ch = 'M';
 871                                        break;
 872                                default:
 873                                        ch = ' ';
 874                                        break;
 875                                }
 876                                if (sym_is_changeable(sym)) {
 877                                        if (sym->rev_dep.tri == mod)
 878                                                item_make(menu,
 879                                                        't', "{%c}", ch);
 880                                        else
 881                                                item_make(menu,
 882                                                        't', "<%c>", ch);
 883                                } else
 884                                        item_make(menu, 't', "-%c-", ch);
 885                                break;
 886                        default:
 887                                tmp = 2 + strlen(sym_get_string_value(sym));
 888                                item_make(menu, 's', "    (%s)",
 889                                                sym_get_string_value(sym));
 890                                tmp = indent - tmp + 4;
 891                                if (tmp < 0)
 892                                        tmp = 0;
 893                                item_add_str("%*c%s%s", tmp, ' ',
 894                                                menu_get_prompt(menu),
 895                                                (sym_has_value(sym) ||
 896                                                 !sym_is_changeable(sym)) ? "" :
 897                                                " (NEW)");
 898                                goto conf_childs;
 899                        }
 900                }
 901                item_add_str("%*c%s%s", indent + 1, ' ',
 902                                menu_get_prompt(menu),
 903                                (sym_has_value(sym) || !sym_is_changeable(sym)) ?
 904                                "" : " (NEW)");
 905                if (menu->prompt && menu->prompt->type == P_MENU) {
 906                        item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
 907                        return;
 908                }
 909        }
 910
 911conf_childs:
 912        indent += doint;
 913        for (child = menu->list; child; child = child->next)
 914                build_conf(child);
 915        indent -= doint;
 916}
 917
 918static void reset_menu(void)
 919{
 920        unpost_menu(curses_menu);
 921        clean_items();
 922}
 923
 924/* adjust the menu to show this item.
 925 * prefer not to scroll the menu if possible*/
 926static void center_item(int selected_index, int *last_top_row)
 927{
 928        int toprow;
 929
 930        set_top_row(curses_menu, *last_top_row);
 931        toprow = top_row(curses_menu);
 932        if (selected_index < toprow ||
 933            selected_index >= toprow+mwin_max_lines) {
 934                toprow = max(selected_index-mwin_max_lines/2, 0);
 935                if (toprow >= item_count(curses_menu)-mwin_max_lines)
 936                        toprow = item_count(curses_menu)-mwin_max_lines;
 937                set_top_row(curses_menu, toprow);
 938        }
 939        set_current_item(curses_menu,
 940                        curses_menu_items[selected_index]);
 941        *last_top_row = toprow;
 942        post_menu(curses_menu);
 943        refresh_all_windows(main_window);
 944}
 945
 946/* this function assumes reset_menu has been called before */
 947static void show_menu(const char *prompt, const char *instructions,
 948                int selected_index, int *last_top_row)
 949{
 950        int maxx, maxy;
 951        WINDOW *menu_window;
 952
 953        current_instructions = instructions;
 954
 955        clear();
 956        print_in_middle(stdscr, 1, getmaxx(stdscr),
 957                        menu_backtitle,
 958                        attr_main_heading);
 959
 960        wattrset(main_window, attr_main_menu_box);
 961        box(main_window, 0, 0);
 962        wattrset(main_window, attr_main_menu_heading);
 963        mvwprintw(main_window, 0, 3, " %s ", prompt);
 964        wattrset(main_window, attr_normal);
 965
 966        set_menu_items(curses_menu, curses_menu_items);
 967
 968        /* position the menu at the middle of the screen */
 969        scale_menu(curses_menu, &maxy, &maxx);
 970        maxx = min(maxx, mwin_max_cols-2);
 971        maxy = mwin_max_lines;
 972        menu_window = derwin(main_window,
 973                        maxy,
 974                        maxx,
 975                        2,
 976                        (mwin_max_cols-maxx)/2);
 977        keypad(menu_window, TRUE);
 978        set_menu_win(curses_menu, menu_window);
 979        set_menu_sub(curses_menu, menu_window);
 980
 981        /* must reassert this after changing items, otherwise returns to a
 982         * default of 16
 983         */
 984        set_menu_format(curses_menu, maxy, 1);
 985        center_item(selected_index, last_top_row);
 986        set_menu_format(curses_menu, maxy, 1);
 987
 988        print_function_line();
 989
 990        /* Post the menu */
 991        post_menu(curses_menu);
 992        refresh_all_windows(main_window);
 993}
 994
 995static void adj_match_dir(match_f *match_direction)
 996{
 997        if (*match_direction == FIND_NEXT_MATCH_DOWN)
 998                *match_direction =
 999                        MATCH_TINKER_PATTERN_DOWN;
1000        else if (*match_direction == FIND_NEXT_MATCH_UP)
1001                *match_direction =
1002                        MATCH_TINKER_PATTERN_UP;
1003        /* else, do no change.. */
1004}
1005
1006struct match_state
1007{
1008        int in_search;
1009        match_f match_direction;
1010        char pattern[256];
1011};
1012
1013/* Return 0 means I have handled the key. In such a case, ans should hold the
1014 * item to center, or -1 otherwise.
1015 * Else return -1 .
1016 */
1017static int do_match(int key, struct match_state *state, int *ans)
1018{
1019        char c = (char) key;
1020        int terminate_search = 0;
1021        *ans = -1;
1022        if (key == '/' || (state->in_search && key == 27)) {
1023                move(0, 0);
1024                refresh();
1025                clrtoeol();
1026                state->in_search = 1-state->in_search;
1027                bzero(state->pattern, sizeof(state->pattern));
1028                state->match_direction = MATCH_TINKER_PATTERN_DOWN;
1029                return 0;
1030        } else if (!state->in_search)
1031                return 1;
1032
1033        if (isalnum(c) || isgraph(c) || c == ' ') {
1034                state->pattern[strlen(state->pattern)] = c;
1035                state->pattern[strlen(state->pattern)] = '\0';
1036                adj_match_dir(&state->match_direction);
1037                *ans = get_mext_match(state->pattern,
1038                                state->match_direction);
1039        } else if (key == KEY_DOWN) {
1040                state->match_direction = FIND_NEXT_MATCH_DOWN;
1041                *ans = get_mext_match(state->pattern,
1042                                state->match_direction);
1043        } else if (key == KEY_UP) {
1044                state->match_direction = FIND_NEXT_MATCH_UP;
1045                *ans = get_mext_match(state->pattern,
1046                                state->match_direction);
1047        } else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
1048                state->pattern[strlen(state->pattern)-1] = '\0';
1049                adj_match_dir(&state->match_direction);
1050        } else
1051                terminate_search = 1;
1052
1053        if (terminate_search) {
1054                state->in_search = 0;
1055                bzero(state->pattern, sizeof(state->pattern));
1056                move(0, 0);
1057                refresh();
1058                clrtoeol();
1059                return -1;
1060        }
1061        return 0;
1062}
1063
1064static void conf(struct menu *menu)
1065{
1066        struct menu *submenu = NULL;
1067        struct symbol *sym;
1068        int res;
1069        int current_index = 0;
1070        int last_top_row = 0;
1071        struct match_state match_state = {
1072                .in_search = 0,
1073                .match_direction = MATCH_TINKER_PATTERN_DOWN,
1074                .pattern = "",
1075        };
1076
1077        while (!global_exit) {
1078                reset_menu();
1079                current_menu = menu;
1080                build_conf(menu);
1081                if (!child_count)
1082                        break;
1083
1084                show_menu(menu_get_prompt(menu), menu_instructions,
1085                          current_index, &last_top_row);
1086                keypad((menu_win(curses_menu)), TRUE);
1087                while (!global_exit) {
1088                        if (match_state.in_search) {
1089                                mvprintw(0, 0,
1090                                        "searching: %s", match_state.pattern);
1091                                clrtoeol();
1092                        }
1093                        refresh_all_windows(main_window);
1094                        res = wgetch(menu_win(curses_menu));
1095                        if (!res)
1096                                break;
1097                        if (do_match(res, &match_state, &current_index) == 0) {
1098                                if (current_index != -1)
1099                                        center_item(current_index,
1100                                                    &last_top_row);
1101                                continue;
1102                        }
1103                        if (process_special_keys(&res,
1104                                                (struct menu *) item_data()))
1105                                break;
1106                        switch (res) {
1107                        case KEY_DOWN:
1108                        case 'j':
1109                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1110                                break;
1111                        case KEY_UP:
1112                        case 'k':
1113                                menu_driver(curses_menu, REQ_UP_ITEM);
1114                                break;
1115                        case KEY_NPAGE:
1116                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1117                                break;
1118                        case KEY_PPAGE:
1119                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1120                                break;
1121                        case KEY_HOME:
1122                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1123                                break;
1124                        case KEY_END:
1125                                menu_driver(curses_menu, REQ_LAST_ITEM);
1126                                break;
1127                        case 'h':
1128                        case '?':
1129                                show_help((struct menu *) item_data());
1130                                break;
1131                        }
1132                        if (res == 10 || res == 27 ||
1133                                res == 32 || res == 'n' || res == 'y' ||
1134                                res == KEY_LEFT || res == KEY_RIGHT ||
1135                                res == 'm')
1136                                break;
1137                        refresh_all_windows(main_window);
1138                }
1139
1140                refresh_all_windows(main_window);
1141                /* if ESC or left*/
1142                if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
1143                        break;
1144
1145                /* remember location in the menu */
1146                last_top_row = top_row(curses_menu);
1147                current_index = curses_item_index();
1148
1149                if (!item_tag())
1150                        continue;
1151
1152                submenu = (struct menu *) item_data();
1153                if (!submenu || !menu_is_visible(submenu))
1154                        continue;
1155                sym = submenu->sym;
1156
1157                switch (res) {
1158                case ' ':
1159                        if (item_is_tag('t'))
1160                                sym_toggle_tristate_value(sym);
1161                        else if (item_is_tag('m'))
1162                                conf(submenu);
1163                        break;
1164                case KEY_RIGHT:
1165                case 10: /* ENTER WAS PRESSED */
1166                        switch (item_tag()) {
1167                        case 'm':
1168                                if (single_menu_mode)
1169                                        submenu->data =
1170                                                (void *) (long) !submenu->data;
1171                                else
1172                                        conf(submenu);
1173                                break;
1174                        case 't':
1175                                if (sym_is_choice(sym) &&
1176                                    sym_get_tristate_value(sym) == yes)
1177                                        conf_choice(submenu);
1178                                else if (submenu->prompt &&
1179                                         submenu->prompt->type == P_MENU)
1180                                        conf(submenu);
1181                                else if (res == 10)
1182                                        sym_toggle_tristate_value(sym);
1183                                break;
1184                        case 's':
1185                                conf_string(submenu);
1186                                break;
1187                        }
1188                        break;
1189                case 'y':
1190                        if (item_is_tag('t')) {
1191                                if (sym_set_tristate_value(sym, yes))
1192                                        break;
1193                                if (sym_set_tristate_value(sym, mod))
1194                                        btn_dialog(main_window, setmod_text, 0);
1195                        }
1196                        break;
1197                case 'n':
1198                        if (item_is_tag('t'))
1199                                sym_set_tristate_value(sym, no);
1200                        break;
1201                case 'm':
1202                        if (item_is_tag('t'))
1203                                sym_set_tristate_value(sym, mod);
1204                        break;
1205                }
1206        }
1207}
1208
1209static void conf_message_callback(const char *s)
1210{
1211        btn_dialog(main_window, s, 1, "<OK>");
1212}
1213
1214static void show_help(struct menu *menu)
1215{
1216        struct gstr help;
1217
1218        if (!menu)
1219                return;
1220
1221        help = str_new();
1222        menu_get_ext_help(menu, &help);
1223        show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help));
1224        str_free(&help);
1225}
1226
1227static void conf_choice(struct menu *menu)
1228{
1229        const char *prompt = menu_get_prompt(menu);
1230        struct menu *child = NULL;
1231        struct symbol *active;
1232        int selected_index = 0;
1233        int last_top_row = 0;
1234        int res, i = 0;
1235        struct match_state match_state = {
1236                .in_search = 0,
1237                .match_direction = MATCH_TINKER_PATTERN_DOWN,
1238                .pattern = "",
1239        };
1240
1241        active = sym_get_choice_value(menu->sym);
1242        /* this is mostly duplicated from the conf() function. */
1243        while (!global_exit) {
1244                reset_menu();
1245
1246                for (i = 0, child = menu->list; child; child = child->next) {
1247                        if (!show_all_items && !menu_is_visible(child))
1248                                continue;
1249
1250                        if (child->sym == sym_get_choice_value(menu->sym))
1251                                item_make(child, ':', "<X> %s",
1252                                                menu_get_prompt(child));
1253                        else if (child->sym)
1254                                item_make(child, ':', "    %s",
1255                                                menu_get_prompt(child));
1256                        else
1257                                item_make(child, ':', "*** %s ***",
1258                                                menu_get_prompt(child));
1259
1260                        if (child->sym == active){
1261                                last_top_row = top_row(curses_menu);
1262                                selected_index = i;
1263                        }
1264                        i++;
1265                }
1266                show_menu(prompt ? prompt : "Choice Menu",
1267                                radiolist_instructions,
1268                                selected_index,
1269                                &last_top_row);
1270                while (!global_exit) {
1271                        if (match_state.in_search) {
1272                                mvprintw(0, 0, "searching: %s",
1273                                         match_state.pattern);
1274                                clrtoeol();
1275                        }
1276                        refresh_all_windows(main_window);
1277                        res = wgetch(menu_win(curses_menu));
1278                        if (!res)
1279                                break;
1280                        if (do_match(res, &match_state, &selected_index) == 0) {
1281                                if (selected_index != -1)
1282                                        center_item(selected_index,
1283                                                    &last_top_row);
1284                                continue;
1285                        }
1286                        if (process_special_keys(
1287                                                &res,
1288                                                (struct menu *) item_data()))
1289                                break;
1290                        switch (res) {
1291                        case KEY_DOWN:
1292                        case 'j':
1293                                menu_driver(curses_menu, REQ_DOWN_ITEM);
1294                                break;
1295                        case KEY_UP:
1296                        case 'k':
1297                                menu_driver(curses_menu, REQ_UP_ITEM);
1298                                break;
1299                        case KEY_NPAGE:
1300                                menu_driver(curses_menu, REQ_SCR_DPAGE);
1301                                break;
1302                        case KEY_PPAGE:
1303                                menu_driver(curses_menu, REQ_SCR_UPAGE);
1304                                break;
1305                        case KEY_HOME:
1306                                menu_driver(curses_menu, REQ_FIRST_ITEM);
1307                                break;
1308                        case KEY_END:
1309                                menu_driver(curses_menu, REQ_LAST_ITEM);
1310                                break;
1311                        case 'h':
1312                        case '?':
1313                                show_help((struct menu *) item_data());
1314                                break;
1315                        }
1316                        if (res == 10 || res == 27 || res == ' ' ||
1317                                        res == KEY_LEFT){
1318                                break;
1319                        }
1320                        refresh_all_windows(main_window);
1321                }
1322                /* if ESC or left */
1323                if (res == 27 || res == KEY_LEFT)
1324                        break;
1325
1326                child = item_data();
1327                if (!child || !menu_is_visible(child) || !child->sym)
1328                        continue;
1329                switch (res) {
1330                case ' ':
1331                case  10:
1332                case KEY_RIGHT:
1333                        sym_set_tristate_value(child->sym, yes);
1334                        return;
1335                case 'h':
1336                case '?':
1337                        show_help(child);
1338                        active = child->sym;
1339                        break;
1340                case KEY_EXIT:
1341                        return;
1342                }
1343        }
1344}
1345
1346static void conf_string(struct menu *menu)
1347{
1348        const char *prompt = menu_get_prompt(menu);
1349
1350        while (1) {
1351                int res;
1352                const char *heading;
1353
1354                switch (sym_get_type(menu->sym)) {
1355                case S_INT:
1356                        heading = inputbox_instructions_int;
1357                        break;
1358                case S_HEX:
1359                        heading = inputbox_instructions_hex;
1360                        break;
1361                case S_STRING:
1362                        heading = inputbox_instructions_string;
1363                        break;
1364                default:
1365                        heading = "Internal nconf error!";
1366                }
1367                res = dialog_inputbox(main_window,
1368                                prompt ? prompt : "Main Menu",
1369                                heading,
1370                                sym_get_string_value(menu->sym),
1371                                &dialog_input_result,
1372                                &dialog_input_result_len);
1373                switch (res) {
1374                case 0:
1375                        if (sym_set_string_value(menu->sym,
1376                                                dialog_input_result))
1377                                return;
1378                        btn_dialog(main_window,
1379                                "You have made an invalid entry.", 0);
1380                        break;
1381                case 1:
1382                        show_help(menu);
1383                        break;
1384                case KEY_EXIT:
1385                        return;
1386                }
1387        }
1388}
1389
1390static void conf_load(void)
1391{
1392        while (1) {
1393                int res;
1394                res = dialog_inputbox(main_window,
1395                                NULL, load_config_text,
1396                                filename,
1397                                &dialog_input_result,
1398                                &dialog_input_result_len);
1399                switch (res) {
1400                case 0:
1401                        if (!dialog_input_result[0])
1402                                return;
1403                        if (!conf_read(dialog_input_result)) {
1404                                set_config_filename(dialog_input_result);
1405                                conf_set_changed(true);
1406                                return;
1407                        }
1408                        btn_dialog(main_window, "File does not exist!", 0);
1409                        break;
1410                case 1:
1411                        show_scroll_win(main_window,
1412                                        "Load Alternate Configuration",
1413                                        load_config_help);
1414                        break;
1415                case KEY_EXIT:
1416                        return;
1417                }
1418        }
1419}
1420
1421static void conf_save(void)
1422{
1423        while (1) {
1424                int res;
1425                res = dialog_inputbox(main_window,
1426                                NULL, save_config_text,
1427                                filename,
1428                                &dialog_input_result,
1429                                &dialog_input_result_len);
1430                switch (res) {
1431                case 0:
1432                        if (!dialog_input_result[0])
1433                                return;
1434                        res = conf_write(dialog_input_result);
1435                        if (!res) {
1436                                set_config_filename(dialog_input_result);
1437                                return;
1438                        }
1439                        btn_dialog(main_window, "Can't create file!",
1440                                1, "<OK>");
1441                        break;
1442                case 1:
1443                        show_scroll_win(main_window,
1444                                "Save Alternate Configuration",
1445                                save_config_help);
1446                        break;
1447                case KEY_EXIT:
1448                        return;
1449                }
1450        }
1451}
1452
1453static void setup_windows(void)
1454{
1455        int lines, columns;
1456
1457        getmaxyx(stdscr, lines, columns);
1458
1459        if (main_window != NULL)
1460                delwin(main_window);
1461
1462        /* set up the menu and menu window */
1463        main_window = newwin(lines-2, columns-2, 2, 1);
1464        keypad(main_window, TRUE);
1465        mwin_max_lines = lines-7;
1466        mwin_max_cols = columns-6;
1467
1468        /* panels order is from bottom to top */
1469        new_panel(main_window);
1470}
1471
1472int main(int ac, char **av)
1473{
1474        int lines, columns;
1475        char *mode;
1476
1477        if (ac > 1 && strcmp(av[1], "-s") == 0) {
1478                /* Silence conf_read() until the real callback is set up */
1479                conf_set_message_callback(NULL);
1480                av++;
1481        }
1482        conf_parse(av[1]);
1483        conf_read(NULL);
1484
1485        mode = getenv("NCONFIG_MODE");
1486        if (mode) {
1487                if (!strcasecmp(mode, "single_menu"))
1488                        single_menu_mode = 1;
1489        }
1490
1491        /* Initialize curses */
1492        initscr();
1493        /* set color theme */
1494        set_colors();
1495
1496        cbreak();
1497        noecho();
1498        keypad(stdscr, TRUE);
1499        curs_set(0);
1500
1501        getmaxyx(stdscr, lines, columns);
1502        if (columns < 75 || lines < 20) {
1503                endwin();
1504                printf("Your terminal should have at "
1505                        "least 20 lines and 75 columns\n");
1506                return 1;
1507        }
1508
1509        notimeout(stdscr, FALSE);
1510#if NCURSES_REENTRANT
1511        set_escdelay(1);
1512#else
1513        ESCDELAY = 1;
1514#endif
1515
1516        /* set btns menu */
1517        curses_menu = new_menu(curses_menu_items);
1518        menu_opts_off(curses_menu, O_SHOWDESC);
1519        menu_opts_on(curses_menu, O_SHOWMATCH);
1520        menu_opts_on(curses_menu, O_ONEVALUE);
1521        menu_opts_on(curses_menu, O_NONCYCLIC);
1522        menu_opts_on(curses_menu, O_IGNORECASE);
1523        set_menu_mark(curses_menu, " ");
1524        set_menu_fore(curses_menu, attr_main_menu_fore);
1525        set_menu_back(curses_menu, attr_main_menu_back);
1526        set_menu_grey(curses_menu, attr_main_menu_grey);
1527
1528        set_config_filename(conf_get_configname());
1529        setup_windows();
1530
1531        /* check for KEY_FUNC(1) */
1532        if (has_key(KEY_F(1)) == FALSE) {
1533                show_scroll_win(main_window,
1534                                "Instructions",
1535                                menu_no_f_instructions);
1536        }
1537
1538        conf_set_message_callback(conf_message_callback);
1539        /* do the work */
1540        while (!global_exit) {
1541                conf(&rootmenu);
1542                if (!global_exit && do_exit() == 0)
1543                        break;
1544        }
1545        /* ok, we are done */
1546        unpost_menu(curses_menu);
1547        free_menu(curses_menu);
1548        delwin(main_window);
1549        clear();
1550        refresh();
1551        endwin();
1552        return 0;
1553}
1554