summaryrefslogtreecommitdiff
path: root/util/kconfig/symbol.c
diff options
context:
space:
mode:
authorPatrick Georgi <patrick@georgi-clan.de>2014-04-11 20:24:06 +0200
committerPatrick Georgi <patrick@georgi-clan.de>2014-05-07 19:39:28 +0200
commitd520840d4ca7d8fbd9c64946ee5f2d7ea44b8557 (patch)
tree0d51d363fe7ea38242199dc70edd48833d360657 /util/kconfig/symbol.c
parent99d8818af332f4db8ded058c7e5e59e2f56f7bc9 (diff)
downloadcoreboot-d520840d4ca7d8fbd9c64946ee5f2d7ea44b8557.tar.xz
kconfig: update to follow upstream more closely
This might break a bunch of stuff (eg. win32 support), but otherwise introduces nconfig (ncurses based configuration frontend), partial configuration headers for improved dependency tracking (which requires some more build system support) and various bug fixes. Change-Id: I5d8a280810c6a26fc3fd056d5d94cb9e591a0ff5 Signed-off-by: Patrick Georgi <patrick@georgi-clan.de> Reviewed-on: http://review.coreboot.org/5487 Tested-by: build bot (Jenkins) Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Diffstat (limited to 'util/kconfig/symbol.c')
-rw-r--r--util/kconfig/symbol.c556
1 files changed, 473 insertions, 83 deletions
diff --git a/util/kconfig/symbol.c b/util/kconfig/symbol.c
index 06e50a0494..7caabdb51c 100644
--- a/util/kconfig/symbol.c
+++ b/util/kconfig/symbol.c
@@ -7,11 +7,8 @@
#include <stdlib.h>
#include <string.h>
#include <regex.h>
-#ifndef WIN32
#include <sys/utsname.h>
-#endif
-#define LKC_DIRECT_LINK
#include "lkc.h"
struct symbol symbol_yes = {
@@ -38,7 +35,7 @@ tristate modules_val;
struct expr *sym_env_list;
-void sym_add_default(struct symbol *sym, const char *def)
+static void sym_add_default(struct symbol *sym, const char *def)
{
struct property *prop = prop_alloc(P_DEFAULT, sym);
@@ -48,27 +45,19 @@ void sym_add_default(struct symbol *sym, const char *def)
void sym_init(void)
{
struct symbol *sym;
-#ifndef WIN32
struct utsname uts;
-#endif
static bool inited = false;
if (inited)
return;
inited = true;
-#ifndef WIN32
uname(&uts);
-#endif
sym = sym_lookup("UNAME_RELEASE", 0);
sym->type = S_STRING;
sym->flags |= SYMBOL_AUTO;
-#ifndef WIN32
sym_add_default(sym, uts.release);
-#else
- sym_add_default(sym, "");
-#endif
}
enum symbol_type sym_get_type(struct symbol *sym)
@@ -135,7 +124,7 @@ struct property *sym_get_default_prop(struct symbol *sym)
return NULL;
}
-struct property *sym_get_range_prop(struct symbol *sym)
+static struct property *sym_get_range_prop(struct symbol *sym)
{
struct property *prop;
@@ -147,7 +136,7 @@ struct property *sym_get_range_prop(struct symbol *sym)
return NULL;
}
-static int sym_get_range_val(struct symbol *sym, int base)
+static long long sym_get_range_val(struct symbol *sym, int base)
{
sym_calc_value(sym);
switch (sym->type) {
@@ -160,13 +149,14 @@ static int sym_get_range_val(struct symbol *sym, int base)
default:
break;
}
- return strtol(sym->curr.val, NULL, base);
+ return strtoll(sym->curr.val, NULL, base);
}
static void sym_validate_range(struct symbol *sym)
{
struct property *prop;
- int base, val, val2;
+ int base;
+ long long val, val2;
char str[64];
switch (sym->type) {
@@ -182,7 +172,7 @@ static void sym_validate_range(struct symbol *sym)
prop = sym_get_range_prop(sym);
if (!prop)
return;
- val = strtol(sym->curr.val, NULL, base);
+ val = strtoll(sym->curr.val, NULL, base);
val2 = sym_get_range_val(prop->expr->left.sym, base);
if (val >= val2) {
val2 = sym_get_range_val(prop->expr->right.sym, base);
@@ -190,9 +180,9 @@ static void sym_validate_range(struct symbol *sym)
return;
}
if (sym->type == S_INT)
- sprintf(str, "%d", val2);
+ sprintf(str, "%lld", val2);
else
- sprintf(str, "0x%x", val2);
+ sprintf(str, "0x%llx", val2);
sym->curr.val = strdup(str);
}
@@ -215,6 +205,16 @@ static void sym_calc_visibility(struct symbol *sym)
}
if (sym_is_choice_value(sym))
return;
+ /* defaulting to "yes" if no explicit "depends on" are given */
+ tri = yes;
+ if (sym->dir_dep.expr)
+ tri = expr_calc_value(sym->dir_dep.expr);
+ if (tri == mod)
+ tri = yes;
+ if (sym->dir_dep.tri != tri) {
+ sym->dir_dep.tri = tri;
+ sym_set_changed(sym);
+ }
tri = no;
if (sym->rev_dep.expr)
tri = expr_calc_value(sym->rev_dep.expr);
@@ -226,42 +226,68 @@ static void sym_calc_visibility(struct symbol *sym)
}
}
-static struct symbol *sym_calc_choice(struct symbol *sym)
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
{
struct symbol *def_sym;
struct property *prop;
struct expr *e;
- /* is the user choice visible? */
- def_sym = sym->def[S_DEF_USER].val;
- if (def_sym) {
- sym_calc_visibility(def_sym);
- if (def_sym->visible != no)
- return def_sym;
- }
-
/* any of the defaults visible? */
for_all_defaults(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
if (prop->visible.tri == no)
continue;
def_sym = prop_get_symbol(prop);
- sym_calc_visibility(def_sym);
if (def_sym->visible != no)
return def_sym;
}
/* just get the first visible value */
prop = sym_get_choice_prop(sym);
+ expr_list_for_each_sym(prop->expr, e, def_sym)
+ if (def_sym->visible != no)
+ return def_sym;
+
+ /* failed to locate any defaults */
+ return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+ struct symbol *def_sym;
+ struct property *prop;
+ struct expr *e;
+ int flags;
+
+ /* first calculate all choice values' visibilities */
+ flags = sym->flags;
+ prop = sym_get_choice_prop(sym);
expr_list_for_each_sym(prop->expr, e, def_sym) {
sym_calc_visibility(def_sym);
if (def_sym->visible != no)
- return def_sym;
+ flags &= def_sym->flags;
}
- /* no choice? reset tristate value */
- sym->curr.tri = no;
- return NULL;
+ sym->flags &= flags | ~SYMBOL_DEF_USER;
+
+ /* is the user choice visible? */
+ def_sym = sym->def[S_DEF_USER].val;
+ if (def_sym && def_sym->visible != no)
+ return def_sym;
+
+ def_sym = sym_choice_default(sym);
+
+ if (def_sym == NULL)
+ /* no choice? reset tristate value */
+ sym->curr.tri = no;
+
+ return def_sym;
}
void sym_calc_value(struct symbol *sym)
@@ -275,6 +301,14 @@ void sym_calc_value(struct symbol *sym)
if (sym->flags & SYMBOL_VALID)
return;
+
+ if (sym_is_choice_value(sym) &&
+ sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
+ sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
+ prop = sym_get_choice_prop(sym);
+ sym_calc_value(prop_get_symbol(prop));
+ }
+
sym->flags |= SYMBOL_VALID;
oldval = sym->curr;
@@ -331,6 +365,18 @@ void sym_calc_value(struct symbol *sym)
}
}
calc_newval:
+ if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+ struct expr *e;
+ e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+ sym->dir_dep.expr);
+ fprintf(stderr, "warning: (");
+ expr_fprint(e, stderr);
+ fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+ sym->name);
+ expr_fprint(sym->dir_dep.expr, stderr);
+ fprintf(stderr, ")\n");
+ expr_free(e);
+ }
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
}
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
@@ -375,18 +421,22 @@ void sym_calc_value(struct symbol *sym)
if (sym_is_choice(sym)) {
struct symbol *choice_sym;
- int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
prop = sym_get_choice_prop(sym);
expr_list_for_each_sym(prop->expr, e, choice_sym) {
- choice_sym->flags |= flags;
- if (flags & SYMBOL_CHANGED)
+ if ((sym->flags & SYMBOL_WRITE) &&
+ choice_sym->visible != no)
+ choice_sym->flags |= SYMBOL_WRITE;
+ if (sym->flags & SYMBOL_CHANGED)
sym_set_changed(choice_sym);
}
}
if (sym->flags & SYMBOL_AUTO)
sym->flags &= ~SYMBOL_WRITE;
+
+ if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
+ set_all_choice_values(sym);
}
void sym_clear_all_valid(void)
@@ -545,7 +595,7 @@ bool sym_string_valid(struct symbol *sym, const char *str)
bool sym_string_within_range(struct symbol *sym, const char *str)
{
struct property *prop;
- int val;
+ long long val;
switch (sym->type) {
case S_STRING:
@@ -556,7 +606,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
prop = sym_get_range_prop(sym);
if (!prop)
return true;
- val = strtol(str, NULL, 10);
+ val = strtoll(str, NULL, 10);
return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
val <= sym_get_range_val(prop->expr->right.sym, 10);
case S_HEX:
@@ -565,7 +615,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
prop = sym_get_range_prop(sym);
if (!prop)
return true;
- val = strtol(str, NULL, 16);
+ val = strtoll(str, NULL, 16);
return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
val <= sym_get_range_val(prop->expr->right.sym, 16);
case S_BOOLEAN:
@@ -618,11 +668,11 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
size = strlen(newval) + 1;
if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
size += 2;
- sym->def[S_DEF_USER].val = val = malloc(size);
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
*val++ = '0';
*val++ = 'x';
} else if (!oldval || strcmp(oldval, newval))
- sym->def[S_DEF_USER].val = val = malloc(size);
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
else
return true;
@@ -633,6 +683,80 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
return true;
}
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+ struct property *prop;
+ struct symbol *ds;
+ const char *str;
+ tristate val;
+
+ sym_calc_visibility(sym);
+ sym_calc_value(modules_sym);
+ val = symbol_no.curr.tri;
+ str = symbol_empty.curr.val;
+
+ /* If symbol has a default value look it up */
+ prop = sym_get_default_prop(sym);
+ if (prop != NULL) {
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ /* The visibility may limit the value from yes => mod */
+ val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+ break;
+ default:
+ /*
+ * The following fails to handle the situation
+ * where a default value is further limited by
+ * the valid range.
+ */
+ ds = prop_get_symbol(prop);
+ if (ds != NULL) {
+ sym_calc_value(ds);
+ str = (const char *)ds->curr.val;
+ }
+ }
+ }
+
+ /* Handle select statements */
+ val = EXPR_OR(val, sym->rev_dep.tri);
+
+ /* transpose mod to yes if modules are not enabled */
+ if (val == mod)
+ if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+ val = yes;
+
+ /* transpose mod to yes if type is bool */
+ if (sym->type == S_BOOLEAN && val == mod)
+ val = yes;
+
+ switch (sym->type) {
+ case S_BOOLEAN:
+ case S_TRISTATE:
+ switch (val) {
+ case no: return "n";
+ case mod: return "m";
+ case yes: return "y";
+ }
+ case S_INT:
+ case S_HEX:
+ return str;
+ case S_STRING:
+ return str;
+ case S_OTHER:
+ case S_UNKNOWN:
+ break;
+ }
+ return "";
+}
+
const char *sym_get_string_value(struct symbol *sym)
{
tristate val;
@@ -645,7 +769,8 @@ const char *sym_get_string_value(struct symbol *sym)
case no:
return "n";
case mod:
- return "m";
+ sym_calc_value(modules_sym);
+ return (modules_sym->curr.tri == no) ? "n" : "m";
case yes:
return "y";
}
@@ -661,12 +786,20 @@ bool sym_is_changable(struct symbol *sym)
return sym->visible > sym->rev_dep.tri;
}
+static unsigned strhash(const char *s)
+{
+ /* fnv32 hash */
+ unsigned hash = 2166136261U;
+ for (; *s; s++)
+ hash = (hash ^ *s) * 0x01000193;
+ return hash;
+}
+
struct symbol *sym_lookup(const char *name, int flags)
{
struct symbol *symbol;
- const char *ptr;
char *new_name;
- int hash = 0;
+ int hash;
if (name) {
if (name[0] && !name[1]) {
@@ -676,12 +809,11 @@ struct symbol *sym_lookup(const char *name, int flags)
case 'n': return &symbol_no;
}
}
- for (ptr = name; *ptr; ptr++)
- hash += *ptr;
- hash &= 0xff;
+ hash = strhash(name) % SYMBOL_HASHSIZE;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (!strcmp(symbol->name, name) &&
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
(flags ? symbol->flags & flags
: !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
return symbol;
@@ -689,10 +821,10 @@ struct symbol *sym_lookup(const char *name, int flags)
new_name = strdup(name);
} else {
new_name = NULL;
- hash = 256;
+ hash = 0;
}
- symbol = malloc(sizeof(*symbol));
+ symbol = xmalloc(sizeof(*symbol));
memset(symbol, 0, sizeof(*symbol));
symbol->name = new_name;
symbol->type = S_UNKNOWN;
@@ -707,7 +839,6 @@ struct symbol *sym_lookup(const char *name, int flags)
struct symbol *sym_find(const char *name)
{
struct symbol *symbol = NULL;
- const char *ptr;
int hash = 0;
if (!name)
@@ -720,12 +851,11 @@ struct symbol *sym_find(const char *name)
case 'n': return &symbol_no;
}
}
- for (ptr = name; *ptr; ptr++)
- hash += *ptr;
- hash &= 0xff;
+ hash = strhash(name) % SYMBOL_HASHSIZE;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (!strcmp(symbol->name, name) &&
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
!(symbol->flags & SYMBOL_CONST))
break;
}
@@ -733,42 +863,292 @@ struct symbol *sym_find(const char *name)
return symbol;
}
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+ const char *src;
+ char *res;
+ size_t reslen;
+
+ reslen = strlen(in) + 1;
+ res = xmalloc(reslen);
+ res[0] = '\0';
+
+ while ((src = strchr(in, '$'))) {
+ char *p, name[SYMBOL_MAXLENGTH];
+ const char *symval = "";
+ struct symbol *sym;
+ size_t newlen;
+
+ strncat(res, in, src - in);
+ src++;
+
+ p = name;
+ while (isalnum(*src) || *src == '_')
+ *p++ = *src++;
+ *p = '\0';
+
+ sym = sym_find(name);
+ if (sym != NULL) {
+ sym_calc_value(sym);
+ symval = sym_get_string_value(sym);
+ }
+
+ newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+ if (newlen > reslen) {
+ reslen = newlen;
+ res = realloc(res, reslen);
+ }
+
+ strcat(res, symval);
+ in = src;
+ }
+ strcat(res, in);
+
+ return res;
+}
+
+const char *sym_escape_string_value(const char *in)
+{
+ const char *p;
+ size_t reslen;
+ char *res;
+ size_t l;
+
+ reslen = strlen(in) + strlen("\"\"") + 1;
+
+ p = in;
+ for (;;) {
+ l = strcspn(p, "\"\\");
+ p += l;
+
+ if (p[0] == '\0')
+ break;
+
+ reslen++;
+ p++;
+ }
+
+ res = xmalloc(reslen);
+ res[0] = '\0';
+
+ strcat(res, "\"");
+
+ p = in;
+ for (;;) {
+ l = strcspn(p, "\"\\");
+ strncat(res, p, l);
+ p += l;
+
+ if (p[0] == '\0')
+ break;
+
+ strcat(res, "\\");
+ strncat(res, p++, 1);
+ }
+
+ strcat(res, "\"");
+ return res;
+}
+
+struct sym_match {
+ struct symbol *sym;
+ off_t so, eo;
+};
+
+/* Compare matched symbols as thus:
+ * - first, symbols that match exactly
+ * - then, alphabetical sort
+ */
+static int sym_rel_comp(const void *sym1, const void *sym2)
+{
+ const struct sym_match *s1 = sym1;
+ const struct sym_match *s2 = sym2;
+ int exact1, exact2;
+
+ /* Exact match:
+ * - if matched length on symbol s1 is the length of that symbol,
+ * then this symbol should come first;
+ * - if matched length on symbol s2 is the length of that symbol,
+ * then this symbol should come first.
+ * Note: since the search can be a regexp, both symbols may match
+ * exactly; if this is the case, we can't decide which comes first,
+ * and we fallback to sorting alphabetically.
+ */
+ exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
+ exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
+ if (exact1 && !exact2)
+ return -1;
+ if (!exact1 && exact2)
+ return 1;
+
+ /* As a fallback, sort symbols alphabetically */
+ return strcmp(s1->sym->name, s2->sym->name);
+}
+
struct symbol **sym_re_search(const char *pattern)
{
struct symbol *sym, **sym_arr = NULL;
+ struct sym_match *sym_match_arr = NULL;
int i, cnt, size;
regex_t re;
+ regmatch_t match[1];
cnt = size = 0;
/* Skip if empty */
if (strlen(pattern) == 0)
return NULL;
- if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+ if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
return NULL;
for_all_symbols(i, sym) {
if (sym->flags & SYMBOL_CONST || !sym->name)
continue;
- if (regexec(&re, sym->name, 0, NULL, 0))
+ if (regexec(&re, sym->name, 1, match, 0))
continue;
- if (cnt + 1 >= size) {
- void *tmp = sym_arr;
+ if (cnt >= size) {
+ void *tmp;
size += 16;
- sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
- if (!sym_arr) {
- free(tmp);
- return NULL;
- }
+ tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
+ if (!tmp)
+ goto sym_re_search_free;
+ sym_match_arr = tmp;
}
- sym_arr[cnt++] = sym;
+ sym_calc_value(sym);
+ /* As regexec returned 0, we know we have a match, so
+ * we can use match[0].rm_[se]o without further checks
+ */
+ sym_match_arr[cnt].so = match[0].rm_so;
+ sym_match_arr[cnt].eo = match[0].rm_eo;
+ sym_match_arr[cnt++].sym = sym;
}
- if (sym_arr)
+ if (sym_match_arr) {
+ qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
+ sym_arr = malloc((cnt+1) * sizeof(struct symbol));
+ if (!sym_arr)
+ goto sym_re_search_free;
+ for (i = 0; i < cnt; i++)
+ sym_arr[i] = sym_match_arr[i].sym;
sym_arr[cnt] = NULL;
+ }
+sym_re_search_free:
+ /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
+ free(sym_match_arr);
regfree(&re);
return sym_arr;
}
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note insert() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+ struct dep_stack *prev, *next;
+ struct symbol *sym;
+ struct property *prop;
+ struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+ memset(stack, 0, sizeof(*stack));
+ if (check_top)
+ check_top->next = stack;
+ stack->prev = check_top;
+ stack->sym = sym;
+ check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+ check_top = check_top->prev;
+ if (check_top)
+ check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+ struct dep_stack *stack;
+ struct symbol *sym, *next_sym;
+ struct menu *menu = NULL;
+ struct property *prop;
+ struct dep_stack cv_stack;
+
+ if (sym_is_choice_value(last_sym)) {
+ dep_stack_insert(&cv_stack, last_sym);
+ last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+ }
+
+ for (stack = check_top; stack != NULL; stack = stack->prev)
+ if (stack->sym == last_sym)
+ break;
+ if (!stack) {
+ fprintf(stderr, "unexpected recursive dependency error\n");
+ return;
+ }
+
+ for (; stack; stack = stack->next) {
+ sym = stack->sym;
+ next_sym = stack->next ? stack->next->sym : last_sym;
+ prop = stack->prop;
+ if (prop == NULL)
+ prop = stack->sym->prop;
+
+ /* for choice values find the menu entry (used below) */
+ if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+ for (prop = sym->prop; prop; prop = prop->next) {
+ menu = prop->menu;
+ if (prop->menu)
+ break;
+ }
+ }
+ if (stack->sym == last_sym)
+ fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+ prop->file->name, prop->lineno);
+ if (stack->expr) {
+ fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ prop_get_type_name(prop->type),
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (stack->prop) {
+ fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice(sym)) {
+ fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else if (sym_is_choice_value(sym)) {
+ fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+ menu->file->name, menu->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ } else {
+ fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+ prop->file->name, prop->lineno,
+ sym->name ? sym->name : "<choice>",
+ next_sym->name ? next_sym->name : "<choice>");
+ }
+ }
+
+ if (check_top == &cv_stack)
+ dep_stack_remove();
+}
static struct symbol *sym_check_expr_deps(struct expr *e)
{
@@ -805,24 +1185,33 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, sym);
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
if (sym2)
- return sym2;
+ goto out;
for (prop = sym->prop; prop; prop = prop->next) {
if (prop->type == P_CHOICE || prop->type == P_SELECT)
continue;
+ stack.prop = prop;
sym2 = sym_check_expr_deps(prop->visible.expr);
if (sym2)
break;
if (prop->type != P_DEFAULT || sym_is_choice(sym))
continue;
+ stack.expr = prop->expr;
sym2 = sym_check_expr_deps(prop->expr);
if (sym2)
break;
+ stack.expr = NULL;
}
+out:
+ dep_stack_remove();
+
return sym2;
}
@@ -831,6 +1220,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
struct symbol *sym, *sym2;
struct property *prop;
struct expr *e;
+ struct dep_stack stack;
+
+ dep_stack_insert(&stack, choice);
prop = sym_get_choice_prop(choice);
expr_list_for_each_sym(prop->expr, e, sym)
@@ -844,10 +1236,8 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
expr_list_for_each_sym(prop->expr, e, sym) {
sym2 = sym_check_sym_deps(sym);
- if (sym2) {
- fprintf(stderr, " -> %s", sym->name);
+ if (sym2)
break;
- }
}
out:
expr_list_for_each_sym(prop->expr, e, sym)
@@ -857,6 +1247,8 @@ out:
prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
sym2 = choice;
+ dep_stack_remove();
+
return sym2;
}
@@ -866,18 +1258,20 @@ struct symbol *sym_check_deps(struct symbol *sym)
struct property *prop;
if (sym->flags & SYMBOL_CHECK) {
- fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
- sym->prop->file->name, sym->prop->lineno,
- sym->name ? sym->name : "<choice>");
+ sym_check_print_recursive(sym);
return sym;
}
if (sym->flags & SYMBOL_CHECKED)
return NULL;
if (sym_is_choice_value(sym)) {
+ struct dep_stack stack;
+
/* for choice groups start the check with main choice symbol */
+ dep_stack_insert(&stack, sym);
prop = sym_get_choice_prop(sym);
sym2 = sym_check_deps(prop_get_symbol(prop));
+ dep_stack_remove();
} else if (sym_is_choice(sym)) {
sym2 = sym_check_choice_deps(sym);
} else {
@@ -886,14 +1280,8 @@ struct symbol *sym_check_deps(struct symbol *sym)
sym->flags &= ~SYMBOL_CHECK;
}
- if (sym2) {
- fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
- if (sym2 == sym) {
- fprintf(stderr, "\n");
- zconfnerrs++;
- sym2 = NULL;
- }
- }
+ if (sym2 && sym2 == sym)
+ sym2 = NULL;
return sym2;
}
@@ -903,7 +1291,7 @@ struct property *prop_alloc(enum prop_type type, struct symbol *sym)
struct property *prop;
struct property **propp;
- prop = malloc(sizeof(*prop));
+ prop = xmalloc(sizeof(*prop));
memset(prop, 0, sizeof(*prop));
prop->type = type;
prop->sym = sym;
@@ -947,13 +1335,15 @@ const char *prop_get_type_name(enum prop_type type)
return "select";
case P_RANGE:
return "range";
+ case P_SYMBOL:
+ return "symbol";
case P_UNKNOWN:
break;
}
return "unknown";
}
-void prop_add_env(const char *env)
+static void prop_add_env(const char *env)
{
struct symbol *sym, *sym2;
struct property *prop;