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 oldnoconfig, 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 == oldnoconfig) && 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 != oldnoconfig) { 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 {"oldnoconfig", no_argument, NULL, oldnoconfig}, 458 {NULL, 0, NULL, 0} 459 }; 460 461 static void conf_usage(const char *progname) 462 { 463 464 printf("Usage: %s [option] <kconfig-file>\n", progname); 465 printf("[option] is _one_ of the following:\n"); 466 printf(" --listnewconfig List new options\n"); 467 printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); 468 printf(" --oldconfig Update a configuration using a provided .config as base\n"); 469 printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); 470 printf(" --oldnoconfig Same as silentoldconfig but set new symbols to no\n"); 471 printf(" --defconfig <file> New config with default defined in <file>\n"); 472 printf(" --savedefconfig <file> Save the minimal current configuration to <file>\n"); 473 printf(" --allnoconfig New config where all options are answered with no\n"); 474 printf(" --allyesconfig New config where all options are answered with yes\n"); 475 printf(" --allmodconfig New config where all options are answered with mod\n"); 476 printf(" --alldefconfig New config with all symbols set to default\n"); 477 printf(" --randconfig New config with random answer to all options\n"); 478 } 479 480 int main(int ac, char **av) 481 { 482 const char *progname = av[0]; 483 int opt; 484 const char *name, *defconfig_file = NULL /* gcc uninit */; 485 struct stat tmpstat; 486 487 setlocale(LC_ALL, ""); 488 bindtextdomain(PACKAGE, LOCALEDIR); 489 textdomain(PACKAGE); 490 491 while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) { 492 input_mode = (enum input_mode)opt; 493 switch (opt) { 494 case silentoldconfig: 495 sync_kconfig = 1; 496 break; 497 case defconfig: 498 case savedefconfig: 499 defconfig_file = optarg; 500 break; 501 case randconfig: 502 { 503 struct timeval now; 504 unsigned int seed; 505 506 /* 507 * Use microseconds derived seed, 508 * compensate for systems where it may be zero 509 */ 510 gettimeofday(&now, NULL); 511 512 seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); 513 srand(seed); 514 break; 515 } 516 case oldaskconfig: 517 case oldconfig: 518 case allnoconfig: 519 case allyesconfig: 520 case allmodconfig: 521 case alldefconfig: 522 case listnewconfig: 523 case oldnoconfig: 524 break; 525 case '?': 526 conf_usage(progname); 527 exit(1); 528 break; 529 } 530 } 531 if (ac == optind) { 532 printf(_("%s: Kconfig file missing\n"), av[0]); 533 conf_usage(progname); 534 exit(1); 535 } 536 name = av[optind]; 537 conf_parse(name); 538 //zconfdump(stdout); 539 if (sync_kconfig) { 540 name = conf_get_configname(); 541 if (stat(name, &tmpstat)) { 542 fprintf(stderr, _("***\n" 543 "*** Configuration file \"%s\" not found!\n" 544 "***\n" 545 "*** Please run some configurator (e.g. \"make oldconfig\" or\n" 546 "*** \"make menuconfig\" or \"make xconfig\").\n" 547 "***\n"), name); 548 exit(1); 549 } 550 } 551 552 switch (input_mode) { 553 case defconfig: 554 if (!defconfig_file) 555 defconfig_file = conf_get_default_confname(); 556 if (conf_read(defconfig_file)) { 557 printf(_("***\n" 558 "*** Can't find default configuration \"%s\"!\n" 559 "***\n"), defconfig_file); 560 exit(1); 561 } 562 break; 563 case savedefconfig: 564 case silentoldconfig: 565 case oldaskconfig: 566 case oldconfig: 567 case listnewconfig: 568 case oldnoconfig: 569 conf_read(NULL); 570 break; 571 case allnoconfig: 572 case allyesconfig: 573 case allmodconfig: 574 case alldefconfig: 575 case randconfig: 576 name = getenv("KCONFIG_ALLCONFIG"); 577 if (!name) 578 break; 579 if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { 580 if (conf_read_simple(name, S_DEF_USER)) { 581 fprintf(stderr, 582 _("*** Can't read seed configuration \"%s\"!\n"), 583 name); 584 exit(1); 585 } 586 break; 587 } 588 switch (input_mode) { 589 case allnoconfig: name = "allno.config"; break; 590 case allyesconfig: name = "allyes.config"; break; 591 case allmodconfig: name = "allmod.config"; break; 592 case alldefconfig: name = "alldef.config"; break; 593 case randconfig: name = "allrandom.config"; break; 594 default: break; 595 } 596 if (conf_read_simple(name, S_DEF_USER) && 597 conf_read_simple("all.config", S_DEF_USER)) { 598 fprintf(stderr, 599 _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), 600 name); 601 exit(1); 602 } 603 break; 604 default: 605 break; 606 } 607 608 if (sync_kconfig) { 609 if (conf_get_changed()) { 610 name = getenv("KCONFIG_NOSILENTUPDATE"); 611 if (name && *name) { 612 fprintf(stderr, 613 _("\n*** The configuration requires explicit update.\n\n")); 614 return 1; 615 } 616 } 617 valid_stdin = isatty(0) && isatty(1) && isatty(2); 618 } 619 620 switch (input_mode) { 621 case allnoconfig: 622 conf_set_all_new_symbols(def_no); 623 break; 624 case allyesconfig: 625 conf_set_all_new_symbols(def_yes); 626 break; 627 case allmodconfig: 628 conf_set_all_new_symbols(def_mod); 629 break; 630 case alldefconfig: 631 conf_set_all_new_symbols(def_default); 632 break; 633 case randconfig: 634 conf_set_all_new_symbols(def_random); 635 break; 636 case defconfig: 637 conf_set_all_new_symbols(def_default); 638 break; 639 case savedefconfig: 640 break; 641 case oldaskconfig: 642 rootEntry = &rootmenu; 643 conf(&rootmenu); 644 input_mode = silentoldconfig; 645 /* fall through */ 646 case oldconfig: 647 case listnewconfig: 648 case oldnoconfig: 649 case silentoldconfig: 650 /* Update until a loop caused no more changes */ 651 do { 652 conf_cnt = 0; 653 check_conf(&rootmenu); 654 } while (conf_cnt && 655 (input_mode != listnewconfig && 656 input_mode != oldnoconfig)); 657 break; 658 } 659 660 if (sync_kconfig) { 661 /* silentoldconfig is used during the build so we shall update autoconf. 662 * All other commands are only used to generate a config. 663 */ 664 if (conf_get_changed() && conf_write(NULL)) { 665 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); 666 exit(1); 667 } 668 if (conf_write_autoconf()) { 669 fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); 670 return 1; 671 } 672 } else if (input_mode == savedefconfig) { 673 if (conf_write_defconfig(defconfig_file)) { 674 fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), 675 defconfig_file); 676 return 1; 677 } 678 } else if (input_mode != listnewconfig) { 679 if (conf_write(NULL)) { 680 fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); 681 exit(1); 682 } 683 } 684 return 0; 685 } 686 687 /* 688 * Helper function to facilitate fgets() by Jean Sacren. 689 */ 690 void xfgets(char *str, int size, FILE *in) 691 { 692 if (fgets(str, size, in) == NULL) 693 fprintf(stderr, "\nError in reading or end of file.\n"); 694 } 695