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 20static void conf(struct menu *menu); 21static void check_conf(struct menu *menu); 22static void xfgets(char *str, int size, FILE *in); 23 24enum 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 39static int indent = 1; 40static int tty_stdio; 41static int valid_stdin = 1; 42static int sync_kconfig; 43static int conf_cnt; 44static char line[128]; 45static struct menu *rootEntry; 46 47static 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 57static 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 74static 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 84static 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 133static 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 166static 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; 230help: 231 print_help(menu); 232 } 233} 234 235static 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 354static 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 411conf_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 420static 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 449static 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 471static void conf_usage(const char *progname) 472{ 473 474 printf("Usage: %s [-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 491int 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, "s", long_opts, NULL)) != -1) { 505 if (opt == 's') { 506 conf_set_message_callback(NULL); 507 continue; 508 } 509 input_mode = (enum input_mode)opt; 510 switch (opt) { 511 case silentoldconfig: 512 sync_kconfig = 1; 513 break; 514 case defconfig: 515 case savedefconfig: 516 defconfig_file = optarg; 517 break; 518 case randconfig: 519 { 520 struct timeval now; 521 unsigned int seed; 522 char *seed_env; 523 524 /* 525 * Use microseconds derived seed, 526 * compensate for systems where it may be zero 527 */ 528 gettimeofday(&now, NULL); 529 seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); 530 531 seed_env = getenv("KCONFIG_SEED"); 532 if( seed_env && *seed_env ) { 533 char *endp; 534 int tmp = (int)strtol(seed_env, &endp, 0); 535 if (*endp == '\0') { 536 seed = tmp; 537 } 538 } 539 fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); 540 srand(seed); 541 break; 542 } 543 case oldaskconfig: 544 case oldconfig: 545 case allnoconfig: 546 case allyesconfig: 547 case allmodconfig: 548 case alldefconfig: 549 case listnewconfig: 550 case olddefconfig: 551 break; 552 case '?': 553 conf_usage(progname); 554 exit(1); 555 break; 556 } 557 } 558 if (ac == optind) { 559 printf(_("%s: Kconfig file missing\n"), av[0]); 560 conf_usage(progname); 561 exit(1); 562 } 563 name = av[optind]; 564 conf_parse(name); 565 //zconfdump(stdout); 566 if (sync_kconfig) { 567 name = conf_get_configname(); 568 if (stat(name, &tmpstat)) { 569 fprintf(stderr, _("***\n" 570 "*** Configuration file \"%s\" not found!\n" 571 "***\n" 572 "*** Please run some configurator (e.g. \"make oldconfig\" or\n" 573 "*** \"make menuconfig\" or \"make xconfig\").\n" 574 "***\n"), name); 575 exit(1); 576 } 577 } 578 579 switch (input_mode) { 580 case defconfig: 581 if (!defconfig_file) 582 defconfig_file = conf_get_default_confname(); 583 if (conf_read(defconfig_file)) { 584 printf(_("***\n" 585 "*** Can't find default configuration \"%s\"!\n" 586 "***\n"), defconfig_file); 587 exit(1); 588 } 589 break; 590 case savedefconfig: 591 case silentoldconfig: 592 case oldaskconfig: 593 case oldconfig: 594 case listnewconfig: 595 case olddefconfig: 596 conf_read(NULL); 597 break; 598 case allnoconfig: 599 case allyesconfig: 600 case allmodconfig: 601 case alldefconfig: 602 case randconfig: 603 name = getenv("KCONFIG_ALLCONFIG"); 604 if (!name) 605 break; 606 if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { 607 if (conf_read_simple(name, S_DEF_USER)) { 608 fprintf(stderr, 609 _("*** Can't read seed configuration \"%s\"!\n"), 610 name); 611 exit(1); 612 } 613 break; 614 } 615 switch (input_mode) { 616 case allnoconfig: name = "allno.config"; break; 617 case allyesconfig: name = "allyes.config"; break; 618 case allmodconfig: name = "allmod.config"; break; 619 case alldefconfig: name = "alldef.config"; break; 620 case randconfig: name = "allrandom.config"; break; 621 default: break; 622 } 623 if (conf_read_simple(name, S_DEF_USER) && 624 conf_read_simple("all.config", S_DEF_USER)) { 625 fprintf(stderr, 626 _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), 627 name); 628 exit(1); 629 } 630 break; 631 default: 632 break; 633 } 634 635 if (sync_kconfig) { 636 if (conf_get_changed()) { 637 name = getenv("KCONFIG_NOSILENTUPDATE"); 638 if (name && *name) { 639 fprintf(stderr, 640 _("\n*** The configuration requires explicit update.\n\n")); 641 return 1; 642 } 643 } 644 valid_stdin = tty_stdio; 645 } 646 647 switch (input_mode) { 648 case allnoconfig: 649 conf_set_all_new_symbols(def_no); 650 break; 651 case allyesconfig: 652 conf_set_all_new_symbols(def_yes); 653 break; 654 case allmodconfig: 655 conf_set_all_new_symbols(def_mod); 656 break; 657 case alldefconfig: 658 conf_set_all_new_symbols(def_default); 659 break; 660 case randconfig: 661 /* Really nothing to do in this loop */ 662 while (conf_set_all_new_symbols(def_random)) ; 663 break; 664 case defconfig: 665 conf_set_all_new_symbols(def_default); 666 break; 667 case savedefconfig: 668 break; 669 case oldaskconfig: 670 rootEntry = &rootmenu; 671 conf(&rootmenu); 672 input_mode = silentoldconfig; 673 /* fall through */ 674 case oldconfig: 675 case listnewconfig: 676 case olddefconfig: 677 case silentoldconfig: 678 /* Update until a loop caused no more changes */ 679 do { 680 conf_cnt = 0; 681 check_conf(&rootmenu); 682 } while (conf_cnt && 683 (input_mode != listnewconfig && 684 input_mode != olddefconfig)); 685 break; 686 } 687 688 if (sync_kconfig) { 689 /* silentoldconfig is used during the build so we shall update autoconf. 690 * All other commands are only used to generate a config. 691 */ 692 if (conf_get_changed() && conf_write(NULL)) { 693 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); 694 exit(1); 695 } 696 if (conf_write_autoconf()) { 697 fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); 698 return 1; 699 } 700 } else if (input_mode == savedefconfig) { 701 if (conf_write_defconfig(defconfig_file)) { 702 fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), 703 defconfig_file); 704 return 1; 705 } 706 } else if (input_mode != listnewconfig) { 707 if (conf_write(NULL)) { 708 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); 709 exit(1); 710 } 711 } 712 return 0; 713} 714 715/* 716 * Helper function to facilitate fgets() by Jean Sacren. 717 */ 718void xfgets(char *str, int size, FILE *in) 719{ 720 if (fgets(str, size, in) == NULL) 721 fprintf(stderr, "\nError in reading or end of file.\n"); 722} 723