struct symbol *modules_sym; static tristate modules_val; staticint sym_warnings;
enum symbol_type sym_get_type(conststruct symbol *sym)
{ enum symbol_type type = sym->type;
if (type == S_TRISTATE && modules_val == no)
type = S_BOOLEAN; return type;
}
constchar *sym_type_name(enum symbol_type type)
{ switch (type) { case S_BOOLEAN: return"bool"; case S_TRISTATE: return"tristate"; case S_INT: return"integer"; case S_HEX: return"hex"; case S_STRING: return"string"; case S_UNKNOWN: return"unknown";
} return"???";
}
/** * 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(conststruct symbol *sym)
{ struct menu *m;
list_for_each_entry(m, &sym->menus, link) if (m->prompt) return m;
return NULL;
}
/** * 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(conststruct symbol *sym)
{ 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;
return NULL;
}
staticstruct property *sym_get_default_prop(struct symbol *sym)
{ struct property *prop;
menu = sym_get_choice_menu(sym); if (menu)
menu->flags |= MENU_CHANGED;
}
staticvoid sym_set_all_changed(void)
{ struct symbol *sym;
for_all_symbols(sym)
sym_set_changed(sym);
}
staticvoid sym_calc_visibility(struct symbol *sym)
{ struct property *prop;
tristate tri;
/* any prompt visible? */
tri = no;
for_all_prompts(sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr);
tri = EXPR_OR(tri, prop->visible.tri);
} if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
tri = yes; if (sym->visible != tri) {
sym->visible = tri;
sym_set_changed(sym);
} 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 && sym_get_type(sym) == S_BOOLEAN)
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); if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
tri = yes; if (sym->rev_dep.tri != tri) {
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);
}
}
/* * 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 menu *choice)
{ struct menu *menu; struct symbol *def_sym; struct property *prop;
/* any of the defaults visible? */
for_all_defaults(choice->sym, prop) {
prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri == no) continue;
def_sym = prop_get_symbol(prop); if (def_sym->visible != no) return def_sym;
}
/* just get the first visible value */
menu_for_each_sub_entry(menu, choice) if (menu->sym && menu->sym->visible != no) return menu->sym;
/* failed to locate any defaults */ return NULL;
}
/* * 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 *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;
}
/* 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;
res = sym; break;
}
}
/* * 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;
bool sym_tristate_within_range(conststruct symbol *sym, tristate val)
{ int type = sym_get_type(sym);
if (sym->visible == no) returnfalse;
if (type != S_BOOLEAN && type != S_TRISTATE) returnfalse;
if (type == S_BOOLEAN && val == mod) returnfalse; if (sym->visible <= sym->rev_dep.tri) returnfalse; return val >= sym->rev_dep.tri && val <= sym->visible;
}
/** * 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;
/* * 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;
/* * 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.
*/ constchar *sym_get_string_default(struct symbol *sym)
{ struct property *prop; struct symbol *ds; constchar *str = "";
tristate val;
sym_calc_visibility(sym);
sym_calc_value(modules_sym);
val = symbol_no.curr.tri;
/* 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 = (constchar *)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;
/* 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: switch (val) { case no: return"n"; case mod: return"m"; case yes: return"y";
} case S_INT: if (!str[0])
str = "0"; break; case S_HEX: if (!str[0])
str = "0x0"; break; default: break;
} return str;
}
constchar *sym_get_string_value(struct symbol *sym)
{
tristate val;
switch (sym->type) { case S_BOOLEAN: case S_TRISTATE:
val = sym_get_tristate_value(sym); switch (val) { case no: return"n"; case mod: return"m"; case yes: return"y";
} break; default:
;
} return sym->curr.val;
}
struct sym_match { struct symbol *sym;
off_t so, eo;
};
/* Compare matched symbols as thus: * - first, symbols that match exactly * - then, alphabetical sort
*/ staticint sym_rel_comp(constvoid *sym1, constvoid *sym2)
{ conststruct sym_match *s1 = sym1; conststruct sym_match *s2 = sym2; int exact1, exact2;
/* Exact match: * - if matched length on symbol s1 is the length of that symbol, * then this symbol should come first; * - if matched length on symbol s2 is the length of that symbol, * then this symbol should come first. * Note: since the search can be a regexp, both symbols may match * exactly; if this is the case, we can't decide which comes first, * and we fallback to sorting alphabetically.
*/
exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); if (exact1 && !exact2) return -1; if (!exact1 && exact2) return 1;
/* As a fallback, sort symbols alphabetically */ return strcmp(s1->sym->name, s2->sym->name);
}
struct symbol **sym_re_search(constchar *pattern)
{ struct symbol *sym, **sym_arr = NULL; struct sym_match *sym_match_arr = NULL; int i, cnt, size;
regex_t re;
regmatch_t match[1];
cnt = size = 0; /* Skip if empty */ if (strlen(pattern) == 0) return NULL; if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) return NULL;
for_all_symbols(sym) { if (sym->flags & SYMBOL_CONST || !sym->name) continue; if (regexec(&re, sym->name, 1, match, 0)) continue; if (cnt >= size) { void *tmp;
size += 16;
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); /* As regexec returned 0, we know we have a match, so * we can use match[0].rm_[se]o without further checks
*/
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 *)); if (!sym_arr) goto sym_re_search_free; for (i = 0; i < cnt; i++)
sym_arr[i] = sym_match_arr[i].sym;
sym_arr[cnt] = NULL;
}
sym_re_search_free: /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
free(sym_match_arr);
regfree(&re);
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 insert() remove() must always match to properly clear the stack.
*/ staticstruct dep_stack { struct dep_stack *prev, *next; struct symbol *sym; struct property *prop; struct expr **expr;
} *check_top;
/* * 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.
*/ staticvoid sym_check_print_recursive(struct symbol *last_sym)
{ struct dep_stack *stack; struct symbol *sym, *next_sym; struct menu *choice; struct dep_stack cv_stack; enum prop_type type;
if (stack->sym == last_sym)
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->filename, choice->lineno);
} elseif (stack->expr == &sym->dir_dep.expr) {
fprintf(stderr, "\tsymbol %s depends on %s\n",
sym->name ? sym->name : "",
next_sym->name);
} elseif (stack->expr == &sym->rev_dep.expr) {
fprintf(stderr, "\tsymbol %s is selected by %s\n",
sym->name, next_sym->name);
} elseif (stack->expr == &sym->implied.expr) {
fprintf(stderr, "\tsymbol %s is implied by %s\n",
sym->name, next_sym->name);
} elseif (stack->expr) {
fprintf(stderr, "\tsymbol %s %s value contains %s\n",
sym->name ? sym->name : "",
prop_get_type_name(type),
next_sym->name);
} else {
fprintf(stderr, "\tsymbol %s %s is visible depending on %s\n",
sym->name ? sym->name : "",
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();
}
staticstruct symbol *sym_check_expr_deps(conststruct expr *e)
{ struct symbol *sym;
if (!e) return NULL; switch (e->type) { case E_OR: case E_AND:
sym = sym_check_expr_deps(e->left.expr); if (sym) return sym; return sym_check_expr_deps(e->right.expr); 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) return sym; return sym_check_deps(e->right.sym); case E_SYMBOL: return sym_check_deps(e->left.sym); default: break;
}
fprintf(stderr, "Oops! How to check %d?\n", e->type); return NULL;
}
/* return NULL when dependencies are OK */ staticstruct symbol *sym_check_sym_deps(struct symbol *sym)
{ struct symbol *sym2; struct property *prop; struct dep_stack stack;
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_SELECT || prop->type == P_IMPLY) continue;
stack.prop = prop;
sym2 = sym_check_expr_deps(prop->visible.expr); if (sym2) break; if (prop->type != P_DEFAULT || sym_is_choice(sym)) continue;
stack.expr = &prop->expr;
sym2 = sym_check_expr_deps(prop->expr); if (sym2) break;
stack.expr = NULL;
}
out:
dep_stack_remove();
return sym2;
}
staticstruct symbol *sym_check_choice_deps(struct symbol *choice)
{ struct menu *choice_menu, *menu; struct symbol *sym2; struct dep_stack stack;
struct symbol *sym_check_deps(struct symbol *sym)
{ struct menu *choice; struct symbol *sym2;
if (sym->flags & SYMBOL_CHECK) {
sym_check_print_recursive(sym); return sym;
} if (sym->flags & SYMBOL_CHECKED) return NULL;
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);
sym2 = sym_check_deps(choice->sym);
dep_stack_remove();
} elseif (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;
}
return sym2;
}
struct symbol *prop_get_symbol(conststruct property *prop)
{ if (prop->expr && prop->expr->type == E_SYMBOL) return prop->expr->left.sym; return NULL;
}
constchar *prop_get_type_name(enum prop_type type)
{ switch (type) { case P_PROMPT: return"prompt"; case P_COMMENT: return"comment"; case P_MENU: return"menu"; case P_DEFAULT: return"default"; case P_SELECT: return"select"; case P_IMPLY: return"imply"; case P_RANGE: return"range"; case P_UNKNOWN: break;
} return"unknown";
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.