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