aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/config/symbol.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-04-18 12:05:16 +0000
committerFelix Fietkau <nbd@openwrt.org>2013-04-18 12:05:16 +0000
commit9d5510a500a1804484152adb8951dda3688658bc (patch)
tree6e4d8725c2956742201d0e14126f7e457b453c66 /scripts/config/symbol.c
parent97e7fdf6fdb8a91da52f622b499181171262af19 (diff)
downloadupstream-9d5510a500a1804484152adb8951dda3688658bc.tar.gz
upstream-9d5510a500a1804484152adb8951dda3688658bc.tar.bz2
upstream-9d5510a500a1804484152adb8951dda3688658bc.zip
build: add new menuconfig code based on linux 3.9
SVN-Revision: 36361
Diffstat (limited to 'scripts/config/symbol.c')
-rw-r--r--scripts/config/symbol.c695
1 files changed, 553 insertions, 142 deletions
diff --git a/scripts/config/symbol.c b/scripts/config/symbol.c
index 49bb254558..ecc5aa5f86 100644
--- a/scripts/config/symbol.c
+++ b/scripts/config/symbol.c
@@ -9,43 +9,43 @@
#include <regex.h>
#include <sys/utsname.h>
-#define LKC_DIRECT_LINK
#include "lkc.h"
struct symbol symbol_yes = {
.name = "y",
.curr = { "y", yes },
- .flags = SYMBOL_YES|SYMBOL_VALID,
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
}, symbol_mod = {
.name = "m",
.curr = { "m", mod },
- .flags = SYMBOL_MOD|SYMBOL_VALID,
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
}, symbol_no = {
.name = "n",
.curr = { "n", no },
- .flags = SYMBOL_NO|SYMBOL_VALID,
+ .flags = SYMBOL_CONST|SYMBOL_VALID,
}, symbol_empty = {
.name = "",
.curr = { "", no },
.flags = SYMBOL_VALID,
};
-int sym_change_count;
+struct symbol *sym_defconfig_list;
struct symbol *modules_sym;
tristate modules_val;
-void sym_add_default(struct symbol *sym, const char *def)
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
{
struct property *prop = prop_alloc(P_DEFAULT, sym);
- prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+ prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
}
void sym_init(void)
{
struct symbol *sym;
struct utsname uts;
- char *p;
static bool inited = false;
if (inited)
@@ -54,19 +54,6 @@ void sym_init(void)
uname(&uts);
- sym = sym_lookup("ARCH", 0);
- sym->type = S_STRING;
- p = getenv("ARCH");
- if (p)
- sym_add_default(sym, p);
-
- sym = sym_lookup("OPENWRTVERSION", 0);
- sym->type = S_STRING;
- sym->flags |= SYMBOL_AUTO;
- p = getenv("OPENWRTVERSION");
- if (p)
- sym_add_default(sym, p);
-
sym = sym_lookup("UNAME_RELEASE", 0);
sym->type = S_STRING;
sym->flags |= SYMBOL_AUTO;
@@ -80,11 +67,8 @@ enum symbol_type sym_get_type(struct symbol *sym)
if (type == S_TRISTATE) {
if (sym_is_choice_value(sym) && sym->visible == yes)
type = S_BOOLEAN;
-/* tristate always enabled */
-#if 0
else if (modules_val == no)
type = S_BOOLEAN;
-#endif
}
return type;
}
@@ -119,6 +103,15 @@ struct property *sym_get_choice_prop(struct symbol *sym)
return NULL;
}
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+ struct property *prop;
+
+ for_all_properties(sym, prop, P_ENV)
+ return prop;
+ return NULL;
+}
+
struct property *sym_get_default_prop(struct symbol *sym)
{
struct property *prop;
@@ -131,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;
@@ -196,26 +189,31 @@ static void sym_calc_visibility(struct symbol *sym)
{
struct property *prop;
tristate tri;
- int deselected = 0;
/* any prompt visible? */
tri = no;
for_all_prompts(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
- tri = E_OR(tri, prop->visible.tri);
+ tri = EXPR_OR(tri, prop->visible.tri);
}
- if (tri == mod && (sym->type != S_TRISTATE))
+ if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
tri = yes;
- if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) {
- tri = no;
- deselected = 1;
- }
if (sym->visible != tri) {
sym->visible = tri;
sym_set_changed(sym);
}
- if (sym_is_choice_value(sym) || deselected)
+ 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);
@@ -227,63 +225,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->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);
- for (e = prop->expr; e; e = e->left.expr) {
- def_sym = e->right.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;
}
-void sym_set_changed(struct symbol *sym)
+static struct symbol *sym_calc_choice(struct symbol *sym)
{
+ struct symbol *def_sym;
struct property *prop;
+ struct expr *e;
+ int flags;
- sym->flags |= SYMBOL_CHANGED;
- for (prop = sym->prop; prop; prop = prop->next) {
- if (prop->menu)
- prop->menu->flags |= MENU_CHANGED;
+ /* 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)
+ flags &= def_sym->flags;
}
-}
-void sym_set_all_changed(void)
-{
- struct symbol *sym;
- int i;
+ sym->flags &= flags | ~SYMBOL_DEF_USER;
- for_all_symbols(i, sym)
- sym_set_changed(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)
@@ -330,24 +333,42 @@ void sym_calc_value(struct symbol *sym)
if (sym_is_choice_value(sym) && sym->visible == yes) {
prop = sym_get_choice_prop(sym);
newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
- } else if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) {
- newval.tri = no;
- } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
- sym->flags |= SYMBOL_WRITE;
- if (sym_has_value(sym))
- newval.tri = sym->user.tri;
- else if (!sym_is_choice(sym)) {
- prop = sym_get_default_prop(sym);
- if (prop)
- newval.tri = expr_calc_value(prop->expr);
+ } else {
+ if (sym->visible != no) {
+ /* if the symbol is visible use the user value
+ * if available, otherwise try the default value
+ */
+ sym->flags |= SYMBOL_WRITE;
+ if (sym_has_value(sym)) {
+ newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+ sym->visible);
+ goto calc_newval;
+ }
}
- newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
- } else if (!sym_is_choice(sym)) {
- prop = sym_get_default_prop(sym);
- if (prop) {
+ if (sym->rev_dep.tri != no)
sym->flags |= SYMBOL_WRITE;
- newval.tri = expr_calc_value(prop->expr);
+ if (!sym_is_choice(sym)) {
+ prop = sym_get_default_prop(sym);
+ if (prop) {
+ sym->flags |= SYMBOL_WRITE;
+ newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+ prop->visible.tri);
+ }
+ }
+ 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)
newval.tri = yes;
@@ -358,7 +379,7 @@ void sym_calc_value(struct symbol *sym)
if (sym->visible != no) {
sym->flags |= SYMBOL_WRITE;
if (sym_has_value(sym)) {
- newval.val = sym->user.val;
+ newval.val = sym->def[S_DEF_USER].val;
break;
}
}
@@ -382,7 +403,6 @@ void sym_calc_value(struct symbol *sym)
sym_validate_range(sym);
if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
- sym->flags &= ~SYMBOL_VALID;
sym_set_changed(sym);
if (modules_sym == sym) {
sym_set_all_changed();
@@ -391,12 +411,15 @@ void sym_calc_value(struct symbol *sym)
}
if (sym_is_choice(sym)) {
- int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+ struct symbol *choice_sym;
+
prop = sym_get_choice_prop(sym);
- for (e = prop->expr; e; e = e->left.expr) {
- e->right.sym->flags |= flags;
- if (flags & SYMBOL_CHANGED)
- sym_set_changed(e->right.sym);
+ expr_list_for_each_sym(prop->expr, e, choice_sym) {
+ if ((sym->flags & SYMBOL_WRITE) &&
+ choice_sym->visible != no)
+ choice_sym->flags |= SYMBOL_WRITE;
+ if (sym->flags & SYMBOL_CHANGED)
+ sym_set_changed(choice_sym);
}
}
@@ -411,11 +434,31 @@ void sym_clear_all_valid(void)
for_all_symbols(i, sym)
sym->flags &= ~SYMBOL_VALID;
- sym_change_count++;
+ sym_add_change_count(1);
if (modules_sym)
sym_calc_value(modules_sym);
}
+void sym_set_changed(struct symbol *sym)
+{
+ struct property *prop;
+
+ sym->flags |= SYMBOL_CHANGED;
+ for (prop = sym->prop; prop; prop = prop->next) {
+ if (prop->menu)
+ prop->menu->flags |= MENU_CHANGED;
+ }
+}
+
+void sym_set_all_changed(void)
+{
+ struct symbol *sym;
+ int i;
+
+ for_all_symbols(i, sym)
+ sym_set_changed(sym);
+}
+
bool sym_tristate_within_range(struct symbol *sym, tristate val)
{
int type = sym_get_type(sym);
@@ -442,8 +485,8 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
if (oldval != val && !sym_tristate_within_range(sym, val))
return false;
- if (sym->flags & SYMBOL_NEW) {
- sym->flags &= ~SYMBOL_NEW;
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
sym_set_changed(sym);
}
/*
@@ -455,19 +498,18 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
struct property *prop;
struct expr *e;
- cs->user.val = sym;
- cs->flags &= ~SYMBOL_NEW;
+ cs->def[S_DEF_USER].val = sym;
+ cs->flags |= SYMBOL_DEF_USER;
prop = sym_get_choice_prop(cs);
for (e = prop->expr; e; e = e->left.expr) {
if (e->right.sym->visible != no)
- e->right.sym->flags &= ~SYMBOL_NEW;
+ e->right.sym->flags |= SYMBOL_DEF_USER;
}
}
- sym->user.tri = val;
- if (oldval != val) {
+ sym->def[S_DEF_USER].tri = val;
+ if (oldval != val)
sym_clear_all_valid();
- }
return true;
}
@@ -605,20 +647,20 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
if (!sym_string_within_range(sym, newval))
return false;
- if (sym->flags & SYMBOL_NEW) {
- sym->flags &= ~SYMBOL_NEW;
+ if (!(sym->flags & SYMBOL_DEF_USER)) {
+ sym->flags |= SYMBOL_DEF_USER;
sym_set_changed(sym);
}
- oldval = sym->user.val;
+ oldval = sym->def[S_DEF_USER].val;
size = strlen(newval) + 1;
if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
size += 2;
- sym->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->user.val = val = malloc(size);
+ sym->def[S_DEF_USER].val = val = xmalloc(size);
else
return true;
@@ -629,6 +671,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;
@@ -641,7 +757,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";
}
@@ -657,12 +774,20 @@ bool sym_is_changable(struct symbol *sym)
return sym->visible > sym->rev_dep.tri;
}
-struct symbol *sym_lookup(const char *name, int isconst)
+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]) {
@@ -672,30 +797,26 @@ struct symbol *sym_lookup(const char *name, int isconst)
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 ((isconst && symbol->flags & SYMBOL_CONST) ||
- (!isconst && !(symbol->flags & SYMBOL_CONST)))
- return symbol;
- }
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
+ (flags ? symbol->flags & flags
+ : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+ return symbol;
}
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;
- symbol->flags = SYMBOL_NEW;
- if (isconst)
- symbol->flags |= SYMBOL_CONST;
+ symbol->flags |= flags;
symbol->next = symbol_hash[hash];
symbol_hash[hash] = symbol;
@@ -706,7 +827,6 @@ struct symbol *sym_lookup(const char *name, int isconst)
struct symbol *sym_find(const char *name)
{
struct symbol *symbol = NULL;
- const char *ptr;
int hash = 0;
if (!name)
@@ -719,12 +839,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;
}
@@ -732,6 +851,98 @@ 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 symbol **sym_re_search(const char *pattern)
{
struct symbol *sym, **sym_arr = NULL;
@@ -769,8 +980,112 @@ 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));
+ }
-struct symbol *sym_check_deps(struct symbol *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)
{
@@ -802,44 +1117,109 @@ static struct symbol *sym_check_expr_deps(struct expr *e)
return NULL;
}
-struct symbol *sym_check_deps(struct symbol *sym)
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
{
struct symbol *sym2;
struct property *prop;
+ struct dep_stack stack;
- if (sym->flags & SYMBOL_CHECK) {
- printf("Warning! Found recursive dependency: %s", sym->name);
- return sym;
- }
- if (sym->flags & SYMBOL_CHECKED)
- return NULL;
+ dep_stack_insert(&stack, sym);
- sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
sym2 = sym_check_expr_deps(sym->rev_dep.expr);
if (sym2)
goto out;
for (prop = sym->prop; prop; prop = prop->next) {
- if (prop->type == P_CHOICE || prop->type == P_SELECT || prop->type == P_DESELECT)
+ if (prop->type == P_CHOICE || prop->type == P_SELECT)
continue;
+ stack.prop = prop;
sym2 = sym_check_expr_deps(prop->visible.expr);
if (sym2)
- goto out;
+ break;
if (prop->type != P_DEFAULT || sym_is_choice(sym))
continue;
+ stack.expr = prop->expr;
sym2 = sym_check_expr_deps(prop->expr);
if (sym2)
- goto out;
+ break;
+ stack.expr = NULL;
}
+
out:
- if (sym2) {
- printf(" %s", sym->name);
- if (sym2 == sym) {
- printf("\n");
- sym2 = NULL;
- }
+ dep_stack_remove();
+
+ return sym2;
+}
+
+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)
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+ choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(choice);
+ choice->flags &= ~SYMBOL_CHECK;
+ if (sym2)
+ goto out;
+
+ expr_list_for_each_sym(prop->expr, e, sym) {
+ sym2 = sym_check_sym_deps(sym);
+ if (sym2)
+ break;
+ }
+out:
+ expr_list_for_each_sym(prop->expr, e, sym)
+ sym->flags &= ~SYMBOL_CHECK;
+
+ if (sym2 && sym_is_choice_value(sym2) &&
+ prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+ sym2 = choice;
+
+ dep_stack_remove();
+
+ return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+ struct symbol *sym2;
+ struct property *prop;
+
+ if (sym->flags & SYMBOL_CHECK) {
+ sym_check_print_recursive(sym);
+ return sym;
}
- sym->flags &= ~SYMBOL_CHECK;
+ 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 {
+ sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+ sym2 = sym_check_sym_deps(sym);
+ sym->flags &= ~SYMBOL_CHECK;
+ }
+
+ if (sym2 && sym2 == sym)
+ sym2 = NULL;
+
return sym2;
}
@@ -848,7 +1228,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;
@@ -868,7 +1248,7 @@ struct property *prop_alloc(enum prop_type type, struct symbol *sym)
struct symbol *prop_get_symbol(struct property *prop)
{
if (prop->expr && (prop->expr->type == E_SYMBOL ||
- prop->expr->type == E_CHOICE))
+ prop->expr->type == E_LIST))
return prop->expr->left.sym;
return NULL;
}
@@ -878,6 +1258,8 @@ const char *prop_get_type_name(enum prop_type type)
switch (type) {
case P_PROMPT:
return "prompt";
+ case P_ENV:
+ return "env";
case P_COMMENT:
return "comment";
case P_MENU:
@@ -888,12 +1270,41 @@ const char *prop_get_type_name(enum prop_type type)
return "choice";
case P_SELECT:
return "select";
- case P_DESELECT:
- return "deselect";
case P_RANGE:
return "range";
+ case P_SYMBOL:
+ return "symbol";
case P_UNKNOWN:
break;
}
return "unknown";
}
+
+static void prop_add_env(const char *env)
+{
+ struct symbol *sym, *sym2;
+ struct property *prop;
+ char *p;
+
+ sym = current_entry->sym;
+ sym->flags |= SYMBOL_AUTO;
+ for_all_properties(sym, prop, P_ENV) {
+ sym2 = prop_get_symbol(prop);
+ if (strcmp(sym2->name, env))
+ menu_warn(current_entry, "redefining environment symbol from %s",
+ sym2->name);
+ return;
+ }
+
+ prop = prop_alloc(P_ENV, sym);
+ prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+ sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+ sym_env_list->right.sym = sym;
+
+ p = getenv(env);
+ if (p)
+ sym_add_default(sym, p);
+ else
+ menu_warn(current_entry, "environment variable %s undefined", env);
+}