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