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 void strip(char *str) 41 { 42 char *p = str; 43 int l; 44 45 while ((isspace(*p))) 46 p++; 47 l = strlen(p); 48 if (p != str) 49 memmove(str, p, l + 1); 50 if (!l) 51 return; 52 p = str + l - 1; 53 while ((isspace(*p))) 54 *p-- = 0; 55 } 56 57 static void check_stdin(void) 58 { 59 if (!valid_stdin && input_mode == ask_silent) { 60 printf(_("aborted!\n\n")); 61 printf(_("Console input/output is redirected. ")); 62 printf(_("Run 'make oldconfig' to update configuration.\n\n")); 63 exit(1); 64 } 65 } 66 67 static void conf_askvalue(struct symbol *sym, const char *def) 68 { 69 enum symbol_type type = sym_get_type(sym); 70 tristate val; 71 72 if (!sym_has_value(sym)) 73 printf("(NEW) "); 74 75 line[0] = '\n'; 76 line[1] = 0; 77 78 if (!sym_is_changable(sym)) { 79 printf("%s\n", def); 80 line[0] = '\n'; 81 line[1] = 0; 82 return; 83 } 84 85 switch (input_mode) { 86 case set_no: 87 case set_mod: 88 case set_yes: 89 case set_random: 90 if (sym_has_value(sym)) { 91 printf("%s\n", def); 92 return; 93 } 94 break; 95 case ask_new: 96 case ask_silent: 97 if (sym_has_value(sym)) { 98 printf("%s\n", def); 99 return; 100 } 101 check_stdin(); 102 case ask_all: 103 fflush(stdout); 104 fgets(line, 128, stdin); 105 return; 106 case set_default: 107 printf("%s\n", def); 108 return; 109 default: 110 break; 111 } 112 113 switch (type) { 114 case S_INT: 115 case S_HEX: 116 case S_STRING: 117 printf("%s\n", def); 118 return; 119 default: 120 ; 121 } 122 switch (input_mode) { 123 case set_yes: 124 if (sym_tristate_within_range(sym, yes)) { 125 line[0] = 'y'; 126 line[1] = '\n'; 127 line[2] = 0; 128 break; 129 } 130 case set_mod: 131 if (type == S_TRISTATE) { 132 if (sym_tristate_within_range(sym, mod)) { 133 line[0] = 'm'; 134 line[1] = '\n'; 135 line[2] = 0; 136 break; 137 } 138 } else { 139 if (sym_tristate_within_range(sym, yes)) { 140 line[0] = 'y'; 141 line[1] = '\n'; 142 line[2] = 0; 143 break; 144 } 145 } 146 case set_no: 147 if (sym_tristate_within_range(sym, no)) { 148 line[0] = 'n'; 149 line[1] = '\n'; 150 line[2] = 0; 151 break; 152 } 153 case set_random: 154 do { 155 val = (tristate)(random() % 3); 156 } while (!sym_tristate_within_range(sym, val)); 157 switch (val) { 158 case no: line[0] = 'n'; break; 159 case mod: line[0] = 'm'; break; 160 case yes: line[0] = 'y'; break; 161 } 162 line[1] = '\n'; 163 line[2] = 0; 164 break; 165 default: 166 break; 167 } 168 printf("%s", line); 169 } 170 171 int conf_string(struct menu *menu) 172 { 173 struct symbol *sym = menu->sym; 174 const char *def, *help; 175 176 while (1) { 177 printf("%*s%s ", indent - 1, "", menu->prompt->text); 178 printf("(%s) ", sym->name); 179 def = sym_get_string_value(sym); 180 if (sym_get_string_value(sym)) 181 printf("[%s] ", def); 182 conf_askvalue(sym, def); 183 switch (line[0]) { 184 case '\n': 185 break; 186 case '?': 187 /* print help */ 188 if (line[1] == '\n') { 189 help = nohelp_text; 190 if (menu->sym->help) 191 help = menu->sym->help; 192 printf("\n%s\n", menu->sym->help); 193 def = NULL; 194 break; 195 } 196 default: 197 line[strlen(line)-1] = 0; 198 def = line; 199 } 200 if (def && sym_set_string_value(sym, def)) 201 return 0; 202 } 203 } 204 205 static int conf_sym(struct menu *menu) 206 { 207 struct symbol *sym = menu->sym; 208 int type; 209 tristate oldval, newval; 210 const char *help; 211 212 while (1) { 213 printf("%*s%s ", indent - 1, "", menu->prompt->text); 214 if (sym->name) 215 printf("(%s) ", sym->name); 216 type = sym_get_type(sym); 217 putchar('['); 218 oldval = sym_get_tristate_value(sym); 219 switch (oldval) { 220 case no: 221 putchar('N'); 222 break; 223 case mod: 224 putchar('M'); 225 break; 226 case yes: 227 putchar('Y'); 228 break; 229 } 230 if (oldval != no && sym_tristate_within_range(sym, no)) 231 printf("/n"); 232 if (oldval != mod && sym_tristate_within_range(sym, mod)) 233 printf("/m"); 234 if (oldval != yes && sym_tristate_within_range(sym, yes)) 235 printf("/y"); 236 if (sym->help) 237 printf("/?"); 238 printf("] "); 239 conf_askvalue(sym, sym_get_string_value(sym)); 240 strip(line); 241 242 switch (line[0]) { 243 case 'n': 244 case 'N': 245 newval = no; 246 if (!line[1] || !strcmp(&line[1], "o")) 247 break; 248 continue; 249 case 'm': 250 case 'M': 251 newval = mod; 252 if (!line[1]) 253 break; 254 continue; 255 case 'y': 256 case 'Y': 257 newval = yes; 258 if (!line[1] || !strcmp(&line[1], "es")) 259 break; 260 continue; 261 case 0: 262 newval = oldval; 263 break; 264 case '?': 265 goto help; 266 default: 267 continue; 268 } 269 if (sym_set_tristate_value(sym, newval)) 270 return 0; 271 help: 272 help = nohelp_text; 273 if (sym->help) 274 help = sym->help; 275 printf("\n%s\n", help); 276 } 277 } 278 279 static int conf_choice(struct menu *menu) 280 { 281 struct symbol *sym, *def_sym; 282 struct menu *child; 283 int type; 284 bool is_new; 285 286 sym = menu->sym; 287 type = sym_get_type(sym); 288 is_new = !sym_has_value(sym); 289 if (sym_is_changable(sym)) { 290 conf_sym(menu); 291 sym_calc_value(sym); 292 switch (sym_get_tristate_value(sym)) { 293 case no: 294 return 1; 295 case mod: 296 return 0; 297 case yes: 298 break; 299 } 300 } else { 301 switch (sym_get_tristate_value(sym)) { 302 case no: 303 return 1; 304 case mod: 305 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); 306 return 0; 307 case yes: 308 break; 309 } 310 } 311 312 while (1) { 313 int cnt, def; 314 315 printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); 316 def_sym = sym_get_choice_value(sym); 317 cnt = def = 0; 318 line[0] = 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 fprintf(stderr, "See README for usage info\n"); 536 exit(0); 537 } 538 } 539 name = av[i]; 540 if (!name) { 541 printf(_("%s: Kconfig file missing\n"), av[0]); 542 exit(1); 543 } 544 conf_parse(name); 545 //zconfdump(stdout); 546 switch (input_mode) { 547 case set_default: 548 if (!defconfig_file) 549 defconfig_file = conf_get_default_confname(); 550 if (conf_read(defconfig_file)) { 551 printf("***\n" 552 "*** Can't find default configuration \"%s\"!\n" 553 "***\n", defconfig_file); 554 exit(1); 555 } 556 break; 557 case ask_silent: 558 if (stat(".config", &tmpstat)) { 559 printf(_("***\n" 560 "*** You have not yet configured your "PROJECT_NAME"!\n" 561 "***\n" 562 "*** Please run some configurator (e.g. \"make oldconfig\" or\n" 563 "*** \"make menuconfig\" or \"make xconfig\").\n" 564 "***\n")); 565 exit(1); 566 } 567 case ask_all: 568 case ask_new: 569 conf_read(NULL); 570 break; 571 case set_no: 572 case set_mod: 573 case set_yes: 574 case set_random: 575 name = getenv("KCONFIG_ALLCONFIG"); 576 if (name && !stat(name, &tmpstat)) { 577 conf_read_simple(name, S_DEF_USER); 578 break; 579 } 580 switch (input_mode) { 581 case set_no: name = "allno.config"; break; 582 case set_mod: name = "allmod.config"; break; 583 case set_yes: name = "allyes.config"; break; 584 case set_random: name = "allrandom.config"; break; 585 default: break; 586 } 587 if (!stat(name, &tmpstat)) 588 conf_read_simple(name, S_DEF_USER); 589 else if (!stat("all.config", &tmpstat)) 590 conf_read_simple("all.config", S_DEF_USER); 591 break; 592 default: 593 break; 594 } 595 596 if (input_mode != ask_silent) { 597 rootEntry = &rootmenu; 598 conf(&rootmenu); 599 if (input_mode == ask_all) { 600 input_mode = ask_silent; 601 valid_stdin = 1; 602 } 603 } else if (sym_change_count) { 604 name = getenv("KCONFIG_NOSILENTUPDATE"); 605 if (name && *name) { 606 fprintf(stderr, _("\n*** "PROJECT_NAME" configuration requires explicit update.\n\n")); 607 return 1; 608 } 609 } else 610 goto skip_check; 611 612 do { 613 conf_cnt = 0; 614 check_conf(&rootmenu); 615 } while (conf_cnt); 616 617 if (!conf_write(NULL)) { 618 skip_check: 619 if (!(input_mode == ask_silent && conf_write_autoconf())) 620 return 0; 621 } 622 fprintf(stderr, _("\n*** Error writing "PROJECT_NAME" configuration.\n\n")); 623 return 1; 624 } 625