Chameleon

Chameleon Svn Source Tree

Root/tags/2.0/i386/config/symbol.c

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

Archive Download this file

Revision: 1808