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