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