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