linux/scripts/kconfig/mconf.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
   3 * Released under the terms of the GNU GPL v2.0.
   4 *
   5 * Introduced single menu mode (show all sub-menus in one large tree).
   6 * 2002-11-06 Petr Baudis <pasky@ucw.cz>
   7 *
   8 * i18n, 2005, Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   9 */
  10
  11#include <ctype.h>
  12#include <errno.h>
  13#include <fcntl.h>
  14#include <limits.h>
  15#include <stdarg.h>
  16#include <stdlib.h>
  17#include <string.h>
  18#include <signal.h>
  19#include <unistd.h>
  20#include <locale.h>
  21
  22#include "lkc.h"
  23#include "lxdialog/dialog.h"
  24
  25static const char mconf_readme[] = N_(
  26"Overview\n"
  27"--------\n"
  28"This interface let you select features and parameters for the build.\n"
  29"Features can either be built-in, modularized, or ignored. Parameters\n"
  30"must be entered in as decimal or hexadecimal numbers or text.\n"
  31"\n"
  32"Menu items beginning with following braces represent features that\n"
  33"  [ ] can be built in or removed\n"
  34"  < > can be built in, modularized or removed\n"
  35"  { } can be built in or modularized (selected by other feature)\n"
  36"  - - are selected by other feature,\n"
  37"while *, M or whitespace inside braces means to build in, build as\n"
  38"a module or to exclude the feature respectively.\n"
  39"\n"
  40"To change any of these features, highlight it with the cursor\n"
  41"keys and press <Y> to build it in, <M> to make it a module or\n"
  42"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
  43"through the available options (ie. Y->N->M->Y).\n"
  44"\n"
  45"Some additional keyboard hints:\n"
  46"\n"
  47"Menus\n"
  48"----------\n"
  49"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
  50"   you wish to change or submenu wish to select and press <Enter>.\n"
  51"   Submenus are designated by \"--->\".\n"
  52"\n"
  53"   Shortcut: Press the option's highlighted letter (hotkey).\n"
  54"             Pressing a hotkey more than once will sequence\n"
  55"             through all visible items which use that hotkey.\n"
  56"\n"
  57"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
  58"   unseen options into view.\n"
  59"\n"
  60"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
  61"   and press <ENTER>.\n"
  62"\n"
  63"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
  64"             using those letters.  You may press a single <ESC>, but\n"
  65"             there is a delayed response which you may find annoying.\n"
  66"\n"
  67"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
  68"   <Exit> and <Help>.\n"
  69"\n"
  70"o  To get help with an item, use the cursor keys to highlight <Help>\n"
  71"   and press <ENTER>.\n"
  72"\n"
  73"   Shortcut: Press <H> or <?>.\n"
  74"\n"
  75"o  To toggle the display of hidden options, press <Z>.\n"
  76"\n"
  77"\n"
  78"Radiolists  (Choice lists)\n"
  79"-----------\n"
  80"o  Use the cursor keys to select the option you wish to set and press\n"
  81"   <S> or the <SPACE BAR>.\n"
  82"\n"
  83"   Shortcut: Press the first letter of the option you wish to set then\n"
  84"             press <S> or <SPACE BAR>.\n"
  85"\n"
  86"o  To see available help for the item, use the cursor keys to highlight\n"
  87"   <Help> and Press <ENTER>.\n"
  88"\n"
  89"   Shortcut: Press <H> or <?>.\n"
  90"\n"
  91"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
  92"   <Help>\n"
  93"\n"
  94"\n"
  95"Data Entry\n"
  96"-----------\n"
  97"o  Enter the requested information and press <ENTER>\n"
  98"   If you are entering hexadecimal values, it is not necessary to\n"
  99"   add the '0x' prefix to the entry.\n"
 100"\n"
 101"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
 102"   and press <ENTER>.  You can try <TAB><H> as well.\n"
 103"\n"
 104"\n"
 105"Text Box    (Help Window)\n"
 106"--------\n"
 107"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
 108"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
 109"   who are familiar with less and lynx.\n"
 110"\n"
 111"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
 112"\n"
 113"\n"
 114"Alternate Configuration Files\n"
 115"-----------------------------\n"
 116"Menuconfig supports the use of alternate configuration files for\n"
 117"those who, for various reasons, find it necessary to switch\n"
 118"between different configurations.\n"
 119"\n"
 120"At the end of the main menu you will find two options.  One is\n"
 121"for saving the current configuration to a file of your choosing.\n"
 122"The other option is for loading a previously saved alternate\n"
 123"configuration.\n"
 124"\n"
 125"Even if you don't use alternate configuration files, but you\n"
 126"find during a Menuconfig session that you have completely messed\n"
 127"up your settings, you may use the \"Load Alternate...\" option to\n"
 128"restore your previously saved settings from \".config\" without\n"
 129"restarting Menuconfig.\n"
 130"\n"
 131"Other information\n"
 132"-----------------\n"
 133"If you use Menuconfig in an XTERM window make sure you have your\n"
 134"$TERM variable set to point to a xterm definition which supports color.\n"
 135"Otherwise, Menuconfig will look rather bad.  Menuconfig will not\n"
 136"display correctly in a RXVT window because rxvt displays only one\n"
 137"intensity of color, bright.\n"
 138"\n"
 139"Menuconfig will display larger menus on screens or xterms which are\n"
 140"set to display more than the standard 25 row by 80 column geometry.\n"
 141"In order for this to work, the \"stty size\" command must be able to\n"
 142"display the screen's current row and column geometry.  I STRONGLY\n"
 143"RECOMMEND that you make sure you do NOT have the shell variables\n"
 144"LINES and COLUMNS exported into your environment.  Some distributions\n"
 145"export those variables via /etc/profile.  Some ncurses programs can\n"
 146"become confused when those variables (LINES & COLUMNS) don't reflect\n"
 147"the true screen size.\n"
 148"\n"
 149"Optional personality available\n"
 150"------------------------------\n"
 151"If you prefer to have all of the options listed in a single menu, rather\n"
 152"than the default multimenu hierarchy, run the menuconfig with\n"
 153"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
 154"\n"
 155"make MENUCONFIG_MODE=single_menu menuconfig\n"
 156"\n"
 157"<Enter> will then unroll the appropriate category, or enfold it if it\n"
 158"is already unrolled.\n"
 159"\n"
 160"Note that this mode can eventually be a little more CPU expensive\n"
 161"(especially with a larger number of unrolled categories) than the\n"
 162"default mode.\n"
 163"\n"
 164"Different color themes available\n"
 165"--------------------------------\n"
 166"It is possible to select different color themes using the variable\n"
 167"MENUCONFIG_COLOR. To select a theme use:\n"
 168"\n"
 169"make MENUCONFIG_COLOR=<theme> menuconfig\n"
 170"\n"
 171"Available themes are\n"
 172" mono       => selects colors suitable for monochrome displays\n"
 173" blackbg    => selects a color scheme with black background\n"
 174" classic    => theme with blue background. The classic look\n"
 175" bluetitle  => a LCD friendly version of classic. (default)\n"
 176"\n"),
 177menu_instructions[] = N_(
 178        "Arrow keys navigate the menu.  "
 179        "<Enter> selects submenus --->.  "
 180        "Highlighted letters are hotkeys.  "
 181        "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
 182        "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
 183        "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
 184radiolist_instructions[] = N_(
 185        "Use the arrow keys to navigate this window or "
 186        "press the hotkey of the item you wish to select "
 187        "followed by the <SPACE BAR>. "
 188        "Press <?> for additional information about this option."),
 189inputbox_instructions_int[] = N_(
 190        "Please enter a decimal value. "
 191        "Fractions will not be accepted.  "
 192        "Use the <TAB> key to move from the input field to the buttons below it."),
 193inputbox_instructions_hex[] = N_(
 194        "Please enter a hexadecimal value. "
 195        "Use the <TAB> key to move from the input field to the buttons below it."),
 196inputbox_instructions_string[] = N_(
 197        "Please enter a string value. "
 198        "Use the <TAB> key to move from the input field to the buttons below it."),
 199setmod_text[] = N_(
 200        "This feature depends on another which has been configured as a module.\n"
 201        "As a result, this feature will be built as a module."),
 202load_config_text[] = N_(
 203        "Enter the name of the configuration file you wish to load.  "
 204        "Accept the name shown to restore the configuration you "
 205        "last retrieved.  Leave blank to abort."),
 206load_config_help[] = N_(
 207        "\n"
 208        "For various reasons, one may wish to keep several different\n"
 209        "configurations available on a single machine.\n"
 210        "\n"
 211        "If you have saved a previous configuration in a file other than the\n"
 212        "default one, entering its name here will allow you to modify that\n"
 213        "configuration.\n"
 214        "\n"
 215        "If you are uncertain, then you have probably never used alternate\n"
 216        "configuration files. You should therefore leave this blank to abort.\n"),
 217save_config_text[] = N_(
 218        "Enter a filename to which this configuration should be saved "
 219        "as an alternate.  Leave blank to abort."),
 220save_config_help[] = N_(
 221        "\n"
 222        "For various reasons, one may wish to keep different configurations\n"
 223        "available on a single machine.\n"
 224        "\n"
 225        "Entering a file name here will allow you to later retrieve, modify\n"
 226        "and use the current configuration as an alternate to whatever\n"
 227        "configuration options you have selected at that time.\n"
 228        "\n"
 229        "If you are uncertain what all this means then you should probably\n"
 230        "leave this blank.\n"),
 231search_help[] = N_(
 232        "\n"
 233        "Search for symbols and display their relations.\n"
 234        "Regular expressions are allowed.\n"
 235        "Example: search for \"^FOO\"\n"
 236        "Result:\n"
 237        "-----------------------------------------------------------------\n"
 238        "Symbol: FOO [=m]\n"
 239        "Prompt: Foo bus is used to drive the bar HW\n"
 240        "Defined at drivers/pci/Kconfig:47\n"
 241        "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
 242        "Location:\n"
 243        "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
 244        "    -> PCI support (PCI [=y])\n"
 245        "      -> PCI access mode (<choice> [=y])\n"
 246        "Selects: LIBCRC32\n"
 247        "Selected by: BAR\n"
 248        "-----------------------------------------------------------------\n"
 249        "o The line 'Prompt:' shows the text used in the menu structure for\n"
 250        "  this symbol\n"
 251        "o The 'Defined at' line tell at what file / line number the symbol\n"
 252        "  is defined\n"
 253        "o The 'Depends on:' line tell what symbols needs to be defined for\n"
 254        "  this symbol to be visible in the menu (selectable)\n"
 255        "o The 'Location:' lines tell where in the menu structure this symbol\n"
 256        "  is located\n"
 257        "    A location followed by a [=y] indicate that this is a selectable\n"
 258        "    menu item - and current value is displayed inside brackets.\n"
 259        "o The 'Selects:' line tell what symbol will be automatically\n"
 260        "  selected if this symbol is selected (y or m)\n"
 261        "o The 'Selected by' line tell what symbol has selected this symbol\n"
 262        "\n"
 263        "Only relevant lines are shown.\n"
 264        "\n\n"
 265        "Search examples:\n"
 266        "Examples: USB  => find all symbols containing USB\n"
 267        "          ^USB => find all symbols starting with USB\n"
 268        "          USB$ => find all symbols ending with USB\n"
 269        "\n");
 270
 271static int indent;
 272static struct menu *current_menu;
 273static int child_count;
 274static int single_menu_mode;
 275static int show_all_options;
 276static int saved_x, saved_y;
 277
 278static void conf(struct menu *menu);
 279static void conf_choice(struct menu *menu);
 280static void conf_string(struct menu *menu);
 281static void conf_load(void);
 282static void conf_save(void);
 283static void show_textbox(const char *title, const char *text, int r, int c);
 284static void show_helptext(const char *title, const char *text);
 285static void show_help(struct menu *menu);
 286
 287static char filename[PATH_MAX+1];
 288static void set_config_filename(const char *config_filename)
 289{
 290        static char menu_backtitle[PATH_MAX+128];
 291        int size;
 292
 293        size = snprintf(menu_backtitle, sizeof(menu_backtitle),
 294                        "%s - %s", config_filename, rootmenu.prompt->text);
 295        if (size >= sizeof(menu_backtitle))
 296                menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
 297        set_dialog_backtitle(menu_backtitle);
 298
 299        size = snprintf(filename, sizeof(filename), "%s", config_filename);
 300        if (size >= sizeof(filename))
 301                filename[sizeof(filename)-1] = '\0';
 302}
 303
 304
 305static void search_conf(void)
 306{
 307        struct symbol **sym_arr;
 308        struct gstr res;
 309        char *dialog_input;
 310        int dres;
 311again:
 312        dialog_clear();
 313        dres = dialog_inputbox(_("Search Configuration Parameter"),
 314                              _("Enter " CONFIG_ " (sub)string to search for "
 315                                "(with or without \"" CONFIG_ "\")"),
 316                              10, 75, "");
 317        switch (dres) {
 318        case 0:
 319                break;
 320        case 1:
 321                show_helptext(_("Search Configuration"), search_help);
 322                goto again;
 323        default:
 324                return;
 325        }
 326
 327        /* strip the prefix if necessary */
 328        dialog_input = dialog_input_result;
 329        if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
 330                dialog_input += strlen(CONFIG_);
 331
 332        sym_arr = sym_re_search(dialog_input);
 333        res = get_relations_str(sym_arr);
 334        free(sym_arr);
 335        show_textbox(_("Search Results"), str_get(&res), 0, 0);
 336        str_free(&res);
 337}
 338
 339static void build_conf(struct menu *menu)
 340{
 341        struct symbol *sym;
 342        struct property *prop;
 343        struct menu *child;
 344        int type, tmp, doint = 2;
 345        tristate val;
 346        char ch;
 347        bool visible;
 348
 349        /*
 350         * note: menu_is_visible() has side effect that it will
 351         * recalc the value of the symbol.
 352         */
 353        visible = menu_is_visible(menu);
 354        if (show_all_options && !menu_has_prompt(menu))
 355                return;
 356        else if (!show_all_options && !visible)
 357                return;
 358
 359        sym = menu->sym;
 360        prop = menu->prompt;
 361        if (!sym) {
 362                if (prop && menu != current_menu) {
 363                        const char *prompt = menu_get_prompt(menu);
 364                        switch (prop->type) {
 365                        case P_MENU:
 366                                child_count++;
 367                                prompt = _(prompt);
 368                                if (single_menu_mode) {
 369                                        item_make("%s%*c%s",
 370                                                  menu->data ? "-->" : "++>",
 371                                                  indent + 1, ' ', prompt);
 372                                } else
 373                                        item_make("   %*c%s  --->", indent + 1, ' ', prompt);
 374
 375                                item_set_tag('m');
 376                                item_set_data(menu);
 377                                if (single_menu_mode && menu->data)
 378                                        goto conf_childs;
 379                                return;
 380                        case P_COMMENT:
 381                                if (prompt) {
 382                                        child_count++;
 383                                        item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
 384                                        item_set_tag(':');
 385                                        item_set_data(menu);
 386                                }
 387                                break;
 388                        default:
 389                                if (prompt) {
 390                                        child_count++;
 391                                        item_make("---%*c%s", indent + 1, ' ', _(prompt));
 392                                        item_set_tag(':');
 393                                        item_set_data(menu);
 394                                }
 395                        }
 396                } else
 397                        doint = 0;
 398                goto conf_childs;
 399        }
 400
 401        type = sym_get_type(sym);
 402        if (sym_is_choice(sym)) {
 403                struct symbol *def_sym = sym_get_choice_value(sym);
 404                struct menu *def_menu = NULL;
 405
 406                child_count++;
 407                for (child = menu->list; child; child = child->next) {
 408                        if (menu_is_visible(child) && child->sym == def_sym)
 409                                def_menu = child;
 410                }
 411
 412                val = sym_get_tristate_value(sym);
 413                if (sym_is_changable(sym)) {
 414                        switch (type) {
 415                        case S_BOOLEAN:
 416                                item_make("[%c]", val == no ? ' ' : '*');
 417                                break;
 418                        case S_TRISTATE:
 419                                switch (val) {
 420                                case yes: ch = '*'; break;
 421                                case mod: ch = 'M'; break;
 422                                default:  ch = ' '; break;
 423                                }
 424                                item_make("<%c>", ch);
 425                                break;
 426                        }
 427                        item_set_tag('t');
 428                        item_set_data(menu);
 429                } else {
 430                        item_make("   ");
 431                        item_set_tag(def_menu ? 't' : ':');
 432                        item_set_data(menu);
 433                }
 434
 435                item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
 436                if (val == yes) {
 437                        if (def_menu) {
 438                                item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
 439                                item_add_str("  --->");
 440                                if (def_menu->list) {
 441                                        indent += 2;
 442                                        build_conf(def_menu);
 443                                        indent -= 2;
 444                                }
 445                        }
 446                        return;
 447                }
 448        } else {
 449                if (menu == current_menu) {
 450                        item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
 451                        item_set_tag(':');
 452                        item_set_data(menu);
 453                        goto conf_childs;
 454                }
 455                child_count++;
 456                val = sym_get_tristate_value(sym);
 457                if (sym_is_choice_value(sym) && val == yes) {
 458                        item_make("   ");
 459                        item_set_tag(':');
 460                        item_set_data(menu);
 461                } else {
 462                        switch (type) {
 463                        case S_BOOLEAN:
 464                                if (sym_is_changable(sym))
 465                                        item_make("[%c]", val == no ? ' ' : '*');
 466                                else
 467                                        item_make("-%c-", val == no ? ' ' : '*');
 468                                item_set_tag('t');
 469                                item_set_data(menu);
 470                                break;
 471                        case S_TRISTATE:
 472                                switch (val) {
 473                                case yes: ch = '*'; break;
 474                                case mod: ch = 'M'; break;
 475                                default:  ch = ' '; break;
 476                                }
 477                                if (sym_is_changable(sym)) {
 478                                        if (sym->rev_dep.tri == mod)
 479                                                item_make("{%c}", ch);
 480                                        else
 481                                                item_make("<%c>", ch);
 482                                } else
 483                                        item_make("-%c-", ch);
 484                                item_set_tag('t');
 485                                item_set_data(menu);
 486                                break;
 487                        default:
 488                                tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
 489                                item_make("(%s)", sym_get_string_value(sym));
 490                                tmp = indent - tmp + 4;
 491                                if (tmp < 0)
 492                                        tmp = 0;
 493                                item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
 494                                             (sym_has_value(sym) || !sym_is_changable(sym)) ?
 495                                             "" : _(" (NEW)"));
 496                                item_set_tag('s');
 497                                item_set_data(menu);
 498                                goto conf_childs;
 499                        }
 500                }
 501                item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
 502                          (sym_has_value(sym) || !sym_is_changable(sym)) ?
 503                          "" : _(" (NEW)"));
 504                if (menu->prompt->type == P_MENU) {
 505                        item_add_str("  --->");
 506                        return;
 507                }
 508        }
 509
 510conf_childs:
 511        indent += doint;
 512        for (child = menu->list; child; child = child->next)
 513                build_conf(child);
 514        indent -= doint;
 515}
 516
 517static void conf(struct menu *menu)
 518{
 519        struct menu *submenu;
 520        const char *prompt = menu_get_prompt(menu);
 521        struct symbol *sym;
 522        struct menu *active_menu = NULL;
 523        int res;
 524        int s_scroll = 0;
 525
 526        while (1) {
 527                item_reset();
 528                current_menu = menu;
 529                build_conf(menu);
 530                if (!child_count)
 531                        break;
 532                if (menu == &rootmenu) {
 533                        item_make("--- ");
 534                        item_set_tag(':');
 535                        item_make(_("    Load an Alternate Configuration File"));
 536                        item_set_tag('L');
 537                        item_make(_("    Save an Alternate Configuration File"));
 538                        item_set_tag('S');
 539                }
 540                dialog_clear();
 541                res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
 542                                  _(menu_instructions),
 543                                  active_menu, &s_scroll);
 544                if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 545                        break;
 546                if (!item_activate_selected())
 547                        continue;
 548                if (!item_tag())
 549                        continue;
 550
 551                submenu = item_data();
 552                active_menu = item_data();
 553                if (submenu)
 554                        sym = submenu->sym;
 555                else
 556                        sym = NULL;
 557
 558                switch (res) {
 559                case 0:
 560                        switch (item_tag()) {
 561                        case 'm':
 562                                if (single_menu_mode)
 563                                        submenu->data = (void *) (long) !submenu->data;
 564                                else
 565                                        conf(submenu);
 566                                break;
 567                        case 't':
 568                                if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 569                                        conf_choice(submenu);
 570                                else if (submenu->prompt->type == P_MENU)
 571                                        conf(submenu);
 572                                break;
 573                        case 's':
 574                                conf_string(submenu);
 575                                break;
 576                        case 'L':
 577                                conf_load();
 578                                break;
 579                        case 'S':
 580                                conf_save();
 581                                break;
 582                        }
 583                        break;
 584                case 2:
 585                        if (sym)
 586                                show_help(submenu);
 587                        else
 588                                show_helptext(_("README"), _(mconf_readme));
 589                        break;
 590                case 3:
 591                        if (item_is_tag('t')) {
 592                                if (sym_set_tristate_value(sym, yes))
 593                                        break;
 594                                if (sym_set_tristate_value(sym, mod))
 595                                        show_textbox(NULL, setmod_text, 6, 74);
 596                        }
 597                        break;
 598                case 4:
 599                        if (item_is_tag('t'))
 600                                sym_set_tristate_value(sym, no);
 601                        break;
 602                case 5:
 603                        if (item_is_tag('t'))
 604                                sym_set_tristate_value(sym, mod);
 605                        break;
 606                case 6:
 607                        if (item_is_tag('t'))
 608                                sym_toggle_tristate_value(sym);
 609                        else if (item_is_tag('m'))
 610                                conf(submenu);
 611                        break;
 612                case 7:
 613                        search_conf();
 614                        break;
 615                case 8:
 616                        show_all_options = !show_all_options;
 617                        break;
 618                }
 619        }
 620}
 621
 622static void show_textbox(const char *title, const char *text, int r, int c)
 623{
 624        dialog_clear();
 625        dialog_textbox(title, text, r, c);
 626}
 627
 628static void show_helptext(const char *title, const char *text)
 629{
 630        show_textbox(title, text, 0, 0);
 631}
 632
 633static void show_help(struct menu *menu)
 634{
 635        struct gstr help = str_new();
 636
 637        help.max_width = getmaxx(stdscr) - 10;
 638        menu_get_ext_help(menu, &help);
 639
 640        show_helptext(_(menu_get_prompt(menu)), str_get(&help));
 641        str_free(&help);
 642}
 643
 644static void conf_choice(struct menu *menu)
 645{
 646        const char *prompt = _(menu_get_prompt(menu));
 647        struct menu *child;
 648        struct symbol *active;
 649
 650        active = sym_get_choice_value(menu->sym);
 651        while (1) {
 652                int res;
 653                int selected;
 654                item_reset();
 655
 656                current_menu = menu;
 657                for (child = menu->list; child; child = child->next) {
 658                        if (!menu_is_visible(child))
 659                                continue;
 660                        if (child->sym)
 661                                item_make("%s", _(menu_get_prompt(child)));
 662                        else {
 663                                item_make("*** %s ***", _(menu_get_prompt(child)));
 664                                item_set_tag(':');
 665                        }
 666                        item_set_data(child);
 667                        if (child->sym == active)
 668                                item_set_selected(1);
 669                        if (child->sym == sym_get_choice_value(menu->sym))
 670                                item_set_tag('X');
 671                }
 672                dialog_clear();
 673                res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
 674                                        _(radiolist_instructions),
 675                                         15, 70, 6);
 676                selected = item_activate_selected();
 677                switch (res) {
 678                case 0:
 679                        if (selected) {
 680                                child = item_data();
 681                                if (!child->sym)
 682                                        break;
 683
 684                                sym_set_tristate_value(child->sym, yes);
 685                        }
 686                        return;
 687                case 1:
 688                        if (selected) {
 689                                child = item_data();
 690                                show_help(child);
 691                                active = child->sym;
 692                        } else
 693                                show_help(menu);
 694                        break;
 695                case KEY_ESC:
 696                        return;
 697                case -ERRDISPLAYTOOSMALL:
 698                        return;
 699                }
 700        }
 701}
 702
 703static void conf_string(struct menu *menu)
 704{
 705        const char *prompt = menu_get_prompt(menu);
 706
 707        while (1) {
 708                int res;
 709                const char *heading;
 710
 711                switch (sym_get_type(menu->sym)) {
 712                case S_INT:
 713                        heading = _(inputbox_instructions_int);
 714                        break;
 715                case S_HEX:
 716                        heading = _(inputbox_instructions_hex);
 717                        break;
 718                case S_STRING:
 719                        heading = _(inputbox_instructions_string);
 720                        break;
 721                default:
 722                        heading = _("Internal mconf error!");
 723                }
 724                dialog_clear();
 725                res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
 726                                      heading, 10, 75,
 727                                      sym_get_string_value(menu->sym));
 728                switch (res) {
 729                case 0:
 730                        if (sym_set_string_value(menu->sym, dialog_input_result))
 731                                return;
 732                        show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
 733                        break;
 734                case 1:
 735                        show_help(menu);
 736                        break;
 737                case KEY_ESC:
 738                        return;
 739                }
 740        }
 741}
 742
 743static void conf_load(void)
 744{
 745
 746        while (1) {
 747                int res;
 748                dialog_clear();
 749                res = dialog_inputbox(NULL, load_config_text,
 750                                      11, 55, filename);
 751                switch(res) {
 752                case 0:
 753                        if (!dialog_input_result[0])
 754                                return;
 755                        if (!conf_read(dialog_input_result)) {
 756                                set_config_filename(dialog_input_result);
 757                                sym_set_change_count(1);
 758                                return;
 759                        }
 760                        show_textbox(NULL, _("File does not exist!"), 5, 38);
 761                        break;
 762                case 1:
 763                        show_helptext(_("Load Alternate Configuration"), load_config_help);
 764                        break;
 765                case KEY_ESC:
 766                        return;
 767                }
 768        }
 769}
 770
 771static void conf_save(void)
 772{
 773        while (1) {
 774                int res;
 775                dialog_clear();
 776                res = dialog_inputbox(NULL, save_config_text,
 777                                      11, 55, filename);
 778                switch(res) {
 779                case 0:
 780                        if (!dialog_input_result[0])
 781                                return;
 782                        if (!conf_write(dialog_input_result)) {
 783                                set_config_filename(dialog_input_result);
 784                                return;
 785                        }
 786                        show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
 787                        break;
 788                case 1:
 789                        show_helptext(_("Save Alternate Configuration"), save_config_help);
 790                        break;
 791                case KEY_ESC:
 792                        return;
 793                }
 794        }
 795}
 796
 797static int handle_exit(void)
 798{
 799        int res;
 800
 801        dialog_clear();
 802        if (conf_get_changed())
 803                res = dialog_yesno(NULL,
 804                                   _("Do you wish to save your new configuration ?\n"
 805                                     "<ESC><ESC> to continue."),
 806                                   6, 60);
 807        else
 808                res = -1;
 809
 810        end_dialog(saved_x, saved_y);
 811
 812        switch (res) {
 813        case 0:
 814                if (conf_write(filename)) {
 815                        fprintf(stderr, _("\n\n"
 816                                          "Error while writing of the configuration.\n"
 817                                          "Your configuration changes were NOT saved."
 818                                          "\n\n"));
 819                        return 1;
 820                }
 821                /* fall through */
 822        case -1:
 823                printf(_("\n\n"
 824                         "*** End of the configuration.\n"
 825                         "*** Execute 'make' to start the build or try 'make help'."
 826                         "\n\n"));
 827                res = 0;
 828                break;
 829        default:
 830                fprintf(stderr, _("\n\n"
 831                                  "Your configuration changes were NOT saved."
 832                                  "\n\n"));
 833                if (res != KEY_ESC)
 834                        res = 0;
 835        }
 836
 837        return res;
 838}
 839
 840static void sig_handler(int signo)
 841{
 842        exit(handle_exit());
 843}
 844
 845int main(int ac, char **av)
 846{
 847        char *mode;
 848        int res;
 849
 850        setlocale(LC_ALL, "");
 851        bindtextdomain(PACKAGE, LOCALEDIR);
 852        textdomain(PACKAGE);
 853
 854        signal(SIGINT, sig_handler);
 855
 856        conf_parse(av[1]);
 857        conf_read(NULL);
 858
 859        mode = getenv("MENUCONFIG_MODE");
 860        if (mode) {
 861                if (!strcasecmp(mode, "single_menu"))
 862                        single_menu_mode = 1;
 863        }
 864
 865        initscr();
 866
 867        getyx(stdscr, saved_y, saved_x);
 868        if (init_dialog(NULL)) {
 869                fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
 870                fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
 871                return 1;
 872        }
 873
 874        set_config_filename(conf_get_configname());
 875        do {
 876                conf(&rootmenu);
 877                res = handle_exit();
 878        } while (res == KEY_ESC);
 879
 880        return res;
 881}
 882
 883