add initial version of a package feeds management script
[openwrt/openwrt.git] / scripts / config / symbol.c
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("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
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 /* tristate always enabled */
85 #if 0
86 else if (modules_val == no)
87 type = S_BOOLEAN;
88 #endif
89 }
90 return type;
91 }
92
93 const 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
114 struct 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
123 struct 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
135 struct 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
147 static 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
163 static 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
196 static 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
231 static 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
270 void 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
382 void 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
394 void 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
405 void 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
414 bool 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
433 bool 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
472 tristate 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
495 bool 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
538 bool 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
580 bool 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
629 const 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
652 bool sym_is_changable(struct symbol *sym)
653 {
654 return sym->visible > sym->rev_dep.tri;
655 }
656
657 struct 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
703 struct 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
732 struct 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
769 struct symbol *sym_check_deps(struct symbol *sym);
770
771 static 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
801 struct 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 }
830 out:
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
842 struct 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
864 struct 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
872 const 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 }