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 <regex.h> 10 #include <sys/utsname.h> 11 12 #define LKC_DIRECT_LINK 13 #include "lkc.h" 14 15 struct symbol symbol_yes = { 16 .name = "y", 17 .curr = { "y", yes }, 18 .flags = SYMBOL_YES|SYMBOL_VALID, 19 }, symbol_mod = { 20 .name = "m", 21 .curr = { "m", mod }, 22 .flags = SYMBOL_MOD|SYMBOL_VALID, 23 }, symbol_no = { 24 .name = "n", 25 .curr = { "n", no }, 26 .flags = SYMBOL_NO|SYMBOL_VALID, 27 }, symbol_empty = { 28 .name = "", 29 .curr = { "", no }, 30 .flags = SYMBOL_VALID, 31 }; 32 33 int sym_change_count; 34 struct symbol *modules_sym; 35 tristate modules_val; 36 37 void sym_add_default(struct symbol *sym, const char *def) 38 { 39 struct property *prop = prop_alloc(P_DEFAULT, sym); 40 41 prop->expr = expr_alloc_symbol(sym_lookup(def, 1)); 42 } 43 44 void sym_init(void) 45 { 46 struct symbol *sym; 47 struct utsname uts; 48 char *p; 49 static bool inited = false; 50 51 if (inited) 52 return; 53 inited = true; 54 55 uname(&uts); 56 57 sym = sym_lookup("ARCH", 0); 58 sym->type = S_STRING; 59 sym->flags |= SYMBOL_AUTO; 60 p = getenv("ARCH"); 61 if (p) 62 sym_add_default(sym, p); 63 64 sym = sym_lookup("KERNELRELEASE", 0); 65 sym->type = S_STRING; 66 sym->flags |= SYMBOL_AUTO; 67 p = getenv("KERNELRELEASE"); 68 if (p) 69 sym_add_default(sym, p); 70 71 sym = sym_lookup("UNAME_RELEASE", 0); 72 sym->type = S_STRING; 73 sym->flags |= SYMBOL_AUTO; 74 sym_add_default(sym, uts.release); 75 } 76 77 enum symbol_type sym_get_type(struct symbol *sym) 78 { 79 enum symbol_type type = sym->type; 80 81 if (type == S_TRISTATE) { 82 if (sym_is_choice_value(sym) && sym->visible == yes) 83 type = S_BOOLEAN; 84 else if (modules_val == no) 85 type = S_BOOLEAN; 86 } 87 return type; 88 } 89 90 const char *sym_type_name(enum symbol_type type) 91 { 92 switch (type) { 93 case S_BOOLEAN: 94 return "boolean"; 95 case S_TRISTATE: 96 return "tristate"; 97 case S_INT: 98 return "integer"; 99 case S_HEX: 100 return "hex"; 101 case S_STRING: 102 return "string"; 103 case S_UNKNOWN: 104 return "unknown"; 105 case S_OTHER: 106 break; 107 } 108 return "???"; 109 } 110 111 struct property *sym_get_choice_prop(struct symbol *sym) 112 { 113 struct property *prop; 114 115 for_all_choices(sym, prop) 116 return prop; 117 return NULL; 118 } 119 120 struct property *sym_get_default_prop(struct symbol *sym) 121 { 122 struct property *prop; 123 124 for_all_defaults(sym, prop) { 125 prop->visible.tri = expr_calc_value(prop->visible.expr); 126 if (prop->visible.tri != no) 127 return prop; 128 } 129 return NULL; 130 } 131 132 struct property *sym_get_range_prop(struct symbol *sym) 133 { 134 struct property *prop; 135 136 for_all_properties(sym, prop, P_RANGE) { 137 prop->visible.tri = expr_calc_value(prop->visible.expr); 138 if (prop->visible.tri != no) 139 return prop; 140 } 141 return NULL; 142 } 143 144 static void sym_calc_visibility(struct symbol *sym) 145 { 146 struct property *prop; 147 tristate tri; 148 149 /* any prompt visible? */ 150 tri = no; 151 for_all_prompts(sym, prop) { 152 prop->visible.tri = expr_calc_value(prop->visible.expr); 153 tri = E_OR(tri, prop->visible.tri); 154 } 155 if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) 156 tri = yes; 157 if (sym->visible != tri) { 158 sym->visible = tri; 159 sym_set_changed(sym); 160 } 161 if (sym_is_choice_value(sym)) 162 return; 163 tri = no; 164 if (sym->rev_dep.expr) 165 tri = expr_calc_value(sym->rev_dep.expr); 166 if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 167 tri = yes; 168 if (sym->rev_dep.tri != tri) { 169 sym->rev_dep.tri = tri; 170 sym_set_changed(sym); 171 } 172 } 173 174 static struct symbol *sym_calc_choice(struct symbol *sym) 175 { 176 struct symbol *def_sym; 177 struct property *prop; 178 struct expr *e; 179 180 /* is the user choice visible? */ 181 def_sym = sym->user.val; 182 if (def_sym) { 183 sym_calc_visibility(def_sym); 184 if (def_sym->visible != no) 185 return def_sym; 186 } 187 188 /* any of the defaults visible? */ 189 for_all_defaults(sym, prop) { 190 prop->visible.tri = expr_calc_value(prop->visible.expr); 191 if (prop->visible.tri == no) 192 continue; 193 def_sym = prop_get_symbol(prop); 194 sym_calc_visibility(def_sym); 195 if (def_sym->visible != no) 196 return def_sym; 197 } 198 199 /* just get the first visible value */ 200 prop = sym_get_choice_prop(sym); 201 for (e = prop->expr; e; e = e->left.expr) { 202 def_sym = e->right.sym; 203 sym_calc_visibility(def_sym); 204 if (def_sym->visible != no) 205 return def_sym; 206 } 207 208 /* no choice? reset tristate value */ 209 sym->curr.tri = no; 210 return NULL; 211 } 212 213 void sym_calc_value(struct symbol *sym) 214 { 215 struct symbol_value newval, oldval; 216 struct property *prop; 217 struct expr *e; 218 219 if (!sym) 220 return; 221 222 if (sym->flags & SYMBOL_VALID) 223 return; 224 sym->flags |= SYMBOL_VALID; 225 226 oldval = sym->curr; 227 228 switch (sym->type) { 229 case S_INT: 230 case S_HEX: 231 case S_STRING: 232 newval = symbol_empty.curr; 233 break; 234 case S_BOOLEAN: 235 case S_TRISTATE: 236 newval = symbol_no.curr; 237 break; 238 default: 239 sym->curr.val = sym->name; 240 sym->curr.tri = no; 241 return; 242 } 243 if (!sym_is_choice_value(sym)) 244 sym->flags &= ~SYMBOL_WRITE; 245 246 sym_calc_visibility(sym); 247 248 /* set default if recursively called */ 249 sym->curr = newval; 250 251 switch (sym_get_type(sym)) { 252 case S_BOOLEAN: 253 case S_TRISTATE: 254 if (sym_is_choice_value(sym) && sym->visible == yes) { 255 prop = sym_get_choice_prop(sym); 256 newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; 257 } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) { 258 sym->flags |= SYMBOL_WRITE; 259 if (sym_has_value(sym)) 260 newval.tri = sym->user.tri; 261 else if (!sym_is_choice(sym)) { 262 prop = sym_get_default_prop(sym); 263 if (prop) 264 newval.tri = expr_calc_value(prop->expr); 265 } 266 newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri); 267 } else if (!sym_is_choice(sym)) { 268 prop = sym_get_default_prop(sym); 269 if (prop) { 270 sym->flags |= SYMBOL_WRITE; 271 newval.tri = expr_calc_value(prop->expr); 272 } 273 } 274 if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) 275 newval.tri = yes; 276 break; 277 case S_STRING: 278 case S_HEX: 279 case S_INT: 280 if (sym->visible != no) { 281 sym->flags |= SYMBOL_WRITE; 282 if (sym_has_value(sym)) { 283 newval.val = sym->user.val; 284 break; 285 } 286 } 287 prop = sym_get_default_prop(sym); 288 if (prop) { 289 struct symbol *ds = prop_get_symbol(prop); 290 if (ds) { 291 sym->flags |= SYMBOL_WRITE; 292 sym_calc_value(ds); 293 newval.val = ds->curr.val; 294 } 295 } 296 break; 297 default: 298 ; 299 } 300 301 sym->curr = newval; 302 if (sym_is_choice(sym) && newval.tri == yes) 303 sym->curr.val = sym_calc_choice(sym); 304 305 if (memcmp(&oldval, &sym->curr, sizeof(oldval))) 306 sym_set_changed(sym); 307 if (modules_sym == sym) 308 modules_val = modules_sym->curr.tri; 309 310 if (sym_is_choice(sym)) { 311 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); 312 prop = sym_get_choice_prop(sym); 313 for (e = prop->expr; e; e = e->left.expr) { 314 e->right.sym->flags |= flags; 315 if (flags & SYMBOL_CHANGED) 316 sym_set_changed(e->right.sym); 317 } 318 } 319 } 320 321 void sym_clear_all_valid(void) 322 { 323 struct symbol *sym; 324 int i; 325 326 for_all_symbols(i, sym) 327 sym->flags &= ~SYMBOL_VALID; 328 sym_change_count++; 329 if (modules_sym) 330 sym_calc_value(modules_sym); 331 } 332 333 void sym_set_changed(struct symbol *sym) 334 { 335 struct property *prop; 336 337 sym->flags |= SYMBOL_CHANGED; 338 for (prop = sym->prop; prop; prop = prop->next) { 339 if (prop->menu) 340 prop->menu->flags |= MENU_CHANGED; 341 } 342 } 343 344 void sym_set_all_changed(void) 345 { 346 struct symbol *sym; 347 int i; 348 349 for_all_symbols(i, sym) 350 sym_set_changed(sym); 351 } 352 353 bool sym_tristate_within_range(struct symbol *sym, tristate val) 354 { 355 int type = sym_get_type(sym); 356 357 if (sym->visible == no) 358 return false; 359 360 if (type != S_BOOLEAN && type != S_TRISTATE) 361 return false; 362 363 if (type == S_BOOLEAN && val == mod) 364 return false; 365 if (sym->visible <= sym->rev_dep.tri) 366 return false; 367 if (sym_is_choice_value(sym) && sym->visible == yes) 368 return val == yes; 369 return val >= sym->rev_dep.tri && val <= sym->visible; 370 } 371 372 bool sym_set_tristate_value(struct symbol *sym, tristate val) 373 { 374 tristate oldval = sym_get_tristate_value(sym); 375 376 if (oldval != val && !sym_tristate_within_range(sym, val)) 377 return false; 378 379 if (sym->flags & SYMBOL_NEW) { 380 sym->flags &= ~SYMBOL_NEW; 381 sym_set_changed(sym); 382 } 383 if (sym_is_choice_value(sym) && val == yes) { 384 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 385 386 cs->user.val = sym; 387 cs->flags &= ~SYMBOL_NEW; 388 } 389 390 sym->user.tri = val; 391 if (oldval != val) { 392 sym_clear_all_valid(); 393 if (sym == modules_sym) 394 sym_set_all_changed(); 395 } 396 397 return true; 398 } 399 400 tristate sym_toggle_tristate_value(struct symbol *sym) 401 { 402 tristate oldval, newval; 403 404 oldval = newval = sym_get_tristate_value(sym); 405 do { 406 switch (newval) { 407 case no: 408 newval = mod; 409 break; 410 case mod: 411 newval = yes; 412 break; 413 case yes: 414 newval = no; 415 break; 416 } 417 if (sym_set_tristate_value(sym, newval)) 418 break; 419 } while (oldval != newval); 420 return newval; 421 } 422 423 bool sym_string_valid(struct symbol *sym, const char *str) 424 { 425 signed char ch; 426 427 switch (sym->type) { 428 case S_STRING: 429 return true; 430 case S_INT: 431 ch = *str++; 432 if (ch == '-') 433 ch = *str++; 434 if (!isdigit(ch)) 435 return false; 436 if (ch == '0' && *str != 0) 437 return false; 438 while ((ch = *str++)) { 439 if (!isdigit(ch)) 440 return false; 441 } 442 return true; 443 case S_HEX: 444 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) 445 str += 2; 446 ch = *str++; 447 do { 448 if (!isxdigit(ch)) 449 return false; 450 } while ((ch = *str++)); 451 return true; 452 case S_BOOLEAN: 453 case S_TRISTATE: 454 switch (str[0]) { 455 case 'y': case 'Y': 456 case 'm': case 'M': 457 case 'n': case 'N': 458 return true; 459 } 460 return false; 461 default: 462 return false; 463 } 464 } 465 466 bool sym_string_within_range(struct symbol *sym, const char *str) 467 { 468 struct property *prop; 469 int val; 470 471 switch (sym->type) { 472 case S_STRING: 473 return sym_string_valid(sym, str); 474 case S_INT: 475 if (!sym_string_valid(sym, str)) 476 return false; 477 prop = sym_get_range_prop(sym); 478 if (!prop) 479 return true; 480 val = strtol(str, NULL, 10); 481 return val >= strtol(prop->expr->left.sym->name, NULL, 10) && 482 val <= strtol(prop->expr->right.sym->name, NULL, 10); 483 case S_HEX: 484 if (!sym_string_valid(sym, str)) 485 return false; 486 prop = sym_get_range_prop(sym); 487 if (!prop) 488 return true; 489 val = strtol(str, NULL, 16); 490 return val >= strtol(prop->expr->left.sym->name, NULL, 16) && 491 val <= strtol(prop->expr->right.sym->name, NULL, 16); 492 case S_BOOLEAN: 493 case S_TRISTATE: 494 switch (str[0]) { 495 case 'y': case 'Y': 496 return sym_tristate_within_range(sym, yes); 497 case 'm': case 'M': 498 return sym_tristate_within_range(sym, mod); 499 case 'n': case 'N': 500 return sym_tristate_within_range(sym, no); 501 } 502 return false; 503 default: 504 return false; 505 } 506 } 507 508 bool sym_set_string_value(struct symbol *sym, const char *newval) 509 { 510 const char *oldval; 511 char *val; 512 int size; 513 514 switch (sym->type) { 515 case S_BOOLEAN: 516 case S_TRISTATE: 517 switch (newval[0]) { 518 case 'y': case 'Y': 519 return sym_set_tristate_value(sym, yes); 520 case 'm': case 'M': 521 return sym_set_tristate_value(sym, mod); 522 case 'n': case 'N': 523 return sym_set_tristate_value(sym, no); 524 } 525 return false; 526 default: 527 ; 528 } 529 530 if (!sym_string_within_range(sym, newval)) 531 return false; 532 533 if (sym->flags & SYMBOL_NEW) { 534 sym->flags &= ~SYMBOL_NEW; 535 sym_set_changed(sym); 536 } 537 538 oldval = sym->user.val; 539 size = strlen(newval) + 1; 540 if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { 541 size += 2; 542 sym->user.val = val = malloc(size); 543 *val++ = '0'; 544 *val++ = 'x'; 545 } else if (!oldval || strcmp(oldval, newval)) 546 sym->user.val = val = malloc(size); 547 else 548 return true; 549 550 strcpy(val, newval); 551 free((void *)oldval); 552 sym_clear_all_valid(); 553 554 return true; 555 } 556 557 const char *sym_get_string_value(struct symbol *sym) 558 { 559 tristate val; 560 561 switch (sym->type) { 562 case S_BOOLEAN: 563 case S_TRISTATE: 564 val = sym_get_tristate_value(sym); 565 switch (val) { 566 case no: 567 return "n"; 568 case mod: 569 return "m"; 570 case yes: 571 return "y"; 572 } 573 break; 574 default: 575 ; 576 } 577 return (const char *)sym->curr.val; 578 } 579 580 bool sym_is_changable(struct symbol *sym) 581 { 582 return sym->visible > sym->rev_dep.tri; 583 } 584 585 struct symbol *sym_lookup(const char *name, int isconst) 586 { 587 struct symbol *symbol; 588 const char *ptr; 589 char *new_name; 590 int hash = 0; 591 592 if (name) { 593 if (name[0] && !name[1]) { 594 switch (name[0]) { 595 case 'y': return &symbol_yes; 596 case 'm': return &symbol_mod; 597 case 'n': return &symbol_no; 598 } 599 } 600 for (ptr = name; *ptr; ptr++) 601 hash += *ptr; 602 hash &= 0xff; 603 604 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 605 if (!strcmp(symbol->name, name)) { 606 if ((isconst && symbol->flags & SYMBOL_CONST) || 607 (!isconst && !(symbol->flags & SYMBOL_CONST))) 608 return symbol; 609 } 610 } 611 new_name = strdup(name); 612 } else { 613 new_name = NULL; 614 hash = 256; 615 } 616 617 symbol = malloc(sizeof(*symbol)); 618 memset(symbol, 0, sizeof(*symbol)); 619 symbol->name = new_name; 620 symbol->type = S_UNKNOWN; 621 symbol->flags = SYMBOL_NEW; 622 if (isconst) 623 symbol->flags |= SYMBOL_CONST; 624 625 symbol->next = symbol_hash[hash]; 626 symbol_hash[hash] = symbol; 627 628 return symbol; 629 } 630 631 struct symbol *sym_find(const char *name) 632 { 633 struct symbol *symbol = NULL; 634 const char *ptr; 635 int hash = 0; 636 637 if (!name) 638 return NULL; 639 640 if (name[0] && !name[1]) { 641 switch (name[0]) { 642 case 'y': return &symbol_yes; 643 case 'm': return &symbol_mod; 644 case 'n': return &symbol_no; 645 } 646 } 647 for (ptr = name; *ptr; ptr++) 648 hash += *ptr; 649 hash &= 0xff; 650 651 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 652 if (!strcmp(symbol->name, name) && 653 !(symbol->flags & SYMBOL_CONST)) 654 break; 655 } 656 657 return symbol; 658 } 659 660 struct symbol **sym_re_search(const char *pattern) 661 { 662 struct symbol *sym, **sym_arr = NULL; 663 int i, cnt, size; 664 regex_t re; 665 666 cnt = size = 0; 667 /* Skip if empty */ 668 if (strlen(pattern) == 0) 669 return NULL; 670 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) 671 return NULL; 672 673 for_all_symbols(i, sym) { 674 if (sym->flags & SYMBOL_CONST || !sym->name) 675 continue; 676 if (regexec(&re, sym->name, 0, NULL, 0)) 677 continue; 678 if (cnt + 1 >= size) { 679 void *tmp = sym_arr; 680 size += 16; 681 sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); 682 if (!sym_arr) { 683 free(tmp); 684 return NULL; 685 } 686 } 687 sym_arr[cnt++] = sym; 688 } 689 if (sym_arr) 690 sym_arr[cnt] = NULL; 691 regfree(&re); 692 693 return sym_arr; 694 } 695 696 697 struct symbol *sym_check_deps(struct symbol *sym); 698 699 static struct symbol *sym_check_expr_deps(struct expr *e) 700 { 701 struct symbol *sym; 702 703 if (!e) 704 return NULL; 705 switch (e->type) { 706 case E_OR: 707 case E_AND: 708 sym = sym_check_expr_deps(e->left.expr); 709 if (sym) 710 return sym; 711 return sym_check_expr_deps(e->right.expr); 712 case E_NOT: 713 return sym_check_expr_deps(e->left.expr); 714 case E_EQUAL: 715 case E_UNEQUAL: 716 sym = sym_check_deps(e->left.sym); 717 if (sym) 718 return sym; 719 return sym_check_deps(e->right.sym); 720 case E_SYMBOL: 721 return sym_check_deps(e->left.sym); 722 default: 723 break; 724 } 725 printf("Oops! How to check %d?\n", e->type); 726 return NULL; 727 } 728 729 struct symbol *sym_check_deps(struct symbol *sym) 730 { 731 struct symbol *sym2; 732 struct property *prop; 733 734 if (sym->flags & SYMBOL_CHECK_DONE) 735 return NULL; 736 if (sym->flags & SYMBOL_CHECK) { 737 printf("Warning! Found recursive dependency: %s", sym->name); 738 return sym; 739 } 740 741 sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 742 sym2 = sym_check_expr_deps(sym->rev_dep.expr); 743 if (sym2) 744 goto out; 745 746 for (prop = sym->prop; prop; prop = prop->next) { 747 if (prop->type == P_CHOICE || prop->type == P_SELECT) 748 continue; 749 sym2 = sym_check_expr_deps(prop->visible.expr); 750 if (sym2) 751 goto out; 752 if (prop->type != P_DEFAULT || sym_is_choice(sym)) 753 continue; 754 sym2 = sym_check_expr_deps(prop->expr); 755 if (sym2) 756 goto out; 757 } 758 out: 759 if (sym2) 760 printf(" %s", sym->name); 761 sym->flags &= ~SYMBOL_CHECK; 762 return sym2; 763 } 764 765 struct property *prop_alloc(enum prop_type type, struct symbol *sym) 766 { 767 struct property *prop; 768 struct property **propp; 769 770 prop = malloc(sizeof(*prop)); 771 memset(prop, 0, sizeof(*prop)); 772 prop->type = type; 773 prop->sym = sym; 774 prop->file = current_file; 775 prop->lineno = zconf_lineno(); 776 777 /* append property to the prop list of symbol */ 778 if (sym) { 779 for (propp = &sym->prop; *propp; propp = &(*propp)->next) 780 ; 781 *propp = prop; 782 } 783 784 return prop; 785 } 786 787 struct symbol *prop_get_symbol(struct property *prop) 788 { 789 if (prop->expr && (prop->expr->type == E_SYMBOL || 790 prop->expr->type == E_CHOICE)) 791 return prop->expr->left.sym; 792 return NULL; 793 } 794 795 const char *prop_get_type_name(enum prop_type type) 796 { 797 switch (type) { 798 case P_PROMPT: 799 return "prompt"; 800 case P_COMMENT: 801 return "comment"; 802 case P_MENU: 803 return "menu"; 804 case P_DEFAULT: 805 return "default"; 806 case P_CHOICE: 807 return "choice"; 808 case P_SELECT: 809 return "select"; 810 case P_RANGE: 811 return "range"; 812 case P_UNKNOWN: 813 break; 814 } 815 return "unknown"; 816 } 817