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