diff options
Diffstat (limited to 'scripts/kconfig/symbol.c')
| -rw-r--r-- | scripts/kconfig/symbol.c | 949 |
1 files changed, 467 insertions, 482 deletions
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index d550300ec00c..7e81b3676ee9 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -1,75 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> - * Released under the terms of the GNU GPL v2.0. */ +#include <sys/types.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <regex.h> -#include <sys/utsname.h> +#include <hash.h> +#include <xalloc.h> +#include "internal.h" #include "lkc.h" struct symbol symbol_yes = { .name = "y", + .type = S_TRISTATE, .curr = { "y", yes }, + .menus = LIST_HEAD_INIT(symbol_yes.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_mod = { +}; + +struct symbol symbol_mod = { .name = "m", + .type = S_TRISTATE, .curr = { "m", mod }, + .menus = LIST_HEAD_INIT(symbol_mod.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_no = { +}; + +struct symbol symbol_no = { .name = "n", + .type = S_TRISTATE, .curr = { "n", no }, + .menus = LIST_HEAD_INIT(symbol_no.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_empty = { - .name = "", - .curr = { "", no }, - .flags = SYMBOL_VALID, }; -struct symbol *sym_defconfig_list; struct symbol *modules_sym; -tristate modules_val; - -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, SYMBOL_CONST)); -} +static tristate modules_val; +static int sym_warnings; -void sym_init(void) -{ - struct symbol *sym; - struct utsname uts; - static bool inited = false; - - if (inited) - return; - inited = true; - - uname(&uts); - - sym = sym_lookup("UNAME_RELEASE", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - sym_add_default(sym, uts.release); -} - -enum symbol_type sym_get_type(struct symbol *sym) +enum symbol_type sym_get_type(const struct symbol *sym) { enum symbol_type type = sym->type; - if (type == S_TRISTATE) { - if (sym_is_choice_value(sym) && sym->visible == yes) - type = S_BOOLEAN; - else if (modules_val == no) - type = S_BOOLEAN; - } + if (type == S_TRISTATE && modules_val == no) + type = S_BOOLEAN; return type; } @@ -77,7 +55,7 @@ const char *sym_type_name(enum symbol_type type) { switch (type) { case S_BOOLEAN: - return "boolean"; + return "bool"; case S_TRISTATE: return "tristate"; case S_INT: @@ -88,31 +66,58 @@ const char *sym_type_name(enum symbol_type type) return "string"; case S_UNKNOWN: return "unknown"; - case S_OTHER: - break; } return "???"; } -struct property *sym_get_choice_prop(struct symbol *sym) +/** + * sym_get_prompt_menu - get the menu entry with a prompt + * + * @sym: a symbol pointer + * + * Return: the menu entry with a prompt. + */ +struct menu *sym_get_prompt_menu(const struct symbol *sym) { - struct property *prop; + struct menu *m; + + list_for_each_entry(m, &sym->menus, link) + if (m->prompt) + return m; - for_all_choices(sym, prop) - return prop; return NULL; } -struct property *sym_get_env_prop(struct symbol *sym) +/** + * sym_get_choice_menu - get the parent choice menu if present + * + * @sym: a symbol pointer + * + * Return: a choice menu if this function is called against a choice member. + */ +struct menu *sym_get_choice_menu(const struct symbol *sym) { - struct property *prop; + struct menu *menu = NULL; + + /* + * Choice members must have a prompt. Find a menu entry with a prompt, + * and assume it resides inside a choice block. + */ + menu = sym_get_prompt_menu(sym); + if (!menu) + return NULL; + + do { + menu = menu->parent; + } while (menu && !menu->sym); + + if (menu && menu->sym && sym_is_choice(menu->sym)) + return menu; - for_all_properties(sym, prop, P_ENV) - return prop; return NULL; } -struct property *sym_get_default_prop(struct symbol *sym) +static struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; @@ -124,7 +129,7 @@ struct property *sym_get_default_prop(struct symbol *sym) return NULL; } -static struct property *sym_get_range_prop(struct symbol *sym) +struct property *sym_get_range_prop(struct symbol *sym) { struct property *prop; @@ -136,7 +141,7 @@ static struct property *sym_get_range_prop(struct symbol *sym) return NULL; } -static long sym_get_range_val(struct symbol *sym, int base) +static long long sym_get_range_val(struct symbol *sym, int base) { sym_calc_value(sym); switch (sym->type) { @@ -149,14 +154,15 @@ static long sym_get_range_val(struct symbol *sym, int base) default: break; } - return strtol(sym->curr.val, NULL, base); + return strtoll(sym->curr.val, NULL, base); } static void sym_validate_range(struct symbol *sym) { struct property *prop; - long base, val, val2; - char str[64]; + struct symbol *range_sym; + int base; + long long val, val2; switch (sym->type) { case S_INT: @@ -171,18 +177,36 @@ static void sym_validate_range(struct symbol *sym) prop = sym_get_range_prop(sym); if (!prop) return; - val = strtol(sym->curr.val, NULL, base); - val2 = sym_get_range_val(prop->expr->left.sym, base); + val = strtoll(sym->curr.val, NULL, base); + range_sym = prop->expr->left.sym; + val2 = sym_get_range_val(range_sym, base); if (val >= val2) { - val2 = sym_get_range_val(prop->expr->right.sym, base); + range_sym = prop->expr->right.sym; + val2 = sym_get_range_val(range_sym, base); if (val <= val2) return; } - if (sym->type == S_INT) - sprintf(str, "%ld", val2); - else - sprintf(str, "0x%lx", val2); - sym->curr.val = strdup(str); + sym->curr.val = range_sym->curr.val; +} + +static void sym_set_changed(struct symbol *sym) +{ + struct menu *menu; + + list_for_each_entry(menu, &sym->menus, link) + menu->flags |= MENU_CHANGED; + + menu = sym_get_choice_menu(sym); + if (menu) + menu->flags |= MENU_CHANGED; +} + +static void sym_set_all_changed(void) +{ + struct symbol *sym; + + for_all_symbols(sym) + sym_set_changed(sym); } static void sym_calc_visibility(struct symbol *sym) @@ -190,6 +214,11 @@ static void sym_calc_visibility(struct symbol *sym) struct property *prop; tristate tri; + if (sym->flags & SYMBOL_TRANS) { + sym->visible = yes; + return; + } + /* any prompt visible? */ tri = no; for_all_prompts(sym, prop) { @@ -208,7 +237,7 @@ static void sym_calc_visibility(struct symbol *sym) tri = yes; if (sym->dir_dep.expr) tri = expr_calc_value(sym->dir_dep.expr); - if (tri == mod) + if (tri == mod && sym_get_type(sym) == S_BOOLEAN) tri = yes; if (sym->dir_dep.tri != tri) { sym->dir_dep.tri = tri; @@ -223,6 +252,15 @@ static void sym_calc_visibility(struct symbol *sym) sym->rev_dep.tri = tri; sym_set_changed(sym); } + tri = no; + if (sym->implied.expr) + tri = expr_calc_value(sym->implied.expr); + if (tri == mod && sym_get_type(sym) == S_BOOLEAN) + tri = yes; + if (sym->implied.tri != tri) { + sym->implied.tri = tri; + sym_set_changed(sym); + } } /* @@ -231,14 +269,14 @@ static void sym_calc_visibility(struct symbol *sym) * Next locate the first visible choice value * Return NULL if none was found */ -struct symbol *sym_choice_default(struct symbol *sym) +struct symbol *sym_choice_default(struct menu *choice) { + struct menu *menu; struct symbol *def_sym; struct property *prop; - struct expr *e; /* any of the defaults visible? */ - for_all_defaults(sym, prop) { + for_all_defaults(choice->sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri == no) continue; @@ -248,52 +286,133 @@ struct symbol *sym_choice_default(struct symbol *sym) } /* just get the first visible value */ - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, def_sym) - if (def_sym->visible != no) - return def_sym; + menu_for_each_sub_entry(menu, choice) + if (menu->sym && menu->sym->visible != no) + return menu->sym; /* failed to locate any defaults */ return NULL; } -static struct symbol *sym_calc_choice(struct symbol *sym) +/* + * sym_calc_choice - calculate symbol values in a choice + * + * @choice: a menu of the choice + * + * Return: a chosen symbol + */ +struct symbol *sym_calc_choice(struct menu *choice) { - struct symbol *def_sym; - struct property *prop; - struct expr *e; - int flags; - - /* 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; + struct symbol *res = NULL; + struct symbol *sym; + struct menu *menu; + + /* Traverse the list of choice members in the priority order. */ + list_for_each_entry(sym, &choice->choice_members, choice_link) { + sym_calc_visibility(sym); + if (sym->visible == no) + continue; + + /* The first visible symble with the user value 'y'. */ + if (sym_has_value(sym) && sym->def[S_DEF_USER].tri == yes) { + res = sym; + break; + } + } + + /* + * If 'y' is not found in the user input, use the default, unless it is + * explicitly set to 'n'. + */ + if (!res) { + res = sym_choice_default(choice); + if (res && sym_has_value(res) && res->def[S_DEF_USER].tri == no) + res = NULL; } - sym->flags &= flags | ~SYMBOL_DEF_USER; + /* Still not found. Pick up the first visible, user-unspecified symbol. */ + if (!res) { + menu_for_each_sub_entry(menu, choice) { + sym = menu->sym; + + if (!sym || sym->visible == no || sym_has_value(sym)) + continue; - /* is the user choice visible? */ - def_sym = sym->def[S_DEF_USER].val; - if (def_sym && def_sym->visible != no) - return def_sym; + res = sym; + break; + } + } - def_sym = sym_choice_default(sym); + /* + * Still not found. Traverse the linked list in the _reverse_ order to + * pick up the least prioritized 'n'. + */ + if (!res) { + list_for_each_entry_reverse(sym, &choice->choice_members, + choice_link) { + if (sym->visible == no) + continue; - if (def_sym == NULL) - /* no choice? reset tristate value */ - sym->curr.tri = no; + res = sym; + break; + } + } + + menu_for_each_sub_entry(menu, choice) { + tristate val; + + sym = menu->sym; + + if (!sym || sym->visible == no) + continue; + + val = sym == res ? yes : no; + + if (sym->curr.tri != val) + sym_set_changed(sym); + + sym->curr.tri = val; + sym->flags |= SYMBOL_VALID | SYMBOL_WRITE; + } + + return res; +} + +static void sym_warn_unmet_dep(const struct symbol *sym) +{ + struct gstr gs = str_new(); + + str_printf(&gs, + "\nWARNING: unmet direct dependencies detected for %s\n", + sym->name); + str_printf(&gs, + " Depends on [%c]: ", + sym->dir_dep.tri == mod ? 'm' : 'n'); + expr_gstr_print(sym->dir_dep.expr, &gs); + str_printf(&gs, "\n"); + + expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes, + " Selected by [y]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod, + " Selected by [m]:\n"); + + fputs(str_get(&gs), stderr); + str_free(&gs); + sym_warnings++; +} - return def_sym; +bool sym_dep_errors(void) +{ + if (sym_warnings) + return getenv("KCONFIG_WERROR"); + return false; } void sym_calc_value(struct symbol *sym) { struct symbol_value newval, oldval; - struct property *prop; - struct expr *e; + struct property *prop = NULL; + struct menu *choice_menu; if (!sym) return; @@ -301,52 +420,54 @@ void sym_calc_value(struct symbol *sym) if (sym->flags & SYMBOL_VALID) return; - if (sym_is_choice_value(sym) && - sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { - sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; - prop = sym_get_choice_prop(sym); - sym_calc_value(prop_get_symbol(prop)); - } - sym->flags |= SYMBOL_VALID; oldval = sym->curr; + newval.tri = no; + switch (sym->type) { case S_INT: + newval.val = "0"; + break; case S_HEX: + newval.val = "0x0"; + break; case S_STRING: - newval = symbol_empty.curr; + newval.val = ""; break; case S_BOOLEAN: case S_TRISTATE: - newval = symbol_no.curr; + newval.val = "n"; break; default: sym->curr.val = sym->name; sym->curr.tri = no; return; } - if (!sym_is_choice_value(sym)) - sym->flags &= ~SYMBOL_WRITE; + sym->flags &= ~SYMBOL_WRITE; sym_calc_visibility(sym); + if (sym->visible != no) + sym->flags |= SYMBOL_WRITE; + /* set default if recursively called */ sym->curr = newval; switch (sym_get_type(sym)) { case S_BOOLEAN: case S_TRISTATE: - 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; + choice_menu = sym_get_choice_menu(sym); + + if (choice_menu) { + sym_calc_choice(choice_menu); + newval.tri = sym->curr.tri; } 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); @@ -358,24 +479,21 @@ void sym_calc_value(struct symbol *sym) 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); + if (newval.tri != no) + sym->flags |= SYMBOL_WRITE; + } + if (sym->implied.tri != no) { + sym->flags |= SYMBOL_WRITE; + newval.tri = EXPR_OR(newval.tri, sym->implied.tri); + newval.tri = EXPR_AND(newval.tri, + sym->dir_dep.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); - } + if (sym->dir_dep.tri < sym->rev_dep.tri) + sym_warn_unmet_dep(sym); newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); } if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) @@ -384,12 +502,9 @@ void sym_calc_value(struct symbol *sym) case S_STRING: case S_HEX: case S_INT: - if (sym->visible != no) { - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) { - newval.val = sym->def[S_DEF_USER].val; - break; - } + if (sym->visible != no && sym_has_value(sym)) { + newval.val = sym->def[S_DEF_USER].val; + break; } prop = sym_get_default_prop(sym); if (prop) { @@ -405,9 +520,20 @@ void sym_calc_value(struct symbol *sym) ; } + /* + * If the symbol lacks a user value but its value comes from a + * single transitional symbol with an existing user value, mark + * this symbol as having a user value to avoid prompting. + */ + if (prop && !sym_has_value(sym)) { + struct symbol *ds = prop_get_symbol(prop); + if (ds && (ds->flags & SYMBOL_TRANS) && sym_has_value(ds)) { + sym->def[S_DEF_USER] = newval; + sym->flags |= SYMBOL_DEF_USER; + } + } + sym->curr = newval; - if (sym_is_choice(sym) && newval.tri == yes) - sym->curr.val = sym_calc_choice(sym); sym_validate_range(sym); if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { @@ -418,59 +544,22 @@ void sym_calc_value(struct symbol *sym) } } - if (sym_is_choice(sym)) { - struct symbol *choice_sym; - - prop = sym_get_choice_prop(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); - } - } - - if (sym->flags & SYMBOL_AUTO) + if (sym_is_choice(sym) || sym->flags & SYMBOL_TRANS) sym->flags &= ~SYMBOL_WRITE; - - if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) - set_all_choice_values(sym); } void sym_clear_all_valid(void) { struct symbol *sym; - int i; - for_all_symbols(i, sym) + for_all_symbols(sym) sym->flags &= ~SYMBOL_VALID; - 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); + expr_invalidate_all(); + conf_set_changed(true); + sym_calc_value(modules_sym); } -bool sym_tristate_within_range(struct symbol *sym, tristate val) +bool sym_tristate_within_range(const struct symbol *sym, tristate val) { int type = sym_get_type(sym); @@ -484,8 +573,6 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val) 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; } @@ -493,42 +580,75 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val) { tristate oldval = sym_get_tristate_value(sym); - if (oldval != val && !sym_tristate_within_range(sym, val)) + if (!sym_tristate_within_range(sym, val)) return false; - if (!(sym->flags & SYMBOL_DEF_USER)) { + if (!(sym->flags & SYMBOL_DEF_USER) || sym->def[S_DEF_USER].tri != val) { + sym->def[S_DEF_USER].tri = val; sym->flags |= SYMBOL_DEF_USER; sym_set_changed(sym); } - /* - * setting a choice value also resets the new flag of the choice - * symbol and all other choice values. - */ - if (sym_is_choice_value(sym) && val == yes) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - struct property *prop; - struct expr *e; - - 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_DEF_USER; - } - } - sym->def[S_DEF_USER].tri = val; if (oldval != val) sym_clear_all_valid(); return true; } +/** + * choice_set_value - set the user input to a choice + * + * @choice: menu entry for the choice + * @sym: selected symbol + */ +void choice_set_value(struct menu *choice, struct symbol *sym) +{ + struct menu *menu; + bool changed = false; + + menu_for_each_sub_entry(menu, choice) { + tristate val; + + if (!menu->sym) + continue; + + if (menu->sym->visible == no) + continue; + + val = menu->sym == sym ? yes : no; + + if (menu->sym->curr.tri != val) + changed = true; + + menu->sym->def[S_DEF_USER].tri = val; + menu->sym->flags |= SYMBOL_DEF_USER; + + /* + * Now, the user has explicitly enabled or disabled this symbol, + * it should be given the highest priority. We are possibly + * setting multiple symbols to 'n', where the first symbol is + * given the least prioritized 'n'. This works well when the + * choice block ends up with selecting 'n' symbol. + * (see sym_calc_choice()) + */ + list_move(&menu->sym->choice_link, &choice->choice_members); + } + + if (changed) + sym_clear_all_valid(); +} + tristate sym_toggle_tristate_value(struct symbol *sym) { + struct menu *choice; tristate oldval, newval; + choice = sym_get_choice_menu(sym); + if (choice) { + choice_set_value(choice, sym); + return yes; + } + oldval = newval = sym_get_tristate_value(sym); do { switch (newval) { @@ -594,7 +714,7 @@ bool sym_string_valid(struct symbol *sym, const char *str) bool sym_string_within_range(struct symbol *sym, const char *str) { struct property *prop; - long val; + long long val; switch (sym->type) { case S_STRING: @@ -605,7 +725,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str) prop = sym_get_range_prop(sym); if (!prop) return true; - val = strtol(str, NULL, 10); + val = strtoll(str, NULL, 10); return val >= sym_get_range_val(prop->expr->left.sym, 10) && val <= sym_get_range_val(prop->expr->right.sym, 10); case S_HEX: @@ -614,7 +734,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str) prop = sym_get_range_prop(sym); if (!prop) return true; - val = strtol(str, NULL, 16); + val = strtoll(str, NULL, 16); return val >= sym_get_range_val(prop->expr->left.sym, 16) && val <= sym_get_range_val(prop->expr->right.sym, 16); case S_BOOLEAN: @@ -693,13 +813,12 @@ const char *sym_get_string_default(struct symbol *sym) { struct property *prop; struct symbol *ds; - const char *str; + 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); @@ -736,6 +855,10 @@ const char *sym_get_string_default(struct symbol *sym) if (sym->type == S_BOOLEAN && val == mod) val = yes; + /* adjust the default value if this symbol is implied by another */ + if (val < sym->implied.tri) + val = sym->implied.tri; + switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: @@ -745,15 +868,17 @@ const char *sym_get_string_default(struct symbol *sym) case yes: return "y"; } case S_INT: + if (!str[0]) + str = "0"; + break; case S_HEX: - return str; - case S_STRING: - return str; - case S_OTHER: - case S_UNKNOWN: + if (!str[0]) + str = "0x0"; + break; + default: break; } - return ""; + return str; } const char *sym_get_string_value(struct symbol *sym) @@ -768,8 +893,7 @@ const char *sym_get_string_value(struct symbol *sym) case no: return "n"; case mod: - sym_calc_value(modules_sym); - return (modules_sym->curr.tri == no) ? "n" : "m"; + return "m"; case yes: return "y"; } @@ -777,23 +901,21 @@ const char *sym_get_string_value(struct symbol *sym) default: ; } - return (const char *)sym->curr.val; + return sym->curr.val; } -bool sym_is_changable(struct symbol *sym) +bool sym_is_changeable(const struct symbol *sym) { - return sym->visible > sym->rev_dep.tri; + return !sym_is_choice(sym) && sym->visible > sym->rev_dep.tri; } -static unsigned strhash(const char *s) +bool sym_is_choice_value(const struct symbol *sym) { - /* fnv32 hash */ - unsigned hash = 2166136261U; - for (; *s; s++) - hash = (hash ^ *s) * 0x01000193; - return hash; + return !list_empty(&sym->choice_link); } +HASHTABLE_DEFINE(sym_hashtable, SYMBOL_HASHSIZE); + struct symbol *sym_lookup(const char *name, int flags) { struct symbol *symbol; @@ -808,16 +930,16 @@ struct symbol *sym_lookup(const char *name, int flags) case 'n': return &symbol_no; } } - hash = strhash(name) % SYMBOL_HASHSIZE; + hash = hash_str(name); - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && !strcmp(symbol->name, name) && (flags ? symbol->flags & flags - : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) + : !(symbol->flags & SYMBOL_CONST))) return symbol; } - new_name = strdup(name); + new_name = xstrdup(name); } else { new_name = NULL; hash = 0; @@ -827,10 +949,11 @@ struct symbol *sym_lookup(const char *name, int flags) memset(symbol, 0, sizeof(*symbol)); symbol->name = new_name; symbol->type = S_UNKNOWN; - symbol->flags |= flags; + symbol->flags = flags; + INIT_LIST_HEAD(&symbol->menus); + INIT_LIST_HEAD(&symbol->choice_link); - symbol->next = symbol_hash[hash]; - symbol_hash[hash] = symbol; + hash_add(sym_hashtable, &symbol->node, hash); return symbol; } @@ -850,9 +973,9 @@ struct symbol *sym_find(const char *name) case 'n': return &symbol_no; } } - hash = strhash(name) % SYMBOL_HASHSIZE; + hash = hash_str(name); - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { + hash_for_each_possible(sym_hashtable, symbol, node, hash) { if (symbol->name && !strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) @@ -862,98 +985,6 @@ 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 sym_match { struct symbol *sym; off_t so, eo; @@ -963,11 +994,11 @@ struct sym_match { * - first, symbols that match exactly * - then, alphabetical sort */ -static int sym_rel_comp( const void *sym1, const void *sym2 ) +static int sym_rel_comp(const void *sym1, const void *sym2) { - struct sym_match *s1 = *(struct sym_match **)sym1; - struct sym_match *s2 = *(struct sym_match **)sym2; - int l1, l2; + const struct sym_match *s1 = sym1; + const struct sym_match *s2 = sym2; + int exact1, exact2; /* Exact match: * - if matched length on symbol s1 is the length of that symbol, @@ -978,11 +1009,11 @@ static int sym_rel_comp( const void *sym1, const void *sym2 ) * exactly; if this is the case, we can't decide which comes first, * and we fallback to sorting alphabetically. */ - l1 = s1->eo - s1->so; - l2 = s2->eo - s2->so; - if (l1 == strlen(s1->sym->name) && l2 != strlen(s2->sym->name)) + exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); + exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); + if (exact1 && !exact2) return -1; - if (l1 != strlen(s1->sym->name) && l2 == strlen(s2->sym->name)) + if (!exact1 && exact2) return 1; /* As a fallback, sort symbols alphabetically */ @@ -992,7 +1023,7 @@ static int sym_rel_comp( const void *sym1, const void *sym2 ) struct symbol **sym_re_search(const char *pattern) { struct symbol *sym, **sym_arr = NULL; - struct sym_match **sym_match_arr = NULL; + struct sym_match *sym_match_arr = NULL; int i, cnt, size; regex_t re; regmatch_t match[1]; @@ -1004,48 +1035,39 @@ struct symbol **sym_re_search(const char *pattern) if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) return NULL; - for_all_symbols(i, sym) { - struct sym_match *tmp_sym_match; + for_all_symbols(sym) { if (sym->flags & SYMBOL_CONST || !sym->name) continue; if (regexec(&re, sym->name, 1, match, 0)) continue; - if (cnt + 1 >= size) { + if (cnt >= size) { void *tmp; size += 16; - tmp = realloc(sym_match_arr, size * sizeof(struct sym_match *)); - if (!tmp) { + tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); + if (!tmp) goto sym_re_search_free; - } sym_match_arr = tmp; } sym_calc_value(sym); - tmp_sym_match = (struct sym_match*)malloc(sizeof(struct sym_match)); - if (!tmp_sym_match) - goto sym_re_search_free; - tmp_sym_match->sym = sym; - /* As regexec return 0, we know we have a match, so + /* As regexec returned 0, we know we have a match, so * we can use match[0].rm_[se]o without further checks */ - tmp_sym_match->so = match[0].rm_so; - tmp_sym_match->eo = match[0].rm_eo; - sym_match_arr[cnt++] = tmp_sym_match; + sym_match_arr[cnt].so = match[0].rm_so; + sym_match_arr[cnt].eo = match[0].rm_eo; + sym_match_arr[cnt++].sym = sym; } if (sym_match_arr) { - qsort(sym_match_arr, cnt, sizeof(struct sym_match*), sym_rel_comp); - sym_arr = malloc((cnt+1) * sizeof(struct symbol)); + qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); + sym_arr = malloc((cnt+1) * sizeof(struct symbol *)); if (!sym_arr) goto sym_re_search_free; for (i = 0; i < cnt; i++) - sym_arr[i] = sym_match_arr[i]->sym; + sym_arr[i] = sym_match_arr[i].sym; sym_arr[cnt] = NULL; } sym_re_search_free: - if (sym_match_arr) { - for (i = 0; i < cnt; i++) - free(sym_match_arr[i]); - free(sym_match_arr); - } + /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ + free(sym_match_arr); regfree(&re); return sym_arr; @@ -1055,13 +1077,13 @@ sym_re_search_free: * 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. + * Note insert() 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; + struct expr **expr; } *check_top; static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) @@ -1090,13 +1112,14 @@ 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 menu *choice; struct dep_stack cv_stack; + enum prop_type type; - if (sym_is_choice_value(last_sym)) { + choice = sym_get_choice_menu(last_sym); + if (choice) { dep_stack_insert(&cv_stack, last_sym); - last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); + last_sym = choice->sym; } for (stack = check_top; stack != NULL; stack = stack->prev) @@ -1110,55 +1133,50 @@ static void sym_check_print_recursive(struct symbol *last_sym) 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; - } - } + type = stack->prop ? stack->prop->type : P_UNKNOWN; + 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, + fprintf(stderr, "error: recursive dependency detected!\n"); + + if (sym_is_choice(next_sym)) { + choice = list_first_entry(&next_sym->menus, struct menu, link); + + fprintf(stderr, "\tsymbol %s is part of choice block at %s:%d\n", 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, + choice->filename, choice->lineno); + } else if (stack->expr == &sym->dir_dep.expr) { + fprintf(stderr, "\tsymbol %s depends on %s\n", 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, + next_sym->name); + } else if (stack->expr == &sym->rev_dep.expr) { + fprintf(stderr, "\tsymbol %s is selected by %s\n", + sym->name, next_sym->name); + } else if (stack->expr == &sym->implied.expr) { + fprintf(stderr, "\tsymbol %s is implied by %s\n", + sym->name, next_sym->name); + } else if (stack->expr) { + fprintf(stderr, "\tsymbol %s %s value contains %s\n", sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); + prop_get_type_name(type), + next_sym->name); } else { - fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", - prop->file->name, prop->lineno, + fprintf(stderr, "\tsymbol %s %s is visible depending on %s\n", sym->name ? sym->name : "<choice>", - next_sym->name ? next_sym->name : "<choice>"); + prop_get_type_name(type), + next_sym->name); } } + fprintf(stderr, + "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n" + "subsection \"Kconfig recursive dependency limitations\"\n" + "\n"); + if (check_top == &cv_stack) dep_stack_remove(); } -static struct symbol *sym_check_expr_deps(struct expr *e) +static struct symbol *sym_check_expr_deps(const struct expr *e) { struct symbol *sym; @@ -1174,6 +1192,10 @@ static struct symbol *sym_check_expr_deps(struct expr *e) case E_NOT: return sym_check_expr_deps(e->left.expr); case E_EQUAL: + case E_GEQ: + case E_GTH: + case E_LEQ: + case E_LTH: case E_UNEQUAL: sym = sym_check_deps(e->left.sym); if (sym) @@ -1184,7 +1206,7 @@ static struct symbol *sym_check_expr_deps(struct expr *e) default: break; } - printf("Oops! How to check %d?\n", e->type); + fprintf(stderr, "Oops! How to check %d?\n", e->type); return NULL; } @@ -1197,12 +1219,25 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) dep_stack_insert(&stack, sym); + stack.expr = &sym->dir_dep.expr; + sym2 = sym_check_expr_deps(sym->dir_dep.expr); + if (sym2) + goto out; + + stack.expr = &sym->rev_dep.expr; sym2 = sym_check_expr_deps(sym->rev_dep.expr); if (sym2) goto out; + stack.expr = &sym->implied.expr; + sym2 = sym_check_expr_deps(sym->implied.expr); + if (sym2) + goto out; + + stack.expr = NULL; + for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT) + if (prop->type == P_SELECT || prop->type == P_IMPLY) continue; stack.prop = prop; sym2 = sym_check_expr_deps(prop->visible.expr); @@ -1210,7 +1245,7 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) break; if (prop->type != P_DEFAULT || sym_is_choice(sym)) continue; - stack.expr = prop->expr; + stack.expr = &prop->expr; sym2 = sym_check_expr_deps(prop->expr); if (sym2) break; @@ -1225,16 +1260,18 @@ out: static struct symbol *sym_check_choice_deps(struct symbol *choice) { - struct symbol *sym, *sym2; - struct property *prop; - struct expr *e; + struct menu *choice_menu, *menu; + struct symbol *sym2; 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_menu = list_first_entry(&choice->menus, struct menu, link); + + menu_for_each_sub_entry(menu, choice_menu) { + if (menu->sym) + menu->sym->flags |= SYMBOL_CHECK | SYMBOL_CHECKED; + } choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); sym2 = sym_check_sym_deps(choice); @@ -1242,18 +1279,25 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice) if (sym2) goto out; - expr_list_for_each_sym(prop->expr, e, sym) { - sym2 = sym_check_sym_deps(sym); + menu_for_each_sub_entry(menu, choice_menu) { + if (!menu->sym) + continue; + sym2 = sym_check_sym_deps(menu->sym); if (sym2) break; } out: - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags &= ~SYMBOL_CHECK; + menu_for_each_sub_entry(menu, choice_menu) + if (menu->sym) + menu->sym->flags &= ~SYMBOL_CHECK; - if (sym2 && sym_is_choice_value(sym2) && - prop_get_symbol(sym_get_choice_prop(sym2)) == choice) - sym2 = choice; + if (sym2) { + struct menu *choice_menu2; + + choice_menu2 = sym_get_choice_menu(sym2); + if (choice_menu2 == choice_menu) + sym2 = choice; + } dep_stack_remove(); @@ -1262,8 +1306,8 @@ out: struct symbol *sym_check_deps(struct symbol *sym) { + struct menu *choice; struct symbol *sym2; - struct property *prop; if (sym->flags & SYMBOL_CHECK) { sym_check_print_recursive(sym); @@ -1272,13 +1316,13 @@ struct symbol *sym_check_deps(struct symbol *sym) if (sym->flags & SYMBOL_CHECKED) return NULL; - if (sym_is_choice_value(sym)) { + choice = sym_get_choice_menu(sym); + if (choice) { 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)); + sym2 = sym_check_deps(choice->sym); dep_stack_remove(); } else if (sym_is_choice(sym)) { sym2 = sym_check_choice_deps(sym); @@ -1288,38 +1332,12 @@ struct symbol *sym_check_deps(struct symbol *sym) sym->flags &= ~SYMBOL_CHECK; } - if (sym2 && sym2 == sym) - sym2 = NULL; - return sym2; } -struct property *prop_alloc(enum prop_type type, struct symbol *sym) -{ - struct property *prop; - struct property **propp; - - prop = xmalloc(sizeof(*prop)); - memset(prop, 0, sizeof(*prop)); - prop->type = type; - prop->sym = sym; - prop->file = current_file; - prop->lineno = zconf_lineno(); - - /* append property to the prop list of symbol */ - if (sym) { - for (propp = &sym->prop; *propp; propp = &(*propp)->next) - ; - *propp = prop; - } - - return prop; -} - -struct symbol *prop_get_symbol(struct property *prop) +struct symbol *prop_get_symbol(const struct property *prop) { - if (prop->expr && (prop->expr->type == E_SYMBOL || - prop->expr->type == E_LIST)) + if (prop->expr && prop->expr->type == E_SYMBOL) return prop->expr->left.sym; return NULL; } @@ -1329,53 +1347,20 @@ 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: return "menu"; case P_DEFAULT: return "default"; - case P_CHOICE: - return "choice"; case P_SELECT: return "select"; + case P_IMPLY: + return "imply"; 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); -} |
