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 <unistd.h>
  19#include <locale.h>
  20
  21#define LKC_DIRECT_LINK
  22#include "lkc.h"
  23#include "lxdialog/dialog.h"
  24
  25static const char mconf_readme[] = N_(
  26"Overview\n"
  27"--------\n"
  28"Some kernel features may be built directly into the kernel.\n"
  29"Some may be made into loadable runtime modules.  Some features\n"
  30"may be completely removed altogether.  There are also certain\n"
  31"kernel parameters which are not really features, but must be\n"
  32"entered in as decimal or hexadecimal numbers or possibly text.\n"
  33"\n"
  34"Menu items 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 (selected by other feature)\n"
  38"  - - are selected by other feature,\n"
  39"while *, M or whitespace inside braces means to build in, build as\n"
  40"a module or to exclude the feature respectively.\n"
  41"\n"
  42"To change any of these features, highlight it with the cursor\n"
  43"keys and press <Y> to build it in, <M> to make it a module or\n"
  44"<N> to removed it.  You may also press the <Space Bar> to cycle\n"
  45"through the available options (ie. Y->N->M->Y).\n"
  46"\n"
  47"Some additional keyboard hints:\n"
  48"\n"
  49"Menus\n"
  50"----------\n"
  51"o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
  52"   you wish to change or submenu wish to select and press <Enter>.\n"
  53"   Submenus are designated by \"--->\".\n"
  54"\n"
  55"   Shortcut: Press the option's highlighted letter (hotkey).\n"
  56"             Pressing a hotkey more than once will sequence\n"
  57"             through all visible items which use that hotkey.\n"
  58"\n"
  59"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
  60"   unseen options into view.\n"
  61"\n"
  62"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
  63"   and press <ENTER>.\n"
  64"\n"
  65"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
  66"             using those letters.  You may press a single <ESC>, but\n"
  67"             there is a delayed response which you may find annoying.\n"
  68"\n"
  69"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
  70"   <Exit> and <Help>\n"
  71"\n"
  72"o  To get help with an item, use the cursor keys to highlight <Help>\n"
  73"   and Press <ENTER>.\n"
  74"\n"
  75"   Shortcut: Press <H> or <?>.\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 kernel 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 kernel options listed in a single\n"
 152"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
 153"with 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."),
 202nohelp_text[] = N_(
 203        "There is no help available for this kernel option.\n"),
 204load_config_text[] = N_(
 205        "Enter the name of the configuration file you wish to load.  "
 206        "Accept the name shown to restore the configuration you "
 207        "last retrieved.  Leave blank to abort."),
 208load_config_help[] = N_(
 209        "\n"
 210        "For various reasons, one may wish to keep several different kernel\n"
 211        "configurations available on a single machine.\n"
 212        "\n"
 213        "If you have saved a previous configuration in a file other than the\n"
 214        "kernel's default, entering the name of the file here will allow you\n"
 215        "to modify that configuration.\n"
 216        "\n"
 217        "If you are uncertain, then you have probably never used alternate\n"
 218        "configuration files.  You should therefor leave this blank to abort.\n"),
 219save_config_text[] = N_(
 220        "Enter a filename to which this configuration should be saved "
 221        "as an alternate.  Leave blank to abort."),
 222save_config_help[] = N_(
 223        "\n"
 224        "For various reasons, one may wish to keep different kernel\n"
 225        "configurations available on a single machine.\n"
 226        "\n"
 227        "Entering a file name here will allow you to later retrieve, modify\n"
 228        "and use the current configuration as an alternate to whatever\n"
 229        "configuration options you have selected at that time.\n"
 230        "\n"
 231        "If you are uncertain what all this means then you should probably\n"
 232        "leave this blank.\n"),
 233search_help[] = N_(
 234        "\n"
 235        "Search for CONFIG_ symbols and display their relations.\n"
 236        "Regular expressions are allowed.\n"
 237        "Example: search for \"^FOO\"\n"
 238        "Result:\n"
 239        "-----------------------------------------------------------------\n"
 240        "Symbol: FOO [=m]\n"
 241        "Prompt: Foo bus is used to drive the bar HW\n"
 242        "Defined at drivers/pci/Kconfig:47\n"
 243        "Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
 244        "Location:\n"
 245        "  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
 246        "    -> PCI support (PCI [=y])\n"
 247        "      -> PCI access mode (<choice> [=y])\n"
 248        "Selects: LIBCRC32\n"
 249        "Selected by: BAR\n"
 250        "-----------------------------------------------------------------\n"
 251        "o The line 'Prompt:' shows the text used in the menu structure for\n"
 252        "  this CONFIG_ symbol\n"
 253        "o The 'Defined at' line tell at what file / line number the symbol\n"
 254        "  is defined\n"
 255        "o The 'Depends on:' line tell what symbols needs to be defined for\n"
 256        "  this symbol to be visible in the menu (selectable)\n"
 257        "o The 'Location:' lines tell where in the menu structure this symbol\n"
 258        "  is located\n"
 259        "    A location followed by a [=y] indicate that this is a selectable\n"
 260        "    menu item - and current value is displayed inside brackets.\n"
 261        "o The 'Selects:' line tell what symbol will be automatically\n"
 262        "  selected if this symbol is selected (y or m)\n"
 263        "o The 'Selected by' line tell what symbol has selected this symbol\n"
 264        "\n"
 265        "Only relevant lines are shown.\n"
 266        "\n\n"
 267        "Search examples:\n"
 268        "Examples: USB  => find all CONFIG_ symbols containing USB\n"
 269        "          ^USB => find all CONFIG_ symbols starting with USB\n"
 270        "          USB$ => find all CONFIG_ symbols ending with USB\n"
 271        "\n");
 272
 273static int indent;
 274static struct menu *current_menu;
 275static int child_count;
 276static int single_menu_mode;
 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 void get_prompt_str(struct gstr *r, struct property *prop)
 288{
 289        int i, j;
 290        struct menu *submenu[8], *menu;
 291
 292        str_printf(r, _("Prompt: %s\n"), _(prop->text));
 293        str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
 294                prop->menu->lineno);
 295        if (!expr_is_yes(prop->visible.expr)) {
 296                str_append(r, _("  Depends on: "));
 297                expr_gstr_print(prop->visible.expr, r);
 298                str_append(r, "\n");
 299        }
 300        menu = prop->menu->parent;
 301        for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
 302                submenu[i++] = menu;
 303        if (i > 0) {
 304                str_printf(r, _("  Location:\n"));
 305                for (j = 4; --i >= 0; j += 2) {
 306                        menu = submenu[i];
 307                        str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
 308                        if (menu->sym) {
 309                                str_printf(r, " (%s [=%s])", menu->sym->name ?
 310                                        menu->sym->name : _("<choice>"),
 311                                        sym_get_string_value(menu->sym));
 312                        }
 313                        str_append(r, "\n");
 314                }
 315        }
 316}
 317
 318static void get_symbol_str(struct gstr *r, struct symbol *sym)
 319{
 320        bool hit;
 321        struct property *prop;
 322
 323        if (sym && sym->name)
 324                str_printf(r, "Symbol: %s [=%s]\n", sym->name,
 325                                                    sym_get_string_value(sym));
 326        for_all_prompts(sym, prop)
 327                get_prompt_str(r, prop);
 328        hit = false;
 329        for_all_properties(sym, prop, P_SELECT) {
 330                if (!hit) {
 331                        str_append(r, "  Selects: ");
 332                        hit = true;
 333                } else
 334                        str_printf(r, " && ");
 335                expr_gstr_print(prop->expr, r);
 336        }
 337        if (hit)
 338                str_append(r, "\n");
 339        if (sym->rev_dep.expr) {
 340                str_append(r, _("  Selected by: "));
 341                expr_gstr_print(sym->rev_dep.expr, r);
 342                str_append(r, "\n");
 343        }
 344        str_append(r, "\n\n");
 345}
 346
 347static struct gstr get_relations_str(struct symbol **sym_arr)
 348{
 349        struct symbol *sym;
 350        struct gstr res = str_new();
 351        int i;
 352
 353        for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
 354                get_symbol_str(&res, sym);
 355        if (!i)
 356                str_append(&res, _("No matches found.\n"));
 357        return res;
 358}
 359
 360static char filename[PATH_MAX+1];
 361static void set_config_filename(const char *config_filename)
 362{
 363        static char menu_backtitle[PATH_MAX+128];
 364        int size;
 365        struct symbol *sym;
 366
 367        sym = sym_lookup("KERNELVERSION", 0);
 368        sym_calc_value(sym);
 369        size = snprintf(menu_backtitle, sizeof(menu_backtitle),
 370                        _("%s - Linux Kernel v%s Configuration"),
 371                        config_filename, sym_get_string_value(sym));
 372        if (size >= sizeof(menu_backtitle))
 373                menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
 374        set_dialog_backtitle(menu_backtitle);
 375
 376        size = snprintf(filename, sizeof(filename), "%s", config_filename);
 377        if (size >= sizeof(filename))
 378                filename[sizeof(filename)-1] = '\0';
 379}
 380
 381
 382static void search_conf(void)
 383{
 384        struct symbol **sym_arr;
 385        struct gstr res;
 386        char *dialog_input;
 387        int dres;
 388again:
 389        dialog_clear();
 390        dres = dialog_inputbox(_("Search Configuration Parameter"),
 391                              _("Enter CONFIG_ (sub)string to search for "
 392                                "(with or without \"CONFIG\")"),
 393                              10, 75, "");
 394        switch (dres) {
 395        case 0:
 396                break;
 397        case 1:
 398                show_helptext(_("Search Configuration"), search_help);
 399                goto again;
 400        default:
 401                return;
 402        }
 403
 404        /* strip CONFIG_ if necessary */
 405        dialog_input = dialog_input_result;
 406        if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
 407                dialog_input += 7;
 408
 409        sym_arr = sym_re_search(dialog_input);
 410        res = get_relations_str(sym_arr);
 411        free(sym_arr);
 412        show_textbox(_("Search Results"), str_get(&res), 0, 0);
 413        str_free(&res);
 414}
 415
 416static void build_conf(struct menu *menu)
 417{
 418        struct symbol *sym;
 419        struct property *prop;
 420        struct menu *child;
 421        int type, tmp, doint = 2;
 422        tristate val;
 423        char ch;
 424
 425        if (!menu_is_visible(menu))
 426                return;
 427
 428        sym = menu->sym;
 429        prop = menu->prompt;
 430        if (!sym) {
 431                if (prop && menu != current_menu) {
 432                        const char *prompt = menu_get_prompt(menu);
 433                        switch (prop->type) {
 434                        case P_MENU:
 435                                child_count++;
 436                                prompt = _(prompt);
 437                                if (single_menu_mode) {
 438                                        item_make("%s%*c%s",
 439                                                  menu->data ? "-->" : "++>",
 440                                                  indent + 1, ' ', prompt);
 441                                } else
 442                                        item_make("   %*c%s  --->", indent + 1, ' ', prompt);
 443
 444                                item_set_tag('m');
 445                                item_set_data(menu);
 446                                if (single_menu_mode && menu->data)
 447                                        goto conf_childs;
 448                                return;
 449                        case P_COMMENT:
 450                                if (prompt) {
 451                                        child_count++;
 452                                        item_make("   %*c*** %s ***", indent + 1, ' ', _(prompt));
 453                                        item_set_tag(':');
 454                                        item_set_data(menu);
 455                                }
 456                                break;
 457                        default:
 458                                if (prompt) {
 459                                        child_count++;
 460                                        item_make("---%*c%s", indent + 1, ' ', _(prompt));
 461                                        item_set_tag(':');
 462                                        item_set_data(menu);
 463                                }
 464                        }
 465                } else
 466                        doint = 0;
 467                goto conf_childs;
 468        }
 469
 470        type = sym_get_type(sym);
 471        if (sym_is_choice(sym)) {
 472                struct symbol *def_sym = sym_get_choice_value(sym);
 473                struct menu *def_menu = NULL;
 474
 475                child_count++;
 476                for (child = menu->list; child; child = child->next) {
 477                        if (menu_is_visible(child) && child->sym == def_sym)
 478                                def_menu = child;
 479                }
 480
 481                val = sym_get_tristate_value(sym);
 482                if (sym_is_changable(sym)) {
 483                        switch (type) {
 484                        case S_BOOLEAN:
 485                                item_make("[%c]", val == no ? ' ' : '*');
 486                                break;
 487                        case S_TRISTATE:
 488                                switch (val) {
 489                                case yes: ch = '*'; break;
 490                                case mod: ch = 'M'; break;
 491                                default:  ch = ' '; break;
 492                                }
 493                                item_make("<%c>", ch);
 494                                break;
 495                        }
 496                        item_set_tag('t');
 497                        item_set_data(menu);
 498                } else {
 499                        item_make("   ");
 500                        item_set_tag(def_menu ? 't' : ':');
 501                        item_set_data(menu);
 502                }
 503
 504                item_add_str("%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
 505                if (val == yes) {
 506                        if (def_menu) {
 507                                item_add_str(" (%s)", _(menu_get_prompt(def_menu)));
 508                                item_add_str("  --->");
 509                                if (def_menu->list) {
 510                                        indent += 2;
 511                                        build_conf(def_menu);
 512                                        indent -= 2;
 513                                }
 514                        }
 515                        return;
 516                }
 517        } else {
 518                if (menu == current_menu) {
 519                        item_make("---%*c%s", indent + 1, ' ', _(menu_get_prompt(menu)));
 520                        item_set_tag(':');
 521                        item_set_data(menu);
 522                        goto conf_childs;
 523                }
 524                child_count++;
 525                val = sym_get_tristate_value(sym);
 526                if (sym_is_choice_value(sym) && val == yes) {
 527                        item_make("   ");
 528                        item_set_tag(':');
 529                        item_set_data(menu);
 530                } else {
 531                        switch (type) {
 532                        case S_BOOLEAN:
 533                                if (sym_is_changable(sym))
 534                                        item_make("[%c]", val == no ? ' ' : '*');
 535                                else
 536                                        item_make("-%c-", val == no ? ' ' : '*');
 537                                item_set_tag('t');
 538                                item_set_data(menu);
 539                                break;
 540                        case S_TRISTATE:
 541                                switch (val) {
 542                                case yes: ch = '*'; break;
 543                                case mod: ch = 'M'; break;
 544                                default:  ch = ' '; break;
 545                                }
 546                                if (sym_is_changable(sym)) {
 547                                        if (sym->rev_dep.tri == mod)
 548                                                item_make("{%c}", ch);
 549                                        else
 550                                                item_make("<%c>", ch);
 551                                } else
 552                                        item_make("-%c-", ch);
 553                                item_set_tag('t');
 554                                item_set_data(menu);
 555                                break;
 556                        default:
 557                                tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
 558                                item_make("(%s)", sym_get_string_value(sym));
 559                                tmp = indent - tmp + 4;
 560                                if (tmp < 0)
 561                                        tmp = 0;
 562                                item_add_str("%*c%s%s", tmp, ' ', _(menu_get_prompt(menu)),
 563                                             (sym_has_value(sym) || !sym_is_changable(sym)) ?
 564                                             "" : _(" (NEW)"));
 565                                item_set_tag('s');
 566                                item_set_data(menu);
 567                                goto conf_childs;
 568                        }
 569                }
 570                item_add_str("%*c%s%s", indent + 1, ' ', _(menu_get_prompt(menu)),
 571                          (sym_has_value(sym) || !sym_is_changable(sym)) ?
 572                          "" : _(" (NEW)"));
 573                if (menu->prompt->type == P_MENU) {
 574                        item_add_str("  --->");
 575                        return;
 576                }
 577        }
 578
 579conf_childs:
 580        indent += doint;
 581        for (child = menu->list; child; child = child->next)
 582                build_conf(child);
 583        indent -= doint;
 584}
 585
 586static void conf(struct menu *menu)
 587{
 588        struct menu *submenu;
 589        const char *prompt = menu_get_prompt(menu);
 590        struct symbol *sym;
 591        struct menu *active_menu = NULL;
 592        int res;
 593        int s_scroll = 0;
 594
 595        while (1) {
 596                item_reset();
 597                current_menu = menu;
 598                build_conf(menu);
 599                if (!child_count)
 600                        break;
 601                if (menu == &rootmenu) {
 602                        item_make("--- ");
 603                        item_set_tag(':');
 604                        item_make(_("    Load an Alternate Configuration File"));
 605                        item_set_tag('L');
 606                        item_make(_("    Save an Alternate Configuration File"));
 607                        item_set_tag('S');
 608                }
 609                dialog_clear();
 610                res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
 611                                  _(menu_instructions),
 612                                  active_menu, &s_scroll);
 613                if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 614                        break;
 615                if (!item_activate_selected())
 616                        continue;
 617                if (!item_tag())
 618                        continue;
 619
 620                submenu = item_data();
 621                active_menu = item_data();
 622                if (submenu)
 623                        sym = submenu->sym;
 624                else
 625                        sym = NULL;
 626
 627                switch (res) {
 628                case 0:
 629                        switch (item_tag()) {
 630                        case 'm':
 631                                if (single_menu_mode)
 632                                        submenu->data = (void *) (long) !submenu->data;
 633                                else
 634                                        conf(submenu);
 635                                break;
 636                        case 't':
 637                                if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 638                                        conf_choice(submenu);
 639                                else if (submenu->prompt->type == P_MENU)
 640                                        conf(submenu);
 641                                break;
 642                        case 's':
 643                                conf_string(submenu);
 644                                break;
 645                        case 'L':
 646                                conf_load();
 647                                break;
 648                        case 'S':
 649                                conf_save();
 650                                break;
 651                        }
 652                        break;
 653                case 2:
 654                        if (sym)
 655                                show_help(submenu);
 656                        else
 657                                show_helptext(_("README"), _(mconf_readme));
 658                        break;
 659                case 3:
 660                        if (item_is_tag('t')) {
 661                                if (sym_set_tristate_value(sym, yes))
 662                                        break;
 663                                if (sym_set_tristate_value(sym, mod))
 664                                        show_textbox(NULL, setmod_text, 6, 74);
 665                        }
 666                        break;
 667                case 4:
 668                        if (item_is_tag('t'))
 669                                sym_set_tristate_value(sym, no);
 670                        break;
 671                case 5:
 672                        if (item_is_tag('t'))
 673                                sym_set_tristate_value(sym, mod);
 674                        break;
 675                case 6:
 676                        if (item_is_tag('t'))
 677                                sym_toggle_tristate_value(sym);
 678                        else if (item_is_tag('m'))
 679                                conf(submenu);
 680                        break;
 681                case 7:
 682                        search_conf();
 683                        break;
 684                }
 685        }
 686}
 687
 688static void show_textbox(const char *title, const char *text, int r, int c)
 689{
 690        dialog_clear();
 691        dialog_textbox(title, text, r, c);
 692}
 693
 694static void show_helptext(const char *title, const char *text)
 695{
 696        show_textbox(title, text, 0, 0);
 697}
 698
 699static void show_help(struct menu *menu)
 700{
 701        struct gstr help = str_new();
 702        struct symbol *sym = menu->sym;
 703
 704        if (menu_has_help(menu))
 705        {
 706                if (sym->name) {
 707                        str_printf(&help, "CONFIG_%s:\n\n", sym->name);
 708                        str_append(&help, _(menu_get_help(menu)));
 709                        str_append(&help, "\n");
 710                }
 711        } else {
 712                str_append(&help, nohelp_text);
 713        }
 714        get_symbol_str(&help, sym);
 715        show_helptext(_(menu_get_prompt(menu)), str_get(&help));
 716        str_free(&help);
 717}
 718
 719static void conf_choice(struct menu *menu)
 720{
 721        const char *prompt = _(menu_get_prompt(menu));
 722        struct menu *child;
 723        struct symbol *active;
 724
 725        active = sym_get_choice_value(menu->sym);
 726        while (1) {
 727                int res;
 728                int selected;
 729                item_reset();
 730
 731                current_menu = menu;
 732                for (child = menu->list; child; child = child->next) {
 733                        if (!menu_is_visible(child))
 734                                continue;
 735                        item_make("%s", _(menu_get_prompt(child)));
 736                        item_set_data(child);
 737                        if (child->sym == active)
 738                                item_set_selected(1);
 739                        if (child->sym == sym_get_choice_value(menu->sym))
 740                                item_set_tag('X');
 741                }
 742                dialog_clear();
 743                res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
 744                                        _(radiolist_instructions),
 745                                         15, 70, 6);
 746                selected = item_activate_selected();
 747                switch (res) {
 748                case 0:
 749                        if (selected) {
 750                                child = item_data();
 751                                sym_set_tristate_value(child->sym, yes);
 752                        }
 753                        return;
 754                case 1:
 755                        if (selected) {
 756                                child = item_data();
 757                                show_help(child);
 758                                active = child->sym;
 759                        } else
 760                                show_help(menu);
 761                        break;
 762                case KEY_ESC:
 763                        return;
 764                case -ERRDISPLAYTOOSMALL:
 765                        return;
 766                }
 767        }
 768}
 769
 770static void conf_string(struct menu *menu)
 771{
 772        const char *prompt = menu_get_prompt(menu);
 773
 774        while (1) {
 775                int res;
 776                const char *heading;
 777
 778                switch (sym_get_type(menu->sym)) {
 779                case S_INT:
 780                        heading = _(inputbox_instructions_int);
 781                        break;
 782                case S_HEX:
 783                        heading = _(inputbox_instructions_hex);
 784                        break;
 785                case S_STRING:
 786                        heading = _(inputbox_instructions_string);
 787                        break;
 788                default:
 789                        heading = _("Internal mconf error!");
 790                }
 791                dialog_clear();
 792                res = dialog_inputbox(prompt ? _(prompt) : _("Main Menu"),
 793                                      heading, 10, 75,
 794                                      sym_get_string_value(menu->sym));
 795                switch (res) {
 796                case 0:
 797                        if (sym_set_string_value(menu->sym, dialog_input_result))
 798                                return;
 799                        show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
 800                        break;
 801                case 1:
 802                        show_help(menu);
 803                        break;
 804                case KEY_ESC:
 805                        return;
 806                }
 807        }
 808}
 809
 810static void conf_load(void)
 811{
 812
 813        while (1) {
 814                int res;
 815                dialog_clear();
 816                res = dialog_inputbox(NULL, load_config_text,
 817                                      11, 55, filename);
 818                switch(res) {
 819                case 0:
 820                        if (!dialog_input_result[0])
 821                                return;
 822                        if (!conf_read(dialog_input_result)) {
 823                                set_config_filename(dialog_input_result);
 824                                sym_set_change_count(1);
 825                                return;
 826                        }
 827                        show_textbox(NULL, _("File does not exist!"), 5, 38);
 828                        break;
 829                case 1:
 830                        show_helptext(_("Load Alternate Configuration"), load_config_help);
 831                        break;
 832                case KEY_ESC:
 833                        return;
 834                }
 835        }
 836}
 837
 838static void conf_save(void)
 839{
 840        while (1) {
 841                int res;
 842                dialog_clear();
 843                res = dialog_inputbox(NULL, save_config_text,
 844                                      11, 55, filename);
 845                switch(res) {
 846                case 0:
 847                        if (!dialog_input_result[0])
 848                                return;
 849                        if (!conf_write(dialog_input_result)) {
 850                                set_config_filename(dialog_input_result);
 851                                return;
 852                        }
 853                        show_textbox(NULL, _("Can't create file!  Probably a nonexistent directory."), 5, 60);
 854                        break;
 855                case 1:
 856                        show_helptext(_("Save Alternate Configuration"), save_config_help);
 857                        break;
 858                case KEY_ESC:
 859                        return;
 860                }
 861        }
 862}
 863
 864int main(int ac, char **av)
 865{
 866        int saved_x, saved_y;
 867        char *mode;
 868        int res;
 869
 870        setlocale(LC_ALL, "");
 871        bindtextdomain(PACKAGE, LOCALEDIR);
 872        textdomain(PACKAGE);
 873
 874        conf_parse(av[1]);
 875        conf_read(NULL);
 876
 877        mode = getenv("MENUCONFIG_MODE");
 878        if (mode) {
 879                if (!strcasecmp(mode, "single_menu"))
 880                        single_menu_mode = 1;
 881        }
 882
 883        getyx(stdscr, saved_y, saved_x);
 884        if (init_dialog(NULL)) {
 885                fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
 886                fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
 887                return 1;
 888        }
 889
 890        set_config_filename(conf_get_configname());
 891        do {
 892                conf(&rootmenu);
 893                dialog_clear();
 894                if (conf_get_changed())
 895                        res = dialog_yesno(NULL,
 896                                           _("Do you wish to save your "
 897                                             "new kernel configuration?\n"
 898                                             "<ESC><ESC> to continue."),
 899                                           6, 60);
 900                else
 901                        res = -1;
 902        } while (res == KEY_ESC);
 903        end_dialog(saved_x, saved_y);
 904
 905        switch (res) {
 906        case 0:
 907                if (conf_write(filename)) {
 908                        fprintf(stderr, _("\n\n"
 909                                "Error during writing of the kernel configuration.\n"
 910                                "Your kernel configuration changes were NOT saved."
 911                                "\n\n"));
 912                        return 1;
 913                }
 914        case -1:
 915                printf(_("\n\n"
 916                        "*** End of Linux kernel configuration.\n"
 917                        "*** Execute 'make' to build the kernel or try 'make help'."
 918                        "\n\n"));
 919                break;
 920        default:
 921                fprintf(stderr, _("\n\n"
 922                        "Your kernel configuration changes were NOT saved."
 923                        "\n\n"));
 924        }
 925
 926        return 0;
 927}
 928
 929