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_CONST|SYMBOL_VALID, 19 }, symbol_mod = { 20 .name = "m", 21 .curr = { "m", mod }, 22 .flags = SYMBOL_CONST|SYMBOL_VALID, 23 }, symbol_no = { 24 .name = "n", 25 .curr = { "n", no }, 26 .flags = SYMBOL_CONST|SYMBOL_VALID, 27 }, symbol_empty = { 28 .name = "", 29 .curr = { "", no }, 30 .flags = SYMBOL_VALID, 31 }; 32 33 struct symbol *sym_defconfig_list; 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("KERNELVERSION", 0); 65 sym->type = S_STRING; 66 sym->flags |= SYMBOL_AUTO; 67 p = getenv("KERNELVERSION"); 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 int sym_get_range_val(struct symbol *sym, int base) 145 { 146 sym_calc_value(sym); 147 switch (sym->type) { 148 case S_INT: 149 base = 10; 150 break; 151 case S_HEX: 152 base = 16; 153 break; 154 default: 155 break; 156 } 157 return strtol(sym->curr.val, NULL, base); 158 } 159 160 static void sym_validate_range(struct symbol *sym) 161 { 162 struct property *prop; 163 int base, val, val2; 164 char str[64]; 165 166 switch (sym->type) { 167 case S_INT: 168 base = 10; 169 break; 170 case S_HEX: 171 base = 16; 172 break; 173 default: 174 return; 175 } 176 prop = sym_get_range_prop(sym); 177 if (!prop) 178 return; 179 val = strtol(sym->curr.val, NULL, base); 180 val2 = sym_get_range_val(prop->expr->left.sym, base); 181 if (val >= val2) { 182 val2 = sym_get_range_val(prop->expr->right.sym, base); 183 if (val <= val2) 184 return; 185 } 186 if (sym->type == S_INT) 187 sprintf(str, "%d", val2); 188 else 189 sprintf(str, "0x%x", val2); 190 sym->curr.val = strdup(str); 191 } 192 193 static void sym_calc_visibility(struct symbol *sym) 194 { 195 struct property *prop; 196 tristate tri; 197 198 /* any prompt visible? */ 199 tri = no; 200 for_all_prompts(sym, prop) { 201 prop->visible.tri = expr_calc_value(prop->visible.expr); 202 tri = E_OR(tri, prop->visible.tri); 203 } 204 if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) 205 tri = yes; 206 if (sym->visible != tri) { 207 sym->visible = tri; 208 sym_set_changed(sym); 209 } 210 if (sym_is_choice_value(sym)) 211 return; 212 tri = no; 213 if (sym->rev_dep.expr) 214 tri = expr_calc_value(sym->rev_dep.expr); 215 if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 216 tri = yes; 217 if (sym->rev_dep.tri != tri) { 218 sym->rev_dep.tri = tri; 219 sym_set_changed(sym); 220 } 221 } 222 223 static struct symbol *sym_calc_choice(struct symbol *sym) 224 { 225 struct symbol *def_sym; 226 struct property *prop; 227 struct expr *e; 228 229 /* is the user choice visible? */ 230 def_sym = sym->def[S_DEF_USER].val; 231 if (def_sym) { 232 sym_calc_visibility(def_sym); 233 if (def_sym->visible != no) 234 return def_sym; 235 } 236 237 /* any of the defaults visible? */ 238 for_all_defaults(sym, prop) { 239 prop->visible.tri = expr_calc_value(prop->visible.expr); 240 if (prop->visible.tri == no) 241 continue; 242 def_sym = prop_get_symbol(prop); 243 sym_calc_visibility(def_sym); 244 if (def_sym->visible != no) 245 return def_sym; 246 } 247 248 /* just get the first visible value */ 249 prop = sym_get_choice_prop(sym); 250 for (e = prop->expr; e; e = e->left.expr) { 251 def_sym = e->right.sym; 252 sym_calc_visibility(def_sym); 253 if (def_sym->visible != no) 254 return def_sym; 255 } 256 257 /* no choice? reset tristate value */ 258 sym->curr.tri = no; 259 return NULL; 260 } 261 262 void sym_calc_value(struct symbol *sym) 263 { 264 struct symbol_value newval, oldval; 265 struct property *prop; 266 struct expr *e; 267 268 if (!sym) 269 return; 270 271 if (sym->flags & SYMBOL_VALID) 272 return; 273 sym->flags |= SYMBOL_VALID; 274 275 oldval = sym->curr; 276 277 switch (sym->type) { 278 case S_INT: 279 case S_HEX: 280 case S_STRING: 281 newval = symbol_empty.curr; 282 break; 283 case S_BOOLEAN: 284 case S_TRISTATE: 285 newval = symbol_no.curr; 286 break; 287 default: 288 sym->curr.val = sym->name; 289 sym->curr.tri = no; 290 return; 291 } 292 if (!sym_is_choice_value(sym)) 293 sym->flags &= ~SYMBOL_WRITE; 294 295 sym_calc_visibility(sym); 296 297 /* set default if recursively called */ 298 sym->curr = newval; 299 300 switch (sym_get_type(sym)) { 301 case S_BOOLEAN: 302 case S_TRISTATE: 303 if (sym_is_choice_value(sym) && sym->visible == yes) { 304 prop = sym_get_choice_prop(sym); 305 newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; 306 } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) { 307 sym->flags |= SYMBOL_WRITE; 308 if (sym_has_value(sym)) 309 newval.tri = sym->def[S_DEF_USER].tri; 310 else if (!sym_is_choice(sym)) { 311 prop = sym_get_default_prop(sym); 312 if (prop) 313 newval.tri = expr_calc_value(prop->expr); 314 } 315 newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri); 316 } else if (!sym_is_choice(sym)) { 317 prop = sym_get_default_prop(sym); 318 if (prop) { 319 sym->flags |= SYMBOL_WRITE; 320 newval.tri = expr_calc_value(prop->expr); 321 } 322 } 323 if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) 324 newval.tri = yes; 325 break; 326 case S_STRING: 327 case S_HEX: 328 case S_INT: 329 if (sym->visible != no) { 330 sym->flags |= SYMBOL_WRITE; 331 if (sym_has_value(sym)) { 332 newval.val = sym->def[S_DEF_USER].val; 333 break; 334 } 335 } 336 prop = sym_get_default_prop(sym); 337 if (prop) { 338 struct symbol *ds = prop_get_symbol(prop); 339 if (ds) { 340 sym->flags |= SYMBOL_WRITE; 341 sym_calc_value(ds); 342 newval.val = ds->curr.val; 343 } 344 } 345 break; 346 default: 347 ; 348 } 349 350 sym->curr = newval; 351 if (sym_is_choice(sym) && newval.tri == yes) 352 sym->curr.val = sym_calc_choice(sym); 353 sym_validate_range(sym); 354 355 if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { 356 sym_set_changed(sym); 357 if (modules_sym == sym) { 358 sym_set_all_changed(); 359 modules_val = modules_sym->curr.tri; 360 } 361 } 362 363 if (sym_is_choice(sym)) { 364 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); 365 prop = sym_get_choice_prop(sym); 366 for (e = prop->expr; e; e = e->left.expr) { 367 e->right.sym->flags |= flags; 368 if (flags & SYMBOL_CHANGED) 369 sym_set_changed(e->right.sym); 370 } 371 } 372 } 373 374 void sym_clear_all_valid(void) 375 { 376 struct symbol *sym; 377 int i; 378 379 for_all_symbols(i, sym) 380 sym->flags &= ~SYMBOL_VALID; 381 sym_add_change_count(1); 382 if (modules_sym) 383 sym_calc_value(modules_sym); 384 } 385 386 void sym_set_changed(struct symbol *sym) 387 { 388 struct property *prop; 389 390 sym->flags |= SYMBOL_CHANGED; 391 for (prop = sym->prop; prop; prop = prop->next) { 392 if (prop->menu) 393 prop->menu->flags |= MENU_CHANGED; 394 } 395 } 396 397 void sym_set_all_changed(void) 398 { 399 struct symbol *sym; 400 int i; 401 402 for_all_symbols(i, sym) 403 sym_set_changed(sym); 404 } 405 406 bool sym_tristate_within_range(struct symbol *sym, tristate val) 407 { 408 int type = sym_get_type(sym); 409 410 if (sym->visible == no) 411 return false; 412 413 if (type != S_BOOLEAN && type != S_TRISTATE) 414 return false; 415 416 if (type == S_BOOLEAN && val == mod) 417 return false; 418 if (sym->visible <= sym->rev_dep.tri) 419 return false; 420 if (sym_is_choice_value(sym) && sym->visible == yes) 421 return val == yes; 422 return val >= sym->rev_dep.tri && val <= sym->visible; 423 } 424 425 bool sym_set_tristate_value(struct symbol *sym, tristate val) 426 { 427 tristate oldval = sym_get_tristate_value(sym); 428 429 if (oldval != val && !sym_tristate_within_range(sym, val)) 430 return false; 431 432 if (!(sym->flags & SYMBOL_DEF_USER)) { 433 sym->flags |= SYMBOL_DEF_USER; 434 sym_set_changed(sym); 435 } 436 /* 437 * setting a choice value also resets the new flag of the choice 438 * symbol and all other choice values. 439 */ 440 if (sym_is_choice_value(sym) && val == yes) { 441 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 442 struct property *prop; 443 struct expr *e; 444 445 cs->def[S_DEF_USER].val = sym; 446 cs->flags |= SYMBOL_DEF_USER; 447 prop = sym_get_choice_prop(cs); 448 for (e = prop->expr; e; e = e->left.expr) { 449 if (e->right.sym->visible != no) 450 e->right.sym->flags |= SYMBOL_DEF_USER; 451 } 452 } 453 454 sym->def[S_DEF_USER].tri = val; 455 if (oldval != val) 456 sym_clear_all_valid(); 457 458 return true; 459 } 460 461 tristate sym_toggle_tristate_value(struct symbol *sym) 462 { 463 tristate oldval, newval; 464 465 oldval = newval = sym_get_tristate_value(sym); 466 do { 467 switch (newval) { 468 case no: 469 newval = mod; 470 break; 471 case mod: 472 newval = yes; 473 break; 474 case yes: 475 newval = no; 476 break; 477 } 478 if (sym_set_tristate_value(sym, newval)) 479 break; 480 } while (oldval != newval); 481 return newval; 482 } 483 484 bool sym_string_valid(struct symbol *sym, const char *str) 485 { 486 signed char ch; 487 488 switch (sym->type) { 489 case S_STRING: 490 return true; 491 case S_INT: 492 ch = *str++; 493 if (ch == '-') 494 ch = *str++; 495 if (!isdigit(ch)) 496 return false; 497 if (ch == '0' && *str != 0) 498 return false; 499 while ((ch = *str++)) { 500 if (!isdigit(ch)) 501 return false; 502 } 503 return true; 504 case S_HEX: 505 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) 506 str += 2; 507 ch = *str++; 508 do { 509 if (!isxdigit(ch)) 510 return false; 511 } while ((ch = *str++)); 512 return true; 513 case S_BOOLEAN: 514 case S_TRISTATE: 515 switch (str[0]) { 516 case 'y': case 'Y': 517 case 'm': case 'M': 518 case 'n': case 'N': 519 return true; 520 } 521 return false; 522 default: 523 return false; 524 } 525 } 526 527 bool sym_string_within_range(struct symbol *sym, const char *str) 528 { 529 struct property *prop; 530 int val; 531 532 switch (sym->type) { 533 case S_STRING: 534 return sym_string_valid(sym, str); 535 case S_INT: 536 if (!sym_string_valid(sym, str)) 537 return false; 538 prop = sym_get_range_prop(sym); 539 if (!prop) 540 return true; 541 val = strtol(str, NULL, 10); 542 return val >= sym_get_range_val(prop->expr->left.sym, 10) && 543 val <= sym_get_range_val(prop->expr->right.sym, 10); 544 case S_HEX: 545 if (!sym_string_valid(sym, str)) 546 return false; 547 prop = sym_get_range_prop(sym); 548 if (!prop) 549 return true; 550 val = strtol(str, NULL, 16); 551 return val >= sym_get_range_val(prop->expr->left.sym, 16) && 552 val <= sym_get_range_val(prop->expr->right.sym, 16); 553 case S_BOOLEAN: 554 case S_TRISTATE: 555 switch (str[0]) { 556 case 'y': case 'Y': 557 return sym_tristate_within_range(sym, yes); 558 case 'm': case 'M': 559 return sym_tristate_within_range(sym, mod); 560 case 'n': case 'N': 561 return sym_tristate_within_range(sym, no); 562 } 563 return false; 564 default: 565 return false; 566 } 567 } 568 569 bool sym_set_string_value(struct symbol *sym, const char *newval) 570 { 571 const char *oldval; 572 char *val; 573 int size; 574 575 switch (sym->type) { 576 case S_BOOLEAN: 577 case S_TRISTATE: 578 switch (newval[0]) { 579 case 'y': case 'Y': 580 return sym_set_tristate_value(sym, yes); 581 case 'm': case 'M': 582 return sym_set_tristate_value(sym, mod); 583 case 'n': case 'N': 584 return sym_set_tristate_value(sym, no); 585 } 586 return false; 587 default: 588 ; 589 } 590 591 if (!sym_string_within_range(sym, newval)) 592 return false; 593 594 if (!(sym->flags & SYMBOL_DEF_USER)) { 595 sym->flags |= SYMBOL_DEF_USER; 596 sym_set_changed(sym); 597 } 598 599 oldval = sym->def[S_DEF_USER].val; 600 size = strlen(newval) + 1; 601 if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { 602 size += 2; 603 sym->def[S_DEF_USER].val = val = malloc(size); 604 *val++ = '0'; 605 *val++ = 'x'; 606 } else if (!oldval || strcmp(oldval, newval)) 607 sym->def[S_DEF_USER].val = val = malloc(size); 608 else 609 return true; 610 611 strcpy(val, newval); 612 free((void *)oldval); 613 sym_clear_all_valid(); 614 615 return true; 616 } 617 618 const char *sym_get_string_value(struct symbol *sym) 619 { 620 tristate val; 621 622 switch (sym->type) { 623 case S_BOOLEAN: 624 case S_TRISTATE: 625 val = sym_get_tristate_value(sym); 626 switch (val) { 627 case no: 628 return "n"; 629 case mod: 630 return "m"; 631 case yes: 632 return "y"; 633 } 634 break; 635 default: 636 ; 637 } 638 return (const char *)sym->curr.val; 639 } 640 641 bool sym_is_changable(struct symbol *sym) 642 { 643 return sym->visible > sym->rev_dep.tri; 644 } 645 646 struct symbol *sym_lookup(const char *name, int isconst) 647 { 648 struct symbol *symbol; 649 const char *ptr; 650 char *new_name; 651 int hash = 0; 652 653 if (name) { 654 if (name[0] && !name[1]) { 655 switch (name[0]) { 656 case 'y': return &symbol_yes; 657 case 'm': return &symbol_mod; 658 case 'n': return &symbol_no; 659 } 660 } 661 for (ptr = name; *ptr; ptr++) 662 hash += *ptr; 663 hash &= 0xff; 664 665 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 666 if (!strcmp(symbol->name, name)) { 667 if ((isconst && symbol->flags & SYMBOL_CONST) || 668 (!isconst && !(symbol->flags & SYMBOL_CONST))) 669 return symbol; 670 } 671 } 672 new_name = strdup(name); 673 } else { 674 new_name = NULL; 675 hash = 256; 676 } 677 678 symbol = malloc(sizeof(*symbol)); 679 memset(symbol, 0, sizeof(*symbol)); 680 symbol->name = new_name; 681 symbol->type = S_UNKNOWN; 682 if (isconst) 683 symbol->flags |= SYMBOL_CONST; 684 685 symbol->next = symbol_hash[hash]; 686 symbol_hash[hash] = symbol; 687 688 return symbol; 689 } 690 691 struct symbol *sym_find(const char *name) 692 { 693 struct symbol *symbol = NULL; 694 const char *ptr; 695 int hash = 0; 696 697 if (!name) 698 return NULL; 699 700 if (name[0] && !name[1]) { 701 switch (name[0]) { 702 case 'y': return &symbol_yes; 703 case 'm': return &symbol_mod; 704 case 'n': return &symbol_no; 705 } 706 } 707 for (ptr = name; *ptr; ptr++) 708 hash += *ptr; 709 hash &= 0xff; 710 711 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 712 if (!strcmp(symbol->name, name) && 713 !(symbol->flags & SYMBOL_CONST)) 714 break; 715 } 716 717 return symbol; 718 } 719 720 struct symbol **sym_re_search(const char *pattern) 721 { 722 struct symbol *sym, **sym_arr = NULL; 723 int i, cnt, size; 724 regex_t re; 725 726 cnt = size = 0; 727 /* Skip if empty */ 728 if (strlen(pattern) == 0) 729 return NULL; 730 if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE)) 731 return NULL; 732 733 for_all_symbols(i, sym) { 734 if (sym->flags & SYMBOL_CONST || !sym->name) 735 continue; 736 if (regexec(&re, sym->name, 0, NULL, 0)) 737 continue; 738 if (cnt + 1 >= size) { 739 void *tmp = sym_arr; 740 size += 16; 741 sym_arr = realloc(sym_arr, size * sizeof(struct symbol *)); 742 if (!sym_arr) { 743 free(tmp); 744 return NULL; 745 } 746 } 747 sym_arr[cnt++] = sym; 748 } 749 if (sym_arr) 750 sym_arr[cnt] = NULL; 751 regfree(&re); 752 753 return sym_arr; 754 } 755 756 757 struct symbol *sym_check_deps(struct symbol *sym); 758 759 static struct symbol *sym_check_expr_deps(struct expr *e) 760 { 761 struct symbol *sym; 762 763 if (!e) 764 return NULL; 765 switch (e->type) { 766 case E_OR: 767 case E_AND: 768 sym = sym_check_expr_deps(e->left.expr); 769 if (sym) 770 return sym; 771 return sym_check_expr_deps(e->right.expr); 772 case E_NOT: 773 return sym_check_expr_deps(e->left.expr); 774 case E_EQUAL: 775 case E_UNEQUAL: 776 sym = sym_check_deps(e->left.sym); 777 if (sym) 778 return sym; 779 return sym_check_deps(e->right.sym); 780 case E_SYMBOL: 781 return sym_check_deps(e->left.sym); 782 default: 783 break; 784 } 785 printf("Oops! How to check %d?\n", e->type); 786 return NULL; 787 } 788 789 /* return NULL when dependencies are OK */ 790 struct symbol *sym_check_deps(struct symbol *sym) 791 { 792 struct symbol *sym2; 793 struct property *prop; 794 795 if (sym->flags & SYMBOL_CHECK) { 796 fprintf(stderr, "%s:%d:error: found recursive dependency: %s", 797 sym->prop->file->name, sym->prop->lineno, sym->name); 798 return sym; 799 } 800 if (sym->flags & SYMBOL_CHECKED) 801 return NULL; 802 803 sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 804 sym2 = sym_check_expr_deps(sym->rev_dep.expr); 805 if (sym2) 806 goto out; 807 808 for (prop = sym->prop; prop; prop = prop->next) { 809 if (prop->type == P_CHOICE || prop->type == P_SELECT) 810 continue; 811 sym2 = sym_check_expr_deps(prop->visible.expr); 812 if (sym2) 813 goto out; 814 if (prop->type != P_DEFAULT || sym_is_choice(sym)) 815 continue; 816 sym2 = sym_check_expr_deps(prop->expr); 817 if (sym2) 818 goto out; 819 } 820 out: 821 if (sym2) 822 fprintf(stderr, " -> %s%s", sym->name, sym2 == sym? "\n": ""); 823 sym->flags &= ~SYMBOL_CHECK; 824 return sym2; 825 } 826 827 struct property *prop_alloc(enum prop_type type, struct symbol *sym) 828 { 829 struct property *prop; 830 struct property **propp; 831 832 prop = malloc(sizeof(*prop)); 833 memset(prop, 0, sizeof(*prop)); 834 prop->type = type; 835 prop->sym = sym; 836 prop->file = current_file; 837 prop->lineno = zconf_lineno(); 838 839 /* append property to the prop list of symbol */ 840 if (sym) { 841 for (propp = &sym->prop; *propp; propp = &(*propp)->next) 842 ; 843 *propp = prop; 844 } 845 846 return prop; 847 } 848 849 struct symbol *prop_get_symbol(struct property *prop) 850 { 851 if (prop->expr && (prop->expr->type == E_SYMBOL || 852 prop->expr->type == E_CHOICE)) 853 return prop->expr->left.sym; 854 return NULL; 855 } 856 857 const char *prop_get_type_name(enum prop_type type) 858 { 859 switch (type) { 860 case P_PROMPT: 861 return "prompt"; 862 case P_COMMENT: 863 return "comment"; 864 case P_MENU: 865 return "menu"; 866 case P_DEFAULT: 867 return "default"; 868 case P_CHOICE: 869 return "choice"; 870 case P_SELECT: 871 return "select"; 872 case P_RANGE: 873 return "range"; 874 case P_UNKNOWN: 875 break; 876 } 877 return "unknown"; 878 } 879