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