Chameleon

Chameleon Svn Source Tree

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

Archive Download this file

Revision: 2805