linux/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#include <locale.h>
   7#include <ctype.h>
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <time.h>
  12#include <unistd.h>
  13#include <getopt.h>
  14#include <sys/stat.h>
  15#include <sys/time.h>
  16
  17#include "lkc.h"
  18
  19static void conf(struct menu *menu);
  20static void check_conf(struct menu *menu);
  21static void xfgets(char *str, int size, FILE *in);
  22
  23enum input_mode {
  24        oldaskconfig,
  25        silentoldconfig,
  26        oldconfig,
  27        allnoconfig,
  28        allyesconfig,
  29        allmodconfig,
  30        alldefconfig,
  31        randconfig,
  32        defconfig,
  33        savedefconfig,
  34        listnewconfig,
  35        olddefconfig,
  36} input_mode = oldaskconfig;
  37
  38static int indent = 1;
  39static int valid_stdin = 1;
  40static int sync_kconfig;
  41static int conf_cnt;
  42static char line[128];
  43static struct menu *rootEntry;
  44
  45static void print_help(struct menu *menu)
  46{
  47        struct gstr help = str_new();
  48
  49        menu_get_ext_help(menu, &help);
  50
  51        printf("\n%s\n", str_get(&help));
  52        str_free(&help);
  53}
  54
  55static void strip(char *str)
  56{
  57        char *p = str;
  58        int l;
  59
  60        while ((isspace(*p)))
  61                p++;
  62        l = strlen(p);
  63        if (p != str)
  64                memmove(str, p, l + 1);
  65        if (!l)
  66                return;
  67        p = str + l - 1;
  68        while ((isspace(*p)))
  69                *p-- = 0;
  70}
  71
  72static void check_stdin(void)
  73{
  74        if (!valid_stdin) {
  75                printf(_("aborted!\n\n"));
  76                printf(_("Console input/output is redirected. "));
  77                printf(_("Run 'make oldconfig' to update configuration.\n\n"));
  78                exit(1);
  79        }
  80}
  81
  82static int conf_askvalue(struct symbol *sym, const char *def)
  83{
  84        enum symbol_type type = sym_get_type(sym);
  85
  86        if (!sym_has_value(sym))
  87                printf(_("(NEW) "));
  88
  89        line[0] = '\n';
  90        line[1] = 0;
  91
  92        if (!sym_is_changable(sym)) {
  93                printf("%s\n", def);
  94                line[0] = '\n';
  95                line[1] = 0;
  96                return 0;
  97        }
  98
  99        switch (input_mode) {
 100        case oldconfig:
 101        case silentoldconfig:
 102                if (sym_has_value(sym)) {
 103                        printf("%s\n", def);
 104                        return 0;
 105                }
 106                check_stdin();
 107                /* fall through */
 108        case oldaskconfig:
 109                fflush(stdout);
 110                xfgets(line, 128, stdin);
 111                return 1;
 112        default:
 113                break;
 114        }
 115
 116        switch (type) {
 117        case S_INT:
 118        case S_HEX:
 119        case S_STRING:
 120                printf("%s\n", def);
 121                return 1;
 122        default:
 123                ;
 124        }
 125        printf("%s", line);
 126        return 1;
 127}
 128
 129static int conf_string(struct menu *menu)
 130{
 131        struct symbol *sym = menu->sym;
 132        const char *def;
 133
 134        while (1) {
 135                printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
 136                printf("(%s) ", sym->name);
 137                def = sym_get_string_value(sym);
 138                if (sym_get_string_value(sym))
 139                        printf("[%s] ", def);
 140                if (!conf_askvalue(sym, def))
 141                        return 0;
 142                switch (line[0]) {
 143                case '\n':
 144                        break;
 145                case '?':
 146                        /* print help */
 147                        if (line[1] == '\n') {
 148                                print_help(menu);
 149                                def = NULL;
 150                                break;
 151                        }
 152                        /* fall through */
 153                default:
 154                        line[strlen(line)-1] = 0;
 155                        def = line;
 156                }
 157                if (def && sym_set_string_value(sym, def))
 158                        return 0;
 159        }
 160}
 161
 162static int conf_sym(struct menu *menu)
 163{
 164        struct symbol *sym = menu->sym;
 165        tristate oldval, newval;
 166
 167        while (1) {
 168                printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
 169                if (sym->name)
 170                        printf("(%s) ", sym->name);
 171                putchar('[');
 172                oldval = sym_get_tristate_value(sym);
 173                switch (oldval) {
 174                case no:
 175                        putchar('N');
 176                        break;
 177                case mod:
 178                        putchar('M');
 179                        break;
 180                case yes:
 181                        putchar('Y');
 182                        break;
 183                }
 184                if (oldval != no && sym_tristate_within_range(sym, no))
 185                        printf("/n");
 186                if (oldval != mod && sym_tristate_within_range(sym, mod))
 187                        printf("/m");
 188                if (oldval != yes && sym_tristate_within_range(sym, yes))
 189                        printf("/y");
 190                if (menu_has_help(menu))
 191                        printf("/?");
 192                printf("] ");
 193                if (!conf_askvalue(sym, sym_get_string_value(sym)))
 194                        return 0;
 195                strip(line);
 196
 197                switch (line[0]) {
 198                case 'n':
 199                case 'N':
 200                        newval = no;
 201                        if (!line[1] || !strcmp(&line[1], "o"))
 202                                break;
 203                        continue;
 204                case 'm':
 205                case 'M':
 206                        newval = mod;
 207                        if (!line[1])
 208                                break;
 209                        continue;
 210                case 'y':
 211                case 'Y':
 212                        newval = yes;
 213                        if (!line[1] || !strcmp(&line[1], "es"))
 214                                break;
 215                        continue;
 216                case 0:
 217                        newval = oldval;
 218                        break;
 219                case '?':
 220                        goto help;
 221                default:
 222                        continue;
 223                }
 224                if (sym_set_tristate_value(sym, newval))
 225                        return 0;
 226help:
 227                print_help(menu);
 228        }
 229}
 230
 231static int conf_choice(struct menu *menu)
 232{
 233        struct symbol *sym, *def_sym;
 234        struct menu *child;
 235        bool is_new;
 236
 237        sym = menu->sym;
 238        is_new = !sym_has_value(sym);
 239        if (sym_is_changable(sym)) {
 240                conf_sym(menu);
 241                sym_calc_value(sym);
 242                switch (sym_get_tristate_value(sym)) {
 243                case no:
 244                        return 1;
 245                case mod:
 246                        return 0;
 247                case yes:
 248                        break;
 249                }
 250        } else {
 251                switch (sym_get_tristate_value(sym)) {
 252                case no:
 253                        return 1;
 254                case mod:
 255                        printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
 256                        return 0;
 257                case yes:
 258                        break;
 259                }
 260        }
 261
 262        while (1) {
 263                int cnt, def;
 264
 265                printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
 266                def_sym = sym_get_choice_value(sym);
 267                cnt = def = 0;
 268                line[0] = 0;
 269                for (child = menu->list; child; child = child->next) {
 270                        if (!menu_is_visible(child))
 271                                continue;
 272                        if (!child->sym) {
 273                                printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
 274                                continue;
 275                        }
 276                        cnt++;
 277                        if (child->sym == def_sym) {
 278                                def = cnt;
 279                                printf("%*c", indent, '>');
 280                        } else
 281                                printf("%*c", indent, ' ');
 282                        printf(" %d. %s", cnt, _(menu_get_prompt(child)));
 283                        if (child->sym->name)
 284                                printf(" (%s)", child->sym->name);
 285                        if (!sym_has_value(child->sym))
 286                                printf(_(" (NEW)"));
 287                        printf("\n");
 288                }
 289                printf(_("%*schoice"), indent - 1, "");
 290                if (cnt == 1) {
 291                        printf("[1]: 1\n");
 292                        goto conf_childs;
 293                }
 294                printf("[1-%d", cnt);
 295                if (menu_has_help(menu))
 296                        printf("?");
 297                printf("]: ");
 298                switch (input_mode) {
 299                case oldconfig:
 300                case silentoldconfig:
 301                        if (!is_new) {
 302                                cnt = def;
 303                                printf("%d\n", cnt);
 304                                break;
 305                        }
 306                        check_stdin();
 307                        /* fall through */
 308                case oldaskconfig:
 309                        fflush(stdout);
 310                        xfgets(line, 128, stdin);
 311                        strip(line);
 312                        if (line[0] == '?') {
 313                                print_help(menu);
 314                                continue;
 315                        }
 316                        if (!line[0])
 317                                cnt = def;
 318                        else if (isdigit(line[0]))
 319                                cnt = atoi(line);
 320                        else
 321                                continue;
 322                        break;
 323                default:
 324                        break;
 325                }
 326
 327        conf_childs:
 328                for (child = menu->list; child; child = child->next) {
 329                        if (!child->sym || !menu_is_visible(child))
 330                                continue;
 331                        if (!--cnt)
 332                                break;
 333                }
 334                if (!child)
 335                        continue;
 336                if (line[0] && line[strlen(line) - 1] == '?') {
 337                        print_help(child);
 338                        continue;
 339                }
 340                sym_set_choice_value(sym, child->sym);
 341                for (child = child->list; child; child = child->next) {
 342                        indent += 2;
 343                        conf(child);
 344                        indent -= 2;
 345                }
 346                return 1;
 347        }
 348}
 349
 350static void conf(struct menu *menu)
 351{
 352        struct symbol *sym;
 353        struct property *prop;
 354        struct menu *child;
 355
 356        if (!menu_is_visible(menu))
 357                return;
 358
 359        sym = menu->sym;
 360        prop = menu->prompt;
 361        if (prop) {
 362                const char *prompt;
 363
 364                switch (prop->type) {
 365                case P_MENU:
 366                        if ((input_mode == silentoldconfig ||
 367                             input_mode == listnewconfig ||
 368                             input_mode == olddefconfig) &&
 369                            rootEntry != menu) {
 370                                check_conf(menu);
 371                                return;
 372                        }
 373                        /* fall through */
 374                case P_COMMENT:
 375                        prompt = menu_get_prompt(menu);
 376                        if (prompt)
 377                                printf("%*c\n%*c %s\n%*c\n",
 378                                        indent, '*',
 379                                        indent, '*', _(prompt),
 380                                        indent, '*');
 381                default:
 382                        ;
 383                }
 384        }
 385
 386        if (!sym)
 387                goto conf_childs;
 388
 389        if (sym_is_choice(sym)) {
 390                conf_choice(menu);
 391                if (sym->curr.tri != mod)
 392                        return;
 393                goto conf_childs;
 394        }
 395
 396        switch (sym->type) {
 397        case S_INT:
 398        case S_HEX:
 399        case S_STRING:
 400                conf_string(menu);
 401                break;
 402        default:
 403                conf_sym(menu);
 404                break;
 405        }
 406
 407conf_childs:
 408        if (sym)
 409                indent += 2;
 410        for (child = menu->list; child; child = child->next)
 411                conf(child);
 412        if (sym)
 413                indent -= 2;
 414}
 415
 416static void check_conf(struct menu *menu)
 417{
 418        struct symbol *sym;
 419        struct menu *child;
 420
 421        if (!menu_is_visible(menu))
 422                return;
 423
 424        sym = menu->sym;
 425        if (sym && !sym_has_value(sym)) {
 426                if (sym_is_changable(sym) ||
 427                    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
 428                        if (input_mode == listnewconfig) {
 429                                if (sym->name && !sym_is_choice_value(sym)) {
 430                                        printf("%s%s\n", CONFIG_, sym->name);
 431                                }
 432                        } else if (input_mode != olddefconfig) {
 433                                if (!conf_cnt++)
 434                                        printf(_("*\n* Restart config...\n*\n"));
 435                                rootEntry = menu_get_parent_menu(menu);
 436                                conf(rootEntry);
 437                        }
 438                }
 439        }
 440
 441        for (child = menu->list; child; child = child->next)
 442                check_conf(child);
 443}
 444
 445static struct option long_opts[] = {
 446        {"oldaskconfig",    no_argument,       NULL, oldaskconfig},
 447        {"oldconfig",       no_argument,       NULL, oldconfig},
 448        {"silentoldconfig", no_argument,       NULL, silentoldconfig},
 449        {"defconfig",       optional_argument, NULL, defconfig},
 450        {"savedefconfig",   required_argument, NULL, savedefconfig},
 451        {"allnoconfig",     no_argument,       NULL, allnoconfig},
 452        {"allyesconfig",    no_argument,       NULL, allyesconfig},
 453        {"allmodconfig",    no_argument,       NULL, allmodconfig},
 454        {"alldefconfig",    no_argument,       NULL, alldefconfig},
 455        {"randconfig",      no_argument,       NULL, randconfig},
 456        {"listnewconfig",   no_argument,       NULL, listnewconfig},
 457        {"olddefconfig",    no_argument,       NULL, olddefconfig},
 458        /*
 459         * oldnoconfig is an alias of olddefconfig, because people already
 460         * are dependent on its behavior(sets new symbols to their default
 461         * value but not 'n') with the counter-intuitive name.
 462         */
 463        {"oldnoconfig",     no_argument,       NULL, olddefconfig},
 464        {NULL, 0, NULL, 0}
 465};
 466
 467static void conf_usage(const char *progname)
 468{
 469
 470        printf("Usage: %s [option] <kconfig-file>\n", progname);
 471        printf("[option] is _one_ of the following:\n");
 472        printf("  --listnewconfig         List new options\n");
 473        printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
 474        printf("  --oldconfig             Update a configuration using a provided .config as base\n");
 475        printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
 476        printf("  --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
 477        printf("  --oldnoconfig           An alias of olddefconfig\n");
 478        printf("  --defconfig <file>      New config with default defined in <file>\n");
 479        printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
 480        printf("  --allnoconfig           New config where all options are answered with no\n");
 481        printf("  --allyesconfig          New config where all options are answered with yes\n");
 482        printf("  --allmodconfig          New config where all options are answered with mod\n");
 483        printf("  --alldefconfig          New config with all symbols set to default\n");
 484        printf("  --randconfig            New config with random answer to all options\n");
 485}
 486
 487int main(int ac, char **av)
 488{
 489        const char *progname = av[0];
 490        int opt;
 491        const char *name, *defconfig_file = NULL /* gcc uninit */;
 492        struct stat tmpstat;
 493
 494        setlocale(LC_ALL, "");
 495        bindtextdomain(PACKAGE, LOCALEDIR);
 496        textdomain(PACKAGE);
 497
 498        while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
 499                input_mode = (enum input_mode)opt;
 500                switch (opt) {
 501                case silentoldconfig:
 502                        sync_kconfig = 1;
 503                        break;
 504                case defconfig:
 505                case savedefconfig:
 506                        defconfig_file = optarg;
 507                        break;
 508                case randconfig:
 509                {
 510                        struct timeval now;
 511                        unsigned int seed;
 512
 513                        /*
 514                         * Use microseconds derived seed,
 515                         * compensate for systems where it may be zero
 516                         */
 517                        gettimeofday(&now, NULL);
 518
 519                        seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
 520                        srand(seed);
 521                        break;
 522                }
 523                case oldaskconfig:
 524                case oldconfig:
 525                case allnoconfig:
 526                case allyesconfig:
 527                case allmodconfig:
 528                case alldefconfig:
 529                case listnewconfig:
 530                case olddefconfig:
 531                        break;
 532                case '?':
 533                        conf_usage(progname);
 534                        exit(1);
 535                        break;
 536                }
 537        }
 538        if (ac == optind) {
 539                printf(_("%s: Kconfig file missing\n"), av[0]);
 540                conf_usage(progname);
 541                exit(1);
 542        }
 543        name = av[optind];
 544        conf_parse(name);
 545        //zconfdump(stdout);
 546        if (sync_kconfig) {
 547                name = conf_get_configname();
 548                if (stat(name, &tmpstat)) {
 549                        fprintf(stderr, _("***\n"
 550                                "*** Configuration file \"%s\" not found!\n"
 551                                "***\n"
 552                                "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
 553                                "*** \"make menuconfig\" or \"make xconfig\").\n"
 554                                "***\n"), name);
 555                        exit(1);
 556                }
 557        }
 558
 559        switch (input_mode) {
 560        case defconfig:
 561                if (!defconfig_file)
 562                        defconfig_file = conf_get_default_confname();
 563                if (conf_read(defconfig_file)) {
 564                        printf(_("***\n"
 565                                "*** Can't find default configuration \"%s\"!\n"
 566                                "***\n"), defconfig_file);
 567                        exit(1);
 568                }
 569                break;
 570        case savedefconfig:
 571        case silentoldconfig:
 572        case oldaskconfig:
 573        case oldconfig:
 574        case listnewconfig:
 575        case olddefconfig:
 576                conf_read(NULL);
 577                break;
 578        case allnoconfig:
 579        case allyesconfig:
 580        case allmodconfig:
 581        case alldefconfig:
 582        case randconfig:
 583                name = getenv("KCONFIG_ALLCONFIG");
 584                if (!name)
 585                        break;
 586                if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
 587                        if (conf_read_simple(name, S_DEF_USER)) {
 588                                fprintf(stderr,
 589                                        _("*** Can't read seed configuration \"%s\"!\n"),
 590                                        name);
 591                                exit(1);
 592                        }
 593                        break;
 594                }
 595                switch (input_mode) {
 596                case allnoconfig:       name = "allno.config"; break;
 597                case allyesconfig:      name = "allyes.config"; break;
 598                case allmodconfig:      name = "allmod.config"; break;
 599                case alldefconfig:      name = "alldef.config"; break;
 600                case randconfig:        name = "allrandom.config"; break;
 601                default: break;
 602                }
 603                if (conf_read_simple(name, S_DEF_USER) &&
 604                    conf_read_simple("all.config", S_DEF_USER)) {
 605                        fprintf(stderr,
 606                                _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
 607                                name);
 608                        exit(1);
 609                }
 610                break;
 611        default:
 612                break;
 613        }
 614
 615        if (sync_kconfig) {
 616                if (conf_get_changed()) {
 617                        name = getenv("KCONFIG_NOSILENTUPDATE");
 618                        if (name && *name) {
 619                                fprintf(stderr,
 620                                        _("\n*** The configuration requires explicit update.\n\n"));
 621                                return 1;
 622                        }
 623                }
 624                valid_stdin = isatty(0) && isatty(1) && isatty(2);
 625        }
 626
 627        switch (input_mode) {
 628        case allnoconfig:
 629                conf_set_all_new_symbols(def_no);
 630                break;
 631        case allyesconfig:
 632                conf_set_all_new_symbols(def_yes);
 633                break;
 634        case allmodconfig:
 635                conf_set_all_new_symbols(def_mod);
 636                break;
 637        case alldefconfig:
 638                conf_set_all_new_symbols(def_default);
 639                break;
 640        case randconfig:
 641                conf_set_all_new_symbols(def_random);
 642                break;
 643        case defconfig:
 644                conf_set_all_new_symbols(def_default);
 645                break;
 646        case savedefconfig:
 647                break;
 648        case oldaskconfig:
 649                rootEntry = &rootmenu;
 650                conf(&rootmenu);
 651                input_mode = silentoldconfig;
 652                /* fall through */
 653        case oldconfig:
 654        case listnewconfig:
 655        case olddefconfig:
 656        case silentoldconfig:
 657                /* Update until a loop caused no more changes */
 658                do {
 659                        conf_cnt = 0;
 660                        check_conf(&rootmenu);
 661                } while (conf_cnt &&
 662                         (input_mode != listnewconfig &&
 663                          input_mode != olddefconfig));
 664                break;
 665        }
 666
 667        if (sync_kconfig) {
 668                /* silentoldconfig is used during the build so we shall update autoconf.
 669                 * All other commands are only used to generate a config.
 670                 */
 671                if (conf_get_changed() && conf_write(NULL)) {
 672                        fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
 673                        exit(1);
 674                }
 675                if (conf_write_autoconf()) {
 676                        fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
 677                        return 1;
 678                }
 679        } else if (input_mode == savedefconfig) {
 680                if (conf_write_defconfig(defconfig_file)) {
 681                        fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
 682                                defconfig_file);
 683                        return 1;
 684                }
 685        } else if (input_mode != listnewconfig) {
 686                if (conf_write(NULL)) {
 687                        fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
 688                        exit(1);
 689                }
 690        }
 691        return 0;
 692}
 693
 694/*
 695 * Helper function to facilitate fgets() by Jean Sacren.
 696 */
 697void xfgets(char *str, int size, FILE *in)
 698{
 699        if (fgets(str, size, in) == NULL)
 700                fprintf(stderr, "\nError in reading or end of file.\n");
 701}
 702