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