|
@@ -205,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);
|
|
@@ -216,44 +226,63 @@ 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) {
|
|
|
- sym_calc_visibility(def_sym);
|
|
|
+ expr_list_for_each_sym(prop->expr, e, def_sym)
|
|
|
if (def_sym->visible != no)
|
|
|
return def_sym;
|
|
|
- }
|
|
|
|
|
|
- /* no choice? reset tristate value */
|
|
|
- sym->curr.tri = no;
|
|
|
+ /* 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;
|
|
|
+
|
|
|
+ /* first calculate all choice values' visibilities */
|
|
|
+ prop = sym_get_choice_prop(sym);
|
|
|
+ expr_list_for_each_sym(prop->expr, e, def_sym)
|
|
|
+ sym_calc_visibility(def_sym);
|
|
|
+
|
|
|
+ /* 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)
|
|
|
{
|
|
|
struct symbol_value newval, oldval;
|
|
@@ -321,6 +350,14 @@ void sym_calc_value(struct symbol *sym)
|
|
|
}
|
|
|
}
|
|
|
calc_newval:
|
|
|
+ if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
|
|
|
+ fprintf(stderr, "warning: (");
|
|
|
+ expr_fprint(sym->rev_dep.expr, stderr);
|
|
|
+ fprintf(stderr, ") selects %s which has unmet direct dependencies (",
|
|
|
+ sym->name);
|
|
|
+ expr_fprint(sym->dir_dep.expr, stderr);
|
|
|
+ fprintf(stderr, ")\n");
|
|
|
+ }
|
|
|
newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
|
|
|
}
|
|
|
if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
|
|
@@ -365,12 +402,13 @@ 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);
|
|
|
}
|
|
|
}
|
|
@@ -623,6 +661,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 imay 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;
|
|
@@ -765,6 +877,110 @@ struct symbol **sym_re_search(const char *pattern)
|
|
|
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 inser() 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;
|
|
|
+
|
|
|
+ /* 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)
|
|
|
{
|
|
@@ -801,24 +1017,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;
|
|
|
}
|
|
|
|
|
@@ -827,6 +1052,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)
|
|
@@ -840,10 +1068,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)
|
|
@@ -853,6 +1079,8 @@ out:
|
|
|
prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
|
|
|
sym2 = choice;
|
|
|
|
|
|
+ dep_stack_remove();
|
|
|
+
|
|
|
return sym2;
|
|
|
}
|
|
|
|
|
@@ -862,18 +1090,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 {
|
|
@@ -882,14 +1112,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;
|
|
|
}
|
|
@@ -943,6 +1167,8 @@ 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;
|
|
|
}
|