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