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