// SPDX-License-Identifier: GPL-2.0/* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> */ #include <sys/types.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <regex.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,}; struct symbol symbol_mod = { .name = "m", .type = S_TRISTATE, .curr = { "m", mod }, .menus = LIST_HEAD_INIT(symbol_mod.menus), .flags = SYMBOL_CONST|SYMBOL_VALID,}; struct symbol symbol_no = { .name = "n", .type = S_TRISTATE, .curr = { "n", no }, .menus = LIST_HEAD_INIT(symbol_no.menus), .flags = SYMBOL_CONST|SYMBOL_VALID,}; struct symbol *modules_sym;static tristate modules_val;static int sym_warnings; enum symbol_type sym_get_type(const struct symbol *sym){ enum symbol_type type = sym->type; if (type == S_TRISTATE && modules_val == no) type = S_BOOLEAN; return type;} const char *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(const struct 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(const struct 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;} static struct property *sym_get_default_prop(struct symbol *sym){ struct property *prop; for_all_defaults(sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri != no) return prop; } return NULL;} struct property *sym_get_range_prop(struct symbol *sym){ struct property *prop; for_all_properties(sym, prop, P_RANGE) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri != no) return prop; } return NULL;} static long long sym_get_range_val(struct symbol *sym, int base){ sym_calc_value(sym); switch (sym->type) { case S_INT: base = 10; break; case S_HEX: base = 16; break; default: break; } return strtoll(sym->curr.val, NULL, base);} static void sym_validate_range(struct symbol *sym){ struct property *prop; struct symbol *range_sym; int base; long long val, val2; switch (sym->type) { case S_INT: base = 10; break; case S_HEX: base = 16; break; default: return; } prop = sym_get_range_prop(sym); if (!prop) return; val = strtoll(sym->curr.val, NULL, base); range_sym = prop->expr->left.sym; val2 = sym_get_range_val(range_sym, base); if (val >= val2) { range_sym = prop->expr->right.sym; val2 = sym_get_range_val(range_sym, base); if (val <= val2) return; } 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){ struct property *prop; tristate tri; if (sym->flags & SYMBOL_TRANS) { sym->visible = yes; return; } /* 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; 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++;} 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 = NULL; struct menu *choice_menu; if (!sym) return; if (sym->flags & SYMBOL_VALID) return; 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.val = ""; break; case S_BOOLEAN: case S_TRISTATE: newval.val = "n"; break; default: sym->curr.val = sym->name; sym->curr.tri = no; return; } 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: 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 */ if (sym_has_value(sym)) { newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible); goto calc_newval; } } if (sym->rev_dep.tri != no) sym->flags |= SYMBOL_WRITE; if (!sym_is_choice(sym)) { prop = sym_get_default_prop(sym); if (prop) { 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 < 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) newval.tri = yes;Lines 1–500 of 1366. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> */ #include <sys/types.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <regex.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, }; struct symbol symbol_mod = { .name = "m", .type = S_TRISTATE, .curr = { "m", mod }, .menus = LIST_HEAD_INIT(symbol_mod.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; struct symbol symbol_no = { .name = "n", .type = S_TRISTATE, .curr = { "n", no }, .menus = LIST_HEAD_INIT(symbol_no.menus), .flags = SYMBOL_CONST|SYMBOL_VALID, }; struct symbol *modules_sym; static tristate modules_val; static int sym_warnings; enum symbol_type sym_get_type(const struct symbol *sym) { enum symbol_type type = sym->type; if (type == S_TRISTATE && modules_val == no) type = S_BOOLEAN; return type; } const char *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(const struct 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(const struct 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; } static struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; for_all_defaults(sym, prop) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri != no) return prop; } return NULL; } struct property *sym_get_range_prop(struct symbol *sym) { struct property *prop; for_all_properties(sym, prop, P_RANGE) { prop->visible.tri = expr_calc_value(prop->visible.expr); if (prop->visible.tri != no) return prop; } return NULL; } static long long sym_get_range_val(struct symbol *sym, int base) { sym_calc_value(sym); switch (sym->type) { case S_INT: base = 10; break; case S_HEX: base = 16; break; default: break; } return strtoll(sym->curr.val, NULL, base); } static void sym_validate_range(struct symbol *sym) { struct property *prop; struct symbol *range_sym; int base; long long val, val2; switch (sym->type) { case S_INT: base = 10; break; case S_HEX: base = 16; break; default: return; } prop = sym_get_range_prop(sym); if (!prop) return; val = strtoll(sym->curr.val, NULL, base); range_sym = prop->expr->left.sym; val2 = sym_get_range_val(range_sym, base); if (val >= val2) { range_sym = prop->expr->right.sym; val2 = sym_get_range_val(range_sym, base); if (val <= val2) return; } 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) { struct property *prop; tristate tri; if (sym->flags & SYMBOL_TRANS) { sym->visible = yes; return; } /* 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; 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++; } 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 = NULL; struct menu *choice_menu; if (!sym) return; if (sym->flags & SYMBOL_VALID) return; 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.val = ""; break; case S_BOOLEAN: case S_TRISTATE: newval.val = "n"; break; default: sym->curr.val = sym->name; sym->curr.tri = no; return; } 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: 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 */ if (sym_has_value(sym)) { newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, sym->visible); goto calc_newval; } } if (sym->rev_dep.tri != no) sym->flags |= SYMBOL_WRITE; if (!sym_is_choice(sym)) { prop = sym_get_default_prop(sym); if (prop) { 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 < 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) newval.tri = yes;