Commit f3b837df authored by Roman Zippel's avatar Roman Zippel Committed by Ben Collins

[PATCH] reverse dependency support

The 'select' keyword defines a lower limit for symbols and allows to
select other symbols when a symbol is selected, e.g.:

config JOLIET
	bool "Microsoft Joliet CDROM extensions"
	select NLS

This means when JOLIET is selected, NLS will be selected as well.
parent 386ebbf2
......@@ -55,6 +55,13 @@ struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
}
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
{
if (!e1)
return e2;
return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
}
struct expr *expr_copy(struct expr *org)
{
struct expr *e;
......@@ -158,9 +165,22 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{
if (!e1 || !e2 || e1->type != e2->type)
if (!e1 || !e2)
return;
__expr_eliminate_eq(e1->type, ep1, ep2);
switch (e1->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e1->type, ep1, ep2);
default:
;
}
if (e1->type != e2->type) switch (e2->type) {
case E_OR:
case E_AND:
__expr_eliminate_eq(e2->type, ep1, ep2);
default:
;
}
e1 = expr_eliminate_yn(e1);
e2 = expr_eliminate_yn(e2);
}
......@@ -1017,11 +1037,11 @@ void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, in
expr_print(e->right.expr, fn, data, E_AND);
break;
case E_CHOICE:
fn(data, e->right.sym->name);
if (e->left.expr) {
expr_print(e->left.expr, fn, data, E_CHOICE);
fn(data, " ^ ");
expr_print(e->left.expr, fn, data, E_CHOICE);
}
fn(data, e->right.sym->name);
break;
default:
{
......
......@@ -73,6 +73,7 @@ struct symbol {
int flags;
struct property *prop;
struct expr *dep, *dep2;
struct expr_value rev_dep;
};
#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
......@@ -97,7 +98,7 @@ struct symbol {
#define SYMBOL_HASHMASK 0xff
enum prop_type {
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE
P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT
};
struct property {
......@@ -152,6 +153,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
struct expr *expr_copy(struct expr *org);
void expr_free(struct expr *e);
int expr_eq(struct expr *e1, struct expr *e2);
......
......@@ -138,7 +138,7 @@ void menu_finalize(struct menu *parent)
struct menu *menu, *last_menu;
struct symbol *sym;
struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2;
struct expr *parentdep, *basedep, *dep, *dep2, **ep;
sym = parent->sym;
if (parent->list) {
......@@ -177,6 +177,11 @@ void menu_finalize(struct menu *parent)
if (menu->sym && menu->sym->type != S_TRISTATE)
dep = expr_trans_bool(dep);
prop->visible.expr = dep;
if (prop->type == P_SELECT) {
struct symbol *es = prop_get_symbol(prop);
es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
}
}
}
for (menu = parent->list; menu; menu = menu->next)
......@@ -216,12 +221,20 @@ void menu_finalize(struct menu *parent)
for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) && menu->sym) {
menu->sym->flags |= SYMBOL_CHOICEVAL;
for (prop = menu->sym->prop; prop; prop = prop->next) {
if (prop->type != P_DEFAULT)
continue;
fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n",
prop->file->name, prop->lineno);
}
current_entry = menu;
menu_set_type(sym->type);
menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(sym);
prop->expr = expr_alloc_one(E_CHOICE, prop->expr);
prop->expr->right.sym = menu->sym;
for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
;
*ep = expr_alloc_one(E_CHOICE, NULL);
(*ep)->right.sym = menu->sym;
}
if (menu->list && (!menu->prompt || !menu->prompt->text)) {
for (last_menu = menu->list; ; last_menu = last_menu->next) {
......@@ -234,20 +247,46 @@ void menu_finalize(struct menu *parent)
menu->list = NULL;
}
}
if (sym && !sym_is_optional(sym) && parent->prompt) {
sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
expr_alloc_and(parent->prompt->visible.expr,
expr_alloc_symbol(&symbol_mod)));
}
}
bool menu_is_visible(struct menu *menu)
{
struct menu *child;
struct symbol *sym;
tristate visible;
if (!menu->prompt)
return false;
if (menu->sym) {
sym_calc_value(menu->sym);
sym = menu->sym;
if (sym) {
sym_calc_value(sym);
visible = menu->prompt->visible.tri;
} else
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
return visible != no;
if (sym && sym_is_choice(sym)) {
for (child = menu->list; child; child = child->next)
if (menu_is_visible(child))
break;
if (!child)
return false;
}
if (visible != no)
return true;
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
for (child = menu->list; child; child = child->next)
if (menu_is_visible(child))
return true;
return false;
}
const char *menu_get_prompt(struct menu *menu)
......
......@@ -133,17 +133,25 @@ struct property *sym_get_default_prop(struct symbol *sym)
static void sym_calc_visibility(struct symbol *sym)
{
struct property *prop;
tristate visible, oldvisible;
tristate tri;
/* any prompt visible? */
oldvisible = sym->visible;
visible = no;
tri = no;
for_all_prompts(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
visible = E_OR(visible, prop->visible.tri);
tri = E_OR(tri, prop->visible.tri);
}
if (oldvisible != visible) {
sym->visible = visible;
if (sym->visible != tri) {
sym->visible = tri;
sym_set_changed(sym);
}
if (sym_is_choice_value(sym))
return;
tri = no;
if (sym->rev_dep.expr)
tri = expr_calc_value(sym->rev_dep.expr);
if (sym->rev_dep.tri != tri) {
sym->rev_dep.tri = tri;
sym_set_changed(sym);
}
}
......@@ -195,6 +203,7 @@ void sym_calc_value(struct symbol *sym)
if (sym->flags & SYMBOL_VALID)
return;
sym->flags |= SYMBOL_VALID;
oldval = sym->curr;
......@@ -209,11 +218,10 @@ void sym_calc_value(struct symbol *sym)
newval = symbol_no.curr;
break;
default:
newval.val = sym->name;
newval.tri = no;
goto out;
sym->curr.val = sym->name;
sym->curr.tri = no;
return;
}
sym->flags |= SYMBOL_VALID;
if (!sym_is_choice_value(sym))
sym->flags &= ~SYMBOL_WRITE;
......@@ -228,7 +236,7 @@ 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->visible != 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;
......@@ -237,11 +245,7 @@ void sym_calc_value(struct symbol *sym)
if (prop)
newval.tri = expr_calc_value(prop->expr);
}
newval.tri = E_AND(newval.tri, sym->visible);
/* if the symbol is visible and not optionial,
* possibly ignore old user choice. */
if (!sym_is_optional(sym) && newval.tri == no)
newval.tri = sym->visible;
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) {
......@@ -249,6 +253,12 @@ void sym_calc_value(struct symbol *sym)
newval.tri = expr_calc_value(prop->expr);
}
}
if (sym_get_type(sym) == S_BOOLEAN) {
if (newval.tri == mod)
newval.tri = yes;
if (sym->rev_dep.tri == mod)
sym->rev_dep.tri = yes;
}
break;
case S_STRING:
case S_HEX:
......@@ -274,23 +284,6 @@ void sym_calc_value(struct symbol *sym)
;
}
switch (sym_get_type(sym)) {
case S_TRISTATE:
if (newval.tri != mod)
break;
sym_calc_value(modules_sym);
if (modules_sym->curr.tri == no)
newval.tri = yes;
break;
case S_BOOLEAN:
if (newval.tri == mod)
newval.tri = yes;
break;
default:
break;
}
out:
sym->curr = newval;
if (sym_is_choice(sym) && newval.tri == yes)
sym->curr.val = sym_calc_choice(sym);
......@@ -349,19 +342,13 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
if (type != S_BOOLEAN && type != S_TRISTATE)
return false;
switch (val) {
case no:
if (sym_is_choice_value(sym) && sym->visible == yes)
return false;
return sym_is_optional(sym);
case mod:
if (sym_is_choice_value(sym) && sym->visible == yes)
return false;
return type == S_TRISTATE;
case yes:
return type == S_BOOLEAN || sym->visible == yes;
}
return false;
if (type == S_BOOLEAN && val == mod)
return false;
if (sym->visible <= sym->rev_dep.tri)
return false;
if (sym_is_choice_value(sym) && sym->visible == yes)
return val == yes;
return val >= sym->rev_dep.tri && val <= sym->visible;
}
bool sym_set_tristate_value(struct symbol *sym, tristate val)
......@@ -534,15 +521,7 @@ const char *sym_get_string_value(struct symbol *sym)
bool sym_is_changable(struct symbol *sym)
{
if (sym->visible == no)
return false;
/* at least 'n' and 'y'/'m' is selectable */
if (sym_is_optional(sym))
return true;
/* no 'n', so 'y' and 'm' must be selectable */
if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)
return true;
return false;
return sym->visible > sym->rev_dep.tri;
}
struct symbol *sym_lookup(const char *name, int isconst)
......@@ -663,7 +642,10 @@ const char *prop_get_type_name(enum prop_type type)
return "default";
case P_CHOICE:
return "choice";
default:
return "unknown";
case P_SELECT:
return "select";
case P_UNKNOWN:
break;
}
return "unknown";
}
......@@ -1406,6 +1406,7 @@ yyreduce:
case 36:
{
menu_add_symbol(P_SELECT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr);
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
;}
break;
......
......@@ -215,6 +215,7 @@ config_option: T_DEFAULT expr if_expr T_EOL
config_option: T_SELECT T_WORD if_expr T_EOL
{
menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment