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