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