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