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) ...@@ -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; 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 *expr_copy(struct expr *org)
{ {
struct expr *e; struct expr *e;
...@@ -158,9 +165,22 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct 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) void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
{ {
if (!e1 || !e2 || e1->type != e2->type) if (!e1 || !e2)
return; 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); e1 = expr_eliminate_yn(e1);
e2 = expr_eliminate_yn(e2); e2 = expr_eliminate_yn(e2);
} }
...@@ -1017,11 +1037,11 @@ void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, in ...@@ -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); expr_print(e->right.expr, fn, data, E_AND);
break; break;
case E_CHOICE: case E_CHOICE:
fn(data, e->right.sym->name);
if (e->left.expr) { if (e->left.expr) {
expr_print(e->left.expr, fn, data, E_CHOICE);
fn(data, " ^ "); fn(data, " ^ ");
expr_print(e->left.expr, fn, data, E_CHOICE);
} }
fn(data, e->right.sym->name);
break; break;
default: default:
{ {
......
...@@ -73,6 +73,7 @@ struct symbol { ...@@ -73,6 +73,7 @@ struct symbol {
int flags; int flags;
struct property *prop; struct property *prop;
struct expr *dep, *dep2; 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) #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 { ...@@ -97,7 +98,7 @@ struct symbol {
#define SYMBOL_HASHMASK 0xff #define SYMBOL_HASHMASK 0xff
enum prop_type { 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 { struct property {
...@@ -152,6 +153,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); ...@@ -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_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_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_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); struct expr *expr_copy(struct expr *org);
void expr_free(struct expr *e); void expr_free(struct expr *e);
int expr_eq(struct expr *e1, struct expr *e2); int expr_eq(struct expr *e1, struct expr *e2);
......
...@@ -138,7 +138,7 @@ void menu_finalize(struct menu *parent) ...@@ -138,7 +138,7 @@ void menu_finalize(struct menu *parent)
struct menu *menu, *last_menu; struct menu *menu, *last_menu;
struct symbol *sym; struct symbol *sym;
struct property *prop; struct property *prop;
struct expr *parentdep, *basedep, *dep, *dep2; struct expr *parentdep, *basedep, *dep, *dep2, **ep;
sym = parent->sym; sym = parent->sym;
if (parent->list) { if (parent->list) {
...@@ -177,6 +177,11 @@ void menu_finalize(struct menu *parent) ...@@ -177,6 +177,11 @@ void menu_finalize(struct menu *parent)
if (menu->sym && menu->sym->type != S_TRISTATE) if (menu->sym && menu->sym->type != S_TRISTATE)
dep = expr_trans_bool(dep); dep = expr_trans_bool(dep);
prop->visible.expr = 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) for (menu = parent->list; menu; menu = menu->next)
...@@ -216,12 +221,20 @@ void menu_finalize(struct menu *parent) ...@@ -216,12 +221,20 @@ void menu_finalize(struct menu *parent)
for (menu = parent->list; menu; menu = menu->next) { for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) && menu->sym) { if (sym && sym_is_choice(sym) && menu->sym) {
menu->sym->flags |= SYMBOL_CHOICEVAL; 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; current_entry = menu;
menu_set_type(sym->type); menu_set_type(sym->type);
menu_add_symbol(P_CHOICE, sym, NULL); menu_add_symbol(P_CHOICE, sym, NULL);
prop = sym_get_choice_prop(sym); prop = sym_get_choice_prop(sym);
prop->expr = expr_alloc_one(E_CHOICE, prop->expr); for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
prop->expr->right.sym = menu->sym; ;
*ep = expr_alloc_one(E_CHOICE, NULL);
(*ep)->right.sym = menu->sym;
} }
if (menu->list && (!menu->prompt || !menu->prompt->text)) { if (menu->list && (!menu->prompt || !menu->prompt->text)) {
for (last_menu = menu->list; ; last_menu = last_menu->next) { for (last_menu = menu->list; ; last_menu = last_menu->next) {
...@@ -234,20 +247,46 @@ void menu_finalize(struct menu *parent) ...@@ -234,20 +247,46 @@ void menu_finalize(struct menu *parent)
menu->list = NULL; 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) bool menu_is_visible(struct menu *menu)
{ {
struct menu *child;
struct symbol *sym;
tristate visible; tristate visible;
if (!menu->prompt) if (!menu->prompt)
return false; return false;
if (menu->sym) { sym = menu->sym;
sym_calc_value(menu->sym); if (sym) {
sym_calc_value(sym);
visible = menu->prompt->visible.tri; visible = menu->prompt->visible.tri;
} else } else
visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); 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) const char *menu_get_prompt(struct menu *menu)
......
...@@ -133,17 +133,25 @@ struct property *sym_get_default_prop(struct symbol *sym) ...@@ -133,17 +133,25 @@ struct property *sym_get_default_prop(struct symbol *sym)
static void sym_calc_visibility(struct symbol *sym) static void sym_calc_visibility(struct symbol *sym)
{ {
struct property *prop; struct property *prop;
tristate visible, oldvisible; tristate tri;
/* any prompt visible? */ /* any prompt visible? */
oldvisible = sym->visible; tri = no;
visible = no;
for_all_prompts(sym, prop) { for_all_prompts(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr); 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) { if (sym->visible != tri) {
sym->visible = visible; 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); sym_set_changed(sym);
} }
} }
...@@ -195,6 +203,7 @@ void sym_calc_value(struct symbol *sym) ...@@ -195,6 +203,7 @@ void sym_calc_value(struct symbol *sym)
if (sym->flags & SYMBOL_VALID) if (sym->flags & SYMBOL_VALID)
return; return;
sym->flags |= SYMBOL_VALID;
oldval = sym->curr; oldval = sym->curr;
...@@ -209,11 +218,10 @@ void sym_calc_value(struct symbol *sym) ...@@ -209,11 +218,10 @@ void sym_calc_value(struct symbol *sym)
newval = symbol_no.curr; newval = symbol_no.curr;
break; break;
default: default:
newval.val = sym->name; sym->curr.val = sym->name;
newval.tri = no; sym->curr.tri = no;
goto out; return;
} }
sym->flags |= SYMBOL_VALID;
if (!sym_is_choice_value(sym)) if (!sym_is_choice_value(sym))
sym->flags &= ~SYMBOL_WRITE; sym->flags &= ~SYMBOL_WRITE;
...@@ -228,7 +236,7 @@ void sym_calc_value(struct symbol *sym) ...@@ -228,7 +236,7 @@ void sym_calc_value(struct symbol *sym)
if (sym_is_choice_value(sym) && sym->visible == yes) { if (sym_is_choice_value(sym) && sym->visible == yes) {
prop = sym_get_choice_prop(sym); prop = sym_get_choice_prop(sym);
newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; 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; sym->flags |= SYMBOL_WRITE;
if (sym_has_value(sym)) if (sym_has_value(sym))
newval.tri = sym->user.tri; newval.tri = sym->user.tri;
...@@ -237,11 +245,7 @@ void sym_calc_value(struct symbol *sym) ...@@ -237,11 +245,7 @@ void sym_calc_value(struct symbol *sym)
if (prop) if (prop)
newval.tri = expr_calc_value(prop->expr); newval.tri = expr_calc_value(prop->expr);
} }
newval.tri = E_AND(newval.tri, sym->visible); newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
/* 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;
} else if (!sym_is_choice(sym)) { } else if (!sym_is_choice(sym)) {
prop = sym_get_default_prop(sym); prop = sym_get_default_prop(sym);
if (prop) { if (prop) {
...@@ -249,6 +253,12 @@ void sym_calc_value(struct symbol *sym) ...@@ -249,6 +253,12 @@ void sym_calc_value(struct symbol *sym)
newval.tri = expr_calc_value(prop->expr); 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; break;
case S_STRING: case S_STRING:
case S_HEX: case S_HEX:
...@@ -274,23 +284,6 @@ void sym_calc_value(struct symbol *sym) ...@@ -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; sym->curr = newval;
if (sym_is_choice(sym) && newval.tri == yes) if (sym_is_choice(sym) && newval.tri == yes)
sym->curr.val = sym_calc_choice(sym); sym->curr.val = sym_calc_choice(sym);
...@@ -349,19 +342,13 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val) ...@@ -349,19 +342,13 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
if (type != S_BOOLEAN && type != S_TRISTATE) if (type != S_BOOLEAN && type != S_TRISTATE)
return false; return false;
switch (val) { if (type == S_BOOLEAN && val == mod)
case no: return false;
if (sym_is_choice_value(sym) && sym->visible == yes) if (sym->visible <= sym->rev_dep.tri)
return false; return false;
return sym_is_optional(sym); if (sym_is_choice_value(sym) && sym->visible == yes)
case mod: return val == yes;
if (sym_is_choice_value(sym) && sym->visible == yes) return val >= sym->rev_dep.tri && val <= sym->visible;
return false;
return type == S_TRISTATE;
case yes:
return type == S_BOOLEAN || sym->visible == yes;
}
return false;
} }
bool sym_set_tristate_value(struct symbol *sym, tristate val) bool sym_set_tristate_value(struct symbol *sym, tristate val)
...@@ -534,15 +521,7 @@ const char *sym_get_string_value(struct symbol *sym) ...@@ -534,15 +521,7 @@ const char *sym_get_string_value(struct symbol *sym)
bool sym_is_changable(struct symbol *sym) bool sym_is_changable(struct symbol *sym)
{ {
if (sym->visible == no) return sym->visible > sym->rev_dep.tri;
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;
} }
struct symbol *sym_lookup(const char *name, int isconst) struct symbol *sym_lookup(const char *name, int isconst)
...@@ -663,7 +642,10 @@ const char *prop_get_type_name(enum prop_type type) ...@@ -663,7 +642,10 @@ const char *prop_get_type_name(enum prop_type type)
return "default"; return "default";
case P_CHOICE: case P_CHOICE:
return "choice"; return "choice";
default: case P_SELECT:
return "unknown"; return "select";
case P_UNKNOWN:
break;
} }
return "unknown";
} }
...@@ -1406,6 +1406,7 @@ yyreduce: ...@@ -1406,6 +1406,7 @@ yyreduce:
case 36: 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()); printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
;} ;}
break; break;
......
...@@ -215,6 +215,7 @@ config_option: T_DEFAULT expr if_expr T_EOL ...@@ -215,6 +215,7 @@ config_option: T_DEFAULT expr if_expr T_EOL
config_option: T_SELECT T_WORD 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()); 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