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