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