root/scripts/kconfig/conf.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_help
  2. strip
  3. xfgets
  4. conf_askvalue
  5. conf_string
  6. conf_sym
  7. conf_choice
  8. conf
  9. check_conf
  10. conf_usage
  11. main

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
   4  */
   5 
   6 #include <ctype.h>
   7 #include <limits.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 #include <errno.h>
  17 
  18 #include "lkc.h"
  19 
  20 static void conf(struct menu *menu);
  21 static void check_conf(struct menu *menu);
  22 
  23 enum input_mode {
  24         oldaskconfig,
  25         syncconfig,
  26         oldconfig,
  27         allnoconfig,
  28         allyesconfig,
  29         allmodconfig,
  30         alldefconfig,
  31         randconfig,
  32         defconfig,
  33         savedefconfig,
  34         listnewconfig,
  35         olddefconfig,
  36 };
  37 static enum input_mode input_mode = oldaskconfig;
  38 
  39 static int indent = 1;
  40 static int tty_stdio;
  41 static int sync_kconfig;
  42 static int conf_cnt;
  43 static char line[PATH_MAX];
  44 static struct menu *rootEntry;
  45 
  46 static void print_help(struct menu *menu)
  47 {
  48         struct gstr help = str_new();
  49 
  50         menu_get_ext_help(menu, &help);
  51 
  52         printf("\n%s\n", str_get(&help));
  53         str_free(&help);
  54 }
  55 
  56 static void strip(char *str)
  57 {
  58         char *p = str;
  59         int l;
  60 
  61         while ((isspace(*p)))
  62                 p++;
  63         l = strlen(p);
  64         if (p != str)
  65                 memmove(str, p, l + 1);
  66         if (!l)
  67                 return;
  68         p = str + l - 1;
  69         while ((isspace(*p)))
  70                 *p-- = 0;
  71 }
  72 
  73 /* Helper function to facilitate fgets() by Jean Sacren. */
  74 static void xfgets(char *str, int size, FILE *in)
  75 {
  76         if (!fgets(str, size, in))
  77                 fprintf(stderr, "\nError in reading or end of file.\n");
  78 
  79         if (!tty_stdio)
  80                 printf("%s", str);
  81 }
  82 
  83 static int conf_askvalue(struct symbol *sym, const char *def)
  84 {
  85         enum symbol_type type = sym_get_type(sym);
  86 
  87         if (!sym_has_value(sym))
  88                 printf("(NEW) ");
  89 
  90         line[0] = '\n';
  91         line[1] = 0;
  92 
  93         if (!sym_is_changeable(sym)) {
  94                 printf("%s\n", def);
  95                 line[0] = '\n';
  96                 line[1] = 0;
  97                 return 0;
  98         }
  99 
 100         switch (input_mode) {
 101         case oldconfig:
 102         case syncconfig:
 103                 if (sym_has_value(sym)) {
 104                         printf("%s\n", def);
 105                         return 0;
 106                 }
 107                 /* fall through */
 108         case oldaskconfig:
 109                 fflush(stdout);
 110                 xfgets(line, sizeof(line), 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 
 129 static 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 
 162 static 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                 printf("/?] ");
 191                 if (!conf_askvalue(sym, sym_get_string_value(sym)))
 192                         return 0;
 193                 strip(line);
 194 
 195                 switch (line[0]) {
 196                 case 'n':
 197                 case 'N':
 198                         newval = no;
 199                         if (!line[1] || !strcmp(&line[1], "o"))
 200                                 break;
 201                         continue;
 202                 case 'm':
 203                 case 'M':
 204                         newval = mod;
 205                         if (!line[1])
 206                                 break;
 207                         continue;
 208                 case 'y':
 209                 case 'Y':
 210                         newval = yes;
 211                         if (!line[1] || !strcmp(&line[1], "es"))
 212                                 break;
 213                         continue;
 214                 case 0:
 215                         newval = oldval;
 216                         break;
 217                 case '?':
 218                         goto help;
 219                 default:
 220                         continue;
 221                 }
 222                 if (sym_set_tristate_value(sym, newval))
 223                         return 0;
 224 help:
 225                 print_help(menu);
 226         }
 227 }
 228 
 229 static int conf_choice(struct menu *menu)
 230 {
 231         struct symbol *sym, *def_sym;
 232         struct menu *child;
 233         bool is_new;
 234 
 235         sym = menu->sym;
 236         is_new = !sym_has_value(sym);
 237         if (sym_is_changeable(sym)) {
 238                 conf_sym(menu);
 239                 sym_calc_value(sym);
 240                 switch (sym_get_tristate_value(sym)) {
 241                 case no:
 242                         return 1;
 243                 case mod:
 244                         return 0;
 245                 case yes:
 246                         break;
 247                 }
 248         } else {
 249                 switch (sym_get_tristate_value(sym)) {
 250                 case no:
 251                         return 1;
 252                 case mod:
 253                         printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
 254                         return 0;
 255                 case yes:
 256                         break;
 257                 }
 258         }
 259 
 260         while (1) {
 261                 int cnt, def;
 262 
 263                 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
 264                 def_sym = sym_get_choice_value(sym);
 265                 cnt = def = 0;
 266                 line[0] = 0;
 267                 for (child = menu->list; child; child = child->next) {
 268                         if (!menu_is_visible(child))
 269                                 continue;
 270                         if (!child->sym) {
 271                                 printf("%*c %s\n", indent, '*', menu_get_prompt(child));
 272                                 continue;
 273                         }
 274                         cnt++;
 275                         if (child->sym == def_sym) {
 276                                 def = cnt;
 277                                 printf("%*c", indent, '>');
 278                         } else
 279                                 printf("%*c", indent, ' ');
 280                         printf(" %d. %s", cnt, menu_get_prompt(child));
 281                         if (child->sym->name)
 282                                 printf(" (%s)", child->sym->name);
 283                         if (!sym_has_value(child->sym))
 284                                 printf(" (NEW)");
 285                         printf("\n");
 286                 }
 287                 printf("%*schoice", indent - 1, "");
 288                 if (cnt == 1) {
 289                         printf("[1]: 1\n");
 290                         goto conf_childs;
 291                 }
 292                 printf("[1-%d?]: ", cnt);
 293                 switch (input_mode) {
 294                 case oldconfig:
 295                 case syncconfig:
 296                         if (!is_new) {
 297                                 cnt = def;
 298                                 printf("%d\n", cnt);
 299                                 break;
 300                         }
 301                         /* fall through */
 302                 case oldaskconfig:
 303                         fflush(stdout);
 304                         xfgets(line, sizeof(line), stdin);
 305                         strip(line);
 306                         if (line[0] == '?') {
 307                                 print_help(menu);
 308                                 continue;
 309                         }
 310                         if (!line[0])
 311                                 cnt = def;
 312                         else if (isdigit(line[0]))
 313                                 cnt = atoi(line);
 314                         else
 315                                 continue;
 316                         break;
 317                 default:
 318                         break;
 319                 }
 320 
 321         conf_childs:
 322                 for (child = menu->list; child; child = child->next) {
 323                         if (!child->sym || !menu_is_visible(child))
 324                                 continue;
 325                         if (!--cnt)
 326                                 break;
 327                 }
 328                 if (!child)
 329                         continue;
 330                 if (line[0] && line[strlen(line) - 1] == '?') {
 331                         print_help(child);
 332                         continue;
 333                 }
 334                 sym_set_choice_value(sym, child->sym);
 335                 for (child = child->list; child; child = child->next) {
 336                         indent += 2;
 337                         conf(child);
 338                         indent -= 2;
 339                 }
 340                 return 1;
 341         }
 342 }
 343 
 344 static void conf(struct menu *menu)
 345 {
 346         struct symbol *sym;
 347         struct property *prop;
 348         struct menu *child;
 349 
 350         if (!menu_is_visible(menu))
 351                 return;
 352 
 353         sym = menu->sym;
 354         prop = menu->prompt;
 355         if (prop) {
 356                 const char *prompt;
 357 
 358                 switch (prop->type) {
 359                 case P_MENU:
 360                         /*
 361                          * Except in oldaskconfig mode, we show only menus that
 362                          * contain new symbols.
 363                          */
 364                         if (input_mode != oldaskconfig && rootEntry != menu) {
 365                                 check_conf(menu);
 366                                 return;
 367                         }
 368                         /* fall through */
 369                 case P_COMMENT:
 370                         prompt = menu_get_prompt(menu);
 371                         if (prompt)
 372                                 printf("%*c\n%*c %s\n%*c\n",
 373                                         indent, '*',
 374                                         indent, '*', prompt,
 375                                         indent, '*');
 376                 default:
 377                         ;
 378                 }
 379         }
 380 
 381         if (!sym)
 382                 goto conf_childs;
 383 
 384         if (sym_is_choice(sym)) {
 385                 conf_choice(menu);
 386                 if (sym->curr.tri != mod)
 387                         return;
 388                 goto conf_childs;
 389         }
 390 
 391         switch (sym->type) {
 392         case S_INT:
 393         case S_HEX:
 394         case S_STRING:
 395                 conf_string(menu);
 396                 break;
 397         default:
 398                 conf_sym(menu);
 399                 break;
 400         }
 401 
 402 conf_childs:
 403         if (sym)
 404                 indent += 2;
 405         for (child = menu->list; child; child = child->next)
 406                 conf(child);
 407         if (sym)
 408                 indent -= 2;
 409 }
 410 
 411 static void check_conf(struct menu *menu)
 412 {
 413         struct symbol *sym;
 414         struct menu *child;
 415 
 416         if (!menu_is_visible(menu))
 417                 return;
 418 
 419         sym = menu->sym;
 420         if (sym && !sym_has_value(sym)) {
 421                 if (sym_is_changeable(sym) ||
 422                     (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
 423                         if (input_mode == listnewconfig) {
 424                                 if (sym->name) {
 425                                         const char *str;
 426 
 427                                         if (sym->type == S_STRING) {
 428                                                 str = sym_get_string_value(sym);
 429                                                 str = sym_escape_string_value(str);
 430                                                 printf("%s%s=%s\n", CONFIG_, sym->name, str);
 431                                                 free((void *)str);
 432                                         } else {
 433                                                 str = sym_get_string_value(sym);
 434                                                 printf("%s%s=%s\n", CONFIG_, sym->name, str);
 435                                         }
 436                                 }
 437                         } else {
 438                                 if (!conf_cnt++)
 439                                         printf("*\n* Restart config...\n*\n");
 440                                 rootEntry = menu_get_parent_menu(menu);
 441                                 conf(rootEntry);
 442                         }
 443                 }
 444         }
 445 
 446         for (child = menu->list; child; child = child->next)
 447                 check_conf(child);
 448 }
 449 
 450 static struct option long_opts[] = {
 451         {"oldaskconfig",    no_argument,       NULL, oldaskconfig},
 452         {"oldconfig",       no_argument,       NULL, oldconfig},
 453         {"syncconfig",      no_argument,       NULL, syncconfig},
 454         {"defconfig",       required_argument, NULL, defconfig},
 455         {"savedefconfig",   required_argument, NULL, savedefconfig},
 456         {"allnoconfig",     no_argument,       NULL, allnoconfig},
 457         {"allyesconfig",    no_argument,       NULL, allyesconfig},
 458         {"allmodconfig",    no_argument,       NULL, allmodconfig},
 459         {"alldefconfig",    no_argument,       NULL, alldefconfig},
 460         {"randconfig",      no_argument,       NULL, randconfig},
 461         {"listnewconfig",   no_argument,       NULL, listnewconfig},
 462         {"olddefconfig",    no_argument,       NULL, olddefconfig},
 463         {NULL, 0, NULL, 0}
 464 };
 465 
 466 static void conf_usage(const char *progname)
 467 {
 468 
 469         printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
 470         printf("[option] is _one_ of the following:\n");
 471         printf("  --listnewconfig         List new options\n");
 472         printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
 473         printf("  --oldconfig             Update a configuration using a provided .config as base\n");
 474         printf("  --syncconfig            Similar to oldconfig but generates configuration in\n"
 475                "                          include/{generated/,config/}\n");
 476         printf("  --olddefconfig          Same as oldconfig but sets new symbols to their default value\n");
 477         printf("  --defconfig <file>      New config with default defined in <file>\n");
 478         printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
 479         printf("  --allnoconfig           New config where all options are answered with no\n");
 480         printf("  --allyesconfig          New config where all options are answered with yes\n");
 481         printf("  --allmodconfig          New config where all options are answered with mod\n");
 482         printf("  --alldefconfig          New config with all symbols set to default\n");
 483         printf("  --randconfig            New config with random answer to all options\n");
 484 }
 485 
 486 int main(int ac, char **av)
 487 {
 488         const char *progname = av[0];
 489         int opt;
 490         const char *name, *defconfig_file = NULL /* gcc uninit */;
 491         int no_conf_write = 0;
 492 
 493         tty_stdio = isatty(0) && isatty(1);
 494 
 495         while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
 496                 if (opt == 's') {
 497                         conf_set_message_callback(NULL);
 498                         continue;
 499                 }
 500                 input_mode = (enum input_mode)opt;
 501                 switch (opt) {
 502                 case syncconfig:
 503                         /*
 504                          * syncconfig is invoked during the build stage.
 505                          * Suppress distracting "configuration written to ..."
 506                          */
 507                         conf_set_message_callback(NULL);
 508                         sync_kconfig = 1;
 509                         break;
 510                 case defconfig:
 511                 case savedefconfig:
 512                         defconfig_file = optarg;
 513                         break;
 514                 case randconfig:
 515                 {
 516                         struct timeval now;
 517                         unsigned int seed;
 518                         char *seed_env;
 519 
 520                         /*
 521                          * Use microseconds derived seed,
 522                          * compensate for systems where it may be zero
 523                          */
 524                         gettimeofday(&now, NULL);
 525                         seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
 526 
 527                         seed_env = getenv("KCONFIG_SEED");
 528                         if( seed_env && *seed_env ) {
 529                                 char *endp;
 530                                 int tmp = (int)strtol(seed_env, &endp, 0);
 531                                 if (*endp == '\0') {
 532                                         seed = tmp;
 533                                 }
 534                         }
 535                         fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
 536                         srand(seed);
 537                         break;
 538                 }
 539                 case oldaskconfig:
 540                 case oldconfig:
 541                 case allnoconfig:
 542                 case allyesconfig:
 543                 case allmodconfig:
 544                 case alldefconfig:
 545                 case listnewconfig:
 546                 case olddefconfig:
 547                         break;
 548                 case '?':
 549                         conf_usage(progname);
 550                         exit(1);
 551                         break;
 552                 }
 553         }
 554         if (ac == optind) {
 555                 fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
 556                 conf_usage(progname);
 557                 exit(1);
 558         }
 559         name = av[optind];
 560         conf_parse(name);
 561         //zconfdump(stdout);
 562 
 563         switch (input_mode) {
 564         case defconfig:
 565                 if (conf_read(defconfig_file)) {
 566                         fprintf(stderr,
 567                                 "***\n"
 568                                   "*** Can't find default configuration \"%s\"!\n"
 569                                   "***\n",
 570                                 defconfig_file);
 571                         exit(1);
 572                 }
 573                 break;
 574         case savedefconfig:
 575         case syncconfig:
 576         case oldaskconfig:
 577         case oldconfig:
 578         case listnewconfig:
 579         case olddefconfig:
 580                 conf_read(NULL);
 581                 break;
 582         case allnoconfig:
 583         case allyesconfig:
 584         case allmodconfig:
 585         case alldefconfig:
 586         case randconfig:
 587                 name = getenv("KCONFIG_ALLCONFIG");
 588                 if (!name)
 589                         break;
 590                 if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
 591                         if (conf_read_simple(name, S_DEF_USER)) {
 592                                 fprintf(stderr,
 593                                         "*** Can't read seed configuration \"%s\"!\n",
 594                                         name);
 595                                 exit(1);
 596                         }
 597                         break;
 598                 }
 599                 switch (input_mode) {
 600                 case allnoconfig:       name = "allno.config"; break;
 601                 case allyesconfig:      name = "allyes.config"; break;
 602                 case allmodconfig:      name = "allmod.config"; break;
 603                 case alldefconfig:      name = "alldef.config"; break;
 604                 case randconfig:        name = "allrandom.config"; break;
 605                 default: break;
 606                 }
 607                 if (conf_read_simple(name, S_DEF_USER) &&
 608                     conf_read_simple("all.config", S_DEF_USER)) {
 609                         fprintf(stderr,
 610                                 "*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n",
 611                                 name);
 612                         exit(1);
 613                 }
 614                 break;
 615         default:
 616                 break;
 617         }
 618 
 619         if (sync_kconfig) {
 620                 name = getenv("KCONFIG_NOSILENTUPDATE");
 621                 if (name && *name) {
 622                         if (conf_get_changed()) {
 623                                 fprintf(stderr,
 624                                         "\n*** The configuration requires explicit update.\n\n");
 625                                 return 1;
 626                         }
 627                         no_conf_write = 1;
 628                 }
 629         }
 630 
 631         switch (input_mode) {
 632         case allnoconfig:
 633                 conf_set_all_new_symbols(def_no);
 634                 break;
 635         case allyesconfig:
 636                 conf_set_all_new_symbols(def_yes);
 637                 break;
 638         case allmodconfig:
 639                 conf_set_all_new_symbols(def_mod);
 640                 break;
 641         case alldefconfig:
 642                 conf_set_all_new_symbols(def_default);
 643                 break;
 644         case randconfig:
 645                 /* Really nothing to do in this loop */
 646                 while (conf_set_all_new_symbols(def_random)) ;
 647                 break;
 648         case defconfig:
 649                 conf_set_all_new_symbols(def_default);
 650                 break;
 651         case savedefconfig:
 652                 break;
 653         case oldaskconfig:
 654                 rootEntry = &rootmenu;
 655                 conf(&rootmenu);
 656                 input_mode = oldconfig;
 657                 /* fall through */
 658         case oldconfig:
 659         case listnewconfig:
 660         case syncconfig:
 661                 /* Update until a loop caused no more changes */
 662                 do {
 663                         conf_cnt = 0;
 664                         check_conf(&rootmenu);
 665                 } while (conf_cnt);
 666                 break;
 667         case olddefconfig:
 668         default:
 669                 break;
 670         }
 671 
 672         if (input_mode == savedefconfig) {
 673                 if (conf_write_defconfig(defconfig_file)) {
 674                         fprintf(stderr, "n*** Error while saving defconfig to: %s\n\n",
 675                                 defconfig_file);
 676                         return 1;
 677                 }
 678         } else if (input_mode != listnewconfig) {
 679                 if (!no_conf_write && conf_write(NULL)) {
 680                         fprintf(stderr, "\n*** Error during writing of the configuration.\n\n");
 681                         exit(1);
 682                 }
 683 
 684                 /*
 685                  * Create auto.conf if it does not exist.
 686                  * This prevents GNU Make 4.1 or older from emitting
 687                  * "include/config/auto.conf: No such file or directory"
 688                  * in the top-level Makefile
 689                  *
 690                  * syncconfig always creates or updates auto.conf because it is
 691                  * used during the build.
 692                  */
 693                 if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
 694                         fprintf(stderr,
 695                                 "\n*** Error during sync of the configuration.\n\n");
 696                         return 1;
 697                 }
 698         }
 699         return 0;
 700 }

/* [<][>][^][v][top][bottom][index][help] */