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 def = (random() % cnt) + 1; 378 case set_default: 379 case set_yes: 380 case set_mod: 381 case set_no: 382 cnt = def; 383 printf("%d\n", cnt); 384 break; 385 } 386 387 conf_childs: 388 for (child = menu->list; child; child = child->next) { 389 if (!child->sym || !menu_is_visible(child)) 390 continue; 391 if (!--cnt) 392 break; 393 } 394 if (!child) 395 continue; 396 if (line[strlen(line) - 1] == '?') { 397 printf("\n%s\n", get_help(child)); 398 continue; 399 } 400 sym_set_choice_value(sym, child->sym); 401 if (child->list) { 402 indent += 2; 403 conf(child->list); 404 indent -= 2; 405 } 406 return 1; 407 } 408 } 409 410 static void conf(struct menu *menu) 411 { 412 struct symbol *sym; 413 struct property *prop; 414 struct menu *child; 415 416 if (!menu_is_visible(menu)) 417 return; 418 419 sym = menu->sym; 420 prop = menu->prompt; 421 if (prop) { 422 const char *prompt; 423 424 switch (prop->type) { 425 case P_MENU: 426 if (input_mode == ask_silent && rootEntry != menu) { 427 check_conf(menu); 428 return; 429 } 430 case P_COMMENT: 431 prompt = menu_get_prompt(menu); 432 if (prompt) 433 printf("%*c\n%*c %s\n%*c\n", 434 indent, '*', 435 indent, '*', prompt, 436 indent, '*'); 437 default: 438 ; 439 } 440 } 441 442 if (!sym) 443 goto conf_childs; 444 445 if (sym_is_choice(sym)) { 446 conf_choice(menu); 447 if (sym->curr.tri != mod) 448 return; 449 goto conf_childs; 450 } 451 452 switch (sym->type) { 453 case S_INT: 454 case S_HEX: 455 case S_STRING: 456 conf_string(menu); 457 break; 458 default: 459 conf_sym(menu); 460 break; 461 } 462 463 conf_childs: 464 if (sym) 465 indent += 2; 466 for (child = menu->list; child; child = child->next) 467 conf(child); 468 if (sym) 469 indent -= 2; 470 } 471 472 static void check_conf(struct menu *menu) 473 { 474 struct symbol *sym; 475 struct menu *child; 476 477 if (!menu_is_visible(menu)) 478 return; 479 480 sym = menu->sym; 481 if (sym && !sym_has_value(sym)) { 482 if (sym_is_changable(sym) || 483 (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { 484 if (!conf_cnt++) 485 printf(_("*\n* Restart config...\n*\n")); 486 rootEntry = menu_get_parent_menu(menu); 487 conf(rootEntry); 488 } 489 } 490 491 for (child = menu->list; child; child = child->next) 492 check_conf(child); 493 } 494 495 int main(int ac, char **av) 496 { 497 int i = 1; 498 const char *name; 499 struct stat tmpstat; 500 501 if (ac > i && av[i][0] == '-') { 502 switch (av[i++][1]) { 503 case 'o': 504 input_mode = ask_new; 505 break; 506 case 's': 507 input_mode = ask_silent; 508 valid_stdin = isatty(0) && isatty(1) && isatty(2); 509 break; 510 case 'd': 511 input_mode = set_default; 512 break; 513 case 'D': 514 input_mode = set_default; 515 defconfig_file = av[i++]; 516 if (!defconfig_file) { 517 printf(_("%s: No default config file specified\n"), 518 av[0]); 519 exit(1); 520 } 521 break; 522 case 'n': 523 input_mode = set_no; 524 break; 525 case 'm': 526 input_mode = set_mod; 527 break; 528 case 'y': 529 input_mode = set_yes; 530 break; 531 case 'r': 532 input_mode = set_random; 533 srandom(time(NULL)); 534 break; 535 case 'h': 536 case '?': 537 fprintf(stderr, "See README for usage info\n"); 538 exit(0); 539 } 540 } 541 name = av[i]; 542 if (!name) { 543 printf(_("%s: Kconfig file missing\n"), av[0]); 544 exit(1); 545 } 546 conf_parse(name); 547 //zconfdump(stdout); 548 switch (input_mode) { 549 case set_default: 550 if (!defconfig_file) 551 defconfig_file = conf_get_default_confname(); 552 if (conf_read(defconfig_file)) { 553 printf("***\n" 554 "*** Can't find default configuration \"%s\"!\n" 555 "***\n", defconfig_file); 556 exit(1); 557 } 558 break; 559 case ask_silent: 560 if (stat(".config", &tmpstat)) { 561 printf(_("***\n" 562 "*** You have not yet configured your kernel!\n" 563 "*** (missing kernel .config file)\n" 564 "***\n" 565 "*** Please run some configurator (e.g. \"make oldconfig\" or\n" 566 "*** \"make menuconfig\" or \"make xconfig\").\n" 567 "***\n")); 568 exit(1); 569 } 570 case ask_all: 571 case ask_new: 572 conf_read(NULL); 573 break; 574 case set_no: 575 case set_mod: 576 case set_yes: 577 case set_random: 578 name = getenv("KCONFIG_ALLCONFIG"); 579 if (name && !stat(name, &tmpstat)) { 580 conf_read_simple(name, S_DEF_USER); 581 break; 582 } 583 switch (input_mode) { 584 case set_no: name = "allno.config"; break; 585 case set_mod: name = "allmod.config"; break; 586 case set_yes: name = "allyes.config"; break; 587 case set_random: name = "allrandom.config"; break; 588 default: break; 589 } 590 if (!stat(name, &tmpstat)) 591 conf_read_simple(name, S_DEF_USER); 592 else if (!stat("all.config", &tmpstat)) 593 conf_read_simple("all.config", S_DEF_USER); 594 break; 595 default: 596 break; 597 } 598 599 if (input_mode != ask_silent) { 600 rootEntry = &rootmenu; 601 conf(&rootmenu); 602 if (input_mode == ask_all) { 603 input_mode = ask_silent; 604 valid_stdin = 1; 605 } 606 } else if (conf_get_changed()) { 607 name = getenv("KCONFIG_NOSILENTUPDATE"); 608 if (name && *name) { 609 fprintf(stderr, _("\n*** Kernel configuration requires explicit update.\n\n")); 610 return 1; 611 } 612 } else 613 goto skip_check; 614 615 do { 616 conf_cnt = 0; 617 check_conf(&rootmenu); 618 } while (conf_cnt); 619 if (conf_write(NULL)) { 620 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); 621 return 1; 622 } 623 skip_check: 624 if (input_mode == ask_silent && conf_write_autoconf()) { 625 fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n")); 626 return 1; 627 } 628 629 return 0; 630 } 631