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