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 Similar to oldconfig but generates configuration in\n" 488 " include/{generated/,config/} (oldconfig used to be more verbose)\n"); 489 printf(" --olddefconfig Same as oldconfig but sets new symbols to their default value\n"); 490 printf(" --oldnoconfig An alias of olddefconfig\n"); 491 printf(" --defconfig <file> New config with default defined in <file>\n"); 492 printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); 493 printf(" --allnoconfig New config where all options are answered with no\n"); 494 printf(" --allyesconfig New config where all options are answered with yes\n"); 495 printf(" --allmodconfig New config where all options are answered with mod\n"); 496 printf(" --alldefconfig New config with all symbols set to default\n"); 497 printf(" --randconfig New config with random answer to all options\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 struct stat tmpstat; 506 507 setlocale(LC_ALL, ""); 508 bindtextdomain(PACKAGE, LOCALEDIR); 509 textdomain(PACKAGE); 510 511 tty_stdio = isatty(0) && isatty(1) && isatty(2); 512 513 while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) { 514 if (opt == 's') { 515 conf_set_message_callback(NULL); 516 continue; 517 } 518 input_mode = (enum input_mode)opt; 519 switch (opt) { 520 case silentoldconfig: 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 olddefconfig: 560 break; 561 case '?': 562 conf_usage(progname); 563 exit(1); 564 break; 565 } 566 } 567 if (ac == optind) { 568 printf(_("%s: Kconfig file missing\n"), av[0]); 569 conf_usage(progname); 570 exit(1); 571 } 572 name = av[optind]; 573 conf_parse(name); 574 //zconfdump(stdout); 575 if (sync_kconfig) { 576 name = conf_get_configname(); 577 if (stat(name, &tmpstat)) { 578 fprintf(stderr, _("***\n" 579 "*** Configuration file \"%s\" not found!\n" 580 "***\n" 581 "*** Please run some configurator (e.g. \"make oldconfig\" or\n" 582 "*** \"make menuconfig\" or \"make xconfig\").\n" 583 "***\n"), name); 584 exit(1); 585 } 586 } 587 588 switch (input_mode) { 589 case defconfig: 590 if (!defconfig_file) 591 defconfig_file = conf_get_default_confname(); 592 if (conf_read(defconfig_file)) { 593 printf(_("***\n" 594 "*** Can't find default configuration \"%s\"!\n" 595 "***\n"), defconfig_file); 596 exit(1); 597 } 598 break; 599 case savedefconfig: 600 case silentoldconfig: 601 case oldaskconfig: 602 case oldconfig: 603 case listnewconfig: 604 case olddefconfig: 605 conf_read(NULL); 606 break; 607 case allnoconfig: 608 case allyesconfig: 609 case allmodconfig: 610 case alldefconfig: 611 case randconfig: 612 name = getenv("KCONFIG_ALLCONFIG"); 613 if (!name) 614 break; 615 if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { 616 if (conf_read_simple(name, S_DEF_USER)) { 617 fprintf(stderr, 618 _("*** Can't read seed configuration \"%s\"!\n"), 619 name); 620 exit(1); 621 } 622 break; 623 } 624 switch (input_mode) { 625 case allnoconfig: name = "allno.config"; break; 626 case allyesconfig: name = "allyes.config"; break; 627 case allmodconfig: name = "allmod.config"; break; 628 case alldefconfig: name = "alldef.config"; break; 629 case randconfig: name = "allrandom.config"; break; 630 default: break; 631 } 632 if (conf_read_simple(name, S_DEF_USER) && 633 conf_read_simple("all.config", S_DEF_USER)) { 634 fprintf(stderr, 635 _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), 636 name); 637 exit(1); 638 } 639 break; 640 default: 641 break; 642 } 643 644 if (sync_kconfig) { 645 if (conf_get_changed()) { 646 name = getenv("KCONFIG_NOSILENTUPDATE"); 647 if (name && *name) { 648 fprintf(stderr, 649 _("\n*** The configuration requires explicit update.\n\n")); 650 return 1; 651 } 652 } 653 valid_stdin = tty_stdio; 654 } 655 656 switch (input_mode) { 657 case allnoconfig: 658 conf_set_all_new_symbols(def_no); 659 break; 660 case allyesconfig: 661 conf_set_all_new_symbols(def_yes); 662 break; 663 case allmodconfig: 664 conf_set_all_new_symbols(def_mod); 665 break; 666 case alldefconfig: 667 conf_set_all_new_symbols(def_default); 668 break; 669 case randconfig: 670 /* Really nothing to do in this loop */ 671 while (conf_set_all_new_symbols(def_random)) ; 672 break; 673 case defconfig: 674 conf_set_all_new_symbols(def_default); 675 break; 676 case savedefconfig: 677 break; 678 case oldaskconfig: 679 rootEntry = &rootmenu; 680 conf(&rootmenu); 681 input_mode = silentoldconfig; 682 /* fall through */ 683 case oldconfig: 684 case listnewconfig: 685 case olddefconfig: 686 case silentoldconfig: 687 /* Update until a loop caused no more changes */ 688 do { 689 conf_cnt = 0; 690 check_conf(&rootmenu); 691 } while (conf_cnt && 692 (input_mode != listnewconfig && 693 input_mode != olddefconfig)); 694 break; 695 } 696 697 if (sync_kconfig) { 698 /* silentoldconfig is used during the build so we shall update autoconf. 699 * All other commands are only used to generate a config. 700 */ 701 if (conf_get_changed() && conf_write(NULL)) { 702 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); 703 exit(1); 704 } 705 if (conf_write_autoconf()) { 706 fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); 707 return 1; 708 } 709 } else if (input_mode == savedefconfig) { 710 if (conf_write_defconfig(defconfig_file)) { 711 fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), 712 defconfig_file); 713 return 1; 714 } 715 } else if (input_mode != listnewconfig) { 716 if (conf_write(NULL)) { 717 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); 718 exit(1); 719 } 720 } 721 return 0; 722 } 723