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