busybox/scripts/kconfig/conf.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
   6#define _XOPEN_SOURCE 700
   7
   8#include <ctype.h>
   9#include <stdlib.h>
  10#include <stdio.h>
  11#include <string.h>
  12#include <unistd.h>
  13#include <time.h>
  14#include <sys/stat.h>
  15
  16#define LKC_DIRECT_LINK
  17#include "lkc.h"
  18
  19static void conf(struct menu *menu);
  20static void check_conf(struct menu *menu);
  21
  22enum {
  23        ask_all,
  24        ask_new,
  25        ask_silent,
  26        set_default,
  27        set_yes,
  28        set_mod,
  29        set_no,
  30        set_random
  31} input_mode = ask_all;
  32char *defconfig_file;
  33
  34static int indent = 1;
  35static int valid_stdin = 1;
  36static int conf_cnt;
  37static char line[128];
  38static struct menu *rootEntry;
  39
  40static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
  41
  42static void strip(char *str)
  43{
  44        char *p = str;
  45        int l;
  46
  47        while ((isspace(*p)))
  48                p++;
  49        l = strlen(p);
  50        if (p != str)
  51                memmove(str, p, l + 1);
  52        if (!l)
  53                return;
  54        p = str + l - 1;
  55        while ((isspace(*p)))
  56                *p-- = 0;
  57}
  58
  59static void check_stdin(void)
  60{
  61        if (!valid_stdin && input_mode == ask_silent) {
  62                printf(_("aborted!\n\n"));
  63                printf(_("Console input/output is redirected. "));
  64                printf(_("Run 'make oldconfig' to update configuration.\n\n"));
  65                exit(1);
  66        }
  67}
  68
  69static void conf_askvalue(struct symbol *sym, const char *def)
  70{
  71        enum symbol_type type = sym_get_type(sym);
  72        tristate val;
  73
  74        if (!sym_has_value(sym))
  75                printf("(NEW) ");
  76
  77        line[0] = '\n';
  78        line[1] = 0;
  79        line[2] = 0;
  80
  81        if (!sym_is_changable(sym)) {
  82                printf("%s\n", def);
  83                return;
  84        }
  85
  86        // If autoconf run (allnoconfig and such), reset bool and tristates:
  87        // "select ITEM" sets ITEM=y and then parent item might have been
  88        // reset to "n" later. Try to set ITEM to "n" on the second run.
  89        if (type == S_BOOLEAN || type == S_TRISTATE) {
  90                switch (input_mode) {
  91                case set_yes:
  92                        if (sym_tristate_within_range(sym, yes)) {
  93                                line[0] = 'y';
  94                                line[1] = '\n';
  95                                printf("%s", line);
  96                                return;
  97                        }
  98                case set_mod:
  99                        if (type == S_TRISTATE) {
 100                                if (sym_tristate_within_range(sym, mod)) {
 101                                        line[0] = 'm';
 102                                        line[1] = '\n';
 103                                        printf("%s", line);
 104                                        return;
 105                                }
 106                        } else {
 107                                if (sym_tristate_within_range(sym, yes)) {
 108                                        line[0] = 'y';
 109                                        line[1] = '\n';
 110                                        printf("%s", line);
 111                                        return;
 112                                }
 113                        }
 114                case set_no:
 115                        if (sym_tristate_within_range(sym, no)) {
 116                                line[0] = 'n';
 117                                line[1] = '\n';
 118                                printf("%s", line);
 119                                return;
 120                        }
 121                default: // placate compiler
 122                        break;
 123                }
 124        }
 125
 126        switch (input_mode) {
 127        case set_no:
 128        case set_mod:
 129        case set_yes:
 130        case set_random:
 131                if (sym_has_value(sym)) {
 132                        printf("%s\n", def);
 133                        return;
 134                }
 135                break;
 136        case ask_new:
 137        case ask_silent:
 138                if (sym_has_value(sym)) {
 139                        printf("%s\n", def);
 140                        return;
 141                }
 142                check_stdin();
 143        case ask_all:
 144                fflush(stdout);
 145                if (!fgets(line, 128, stdin))
 146                        exit(1);
 147                return;
 148        case set_default:
 149                printf("%s\n", def);
 150                return;
 151        default:
 152                break;
 153        }
 154
 155        switch (type) {
 156        case S_INT:
 157        case S_HEX:
 158        case S_STRING:
 159                printf("%s\n", def);
 160                return;
 161        default:
 162                ;
 163        }
 164        switch (input_mode) {
 165        case set_yes:
 166                if (sym_tristate_within_range(sym, yes)) {
 167                        line[0] = 'y';
 168                        line[1] = '\n';
 169                        line[2] = 0;
 170                        break;
 171                }
 172        case set_mod:
 173                if (type == S_TRISTATE) {
 174                        if (sym_tristate_within_range(sym, mod)) {
 175                                line[0] = 'm';
 176                                line[1] = '\n';
 177                                line[2] = 0;
 178                                break;
 179                        }
 180                } else {
 181                        if (sym_tristate_within_range(sym, yes)) {
 182                                line[0] = 'y';
 183                                line[1] = '\n';
 184                                line[2] = 0;
 185                                break;
 186                        }
 187                }
 188        case set_no:
 189                if (sym_tristate_within_range(sym, no)) {
 190                        line[0] = 'n';
 191                        line[1] = '\n';
 192                        line[2] = 0;
 193                        break;
 194                }
 195        case set_random:
 196                do {
 197                        val = (tristate)(random() % 3);
 198                } while (!sym_tristate_within_range(sym, val));
 199                switch (val) {
 200                case no: line[0] = 'n'; break;
 201                case mod: line[0] = 'm'; break;
 202                case yes: line[0] = 'y'; break;
 203                }
 204                line[1] = '\n';
 205                line[2] = 0;
 206                break;
 207        default:
 208                break;
 209        }
 210        printf("%s", line);
 211}
 212
 213int conf_string(struct menu *menu)
 214{
 215        struct symbol *sym = menu->sym;
 216        const char *def;
 217
 218        while (1) {
 219                printf("%*s%s ", indent - 1, "", menu->prompt->text);
 220                printf("(%s) ", sym->name);
 221                def = sym_get_string_value(sym);
 222                if (sym_get_string_value(sym))
 223                        printf("[%s] ", def);
 224                conf_askvalue(sym, def);
 225                switch (line[0]) {
 226                case '\n':
 227                        break;
 228                case '?':
 229                        /* print help */
 230                        if (line[1] == '\n') {
 231                                printf("\n%s\n", menu->sym->help ? menu->sym->help : nohelp_text);
 232                                def = NULL;
 233                                break;
 234                        }
 235                default:
 236                        line[strlen(line)-1] = 0;
 237                        def = line;
 238                }
 239                if (def && sym_set_string_value(sym, def))
 240                        return 0;
 241        }
 242}
 243
 244static int conf_sym(struct menu *menu)
 245{
 246        struct symbol *sym = menu->sym;
 247        tristate oldval, newval;
 248        const char *help;
 249
 250        while (1) {
 251                printf("%*s%s ", indent - 1, "", menu->prompt->text);
 252                if (sym->name)
 253                        printf("(%s) ", sym->name);
 254                putchar('[');
 255                oldval = sym_get_tristate_value(sym);
 256                switch (oldval) {
 257                case no:
 258                        putchar('N');
 259                        break;
 260                case mod:
 261                        putchar('M');
 262                        break;
 263                case yes:
 264                        putchar('Y');
 265                        break;
 266                }
 267                if (oldval != no && sym_tristate_within_range(sym, no))
 268                        printf("/n");
 269                if (oldval != mod && sym_tristate_within_range(sym, mod))
 270                        printf("/m");
 271                if (oldval != yes && sym_tristate_within_range(sym, yes))
 272                        printf("/y");
 273                if (sym->help)
 274                        printf("/?");
 275                printf("] ");
 276                conf_askvalue(sym, sym_get_string_value(sym));
 277                strip(line);
 278
 279                switch (line[0]) {
 280                case 'n':
 281                case 'N':
 282                        newval = no;
 283                        if (!line[1] || !strcmp(&line[1], "o"))
 284                                break;
 285                        continue;
 286                case 'm':
 287                case 'M':
 288                        newval = mod;
 289                        if (!line[1])
 290                                break;
 291                        continue;
 292                case 'y':
 293                case 'Y':
 294                        newval = yes;
 295                        if (!line[1] || !strcmp(&line[1], "es"))
 296                                break;
 297                        continue;
 298                case 0:
 299                        newval = oldval;
 300                        break;
 301                case '?':
 302                        goto help;
 303                default:
 304                        continue;
 305                }
 306                if (sym_set_tristate_value(sym, newval))
 307                        return 0;
 308help:
 309                help = nohelp_text;
 310                if (sym->help)
 311                        help = sym->help;
 312                printf("\n%s\n", help);
 313        }
 314}
 315
 316static int conf_choice(struct menu *menu)
 317{
 318        struct symbol *sym, *def_sym;
 319        struct menu *child;
 320        bool is_new;
 321
 322        sym = menu->sym;
 323        is_new = !sym_has_value(sym);
 324        if (sym_is_changable(sym)) {
 325                conf_sym(menu);
 326                sym_calc_value(sym);
 327                switch (sym_get_tristate_value(sym)) {
 328                case no:
 329                        return 1;
 330                case mod:
 331                        return 0;
 332                case yes:
 333                        break;
 334                }
 335        } else {
 336                switch (sym_get_tristate_value(sym)) {
 337                case no:
 338                        return 1;
 339                case mod:
 340                        printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
 341                        return 0;
 342                case yes:
 343                        break;
 344                }
 345        }
 346
 347        while (1) {
 348                int cnt, def;
 349
 350                printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
 351                def_sym = sym_get_choice_value(sym);
 352                cnt = def = 0;
 353                line[0] = 0;
 354                for (child = menu->list; child; child = child->next) {
 355                        if (!menu_is_visible(child))
 356                                continue;
 357                        if (!child->sym) {
 358                                printf("%*c %s\n", indent, '*', menu_get_prompt(child));
 359                                continue;
 360                        }
 361                        cnt++;
 362                        if (child->sym == def_sym) {
 363                                def = cnt;
 364                                printf("%*c", indent, '>');
 365                        } else
 366                                printf("%*c", indent, ' ');
 367                        printf(" %d. %s", cnt, menu_get_prompt(child));
 368                        if (child->sym->name)
 369                                printf(" (%s)", child->sym->name);
 370                        if (!sym_has_value(child->sym))
 371                                printf(" (NEW)");
 372                        printf("\n");
 373                }
 374                printf("%*schoice", indent - 1, "");
 375                if (cnt == 1) {
 376                        printf("[1]: 1\n");
 377                        goto conf_childs;
 378                }
 379                printf("[1-%d", cnt);
 380                if (sym->help)
 381                        printf("?");
 382                printf("]: ");
 383                switch (input_mode) {
 384                case ask_new:
 385                case ask_silent:
 386                        if (!is_new) {
 387                                cnt = def;
 388                                printf("%d\n", cnt);
 389                                break;
 390                        }
 391                        check_stdin();
 392                case ask_all:
 393                        fflush(stdout);
 394                        if (!fgets(line, 128, stdin))
 395                                exit(1);
 396                        strip(line);
 397                        if (line[0] == '?') {
 398                                printf("\n%s\n", menu->sym->help ?
 399                                        menu->sym->help : nohelp_text);
 400                                continue;
 401                        }
 402                        if (!line[0])
 403                                cnt = def;
 404                        else if (isdigit(line[0]))
 405                                cnt = atoi(line);
 406                        else
 407                                continue;
 408                        break;
 409                case set_random:
 410                        def = (random() % cnt) + 1;
 411                case set_default:
 412                case set_yes:
 413                case set_mod:
 414                case set_no:
 415                        cnt = def;
 416                        printf("%d\n", cnt);
 417                        break;
 418                }
 419
 420        conf_childs:
 421                for (child = menu->list; child; child = child->next) {
 422                        if (!child->sym || !menu_is_visible(child))
 423                                continue;
 424                        if (!--cnt)
 425                                break;
 426                }
 427                if (!child)
 428                        continue;
 429                if (strlen(line) > 0 && line[strlen(line) - 1] == '?') {
 430                        printf("\n%s\n", child->sym->help ?
 431                                child->sym->help : nohelp_text);
 432                        continue;
 433                }
 434                sym_set_choice_value(sym, child->sym);
 435                if (child->list) {
 436                        indent += 2;
 437                        conf(child->list);
 438                        indent -= 2;
 439                }
 440                return 1;
 441        }
 442}
 443
 444static void conf(struct menu *menu)
 445{
 446        struct symbol *sym;
 447        struct property *prop;
 448        struct menu *child;
 449
 450        if (!menu_is_visible(menu))
 451                return;
 452
 453        sym = menu->sym;
 454        prop = menu->prompt;
 455        if (prop) {
 456                const char *prompt;
 457
 458                switch (prop->type) {
 459                case P_MENU:
 460                        if (input_mode == ask_silent && rootEntry != menu) {
 461                                check_conf(menu);
 462                                return;
 463                        }
 464                case P_COMMENT:
 465                        prompt = menu_get_prompt(menu);
 466                        if (prompt)
 467                                printf("%*c\n%*c %s\n%*c\n",
 468                                        indent, '*',
 469                                        indent, '*', prompt,
 470                                        indent, '*');
 471                default:
 472                        ;
 473                }
 474        }
 475
 476        if (!sym)
 477                goto conf_childs;
 478
 479        if (sym_is_choice(sym)) {
 480                conf_choice(menu);
 481                if (sym->curr.tri != mod)
 482                        return;
 483                goto conf_childs;
 484        }
 485
 486        switch (sym->type) {
 487        case S_INT:
 488        case S_HEX:
 489        case S_STRING:
 490                conf_string(menu);
 491                break;
 492        default:
 493                conf_sym(menu);
 494                break;
 495        }
 496
 497conf_childs:
 498        if (sym)
 499                indent += 2;
 500        for (child = menu->list; child; child = child->next)
 501                conf(child);
 502        if (sym)
 503                indent -= 2;
 504}
 505
 506static void check_conf(struct menu *menu)
 507{
 508        struct symbol *sym;
 509        struct menu *child;
 510
 511        if (!menu_is_visible(menu))
 512                return;
 513
 514        sym = menu->sym;
 515        if (sym && !sym_has_value(sym)) {
 516                if (sym_is_changable(sym) ||
 517                    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
 518                        if (!conf_cnt++)
 519                                printf(_("*\n* Restart config...\n*\n"));
 520                        rootEntry = menu_get_parent_menu(menu);
 521                        conf(rootEntry);
 522                }
 523        }
 524
 525        for (child = menu->list; child; child = child->next)
 526                check_conf(child);
 527}
 528
 529int main(int ac, char **av)
 530{
 531        int i = 1;
 532        const char *name;
 533        struct stat tmpstat;
 534
 535        if (ac > i && av[i][0] == '-') {
 536                switch (av[i++][1]) {
 537                case 'o':
 538                        input_mode = ask_new;
 539                        break;
 540                case 's':
 541                        input_mode = ask_silent;
 542                        valid_stdin = isatty(0); //bbox: && isatty(1) && isatty(2);
 543                        break;
 544                case 'd':
 545                        input_mode = set_default;
 546                        break;
 547                case 'D':
 548                        input_mode = set_default;
 549                        defconfig_file = av[i++];
 550                        if (!defconfig_file) {
 551                                printf(_("%s: No default config file specified\n"),
 552                                        av[0]);
 553                                exit(1);
 554                        }
 555                        break;
 556                case 'n':
 557                        input_mode = set_no;
 558                        break;
 559                case 'm':
 560                        input_mode = set_mod;
 561                        break;
 562                case 'y':
 563                        input_mode = set_yes;
 564                        break;
 565                case 'r':
 566                        input_mode = set_random;
 567                        srandom(time(NULL));
 568                        break;
 569                case 'h':
 570                case '?':
 571                        fprintf(stderr, "See README for usage info\n");
 572                        exit(0);
 573                }
 574        }
 575        name = av[i];
 576        if (!name) {
 577                printf(_("%s: Kconfig file missing\n"), av[0]);
 578        }
 579        conf_parse(name);
 580        //zconfdump(stdout);
 581        switch (input_mode) {
 582        case set_default:
 583                if (!defconfig_file)
 584                        defconfig_file = conf_get_default_confname();
 585                if (conf_read(defconfig_file)) {
 586                        printf("***\n"
 587                                "*** Can't find default configuration \"%s\"!\n"
 588                                "***\n", defconfig_file);
 589                        exit(1);
 590                }
 591                break;
 592        case ask_silent:
 593                if (stat(".config", &tmpstat)) {
 594                        printf(_("***\n"
 595                                "*** You have not yet configured busybox!\n"
 596                                "***\n"
 597                                "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
 598                                "*** \"make menuconfig\" or \"make defconfig\").\n"
 599                                "***\n"));
 600                        exit(1);
 601                }
 602        case ask_all:
 603        case ask_new:
 604                conf_read(NULL);
 605                break;
 606        case set_no:
 607        case set_mod:
 608        case set_yes:
 609        case set_random:
 610                name = getenv("KCONFIG_ALLCONFIG");
 611                if (name && !stat(name, &tmpstat)) {
 612                        conf_read_simple(name);
 613                        break;
 614                }
 615                switch (input_mode) {
 616                case set_no:     name = "allno.config"; break;
 617                case set_mod:    name = "allmod.config"; break;
 618                case set_yes:    name = "allyes.config"; break;
 619                case set_random: name = "allrandom.config"; break;
 620                default: break;
 621                }
 622                if (!stat(name, &tmpstat))
 623                        conf_read_simple(name);
 624                else if (!stat("all.config", &tmpstat))
 625                        conf_read_simple("all.config");
 626                break;
 627        default:
 628                break;
 629        }
 630
 631        if (input_mode != ask_silent) {
 632                rootEntry = &rootmenu;
 633                conf(&rootmenu);
 634                // If autoconf run (allnoconfig and such), run it twice:
 635                // "select ITEM" sets ITEM=y and then parent item
 636                // is reset to "n" later. Second run sets ITEM to "n".
 637                // Example: ADDUSER selects LONG_OPTS.
 638                // allnoconfig must set _both_ to "n".
 639                // Before, LONG_OPTS remained "y".
 640                if (input_mode == set_no
 641                 || input_mode == set_mod
 642                 || input_mode == set_yes
 643                ) {
 644                        rootEntry = &rootmenu;
 645                        conf(&rootmenu);
 646                }
 647                if (input_mode == ask_all) {
 648                        input_mode = ask_silent;
 649                        valid_stdin = 1;
 650                }
 651        }
 652        do {
 653                conf_cnt = 0;
 654                check_conf(&rootmenu);
 655        } while (conf_cnt);
 656        if (conf_write(NULL)) {
 657                fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
 658                return 1;
 659        }
 660        return 0;
 661}
 662