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