Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


imported SEABIOS source tree
[palacios.git] / bios / seabios / tools / 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 #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_CONST|SYMBOL_VALID,
19 }, symbol_mod = {
20         .name = "m",
21         .curr = { "m", mod },
22         .flags = SYMBOL_CONST|SYMBOL_VALID,
23 }, symbol_no = {
24         .name = "n",
25         .curr = { "n", no },
26         .flags = SYMBOL_CONST|SYMBOL_VALID,
27 }, symbol_empty = {
28         .name = "",
29         .curr = { "", no },
30         .flags = SYMBOL_VALID,
31 };
32
33 struct symbol *sym_defconfig_list;
34 struct symbol *modules_sym;
35 tristate modules_val;
36
37 struct expr *sym_env_list;
38
39 static void sym_add_default(struct symbol *sym, const char *def)
40 {
41         struct property *prop = prop_alloc(P_DEFAULT, sym);
42
43         prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
44 }
45
46 void sym_init(void)
47 {
48         struct symbol *sym;
49         struct utsname uts;
50         static bool inited = false;
51
52         if (inited)
53                 return;
54         inited = true;
55
56         uname(&uts);
57
58         sym = sym_lookup("UNAME_RELEASE", 0);
59         sym->type = S_STRING;
60         sym->flags |= SYMBOL_AUTO;
61         sym_add_default(sym, uts.release);
62 }
63
64 enum symbol_type sym_get_type(struct symbol *sym)
65 {
66         enum symbol_type type = sym->type;
67
68         if (type == S_TRISTATE) {
69                 if (sym_is_choice_value(sym) && sym->visible == yes)
70                         type = S_BOOLEAN;
71                 else if (modules_val == no)
72                         type = S_BOOLEAN;
73         }
74         return type;
75 }
76
77 const char *sym_type_name(enum symbol_type type)
78 {
79         switch (type) {
80         case S_BOOLEAN:
81                 return "boolean";
82         case S_TRISTATE:
83                 return "tristate";
84         case S_INT:
85                 return "integer";
86         case S_HEX:
87                 return "hex";
88         case S_STRING:
89                 return "string";
90         case S_UNKNOWN:
91                 return "unknown";
92         case S_OTHER:
93                 break;
94         }
95         return "???";
96 }
97
98 struct property *sym_get_choice_prop(struct symbol *sym)
99 {
100         struct property *prop;
101
102         for_all_choices(sym, prop)
103                 return prop;
104         return NULL;
105 }
106
107 struct property *sym_get_env_prop(struct symbol *sym)
108 {
109         struct property *prop;
110
111         for_all_properties(sym, prop, P_ENV)
112                 return prop;
113         return NULL;
114 }
115
116 struct property *sym_get_default_prop(struct symbol *sym)
117 {
118         struct property *prop;
119
120         for_all_defaults(sym, prop) {
121                 prop->visible.tri = expr_calc_value(prop->visible.expr);
122                 if (prop->visible.tri != no)
123                         return prop;
124         }
125         return NULL;
126 }
127
128 static struct property *sym_get_range_prop(struct symbol *sym)
129 {
130         struct property *prop;
131
132         for_all_properties(sym, prop, P_RANGE) {
133                 prop->visible.tri = expr_calc_value(prop->visible.expr);
134                 if (prop->visible.tri != no)
135                         return prop;
136         }
137         return NULL;
138 }
139
140 static int sym_get_range_val(struct symbol *sym, int base)
141 {
142         sym_calc_value(sym);
143         switch (sym->type) {
144         case S_INT:
145                 base = 10;
146                 break;
147         case S_HEX:
148                 base = 16;
149                 break;
150         default:
151                 break;
152         }
153         return strtol(sym->curr.val, NULL, base);
154 }
155
156 static void sym_validate_range(struct symbol *sym)
157 {
158         struct property *prop;
159         int base, val, val2;
160         char str[64];
161
162         switch (sym->type) {
163         case S_INT:
164                 base = 10;
165                 break;
166         case S_HEX:
167                 base = 16;
168                 break;
169         default:
170                 return;
171         }
172         prop = sym_get_range_prop(sym);
173         if (!prop)
174                 return;
175         val = strtol(sym->curr.val, NULL, base);
176         val2 = sym_get_range_val(prop->expr->left.sym, base);
177         if (val >= val2) {
178                 val2 = sym_get_range_val(prop->expr->right.sym, base);
179                 if (val <= val2)
180                         return;
181         }
182         if (sym->type == S_INT)
183                 sprintf(str, "%d", val2);
184         else
185                 sprintf(str, "0x%x", val2);
186         sym->curr.val = strdup(str);
187 }
188
189 static void sym_calc_visibility(struct symbol *sym)
190 {
191         struct property *prop;
192         tristate tri;
193
194         /* any prompt visible? */
195         tri = no;
196         for_all_prompts(sym, prop) {
197                 prop->visible.tri = expr_calc_value(prop->visible.expr);
198                 tri = EXPR_OR(tri, prop->visible.tri);
199         }
200         if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
201                 tri = yes;
202         if (sym->visible != tri) {
203                 sym->visible = tri;
204                 sym_set_changed(sym);
205         }
206         if (sym_is_choice_value(sym))
207                 return;
208         /* defaulting to "yes" if no explicit "depends on" are given */
209         tri = yes;
210         if (sym->dir_dep.expr)
211                 tri = expr_calc_value(sym->dir_dep.expr);
212         if (tri == mod)
213                 tri = yes;
214         if (sym->dir_dep.tri != tri) {
215                 sym->dir_dep.tri = tri;
216                 sym_set_changed(sym);
217         }
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 /*
230  * Find the default symbol for a choice.
231  * First try the default values for the choice symbol
232  * Next locate the first visible choice value
233  * Return NULL if none was found
234  */
235 struct symbol *sym_choice_default(struct symbol *sym)
236 {
237         struct symbol *def_sym;
238         struct property *prop;
239         struct expr *e;
240
241         /* any of the defaults visible? */
242         for_all_defaults(sym, prop) {
243                 prop->visible.tri = expr_calc_value(prop->visible.expr);
244                 if (prop->visible.tri == no)
245                         continue;
246                 def_sym = prop_get_symbol(prop);
247                 if (def_sym->visible != no)
248                         return def_sym;
249         }
250
251         /* just get the first visible value */
252         prop = sym_get_choice_prop(sym);
253         expr_list_for_each_sym(prop->expr, e, def_sym)
254                 if (def_sym->visible != no)
255                         return def_sym;
256
257         /* failed to locate any defaults */
258         return NULL;
259 }
260
261 static struct symbol *sym_calc_choice(struct symbol *sym)
262 {
263         struct symbol *def_sym;
264         struct property *prop;
265         struct expr *e;
266
267         /* first calculate all choice values' visibilities */
268         prop = sym_get_choice_prop(sym);
269         expr_list_for_each_sym(prop->expr, e, def_sym)
270                 sym_calc_visibility(def_sym);
271
272         /* is the user choice visible? */
273         def_sym = sym->def[S_DEF_USER].val;
274         if (def_sym && def_sym->visible != no)
275                 return def_sym;
276
277         def_sym = sym_choice_default(sym);
278
279         if (def_sym == NULL)
280                 /* no choice? reset tristate value */
281                 sym->curr.tri = no;
282
283         return def_sym;
284 }
285
286 void sym_calc_value(struct symbol *sym)
287 {
288         struct symbol_value newval, oldval;
289         struct property *prop;
290         struct expr *e;
291
292         if (!sym)
293                 return;
294
295         if (sym->flags & SYMBOL_VALID)
296                 return;
297         sym->flags |= SYMBOL_VALID;
298
299         oldval = sym->curr;
300
301         switch (sym->type) {
302         case S_INT:
303         case S_HEX:
304         case S_STRING:
305                 newval = symbol_empty.curr;
306                 break;
307         case S_BOOLEAN:
308         case S_TRISTATE:
309                 newval = symbol_no.curr;
310                 break;
311         default:
312                 sym->curr.val = sym->name;
313                 sym->curr.tri = no;
314                 return;
315         }
316         if (!sym_is_choice_value(sym))
317                 sym->flags &= ~SYMBOL_WRITE;
318
319         sym_calc_visibility(sym);
320
321         /* set default if recursively called */
322         sym->curr = newval;
323
324         switch (sym_get_type(sym)) {
325         case S_BOOLEAN:
326         case S_TRISTATE:
327                 if (sym_is_choice_value(sym) && sym->visible == yes) {
328                         prop = sym_get_choice_prop(sym);
329                         newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
330                 } else {
331                         if (sym->visible != no) {
332                                 /* if the symbol is visible use the user value
333                                  * if available, otherwise try the default value
334                                  */
335                                 sym->flags |= SYMBOL_WRITE;
336                                 if (sym_has_value(sym)) {
337                                         newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
338                                                               sym->visible);
339                                         goto calc_newval;
340                                 }
341                         }
342                         if (sym->rev_dep.tri != no)
343                                 sym->flags |= SYMBOL_WRITE;
344                         if (!sym_is_choice(sym)) {
345                                 prop = sym_get_default_prop(sym);
346                                 if (prop) {
347                                         sym->flags |= SYMBOL_WRITE;
348                                         newval.tri = EXPR_AND(expr_calc_value(prop->expr),
349                                                               prop->visible.tri);
350                                 }
351                         }
352                 calc_newval:
353                         if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
354                                 struct expr *e;
355                                 e = expr_simplify_unmet_dep(sym->rev_dep.expr,
356                                     sym->dir_dep.expr);
357                                 fprintf(stderr, "warning: (");
358                                 expr_fprint(e, stderr);
359                                 fprintf(stderr, ") selects %s which has unmet direct dependencies (",
360                                         sym->name);
361                                 expr_fprint(sym->dir_dep.expr, stderr);
362                                 fprintf(stderr, ")\n");
363                                 expr_free(e);
364                         }
365                         newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
366                 }
367                 if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
368                         newval.tri = yes;
369                 break;
370         case S_STRING:
371         case S_HEX:
372         case S_INT:
373                 if (sym->visible != no) {
374                         sym->flags |= SYMBOL_WRITE;
375                         if (sym_has_value(sym)) {
376                                 newval.val = sym->def[S_DEF_USER].val;
377                                 break;
378                         }
379                 }
380                 prop = sym_get_default_prop(sym);
381                 if (prop) {
382                         struct symbol *ds = prop_get_symbol(prop);
383                         if (ds) {
384                                 sym->flags |= SYMBOL_WRITE;
385                                 sym_calc_value(ds);
386                                 newval.val = ds->curr.val;
387                         }
388                 }
389                 break;
390         default:
391                 ;
392         }
393
394         sym->curr = newval;
395         if (sym_is_choice(sym) && newval.tri == yes)
396                 sym->curr.val = sym_calc_choice(sym);
397         sym_validate_range(sym);
398
399         if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
400                 sym_set_changed(sym);
401                 if (modules_sym == sym) {
402                         sym_set_all_changed();
403                         modules_val = modules_sym->curr.tri;
404                 }
405         }
406
407         if (sym_is_choice(sym)) {
408                 struct symbol *choice_sym;
409
410                 prop = sym_get_choice_prop(sym);
411                 expr_list_for_each_sym(prop->expr, e, choice_sym) {
412                         if ((sym->flags & SYMBOL_WRITE) &&
413                             choice_sym->visible != no)
414                                 choice_sym->flags |= SYMBOL_WRITE;
415                         if (sym->flags & SYMBOL_CHANGED)
416                                 sym_set_changed(choice_sym);
417                 }
418         }
419
420         if (sym->flags & SYMBOL_AUTO)
421                 sym->flags &= ~SYMBOL_WRITE;
422 }
423
424 void sym_clear_all_valid(void)
425 {
426         struct symbol *sym;
427         int i;
428
429         for_all_symbols(i, sym)
430                 sym->flags &= ~SYMBOL_VALID;
431         sym_add_change_count(1);
432         if (modules_sym)
433                 sym_calc_value(modules_sym);
434 }
435
436 void sym_set_changed(struct symbol *sym)
437 {
438         struct property *prop;
439
440         sym->flags |= SYMBOL_CHANGED;
441         for (prop = sym->prop; prop; prop = prop->next) {
442                 if (prop->menu)
443                         prop->menu->flags |= MENU_CHANGED;
444         }
445 }
446
447 void sym_set_all_changed(void)
448 {
449         struct symbol *sym;
450         int i;
451
452         for_all_symbols(i, sym)
453                 sym_set_changed(sym);
454 }
455
456 bool sym_tristate_within_range(struct symbol *sym, tristate val)
457 {
458         int type = sym_get_type(sym);
459
460         if (sym->visible == no)
461                 return false;
462
463         if (type != S_BOOLEAN && type != S_TRISTATE)
464                 return false;
465
466         if (type == S_BOOLEAN && val == mod)
467                 return false;
468         if (sym->visible <= sym->rev_dep.tri)
469                 return false;
470         if (sym_is_choice_value(sym) && sym->visible == yes)
471                 return val == yes;
472         return val >= sym->rev_dep.tri && val <= sym->visible;
473 }
474
475 bool sym_set_tristate_value(struct symbol *sym, tristate val)
476 {
477         tristate oldval = sym_get_tristate_value(sym);
478
479         if (oldval != val && !sym_tristate_within_range(sym, val))
480                 return false;
481
482         if (!(sym->flags & SYMBOL_DEF_USER)) {
483                 sym->flags |= SYMBOL_DEF_USER;
484                 sym_set_changed(sym);
485         }
486         /*
487          * setting a choice value also resets the new flag of the choice
488          * symbol and all other choice values.
489          */
490         if (sym_is_choice_value(sym) && val == yes) {
491                 struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
492                 struct property *prop;
493                 struct expr *e;
494
495                 cs->def[S_DEF_USER].val = sym;
496                 cs->flags |= SYMBOL_DEF_USER;
497                 prop = sym_get_choice_prop(cs);
498                 for (e = prop->expr; e; e = e->left.expr) {
499                         if (e->right.sym->visible != no)
500                                 e->right.sym->flags |= SYMBOL_DEF_USER;
501                 }
502         }
503
504         sym->def[S_DEF_USER].tri = val;
505         if (oldval != val)
506                 sym_clear_all_valid();
507
508         return true;
509 }
510
511 tristate sym_toggle_tristate_value(struct symbol *sym)
512 {
513         tristate oldval, newval;
514
515         oldval = newval = sym_get_tristate_value(sym);
516         do {
517                 switch (newval) {
518                 case no:
519                         newval = mod;
520                         break;
521                 case mod:
522                         newval = yes;
523                         break;
524                 case yes:
525                         newval = no;
526                         break;
527                 }
528                 if (sym_set_tristate_value(sym, newval))
529                         break;
530         } while (oldval != newval);
531         return newval;
532 }
533
534 bool sym_string_valid(struct symbol *sym, const char *str)
535 {
536         signed char ch;
537
538         switch (sym->type) {
539         case S_STRING:
540                 return true;
541         case S_INT:
542                 ch = *str++;
543                 if (ch == '-')
544                         ch = *str++;
545                 if (!isdigit(ch))
546                         return false;
547                 if (ch == '0' && *str != 0)
548                         return false;
549                 while ((ch = *str++)) {
550                         if (!isdigit(ch))
551                                 return false;
552                 }
553                 return true;
554         case S_HEX:
555                 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
556                         str += 2;
557                 ch = *str++;
558                 do {
559                         if (!isxdigit(ch))
560                                 return false;
561                 } while ((ch = *str++));
562                 return true;
563         case S_BOOLEAN:
564         case S_TRISTATE:
565                 switch (str[0]) {
566                 case 'y': case 'Y':
567                 case 'm': case 'M':
568                 case 'n': case 'N':
569                         return true;
570                 }
571                 return false;
572         default:
573                 return false;
574         }
575 }
576
577 bool sym_string_within_range(struct symbol *sym, const char *str)
578 {
579         struct property *prop;
580         int val;
581
582         switch (sym->type) {
583         case S_STRING:
584                 return sym_string_valid(sym, str);
585         case S_INT:
586                 if (!sym_string_valid(sym, str))
587                         return false;
588                 prop = sym_get_range_prop(sym);
589                 if (!prop)
590                         return true;
591                 val = strtol(str, NULL, 10);
592                 return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
593                        val <= sym_get_range_val(prop->expr->right.sym, 10);
594         case S_HEX:
595                 if (!sym_string_valid(sym, str))
596                         return false;
597                 prop = sym_get_range_prop(sym);
598                 if (!prop)
599                         return true;
600                 val = strtol(str, NULL, 16);
601                 return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
602                        val <= sym_get_range_val(prop->expr->right.sym, 16);
603         case S_BOOLEAN:
604         case S_TRISTATE:
605                 switch (str[0]) {
606                 case 'y': case 'Y':
607                         return sym_tristate_within_range(sym, yes);
608                 case 'm': case 'M':
609                         return sym_tristate_within_range(sym, mod);
610                 case 'n': case 'N':
611                         return sym_tristate_within_range(sym, no);
612                 }
613                 return false;
614         default:
615                 return false;
616         }
617 }
618
619 bool sym_set_string_value(struct symbol *sym, const char *newval)
620 {
621         const char *oldval;
622         char *val;
623         int size;
624
625         switch (sym->type) {
626         case S_BOOLEAN:
627         case S_TRISTATE:
628                 switch (newval[0]) {
629                 case 'y': case 'Y':
630                         return sym_set_tristate_value(sym, yes);
631                 case 'm': case 'M':
632                         return sym_set_tristate_value(sym, mod);
633                 case 'n': case 'N':
634                         return sym_set_tristate_value(sym, no);
635                 }
636                 return false;
637         default:
638                 ;
639         }
640
641         if (!sym_string_within_range(sym, newval))
642                 return false;
643
644         if (!(sym->flags & SYMBOL_DEF_USER)) {
645                 sym->flags |= SYMBOL_DEF_USER;
646                 sym_set_changed(sym);
647         }
648
649         oldval = sym->def[S_DEF_USER].val;
650         size = strlen(newval) + 1;
651         if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
652                 size += 2;
653                 sym->def[S_DEF_USER].val = val = malloc(size);
654                 *val++ = '0';
655                 *val++ = 'x';
656         } else if (!oldval || strcmp(oldval, newval))
657                 sym->def[S_DEF_USER].val = val = malloc(size);
658         else
659                 return true;
660
661         strcpy(val, newval);
662         free((void *)oldval);
663         sym_clear_all_valid();
664
665         return true;
666 }
667
668 /*
669  * Find the default value associated to a symbol.
670  * For tristate symbol handle the modules=n case
671  * in which case "m" becomes "y".
672  * If the symbol does not have any default then fallback
673  * to the fixed default values.
674  */
675 const char *sym_get_string_default(struct symbol *sym)
676 {
677         struct property *prop;
678         struct symbol *ds;
679         const char *str;
680         tristate val;
681
682         sym_calc_visibility(sym);
683         sym_calc_value(modules_sym);
684         val = symbol_no.curr.tri;
685         str = symbol_empty.curr.val;
686
687         /* If symbol has a default value look it up */
688         prop = sym_get_default_prop(sym);
689         if (prop != NULL) {
690                 switch (sym->type) {
691                 case S_BOOLEAN:
692                 case S_TRISTATE:
693                         /* The visibility may limit the value from yes => mod */
694                         val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
695                         break;
696                 default:
697                         /*
698                          * The following fails to handle the situation
699                          * where a default value is further limited by
700                          * the valid range.
701                          */
702                         ds = prop_get_symbol(prop);
703                         if (ds != NULL) {
704                                 sym_calc_value(ds);
705                                 str = (const char *)ds->curr.val;
706                         }
707                 }
708         }
709
710         /* Handle select statements */
711         val = EXPR_OR(val, sym->rev_dep.tri);
712
713         /* transpose mod to yes if modules are not enabled */
714         if (val == mod)
715                 if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
716                         val = yes;
717
718         /* transpose mod to yes if type is bool */
719         if (sym->type == S_BOOLEAN && val == mod)
720                 val = yes;
721
722         switch (sym->type) {
723         case S_BOOLEAN:
724         case S_TRISTATE:
725                 switch (val) {
726                 case no: return "n";
727                 case mod: return "m";
728                 case yes: return "y";
729                 }
730         case S_INT:
731         case S_HEX:
732                 return str;
733         case S_STRING:
734                 return str;
735         case S_OTHER:
736         case S_UNKNOWN:
737                 break;
738         }
739         return "";
740 }
741
742 const char *sym_get_string_value(struct symbol *sym)
743 {
744         tristate val;
745
746         switch (sym->type) {
747         case S_BOOLEAN:
748         case S_TRISTATE:
749                 val = sym_get_tristate_value(sym);
750                 switch (val) {
751                 case no:
752                         return "n";
753                 case mod:
754                         return "m";
755                 case yes:
756                         return "y";
757                 }
758                 break;
759         default:
760                 ;
761         }
762         return (const char *)sym->curr.val;
763 }
764
765 bool sym_is_changable(struct symbol *sym)
766 {
767         return sym->visible > sym->rev_dep.tri;
768 }
769
770 static unsigned strhash(const char *s)
771 {
772         /* fnv32 hash */
773         unsigned hash = 2166136261U;
774         for (; *s; s++)
775                 hash = (hash ^ *s) * 0x01000193;
776         return hash;
777 }
778
779 struct symbol *sym_lookup(const char *name, int flags)
780 {
781         struct symbol *symbol;
782         char *new_name;
783         int hash;
784
785         if (name) {
786                 if (name[0] && !name[1]) {
787                         switch (name[0]) {
788                         case 'y': return &symbol_yes;
789                         case 'm': return &symbol_mod;
790                         case 'n': return &symbol_no;
791                         }
792                 }
793                 hash = strhash(name) % SYMBOL_HASHSIZE;
794
795                 for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
796                         if (symbol->name &&
797                             !strcmp(symbol->name, name) &&
798                             (flags ? symbol->flags & flags
799                                    : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
800                                 return symbol;
801                 }
802                 new_name = strdup(name);
803         } else {
804                 new_name = NULL;
805                 hash = 0;
806         }
807
808         symbol = malloc(sizeof(*symbol));
809         memset(symbol, 0, sizeof(*symbol));
810         symbol->name = new_name;
811         symbol->type = S_UNKNOWN;
812         symbol->flags |= flags;
813
814         symbol->next = symbol_hash[hash];
815         symbol_hash[hash] = symbol;
816
817         return symbol;
818 }
819
820 struct symbol *sym_find(const char *name)
821 {
822         struct symbol *symbol = NULL;
823         int hash = 0;
824
825         if (!name)
826                 return NULL;
827
828         if (name[0] && !name[1]) {
829                 switch (name[0]) {
830                 case 'y': return &symbol_yes;
831                 case 'm': return &symbol_mod;
832                 case 'n': return &symbol_no;
833                 }
834         }
835         hash = strhash(name) % SYMBOL_HASHSIZE;
836
837         for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
838                 if (symbol->name &&
839                     !strcmp(symbol->name, name) &&
840                     !(symbol->flags & SYMBOL_CONST))
841                                 break;
842         }
843
844         return symbol;
845 }
846
847 /*
848  * Expand symbol's names embedded in the string given in argument. Symbols'
849  * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
850  * the empty string.
851  */
852 const char *sym_expand_string_value(const char *in)
853 {
854         const char *src;
855         char *res;
856         size_t reslen;
857
858         reslen = strlen(in) + 1;
859         res = malloc(reslen);
860         res[0] = '\0';
861
862         while ((src = strchr(in, '$'))) {
863                 char *p, name[SYMBOL_MAXLENGTH];
864                 const char *symval = "";
865                 struct symbol *sym;
866                 size_t newlen;
867
868                 strncat(res, in, src - in);
869                 src++;
870
871                 p = name;
872                 while (isalnum(*src) || *src == '_')
873                         *p++ = *src++;
874                 *p = '\0';
875
876                 sym = sym_find(name);
877                 if (sym != NULL) {
878                         sym_calc_value(sym);
879                         symval = sym_get_string_value(sym);
880                 }
881
882                 newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
883                 if (newlen > reslen) {
884                         reslen = newlen;
885                         res = realloc(res, reslen);
886                 }
887
888                 strcat(res, symval);
889                 in = src;
890         }
891         strcat(res, in);
892
893         return res;
894 }
895
896 struct symbol **sym_re_search(const char *pattern)
897 {
898         struct symbol *sym, **sym_arr = NULL;
899         int i, cnt, size;
900         regex_t re;
901
902         cnt = size = 0;
903         /* Skip if empty */
904         if (strlen(pattern) == 0)
905                 return NULL;
906         if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
907                 return NULL;
908
909         for_all_symbols(i, sym) {
910                 if (sym->flags & SYMBOL_CONST || !sym->name)
911                         continue;
912                 if (regexec(&re, sym->name, 0, NULL, 0))
913                         continue;
914                 if (cnt + 1 >= size) {
915                         void *tmp = sym_arr;
916                         size += 16;
917                         sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
918                         if (!sym_arr) {
919                                 free(tmp);
920                                 return NULL;
921                         }
922                 }
923                 sym_calc_value(sym);
924                 sym_arr[cnt++] = sym;
925         }
926         if (sym_arr)
927                 sym_arr[cnt] = NULL;
928         regfree(&re);
929
930         return sym_arr;
931 }
932
933 /*
934  * When we check for recursive dependencies we use a stack to save
935  * current state so we can print out relevant info to user.
936  * The entries are located on the call stack so no need to free memory.
937  * Note inser() remove() must always match to properly clear the stack.
938  */
939 static struct dep_stack {
940         struct dep_stack *prev, *next;
941         struct symbol *sym;
942         struct property *prop;
943         struct expr *expr;
944 } *check_top;
945
946 static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
947 {
948         memset(stack, 0, sizeof(*stack));
949         if (check_top)
950                 check_top->next = stack;
951         stack->prev = check_top;
952         stack->sym = sym;
953         check_top = stack;
954 }
955
956 static void dep_stack_remove(void)
957 {
958         check_top = check_top->prev;
959         if (check_top)
960                 check_top->next = NULL;
961 }
962
963 /*
964  * Called when we have detected a recursive dependency.
965  * check_top point to the top of the stact so we use
966  * the ->prev pointer to locate the bottom of the stack.
967  */
968 static void sym_check_print_recursive(struct symbol *last_sym)
969 {
970         struct dep_stack *stack;
971         struct symbol *sym, *next_sym;
972         struct menu *menu = NULL;
973         struct property *prop;
974         struct dep_stack cv_stack;
975
976         if (sym_is_choice_value(last_sym)) {
977                 dep_stack_insert(&cv_stack, last_sym);
978                 last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
979         }
980
981         for (stack = check_top; stack != NULL; stack = stack->prev)
982                 if (stack->sym == last_sym)
983                         break;
984         if (!stack) {
985                 fprintf(stderr, "unexpected recursive dependency error\n");
986                 return;
987         }
988
989         for (; stack; stack = stack->next) {
990                 sym = stack->sym;
991                 next_sym = stack->next ? stack->next->sym : last_sym;
992                 prop = stack->prop;
993                 if (prop == NULL)
994                         prop = stack->sym->prop;
995
996                 /* for choice values find the menu entry (used below) */
997                 if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
998                         for (prop = sym->prop; prop; prop = prop->next) {
999                                 menu = prop->menu;
1000                                 if (prop->menu)
1001                                         break;
1002                         }
1003                 }
1004                 if (stack->sym == last_sym)
1005                         fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
1006                                 prop->file->name, prop->lineno);
1007                 if (stack->expr) {
1008                         fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
1009                                 prop->file->name, prop->lineno,
1010                                 sym->name ? sym->name : "<choice>",
1011                                 prop_get_type_name(prop->type),
1012                                 next_sym->name ? next_sym->name : "<choice>");
1013                 } else if (stack->prop) {
1014                         fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
1015                                 prop->file->name, prop->lineno,
1016                                 sym->name ? sym->name : "<choice>",
1017                                 next_sym->name ? next_sym->name : "<choice>");
1018                 } else if (sym_is_choice(sym)) {
1019                         fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
1020                                 menu->file->name, menu->lineno,
1021                                 sym->name ? sym->name : "<choice>",
1022                                 next_sym->name ? next_sym->name : "<choice>");
1023                 } else if (sym_is_choice_value(sym)) {
1024                         fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
1025                                 menu->file->name, menu->lineno,
1026                                 sym->name ? sym->name : "<choice>",
1027                                 next_sym->name ? next_sym->name : "<choice>");
1028                 } else {
1029                         fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
1030                                 prop->file->name, prop->lineno,
1031                                 sym->name ? sym->name : "<choice>",
1032                                 next_sym->name ? next_sym->name : "<choice>");
1033                 }
1034         }
1035
1036         if (check_top == &cv_stack)
1037                 dep_stack_remove();
1038 }
1039
1040 static struct symbol *sym_check_expr_deps(struct expr *e)
1041 {
1042         struct symbol *sym;
1043
1044         if (!e)
1045                 return NULL;
1046         switch (e->type) {
1047         case E_OR:
1048         case E_AND:
1049                 sym = sym_check_expr_deps(e->left.expr);
1050                 if (sym)
1051                         return sym;
1052                 return sym_check_expr_deps(e->right.expr);
1053         case E_NOT:
1054                 return sym_check_expr_deps(e->left.expr);
1055         case E_EQUAL:
1056         case E_UNEQUAL:
1057                 sym = sym_check_deps(e->left.sym);
1058                 if (sym)
1059                         return sym;
1060                 return sym_check_deps(e->right.sym);
1061         case E_SYMBOL:
1062                 return sym_check_deps(e->left.sym);
1063         default:
1064                 break;
1065         }
1066         printf("Oops! How to check %d?\n", e->type);
1067         return NULL;
1068 }
1069
1070 /* return NULL when dependencies are OK */
1071 static struct symbol *sym_check_sym_deps(struct symbol *sym)
1072 {
1073         struct symbol *sym2;
1074         struct property *prop;
1075         struct dep_stack stack;
1076
1077         dep_stack_insert(&stack, sym);
1078
1079         sym2 = sym_check_expr_deps(sym->rev_dep.expr);
1080         if (sym2)
1081                 goto out;
1082
1083         for (prop = sym->prop; prop; prop = prop->next) {
1084                 if (prop->type == P_CHOICE || prop->type == P_SELECT)
1085                         continue;
1086                 stack.prop = prop;
1087                 sym2 = sym_check_expr_deps(prop->visible.expr);
1088                 if (sym2)
1089                         break;
1090                 if (prop->type != P_DEFAULT || sym_is_choice(sym))
1091                         continue;
1092                 stack.expr = prop->expr;
1093                 sym2 = sym_check_expr_deps(prop->expr);
1094                 if (sym2)
1095                         break;
1096                 stack.expr = NULL;
1097         }
1098
1099 out:
1100         dep_stack_remove();
1101
1102         return sym2;
1103 }
1104
1105 static struct symbol *sym_check_choice_deps(struct symbol *choice)
1106 {
1107         struct symbol *sym, *sym2;
1108         struct property *prop;
1109         struct expr *e;
1110         struct dep_stack stack;
1111
1112         dep_stack_insert(&stack, choice);
1113
1114         prop = sym_get_choice_prop(choice);
1115         expr_list_for_each_sym(prop->expr, e, sym)
1116                 sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
1117
1118         choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
1119         sym2 = sym_check_sym_deps(choice);
1120         choice->flags &= ~SYMBOL_CHECK;
1121         if (sym2)
1122                 goto out;
1123
1124         expr_list_for_each_sym(prop->expr, e, sym) {
1125                 sym2 = sym_check_sym_deps(sym);
1126                 if (sym2)
1127                         break;
1128         }
1129 out:
1130         expr_list_for_each_sym(prop->expr, e, sym)
1131                 sym->flags &= ~SYMBOL_CHECK;
1132
1133         if (sym2 && sym_is_choice_value(sym2) &&
1134             prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
1135                 sym2 = choice;
1136
1137         dep_stack_remove();
1138
1139         return sym2;
1140 }
1141
1142 struct symbol *sym_check_deps(struct symbol *sym)
1143 {
1144         struct symbol *sym2;
1145         struct property *prop;
1146
1147         if (sym->flags & SYMBOL_CHECK) {
1148                 sym_check_print_recursive(sym);
1149                 return sym;
1150         }
1151         if (sym->flags & SYMBOL_CHECKED)
1152                 return NULL;
1153
1154         if (sym_is_choice_value(sym)) {
1155                 struct dep_stack stack;
1156
1157                 /* for choice groups start the check with main choice symbol */
1158                 dep_stack_insert(&stack, sym);
1159                 prop = sym_get_choice_prop(sym);
1160                 sym2 = sym_check_deps(prop_get_symbol(prop));
1161                 dep_stack_remove();
1162         } else if (sym_is_choice(sym)) {
1163                 sym2 = sym_check_choice_deps(sym);
1164         } else {
1165                 sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
1166                 sym2 = sym_check_sym_deps(sym);
1167                 sym->flags &= ~SYMBOL_CHECK;
1168         }
1169
1170         if (sym2 && sym2 == sym)
1171                 sym2 = NULL;
1172
1173         return sym2;
1174 }
1175
1176 struct property *prop_alloc(enum prop_type type, struct symbol *sym)
1177 {
1178         struct property *prop;
1179         struct property **propp;
1180
1181         prop = malloc(sizeof(*prop));
1182         memset(prop, 0, sizeof(*prop));
1183         prop->type = type;
1184         prop->sym = sym;
1185         prop->file = current_file;
1186         prop->lineno = zconf_lineno();
1187
1188         /* append property to the prop list of symbol */
1189         if (sym) {
1190                 for (propp = &sym->prop; *propp; propp = &(*propp)->next)
1191                         ;
1192                 *propp = prop;
1193         }
1194
1195         return prop;
1196 }
1197
1198 struct symbol *prop_get_symbol(struct property *prop)
1199 {
1200         if (prop->expr && (prop->expr->type == E_SYMBOL ||
1201                            prop->expr->type == E_LIST))
1202                 return prop->expr->left.sym;
1203         return NULL;
1204 }
1205
1206 const char *prop_get_type_name(enum prop_type type)
1207 {
1208         switch (type) {
1209         case P_PROMPT:
1210                 return "prompt";
1211         case P_ENV:
1212                 return "env";
1213         case P_COMMENT:
1214                 return "comment";
1215         case P_MENU:
1216                 return "menu";
1217         case P_DEFAULT:
1218                 return "default";
1219         case P_CHOICE:
1220                 return "choice";
1221         case P_SELECT:
1222                 return "select";
1223         case P_RANGE:
1224                 return "range";
1225         case P_SYMBOL:
1226                 return "symbol";
1227         case P_UNKNOWN:
1228                 break;
1229         }
1230         return "unknown";
1231 }
1232
1233 static void prop_add_env(const char *env)
1234 {
1235         struct symbol *sym, *sym2;
1236         struct property *prop;
1237         char *p;
1238
1239         sym = current_entry->sym;
1240         sym->flags |= SYMBOL_AUTO;
1241         for_all_properties(sym, prop, P_ENV) {
1242                 sym2 = prop_get_symbol(prop);
1243                 if (strcmp(sym2->name, env))
1244                         menu_warn(current_entry, "redefining environment symbol from %s",
1245                                   sym2->name);
1246                 return;
1247         }
1248
1249         prop = prop_alloc(P_ENV, sym);
1250         prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
1251
1252         sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
1253         sym_env_list->right.sym = sym;
1254
1255         p = getenv(env);
1256         if (p)
1257                 sym_add_default(sym, p);
1258         else
1259                 menu_warn(current_entry, "environment variable %s undefined", env);
1260 }