summaryrefslogtreecommitdiff
path: root/scripts/kconfig/menu.c
Side-by-side diff
Diffstat (limited to 'scripts/kconfig/menu.c') (more/less context) (ignore whitespace changes)
-rw-r--r--scripts/kconfig/menu.c194
1 files changed, 141 insertions, 53 deletions
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 24be0ec..1631767 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -1,309 +1,397 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
* Released under the terms of the GNU GPL v2.0.
*/
#include <stdlib.h>
#include <string.h>
#define LKC_DIRECT_LINK
#include "lkc.h"
struct menu rootmenu;
struct menu *current_menu, *current_entry;
static struct menu **last_entry_ptr;
struct file *file_list;
struct file *current_file;
void menu_init(void)
{
current_entry = current_menu = &rootmenu;
last_entry_ptr = &rootmenu.list;
}
void menu_add_entry(struct symbol *sym)
{
struct menu *menu;
menu = malloc(sizeof(*menu));
memset(menu, 0, sizeof(*menu));
menu->sym = sym;
menu->parent = current_menu;
menu->file = current_file;
menu->lineno = zconf_lineno();
*last_entry_ptr = menu;
last_entry_ptr = &menu->next;
current_entry = menu;
}
void menu_end_entry(void)
{
}
void menu_add_menu(void)
{
current_menu = current_entry;
last_entry_ptr = &current_entry->list;
}
void menu_end_menu(void)
{
last_entry_ptr = &current_menu->next;
current_menu = current_menu->parent;
}
+struct expr *menu_check_dep(struct expr *e)
+{
+ if (!e)
+ return e;
+
+ switch (e->type) {
+ case E_NOT:
+ e->left.expr = menu_check_dep(e->left.expr);
+ break;
+ case E_OR:
+ case E_AND:
+ e->left.expr = menu_check_dep(e->left.expr);
+ e->right.expr = menu_check_dep(e->right.expr);
+ break;
+ case E_SYMBOL:
+ /* change 'm' into 'm' && MODULES */
+ if (e->left.sym == &symbol_mod)
+ return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+ break;
+ default:
+ break;
+ }
+ return e;
+}
+
void menu_add_dep(struct expr *dep)
{
- current_entry->dep = expr_alloc_and(current_entry->dep, dep);
+ current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
}
void menu_set_type(int type)
{
struct symbol *sym = current_entry->sym;
if (sym->type == type)
return;
if (sym->type == S_UNKNOWN) {
sym->type = type;
return;
}
- fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n",
+ fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n",
current_entry->file->name, current_entry->lineno,
sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type));
}
-struct property *create_prop(enum prop_type type)
-{
- struct property *prop;
-
- prop = malloc(sizeof(*prop));
- memset(prop, 0, sizeof(*prop));
- prop->type = type;
- prop->file = current_file;
- prop->lineno = zconf_lineno();
-
- return prop;
-}
-
-struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep)
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
{
- struct property *prop = create_prop(token);
- struct property **propp;
+ struct property *prop = prop_alloc(type, current_entry->sym);
- prop->sym = current_entry->sym;
prop->menu = current_entry;
prop->text = prompt;
- prop->def = def;
- E_EXPR(prop->visible) = dep;
+ prop->expr = expr;
+ prop->visible.expr = menu_check_dep(dep);
- if (prompt)
+ if (prompt) {
+ if (current_entry->prompt)
+ fprintf(stderr, "%s:%d: prompt redefined\n",
+ current_entry->file->name, current_entry->lineno);
current_entry->prompt = prop;
-
- /* append property to the prop list of symbol */
- if (prop->sym) {
- for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
- ;
- *propp = prop;
}
return prop;
}
-void menu_add_prompt(int token, char *prompt, struct expr *dep)
+void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
{
- current_entry->prompt = menu_add_prop(token, prompt, NULL, dep);
+ menu_add_prop(type, prompt, NULL, dep);
}
-void menu_add_default(int token, struct symbol *def, struct expr *dep)
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
{
- current_entry->prompt = menu_add_prop(token, NULL, def, dep);
+ menu_add_prop(type, NULL, expr, dep);
+}
+
+void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
+{
+ menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
}
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) {
if (sym && sym_is_choice(sym)) {
/* find the first choice value and find out choice type */
for (menu = parent->list; menu; menu = menu->next) {
if (menu->sym) {
current_entry = parent;
menu_set_type(menu->sym->type);
current_entry = menu;
menu_set_type(sym->type);
break;
}
}
parentdep = expr_alloc_symbol(sym);
} else if (parent->prompt)
- parentdep = E_EXPR(parent->prompt->visible);
+ parentdep = parent->prompt->visible.expr;
else
parentdep = parent->dep;
for (menu = parent->list; menu; menu = menu->next) {
basedep = expr_transform(menu->dep);
basedep = expr_alloc_and(expr_copy(parentdep), basedep);
basedep = expr_eliminate_dups(basedep);
menu->dep = basedep;
if (menu->sym)
prop = menu->sym->prop;
else
prop = menu->prompt;
for (; prop; prop = prop->next) {
if (prop->menu != menu)
continue;
- dep = expr_transform(E_EXPR(prop->visible));
+ dep = expr_transform(prop->visible.expr);
dep = expr_alloc_and(expr_copy(basedep), dep);
dep = expr_eliminate_dups(dep);
if (menu->sym && menu->sym->type != S_TRISTATE)
dep = expr_trans_bool(dep);
- E_EXPR(prop->visible) = 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)
menu_finalize(menu);
- } else if (sym && parent->prompt) {
- basedep = E_EXPR(parent->prompt->visible);
+ } else if (sym) {
+ basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
basedep = expr_eliminate_dups(expr_transform(basedep));
last_menu = NULL;
for (menu = parent->next; menu; menu = menu->next) {
- dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep;
+ dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
if (!expr_contains_symbol(dep, sym))
break;
if (expr_depends_symbol(dep, sym))
goto next;
dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
dep = expr_eliminate_dups(expr_transform(dep));
dep2 = expr_copy(basedep);
expr_eliminate_eq(&dep, &dep2);
expr_free(dep);
if (!expr_is_yes(dep2)) {
expr_free(dep2);
break;
}
expr_free(dep2);
next:
menu_finalize(menu);
menu->parent = parent;
last_menu = menu;
}
if (last_menu) {
parent->list = parent->next;
parent->next = last_menu->next;
last_menu->next = NULL;
}
}
for (menu = parent->list; menu; menu = menu->next) {
if (sym && sym_is_choice(sym) && menu->sym) {
menu->sym->flags |= SYMBOL_CHOICEVAL;
+ if (!menu->prompt)
+ fprintf(stderr, "%s:%d:warning: choice value must have a prompt\n",
+ menu->file->name, menu->lineno);
+ for (prop = menu->sym->prop; prop; prop = prop->next) {
+ if (prop->type == P_PROMPT && prop->menu != menu) {
+ fprintf(stderr, "%s:%d:warning: choice values currently only support a single prompt\n",
+ prop->file->name, prop->lineno);
+
+ }
+ if (prop->type == P_DEFAULT)
+ 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_prop(P_CHOICE, NULL, parent->sym, NULL);
- prop = sym_get_choice_prop(parent->sym);
- //dep = expr_alloc_one(E_CHOICE, dep);
- //dep->right.sym = menu->sym;
- prop->dep = expr_alloc_one(E_CHOICE, prop->dep);
- prop->dep->right.sym = menu->sym;
+ menu_add_symbol(P_CHOICE, sym, NULL);
+ prop = sym_get_choice_prop(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) {
last_menu->parent = parent;
if (!last_menu->next)
break;
}
last_menu->next = menu->next;
menu->next = menu->list;
menu->list = NULL;
}
}
+
+ if (sym && !(sym->flags & SYMBOL_WARNED)) {
+ struct symbol *sym2;
+ if (sym->type == S_UNKNOWN)
+ fprintf(stderr, "%s:%d:warning: config symbol defined without type\n",
+ parent->file->name, parent->lineno);
+
+ if (sym_is_choice(sym) && !parent->prompt)
+ fprintf(stderr, "%s:%d:warning: choice must have a prompt\n",
+ parent->file->name, parent->lineno);
+
+ for (prop = sym->prop; prop; prop = prop->next) {
+ switch (prop->type) {
+ case P_DEFAULT:
+ if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
+ prop->expr->type != E_SYMBOL)
+ fprintf(stderr, "%s:%d:warning: default must be a single symbol\n",
+ prop->file->name, prop->lineno);
+ break;
+ case P_SELECT:
+ sym2 = prop_get_symbol(prop);
+ if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
+ (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE))
+ fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n",
+ prop->file->name, prop->lineno);
+ break;
+ case P_RANGE:
+ if (sym->type != S_INT && sym->type != S_HEX)
+ fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n",
+ prop->file->name, prop->lineno);
+ if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
+ !sym_string_valid(sym, prop->expr->right.sym->name))
+ fprintf(stderr, "%s:%d:warning: range is invalid\n",
+ prop->file->name, prop->lineno);
+ break;
+ default:
+ ;
+ }
+ }
+ sym->flags |= SYMBOL_WARNED;
+ }
+
+ 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);
- visible = E_TRI(menu->prompt->visible);
+ sym = menu->sym;
+ if (sym) {
+ sym_calc_value(sym);
+ visible = menu->prompt->visible.tri;
} else
- visible = E_CALC(menu->prompt->visible);
- return visible != no;
+ visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr);
+
+ 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)
{
if (menu->prompt)
return menu->prompt->text;
else if (menu->sym)
return menu->sym->name;
return NULL;
}
struct menu *menu_get_root_menu(struct menu *menu)
{
return &rootmenu;
}
struct menu *menu_get_parent_menu(struct menu *menu)
{
enum prop_type type;
- while (menu != &rootmenu) {
- menu = menu->parent;
+ for (; menu != &rootmenu; menu = menu->parent) {
type = menu->prompt ? menu->prompt->type : 0;
- if (type == P_MENU || type == P_ROOTMENU)
+ if (type == P_MENU)
break;
}
return menu;
}
struct file *file_lookup(const char *name)
{
struct file *file;
for (file = file_list; file; file = file->next) {
if (!strcmp(name, file->name))
return file;
}
file = malloc(sizeof(*file));
memset(file, 0, sizeof(*file));
file->name = strdup(name);
file->next = file_list;
file_list = file;
return file;
}
int file_write_dep(const char *name)
{
struct file *file;
FILE *out;
if (!name)
name = ".config.cmd";
out = fopen("..config.tmp", "w");
if (!out)
return 1;
fprintf(out, "deps_config := \\\n");
for (file = file_list; file; file = file->next) {
if (file->next)
fprintf(out, "\t%s \\\n", file->name);
else
fprintf(out, "\t%s\n", file->name);
}
fprintf(out, "\n.config include/linux/autoconf.h: $(deps_config)\n\n$(deps_config):\n");
fclose(out);
rename("..config.tmp", name);
return 0;
}