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