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