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