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