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("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->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->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->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 modules_val = modules_sym->curr.tri; 359 360 if (sym_is_choice(sym)) { 361 int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); 362 prop = sym_get_choice_prop(sym); 363 for (e = prop->expr; e; e = e->left.expr) { 364 e->right.sym->flags |= flags; 365 if (flags & SYMBOL_CHANGED) 366 sym_set_changed(e->right.sym); 367 } 368 } 369 } 370 371 void sym_clear_all_valid(void) 372 { 373 struct symbol *sym; 374 int i; 375 376 for_all_symbols(i, sym) 377 sym->flags &= ~SYMBOL_VALID; 378 sym_change_count++; 379 if (modules_sym) 380 sym_calc_value(modules_sym); 381 } 382 383 void sym_set_changed(struct symbol *sym) 384 { 385 struct property *prop; 386 387 sym->flags |= SYMBOL_CHANGED; 388 for (prop = sym->prop; prop; prop = prop->next) { 389 if (prop->menu) 390 prop->menu->flags |= MENU_CHANGED; 391 } 392 } 393 394 void sym_set_all_changed(void) 395 { 396 struct symbol *sym; 397 int i; 398 399 for_all_symbols(i, sym) 400 sym_set_changed(sym); 401 } 402 403 bool sym_tristate_within_range(struct symbol *sym, tristate val) 404 { 405 int type = sym_get_type(sym); 406 407 if (sym->visible == no) 408 return false; 409 410 if (type != S_BOOLEAN && type != S_TRISTATE) 411 return false; 412 413 if (type == S_BOOLEAN && val == mod) 414 return false; 415 if (sym->visible <= sym->rev_dep.tri) 416 return false; 417 if (sym_is_choice_value(sym) && sym->visible == yes) 418 return val == yes; 419 return val >= sym->rev_dep.tri && val <= sym->visible; 420 } 421 422 bool sym_set_tristate_value(struct symbol *sym, tristate val) 423 { 424 tristate oldval = sym_get_tristate_value(sym); 425 426 if (oldval != val && !sym_tristate_within_range(sym, val)) 427 return false; 428 429 if (sym->flags & SYMBOL_NEW) { 430 sym->flags &= ~SYMBOL_NEW; 431 sym_set_changed(sym); 432 } 433 /* 434 * setting a choice value also resets the new flag of the choice 435 * symbol and all other choice values. 436 */ 437 if (sym_is_choice_value(sym) && val == yes) { 438 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 439 struct property *prop; 440 struct expr *e; 441 442 cs->user.val = sym; 443 cs->flags &= ~SYMBOL_NEW; 444 prop = sym_get_choice_prop(cs); 445 for (e = prop->expr; e; e = e->left.expr) { 446 if (e->right.sym->visible != no) 447 e->right.sym->flags &= ~SYMBOL_NEW; 448 } 449 } 450 451 sym->user.tri = val; 452 if (oldval != val) { 453 sym_clear_all_valid(); 454 if (sym == modules_sym) 455 sym_set_all_changed(); 456 } 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_NEW) { 595 sym->flags &= ~SYMBOL_NEW; 596 sym_set_changed(sym); 597 } 598 599 oldval = sym->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->user.val = val = malloc(size); 604 *val++ = '0'; 605 *val++ = 'x'; 606 } else if (!oldval || strcmp(oldval, newval)) 607 sym->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 symbol->flags = SYMBOL_NEW; 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 692 struct 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 721 struct 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 758 struct symbol *sym_check_deps(struct symbol *sym); 759 760 static 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 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 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 } 819 out: 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 831 struct 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 853 struct 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 861 const 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