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