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