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 <sys/stat.h> 14 15 #define LKC_DIRECT_LINK 16 #include "lkc.h" 17 18 static void conf(struct menu *menu); 19 static void check_conf(struct menu *menu); 20 21 enum { 22 ask_all, 23 ask_new, 24 ask_silent, 25 set_default, 26 set_yes, 27 set_mod, 28 set_no, 29 set_random 30 } input_mode = ask_all; 31 char *defconfig_file; 32 33 static int indent = 1; 34 static int valid_stdin = 1; 35 static int conf_cnt; 36 static char line[128]; 37 static struct menu *rootEntry; 38 39 static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n"); 40 41 static const char *get_help(struct menu *menu) 42 { 43 if (menu_has_help(menu)) 44 return _(menu_get_help(menu)); 45 else 46 return nohelp_text; 47 } 48 49 static void strip(char *str) 50 { 51 char *p = str; 52 int l; 53 54 while ((isspace(*p))) 55 p++; 56 l = strlen(p); 57 if (p != str) 58 memmove(str, p, l + 1); 59 if (!l) 60 return; 61 p = str + l - 1; 62 while ((isspace(*p))) 63 *p-- = 0; 64 } 65 66 static void check_stdin(void) 67 { 68 if (!valid_stdin && input_mode == ask_silent) { 69 printf(_("aborted!\n\n")); 70 printf(_("Console input/output is redirected. ")); 71 printf(_("Run 'make oldconfig' to update configuration.\n\n")); 72 exit(1); 73 } 74 } 75 76 static int conf_askvalue(struct symbol *sym, const char *def) 77 { 78 enum symbol_type type = sym_get_type(sym); 79 80 if (!sym_has_value(sym)) 81 printf(_("(NEW) ")); 82 83 line[0] = '\n'; 84 line[1] = 0; 85 86 if (!sym_is_changable(sym)) { 87 printf("%s\n", def); 88 line[0] = '\n'; 89 line[1] = 0; 90 return 0; 91 } 92 93 switch (input_mode) { 94 case ask_new: 95 case ask_silent: 96 if (sym_has_value(sym)) { 97 printf("%s\n", def); 98 return 0; 99 } 100 check_stdin(); 101 case ask_all: 102 fflush(stdout); 103 fgets(line, 128, stdin); 104 return 1; 105 default: 106 break; 107 } 108 109 switch (type) { 110 case S_INT: 111 case S_HEX: 112 case S_STRING: 113 printf("%s\n", def); 114 return 1; 115 default: 116 ; 117 } 118 printf("%s", line); 119 return 1; 120 } 121 122 int conf_string(struct menu *menu) 123 { 124 struct symbol *sym = menu->sym; 125 const char *def; 126 127 while (1) { 128 printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); 129 printf("(%s) ", sym->name); 130 def = sym_get_string_value(sym); 131 if (sym_get_string_value(sym)) 132 printf("[%s] ", def); 133 if (!conf_askvalue(sym, def)) 134 return 0; 135 switch (line[0]) { 136 case '\n': 137 break; 138 case '?': 139 /* print help */ 140 if (line[1] == '\n') { 141 printf("\n%s\n", get_help(menu)); 142 def = NULL; 143 break; 144 } 145 default: 146 line[strlen(line)-1] = 0; 147 def = line; 148 } 149 if (def && sym_set_string_value(sym, def)) 150 return 0; 151 } 152 } 153 154 static int conf_sym(struct menu *menu) 155 { 156 struct symbol *sym = menu->sym; 157 int type; 158 tristate oldval, newval; 159 160 while (1) { 161 printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); 162 if (sym->name) 163 printf("(%s) ", sym->name); 164 type = sym_get_type(sym); 165 putchar('['); 166 oldval = sym_get_tristate_value(sym); 167 switch (oldval) { 168 case no: 169 putchar('N'); 170 break; 171 case mod: 172 putchar('M'); 173 break; 174 case yes: 175 putchar('Y'); 176 break; 177 } 178 if (oldval != no && sym_tristate_within_range(sym, no)) 179 printf("/n"); 180 if (oldval != mod && sym_tristate_within_range(sym, mod)) 181 printf("/m"); 182 if (oldval != yes && sym_tristate_within_range(sym, yes)) 183 printf("/y"); 184 if (menu_has_help(menu)) 185 printf("/?"); 186 printf("] "); 187 if (!conf_askvalue(sym, sym_get_string_value(sym))) 188 return 0; 189 strip(line); 190 191 switch (line[0]) { 192 case 'n': 193 case 'N': 194 newval = no; 195 if (!line[1] || !strcmp(&line[1], "o")) 196 break; 197 continue; 198 case 'm': 199 case 'M': 200 newval = mod; 201 if (!line[1]) 202 break; 203 continue; 204 case 'y': 205 case 'Y': 206 newval = yes; 207 if (!line[1] || !strcmp(&line[1], "es")) 208 break; 209 continue; 210 case 0: 211 newval = oldval; 212 break; 213 case '?': 214 goto help; 215 default: 216 continue; 217 } 218 if (sym_set_tristate_value(sym, newval)) 219 return 0; 220 help: 221 printf("\n%s\n", get_help(menu)); 222 } 223 } 224 225 static int conf_choice(struct menu *menu) 226 { 227 struct symbol *sym, *def_sym; 228 struct menu *child; 229 int type; 230 bool is_new; 231 232 sym = menu->sym; 233 type = sym_get_type(sym); 234 is_new = !sym_has_value(sym); 235 if (sym_is_changable(sym)) { 236 conf_sym(menu); 237 sym_calc_value(sym); 238 switch (sym_get_tristate_value(sym)) { 239 case no: 240 return 1; 241 case mod: 242 return 0; 243 case yes: 244 break; 245 } 246 } else { 247 switch (sym_get_tristate_value(sym)) { 248 case no: 249 return 1; 250 case mod: 251 printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); 252 return 0; 253 case yes: 254 break; 255 } 256 } 257 258 while (1) { 259 int cnt, def; 260 261 printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); 262 def_sym = sym_get_choice_value(sym); 263 cnt = def = 0; 264 line[0] = 0; 265 for (child = menu->list; child; child = child->next) { 266 if (!menu_is_visible(child)) 267 continue; 268 if (!child->sym) { 269 printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); 270 continue; 271 } 272 cnt++; 273 if (child->sym == def_sym) { 274 def = cnt; 275 printf("%*c", indent, '>'); 276 } else 277 printf("%*c", indent, ' '); 278 printf(" %d. %s", cnt, _(menu_get_prompt(child))); 279 if (child->sym->name) 280 printf(" (%s)", child->sym->name); 281 if (!sym_has_value(child->sym)) 282 printf(_(" (NEW)")); 283 printf("\n"); 284 } 285 printf(_("%*schoice"), indent - 1, ""); 286 if (cnt == 1) { 287 printf("[1]: 1\n"); 288 goto conf_childs; 289 } 290 printf("[1-%d", cnt); 291 if (menu_has_help(menu)) 292 printf("?"); 293 printf("]: "); 294 switch (input_mode) { 295 case ask_new: 296 case ask_silent: 297 if (!is_new) { 298 cnt = def; 299 printf("%d\n", cnt); 300 break; 301 } 302 check_stdin(); 303 case ask_all: 304 fflush(stdout); 305 fgets(line, 128, stdin); 306 strip(line); 307 if (line[0] == '?') { 308 printf("\n%s\n", get_help(menu)); 309 continue; 310 } 311 if (!line[0]) 312 cnt = def; 313 else if (isdigit(line[0])) 314 cnt = atoi(line); 315 else 316 continue; 317 break; 318 default: 319 break; 320 } 321 322 conf_childs: 323 for (child = menu->list; child; child = child->next) { 324 if (!child->sym || !menu_is_visible(child)) 325 continue; 326 if (!--cnt) 327 break; 328 } 329 if (!child) 330 continue; 331 if (line[strlen(line) - 1] == '?') { 332 printf("\n%s\n", get_help(child)); 333 continue; 334 } 335 sym_set_choice_value(sym, child->sym); 336 for (child = child->list; child; child = child->next) { 337 indent += 2; 338 conf(child); 339 indent -= 2; 340 } 341 return 1; 342 } 343 } 344 345 static void conf(struct menu *menu) 346 { 347 struct symbol *sym; 348 struct property *prop; 349 struct menu *child; 350 351 if (!menu_is_visible(menu)) 352 return; 353 354 sym = menu->sym; 355 prop = menu->prompt; 356 if (prop) { 357 const char *prompt; 358 359 switch (prop->type) { 360 case P_MENU: 361 if (input_mode == ask_silent && rootEntry != menu) { 362 check_conf(menu); 363 return; 364 } 365 case P_COMMENT: 366 prompt = menu_get_prompt(menu); 367 if (prompt) 368 printf("%*c\n%*c %s\n%*c\n", 369 indent, '*', 370 indent, '*', _(prompt), 371 indent, '*'); 372 default: 373 ; 374 } 375 } 376 377 if (!sym) 378 goto conf_childs; 379 380 if (sym_is_choice(sym)) { 381 conf_choice(menu); 382 if (sym->curr.tri != mod) 383 return; 384 goto conf_childs; 385 } 386 387 switch (sym->type) { 388 case S_INT: 389 case S_HEX: 390 case S_STRING: 391 conf_string(menu); 392 break; 393 default: 394 conf_sym(menu); 395 break; 396 } 397 398 conf_childs: 399 if (sym) 400 indent += 2; 401 for (child = menu->list; child; child = child->next) 402 conf(child); 403 if (sym) 404 indent -= 2; 405 } 406 407 static void check_conf(struct menu *menu) 408 { 409 struct symbol *sym; 410 struct menu *child; 411 412 if (!menu_is_visible(menu)) 413 return; 414 415 sym = menu->sym; 416 if (sym && !sym_has_value(sym)) { 417 if (sym_is_changable(sym) || 418 (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { 419 if (!conf_cnt++) 420 printf(_("*\n* Restart config...\n*\n")); 421 rootEntry = menu_get_parent_menu(menu); 422 conf(rootEntry); 423 } 424 } 425 426 for (child = menu->list; child; child = child->next) 427 check_conf(child); 428 } 429 430 static void conf_do_update(void) 431 { 432 /* Update until a loop caused no more changes */ 433 do { 434 conf_cnt = 0; 435 check_conf(&rootmenu); 436 } while (conf_cnt); 437 } 438 439 static int conf_silent_update(void) 440 { 441 const char *name; 442 443 if (conf_get_changed()) { 444 name = getenv("KCONFIG_NOSILENTUPDATE"); 445 if (name && *name) { 446 fprintf(stderr, 447 _("\n*** Kernel configuration requires explicit update.\n\n")); 448 return 1; 449 } 450 conf_do_update(); 451 } 452 return 0; 453 } 454 455 static int conf_update(void) 456 { 457 rootEntry = &rootmenu; 458 conf(&rootmenu); 459 if (input_mode == ask_all) { 460 input_mode = ask_silent; 461 valid_stdin = 1; 462 } 463 conf_do_update(); 464 return 0; 465 } 466 467 int main(int ac, char **av) 468 { 469 int opt; 470 const char *name; 471 struct stat tmpstat; 472 473 setlocale(LC_ALL, ""); 474 bindtextdomain(PACKAGE, LOCALEDIR); 475 textdomain(PACKAGE); 476 477 while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) { 478 switch (opt) { 479 case 'o': 480 input_mode = ask_new; 481 break; 482 case 's': 483 input_mode = ask_silent; 484 valid_stdin = isatty(0) && isatty(1) && isatty(2); 485 break; 486 case 'd': 487 input_mode = set_default; 488 break; 489 case 'D': 490 input_mode = set_default; 491 defconfig_file = optarg; 492 break; 493 case 'n': 494 input_mode = set_no; 495 break; 496 case 'm': 497 input_mode = set_mod; 498 break; 499 case 'y': 500 input_mode = set_yes; 501 break; 502 case 'r': 503 input_mode = set_random; 504 srand(time(NULL)); 505 break; 506 case 'h': 507 printf(_("See README for usage info\n")); 508 exit(0); 509 break; 510 default: 511 fprintf(stderr, _("See README for usage info\n")); 512 exit(1); 513 } 514 } 515 if (ac == optind) { 516 printf(_("%s: Kconfig file missing\n"), av[0]); 517 exit(1); 518 } 519 name = av[optind]; 520 conf_parse(name); 521 //zconfdump(stdout); 522 switch (input_mode) { 523 case set_default: 524 if (!defconfig_file) 525 defconfig_file = conf_get_default_confname(); 526 if (conf_read(defconfig_file)) { 527 printf(_("***\n" 528 "*** Can't find default configuration \"%s\"!\n" 529 "***\n"), defconfig_file); 530 exit(1); 531 } 532 break; 533 case ask_silent: 534 if (stat(".config", &tmpstat)) { 535 printf(_("***\n" 536 "*** You have not yet configured your kernel!\n" 537 "*** (missing kernel .config file)\n" 538 "***\n" 539 "*** Please run some configurator (e.g. \"make oldconfig\" or\n" 540 "*** \"make menuconfig\" or \"make xconfig\").\n" 541 "***\n")); 542 exit(1); 543 } 544 case ask_all: 545 case ask_new: 546 conf_read(NULL); 547 break; 548 case set_no: 549 case set_mod: 550 case set_yes: 551 case set_random: 552 name = getenv("KCONFIG_ALLCONFIG"); 553 if (name && !stat(name, &tmpstat)) { 554 conf_read_simple(name, S_DEF_USER); 555 break; 556 } 557 switch (input_mode) { 558 case set_no: name = "allno.config"; break; 559 case set_mod: name = "allmod.config"; break; 560 case set_yes: name = "allyes.config"; break; 561 case set_random: name = "allrandom.config"; break; 562 default: break; 563 } 564 if (!stat(name, &tmpstat)) 565 conf_read_simple(name, S_DEF_USER); 566 else if (!stat("all.config", &tmpstat)) 567 conf_read_simple("all.config", S_DEF_USER); 568 break; 569 default: 570 break; 571 } 572 switch (input_mode) { 573 case set_no: 574 conf_set_all_new_symbols(def_no); 575 break; 576 case set_yes: 577 conf_set_all_new_symbols(def_yes); 578 break; 579 case set_mod: 580 conf_set_all_new_symbols(def_mod); 581 break; 582 case set_random: 583 conf_set_all_new_symbols(def_random); 584 break; 585 case set_default: 586 conf_set_all_new_symbols(def_default); 587 break; 588 case ask_silent: 589 case ask_new: 590 if (conf_silent_update()) 591 exit(1); 592 break; 593 case ask_all: 594 if (conf_update()) 595 exit(1); 596 break; 597 } 598 599 if (conf_get_changed() && conf_write(NULL)) { 600 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); 601 exit(1); 602 } 603 /* ask_silent is used during the build so we shall update autoconf. 604 * All other commands are only used to generate a config. 605 */ 606 if (input_mode == ask_silent && conf_write_autoconf()) { 607 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); 608 return 1; 609 } 610 return 0; 611 } 612