162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <sys/types.h> 762306a36Sopenharmony_ci#include <ctype.h> 862306a36Sopenharmony_ci#include <stdlib.h> 962306a36Sopenharmony_ci#include <string.h> 1062306a36Sopenharmony_ci#include <regex.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "lkc.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistruct symbol symbol_yes = { 1562306a36Sopenharmony_ci .name = "y", 1662306a36Sopenharmony_ci .curr = { "y", yes }, 1762306a36Sopenharmony_ci .flags = SYMBOL_CONST|SYMBOL_VALID, 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct symbol symbol_mod = { 2162306a36Sopenharmony_ci .name = "m", 2262306a36Sopenharmony_ci .curr = { "m", mod }, 2362306a36Sopenharmony_ci .flags = SYMBOL_CONST|SYMBOL_VALID, 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct symbol symbol_no = { 2762306a36Sopenharmony_ci .name = "n", 2862306a36Sopenharmony_ci .curr = { "n", no }, 2962306a36Sopenharmony_ci .flags = SYMBOL_CONST|SYMBOL_VALID, 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic struct symbol symbol_empty = { 3362306a36Sopenharmony_ci .name = "", 3462306a36Sopenharmony_ci .curr = { "", no }, 3562306a36Sopenharmony_ci .flags = SYMBOL_VALID, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistruct symbol *modules_sym; 3962306a36Sopenharmony_cistatic tristate modules_val; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cienum symbol_type sym_get_type(struct symbol *sym) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci enum symbol_type type = sym->type; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci if (type == S_TRISTATE) { 4662306a36Sopenharmony_ci if (sym_is_choice_value(sym) && sym->visible == yes) 4762306a36Sopenharmony_ci type = S_BOOLEAN; 4862306a36Sopenharmony_ci else if (modules_val == no) 4962306a36Sopenharmony_ci type = S_BOOLEAN; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci return type; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciconst char *sym_type_name(enum symbol_type type) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci switch (type) { 5762306a36Sopenharmony_ci case S_BOOLEAN: 5862306a36Sopenharmony_ci return "bool"; 5962306a36Sopenharmony_ci case S_TRISTATE: 6062306a36Sopenharmony_ci return "tristate"; 6162306a36Sopenharmony_ci case S_INT: 6262306a36Sopenharmony_ci return "integer"; 6362306a36Sopenharmony_ci case S_HEX: 6462306a36Sopenharmony_ci return "hex"; 6562306a36Sopenharmony_ci case S_STRING: 6662306a36Sopenharmony_ci return "string"; 6762306a36Sopenharmony_ci case S_UNKNOWN: 6862306a36Sopenharmony_ci return "unknown"; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci return "???"; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct property *sym_get_choice_prop(struct symbol *sym) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct property *prop; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci for_all_choices(sym, prop) 7862306a36Sopenharmony_ci return prop; 7962306a36Sopenharmony_ci return NULL; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic struct property *sym_get_default_prop(struct symbol *sym) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct property *prop; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for_all_defaults(sym, prop) { 8762306a36Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 8862306a36Sopenharmony_ci if (prop->visible.tri != no) 8962306a36Sopenharmony_ci return prop; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci return NULL; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct property *sym_get_range_prop(struct symbol *sym) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci struct property *prop; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci for_all_properties(sym, prop, P_RANGE) { 9962306a36Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 10062306a36Sopenharmony_ci if (prop->visible.tri != no) 10162306a36Sopenharmony_ci return prop; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci return NULL; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic long long sym_get_range_val(struct symbol *sym, int base) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci sym_calc_value(sym); 10962306a36Sopenharmony_ci switch (sym->type) { 11062306a36Sopenharmony_ci case S_INT: 11162306a36Sopenharmony_ci base = 10; 11262306a36Sopenharmony_ci break; 11362306a36Sopenharmony_ci case S_HEX: 11462306a36Sopenharmony_ci base = 16; 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci default: 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci return strtoll(sym->curr.val, NULL, base); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void sym_validate_range(struct symbol *sym) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct property *prop; 12562306a36Sopenharmony_ci struct symbol *range_sym; 12662306a36Sopenharmony_ci int base; 12762306a36Sopenharmony_ci long long val, val2; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci switch (sym->type) { 13062306a36Sopenharmony_ci case S_INT: 13162306a36Sopenharmony_ci base = 10; 13262306a36Sopenharmony_ci break; 13362306a36Sopenharmony_ci case S_HEX: 13462306a36Sopenharmony_ci base = 16; 13562306a36Sopenharmony_ci break; 13662306a36Sopenharmony_ci default: 13762306a36Sopenharmony_ci return; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci prop = sym_get_range_prop(sym); 14062306a36Sopenharmony_ci if (!prop) 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci val = strtoll(sym->curr.val, NULL, base); 14362306a36Sopenharmony_ci range_sym = prop->expr->left.sym; 14462306a36Sopenharmony_ci val2 = sym_get_range_val(range_sym, base); 14562306a36Sopenharmony_ci if (val >= val2) { 14662306a36Sopenharmony_ci range_sym = prop->expr->right.sym; 14762306a36Sopenharmony_ci val2 = sym_get_range_val(range_sym, base); 14862306a36Sopenharmony_ci if (val <= val2) 14962306a36Sopenharmony_ci return; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci sym->curr.val = range_sym->curr.val; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void sym_set_changed(struct symbol *sym) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct property *prop; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci sym->flags |= SYMBOL_CHANGED; 15962306a36Sopenharmony_ci for (prop = sym->prop; prop; prop = prop->next) { 16062306a36Sopenharmony_ci if (prop->menu) 16162306a36Sopenharmony_ci prop->menu->flags |= MENU_CHANGED; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic void sym_set_all_changed(void) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci struct symbol *sym; 16862306a36Sopenharmony_ci int i; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci for_all_symbols(i, sym) 17162306a36Sopenharmony_ci sym_set_changed(sym); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic void sym_calc_visibility(struct symbol *sym) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct property *prop; 17762306a36Sopenharmony_ci struct symbol *choice_sym = NULL; 17862306a36Sopenharmony_ci tristate tri; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* any prompt visible? */ 18162306a36Sopenharmony_ci tri = no; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (sym_is_choice_value(sym)) 18462306a36Sopenharmony_ci choice_sym = prop_get_symbol(sym_get_choice_prop(sym)); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci for_all_prompts(sym, prop) { 18762306a36Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 18862306a36Sopenharmony_ci /* 18962306a36Sopenharmony_ci * Tristate choice_values with visibility 'mod' are 19062306a36Sopenharmony_ci * not visible if the corresponding choice's value is 19162306a36Sopenharmony_ci * 'yes'. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if (choice_sym && sym->type == S_TRISTATE && 19462306a36Sopenharmony_ci prop->visible.tri == mod && choice_sym->curr.tri == yes) 19562306a36Sopenharmony_ci prop->visible.tri = no; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci tri = EXPR_OR(tri, prop->visible.tri); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) 20062306a36Sopenharmony_ci tri = yes; 20162306a36Sopenharmony_ci if (sym->visible != tri) { 20262306a36Sopenharmony_ci sym->visible = tri; 20362306a36Sopenharmony_ci sym_set_changed(sym); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci if (sym_is_choice_value(sym)) 20662306a36Sopenharmony_ci return; 20762306a36Sopenharmony_ci /* defaulting to "yes" if no explicit "depends on" are given */ 20862306a36Sopenharmony_ci tri = yes; 20962306a36Sopenharmony_ci if (sym->dir_dep.expr) 21062306a36Sopenharmony_ci tri = expr_calc_value(sym->dir_dep.expr); 21162306a36Sopenharmony_ci if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 21262306a36Sopenharmony_ci tri = yes; 21362306a36Sopenharmony_ci if (sym->dir_dep.tri != tri) { 21462306a36Sopenharmony_ci sym->dir_dep.tri = tri; 21562306a36Sopenharmony_ci sym_set_changed(sym); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci tri = no; 21862306a36Sopenharmony_ci if (sym->rev_dep.expr) 21962306a36Sopenharmony_ci tri = expr_calc_value(sym->rev_dep.expr); 22062306a36Sopenharmony_ci if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 22162306a36Sopenharmony_ci tri = yes; 22262306a36Sopenharmony_ci if (sym->rev_dep.tri != tri) { 22362306a36Sopenharmony_ci sym->rev_dep.tri = tri; 22462306a36Sopenharmony_ci sym_set_changed(sym); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci tri = no; 22762306a36Sopenharmony_ci if (sym->implied.expr) 22862306a36Sopenharmony_ci tri = expr_calc_value(sym->implied.expr); 22962306a36Sopenharmony_ci if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 23062306a36Sopenharmony_ci tri = yes; 23162306a36Sopenharmony_ci if (sym->implied.tri != tri) { 23262306a36Sopenharmony_ci sym->implied.tri = tri; 23362306a36Sopenharmony_ci sym_set_changed(sym); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* 23862306a36Sopenharmony_ci * Find the default symbol for a choice. 23962306a36Sopenharmony_ci * First try the default values for the choice symbol 24062306a36Sopenharmony_ci * Next locate the first visible choice value 24162306a36Sopenharmony_ci * Return NULL if none was found 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistruct symbol *sym_choice_default(struct symbol *sym) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct symbol *def_sym; 24662306a36Sopenharmony_ci struct property *prop; 24762306a36Sopenharmony_ci struct expr *e; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci /* any of the defaults visible? */ 25062306a36Sopenharmony_ci for_all_defaults(sym, prop) { 25162306a36Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 25262306a36Sopenharmony_ci if (prop->visible.tri == no) 25362306a36Sopenharmony_ci continue; 25462306a36Sopenharmony_ci def_sym = prop_get_symbol(prop); 25562306a36Sopenharmony_ci if (def_sym->visible != no) 25662306a36Sopenharmony_ci return def_sym; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* just get the first visible value */ 26062306a36Sopenharmony_ci prop = sym_get_choice_prop(sym); 26162306a36Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, def_sym) 26262306a36Sopenharmony_ci if (def_sym->visible != no) 26362306a36Sopenharmony_ci return def_sym; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* failed to locate any defaults */ 26662306a36Sopenharmony_ci return NULL; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic struct symbol *sym_calc_choice(struct symbol *sym) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci struct symbol *def_sym; 27262306a36Sopenharmony_ci struct property *prop; 27362306a36Sopenharmony_ci struct expr *e; 27462306a36Sopenharmony_ci int flags; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* first calculate all choice values' visibilities */ 27762306a36Sopenharmony_ci flags = sym->flags; 27862306a36Sopenharmony_ci prop = sym_get_choice_prop(sym); 27962306a36Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, def_sym) { 28062306a36Sopenharmony_ci sym_calc_visibility(def_sym); 28162306a36Sopenharmony_ci if (def_sym->visible != no) 28262306a36Sopenharmony_ci flags &= def_sym->flags; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci sym->flags &= flags | ~SYMBOL_DEF_USER; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci /* is the user choice visible? */ 28862306a36Sopenharmony_ci def_sym = sym->def[S_DEF_USER].val; 28962306a36Sopenharmony_ci if (def_sym && def_sym->visible != no) 29062306a36Sopenharmony_ci return def_sym; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci def_sym = sym_choice_default(sym); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (def_sym == NULL) 29562306a36Sopenharmony_ci /* no choice? reset tristate value */ 29662306a36Sopenharmony_ci sym->curr.tri = no; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return def_sym; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic void sym_warn_unmet_dep(struct symbol *sym) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct gstr gs = str_new(); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci str_printf(&gs, 30662306a36Sopenharmony_ci "\nWARNING: unmet direct dependencies detected for %s\n", 30762306a36Sopenharmony_ci sym->name); 30862306a36Sopenharmony_ci str_printf(&gs, 30962306a36Sopenharmony_ci " Depends on [%c]: ", 31062306a36Sopenharmony_ci sym->dir_dep.tri == mod ? 'm' : 'n'); 31162306a36Sopenharmony_ci expr_gstr_print(sym->dir_dep.expr, &gs); 31262306a36Sopenharmony_ci str_printf(&gs, "\n"); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes, 31562306a36Sopenharmony_ci " Selected by [y]:\n"); 31662306a36Sopenharmony_ci expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod, 31762306a36Sopenharmony_ci " Selected by [m]:\n"); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci fputs(str_get(&gs), stderr); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_civoid sym_calc_value(struct symbol *sym) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct symbol_value newval, oldval; 32562306a36Sopenharmony_ci struct property *prop; 32662306a36Sopenharmony_ci struct expr *e; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci if (!sym) 32962306a36Sopenharmony_ci return; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (sym->flags & SYMBOL_VALID) 33262306a36Sopenharmony_ci return; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (sym_is_choice_value(sym) && 33562306a36Sopenharmony_ci sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { 33662306a36Sopenharmony_ci sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; 33762306a36Sopenharmony_ci prop = sym_get_choice_prop(sym); 33862306a36Sopenharmony_ci sym_calc_value(prop_get_symbol(prop)); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci sym->flags |= SYMBOL_VALID; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci oldval = sym->curr; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci switch (sym->type) { 34662306a36Sopenharmony_ci case S_INT: 34762306a36Sopenharmony_ci case S_HEX: 34862306a36Sopenharmony_ci case S_STRING: 34962306a36Sopenharmony_ci newval = symbol_empty.curr; 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci case S_BOOLEAN: 35262306a36Sopenharmony_ci case S_TRISTATE: 35362306a36Sopenharmony_ci newval = symbol_no.curr; 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci default: 35662306a36Sopenharmony_ci sym->curr.val = sym->name; 35762306a36Sopenharmony_ci sym->curr.tri = no; 35862306a36Sopenharmony_ci return; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci sym->flags &= ~SYMBOL_WRITE; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci sym_calc_visibility(sym); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (sym->visible != no) 36562306a36Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* set default if recursively called */ 36862306a36Sopenharmony_ci sym->curr = newval; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci switch (sym_get_type(sym)) { 37162306a36Sopenharmony_ci case S_BOOLEAN: 37262306a36Sopenharmony_ci case S_TRISTATE: 37362306a36Sopenharmony_ci if (sym_is_choice_value(sym) && sym->visible == yes) { 37462306a36Sopenharmony_ci prop = sym_get_choice_prop(sym); 37562306a36Sopenharmony_ci newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; 37662306a36Sopenharmony_ci } else { 37762306a36Sopenharmony_ci if (sym->visible != no) { 37862306a36Sopenharmony_ci /* if the symbol is visible use the user value 37962306a36Sopenharmony_ci * if available, otherwise try the default value 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ci if (sym_has_value(sym)) { 38262306a36Sopenharmony_ci newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, 38362306a36Sopenharmony_ci sym->visible); 38462306a36Sopenharmony_ci goto calc_newval; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci if (sym->rev_dep.tri != no) 38862306a36Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 38962306a36Sopenharmony_ci if (!sym_is_choice(sym)) { 39062306a36Sopenharmony_ci prop = sym_get_default_prop(sym); 39162306a36Sopenharmony_ci if (prop) { 39262306a36Sopenharmony_ci newval.tri = EXPR_AND(expr_calc_value(prop->expr), 39362306a36Sopenharmony_ci prop->visible.tri); 39462306a36Sopenharmony_ci if (newval.tri != no) 39562306a36Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci if (sym->implied.tri != no) { 39862306a36Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 39962306a36Sopenharmony_ci newval.tri = EXPR_OR(newval.tri, sym->implied.tri); 40062306a36Sopenharmony_ci newval.tri = EXPR_AND(newval.tri, 40162306a36Sopenharmony_ci sym->dir_dep.tri); 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci calc_newval: 40562306a36Sopenharmony_ci if (sym->dir_dep.tri < sym->rev_dep.tri) 40662306a36Sopenharmony_ci sym_warn_unmet_dep(sym); 40762306a36Sopenharmony_ci newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) 41062306a36Sopenharmony_ci newval.tri = yes; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci case S_STRING: 41362306a36Sopenharmony_ci case S_HEX: 41462306a36Sopenharmony_ci case S_INT: 41562306a36Sopenharmony_ci if (sym->visible != no && sym_has_value(sym)) { 41662306a36Sopenharmony_ci newval.val = sym->def[S_DEF_USER].val; 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci prop = sym_get_default_prop(sym); 42062306a36Sopenharmony_ci if (prop) { 42162306a36Sopenharmony_ci struct symbol *ds = prop_get_symbol(prop); 42262306a36Sopenharmony_ci if (ds) { 42362306a36Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 42462306a36Sopenharmony_ci sym_calc_value(ds); 42562306a36Sopenharmony_ci newval.val = ds->curr.val; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci default: 43062306a36Sopenharmony_ci ; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci sym->curr = newval; 43462306a36Sopenharmony_ci if (sym_is_choice(sym) && newval.tri == yes) 43562306a36Sopenharmony_ci sym->curr.val = sym_calc_choice(sym); 43662306a36Sopenharmony_ci sym_validate_range(sym); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { 43962306a36Sopenharmony_ci sym_set_changed(sym); 44062306a36Sopenharmony_ci if (modules_sym == sym) { 44162306a36Sopenharmony_ci sym_set_all_changed(); 44262306a36Sopenharmony_ci modules_val = modules_sym->curr.tri; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (sym_is_choice(sym)) { 44762306a36Sopenharmony_ci struct symbol *choice_sym; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci prop = sym_get_choice_prop(sym); 45062306a36Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, choice_sym) { 45162306a36Sopenharmony_ci if ((sym->flags & SYMBOL_WRITE) && 45262306a36Sopenharmony_ci choice_sym->visible != no) 45362306a36Sopenharmony_ci choice_sym->flags |= SYMBOL_WRITE; 45462306a36Sopenharmony_ci if (sym->flags & SYMBOL_CHANGED) 45562306a36Sopenharmony_ci sym_set_changed(choice_sym); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (sym->flags & SYMBOL_NO_WRITE) 46062306a36Sopenharmony_ci sym->flags &= ~SYMBOL_WRITE; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) 46362306a36Sopenharmony_ci set_all_choice_values(sym); 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_civoid sym_clear_all_valid(void) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci struct symbol *sym; 46962306a36Sopenharmony_ci int i; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci for_all_symbols(i, sym) 47262306a36Sopenharmony_ci sym->flags &= ~SYMBOL_VALID; 47362306a36Sopenharmony_ci conf_set_changed(true); 47462306a36Sopenharmony_ci sym_calc_value(modules_sym); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cibool sym_tristate_within_range(struct symbol *sym, tristate val) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci int type = sym_get_type(sym); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (sym->visible == no) 48262306a36Sopenharmony_ci return false; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (type != S_BOOLEAN && type != S_TRISTATE) 48562306a36Sopenharmony_ci return false; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (type == S_BOOLEAN && val == mod) 48862306a36Sopenharmony_ci return false; 48962306a36Sopenharmony_ci if (sym->visible <= sym->rev_dep.tri) 49062306a36Sopenharmony_ci return false; 49162306a36Sopenharmony_ci if (sym_is_choice_value(sym) && sym->visible == yes) 49262306a36Sopenharmony_ci return val == yes; 49362306a36Sopenharmony_ci return val >= sym->rev_dep.tri && val <= sym->visible; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cibool sym_set_tristate_value(struct symbol *sym, tristate val) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci tristate oldval = sym_get_tristate_value(sym); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (oldval != val && !sym_tristate_within_range(sym, val)) 50162306a36Sopenharmony_ci return false; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (!(sym->flags & SYMBOL_DEF_USER)) { 50462306a36Sopenharmony_ci sym->flags |= SYMBOL_DEF_USER; 50562306a36Sopenharmony_ci sym_set_changed(sym); 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci /* 50862306a36Sopenharmony_ci * setting a choice value also resets the new flag of the choice 50962306a36Sopenharmony_ci * symbol and all other choice values. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci if (sym_is_choice_value(sym) && val == yes) { 51262306a36Sopenharmony_ci struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 51362306a36Sopenharmony_ci struct property *prop; 51462306a36Sopenharmony_ci struct expr *e; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci cs->def[S_DEF_USER].val = sym; 51762306a36Sopenharmony_ci cs->flags |= SYMBOL_DEF_USER; 51862306a36Sopenharmony_ci prop = sym_get_choice_prop(cs); 51962306a36Sopenharmony_ci for (e = prop->expr; e; e = e->left.expr) { 52062306a36Sopenharmony_ci if (e->right.sym->visible != no) 52162306a36Sopenharmony_ci e->right.sym->flags |= SYMBOL_DEF_USER; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci sym->def[S_DEF_USER].tri = val; 52662306a36Sopenharmony_ci if (oldval != val) 52762306a36Sopenharmony_ci sym_clear_all_valid(); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return true; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_citristate sym_toggle_tristate_value(struct symbol *sym) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci tristate oldval, newval; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci oldval = newval = sym_get_tristate_value(sym); 53762306a36Sopenharmony_ci do { 53862306a36Sopenharmony_ci switch (newval) { 53962306a36Sopenharmony_ci case no: 54062306a36Sopenharmony_ci newval = mod; 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case mod: 54362306a36Sopenharmony_ci newval = yes; 54462306a36Sopenharmony_ci break; 54562306a36Sopenharmony_ci case yes: 54662306a36Sopenharmony_ci newval = no; 54762306a36Sopenharmony_ci break; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci if (sym_set_tristate_value(sym, newval)) 55062306a36Sopenharmony_ci break; 55162306a36Sopenharmony_ci } while (oldval != newval); 55262306a36Sopenharmony_ci return newval; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cibool sym_string_valid(struct symbol *sym, const char *str) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci signed char ch; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci switch (sym->type) { 56062306a36Sopenharmony_ci case S_STRING: 56162306a36Sopenharmony_ci return true; 56262306a36Sopenharmony_ci case S_INT: 56362306a36Sopenharmony_ci ch = *str++; 56462306a36Sopenharmony_ci if (ch == '-') 56562306a36Sopenharmony_ci ch = *str++; 56662306a36Sopenharmony_ci if (!isdigit(ch)) 56762306a36Sopenharmony_ci return false; 56862306a36Sopenharmony_ci if (ch == '0' && *str != 0) 56962306a36Sopenharmony_ci return false; 57062306a36Sopenharmony_ci while ((ch = *str++)) { 57162306a36Sopenharmony_ci if (!isdigit(ch)) 57262306a36Sopenharmony_ci return false; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci return true; 57562306a36Sopenharmony_ci case S_HEX: 57662306a36Sopenharmony_ci if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) 57762306a36Sopenharmony_ci str += 2; 57862306a36Sopenharmony_ci ch = *str++; 57962306a36Sopenharmony_ci do { 58062306a36Sopenharmony_ci if (!isxdigit(ch)) 58162306a36Sopenharmony_ci return false; 58262306a36Sopenharmony_ci } while ((ch = *str++)); 58362306a36Sopenharmony_ci return true; 58462306a36Sopenharmony_ci case S_BOOLEAN: 58562306a36Sopenharmony_ci case S_TRISTATE: 58662306a36Sopenharmony_ci switch (str[0]) { 58762306a36Sopenharmony_ci case 'y': case 'Y': 58862306a36Sopenharmony_ci case 'm': case 'M': 58962306a36Sopenharmony_ci case 'n': case 'N': 59062306a36Sopenharmony_ci return true; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci return false; 59362306a36Sopenharmony_ci default: 59462306a36Sopenharmony_ci return false; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cibool sym_string_within_range(struct symbol *sym, const char *str) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct property *prop; 60162306a36Sopenharmony_ci long long val; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci switch (sym->type) { 60462306a36Sopenharmony_ci case S_STRING: 60562306a36Sopenharmony_ci return sym_string_valid(sym, str); 60662306a36Sopenharmony_ci case S_INT: 60762306a36Sopenharmony_ci if (!sym_string_valid(sym, str)) 60862306a36Sopenharmony_ci return false; 60962306a36Sopenharmony_ci prop = sym_get_range_prop(sym); 61062306a36Sopenharmony_ci if (!prop) 61162306a36Sopenharmony_ci return true; 61262306a36Sopenharmony_ci val = strtoll(str, NULL, 10); 61362306a36Sopenharmony_ci return val >= sym_get_range_val(prop->expr->left.sym, 10) && 61462306a36Sopenharmony_ci val <= sym_get_range_val(prop->expr->right.sym, 10); 61562306a36Sopenharmony_ci case S_HEX: 61662306a36Sopenharmony_ci if (!sym_string_valid(sym, str)) 61762306a36Sopenharmony_ci return false; 61862306a36Sopenharmony_ci prop = sym_get_range_prop(sym); 61962306a36Sopenharmony_ci if (!prop) 62062306a36Sopenharmony_ci return true; 62162306a36Sopenharmony_ci val = strtoll(str, NULL, 16); 62262306a36Sopenharmony_ci return val >= sym_get_range_val(prop->expr->left.sym, 16) && 62362306a36Sopenharmony_ci val <= sym_get_range_val(prop->expr->right.sym, 16); 62462306a36Sopenharmony_ci case S_BOOLEAN: 62562306a36Sopenharmony_ci case S_TRISTATE: 62662306a36Sopenharmony_ci switch (str[0]) { 62762306a36Sopenharmony_ci case 'y': case 'Y': 62862306a36Sopenharmony_ci return sym_tristate_within_range(sym, yes); 62962306a36Sopenharmony_ci case 'm': case 'M': 63062306a36Sopenharmony_ci return sym_tristate_within_range(sym, mod); 63162306a36Sopenharmony_ci case 'n': case 'N': 63262306a36Sopenharmony_ci return sym_tristate_within_range(sym, no); 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci return false; 63562306a36Sopenharmony_ci default: 63662306a36Sopenharmony_ci return false; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cibool sym_set_string_value(struct symbol *sym, const char *newval) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci const char *oldval; 64362306a36Sopenharmony_ci char *val; 64462306a36Sopenharmony_ci int size; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci switch (sym->type) { 64762306a36Sopenharmony_ci case S_BOOLEAN: 64862306a36Sopenharmony_ci case S_TRISTATE: 64962306a36Sopenharmony_ci switch (newval[0]) { 65062306a36Sopenharmony_ci case 'y': case 'Y': 65162306a36Sopenharmony_ci return sym_set_tristate_value(sym, yes); 65262306a36Sopenharmony_ci case 'm': case 'M': 65362306a36Sopenharmony_ci return sym_set_tristate_value(sym, mod); 65462306a36Sopenharmony_ci case 'n': case 'N': 65562306a36Sopenharmony_ci return sym_set_tristate_value(sym, no); 65662306a36Sopenharmony_ci } 65762306a36Sopenharmony_ci return false; 65862306a36Sopenharmony_ci default: 65962306a36Sopenharmony_ci ; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (!sym_string_within_range(sym, newval)) 66362306a36Sopenharmony_ci return false; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (!(sym->flags & SYMBOL_DEF_USER)) { 66662306a36Sopenharmony_ci sym->flags |= SYMBOL_DEF_USER; 66762306a36Sopenharmony_ci sym_set_changed(sym); 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci oldval = sym->def[S_DEF_USER].val; 67162306a36Sopenharmony_ci size = strlen(newval) + 1; 67262306a36Sopenharmony_ci if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { 67362306a36Sopenharmony_ci size += 2; 67462306a36Sopenharmony_ci sym->def[S_DEF_USER].val = val = xmalloc(size); 67562306a36Sopenharmony_ci *val++ = '0'; 67662306a36Sopenharmony_ci *val++ = 'x'; 67762306a36Sopenharmony_ci } else if (!oldval || strcmp(oldval, newval)) 67862306a36Sopenharmony_ci sym->def[S_DEF_USER].val = val = xmalloc(size); 67962306a36Sopenharmony_ci else 68062306a36Sopenharmony_ci return true; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci strcpy(val, newval); 68362306a36Sopenharmony_ci free((void *)oldval); 68462306a36Sopenharmony_ci sym_clear_all_valid(); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return true; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/* 69062306a36Sopenharmony_ci * Find the default value associated to a symbol. 69162306a36Sopenharmony_ci * For tristate symbol handle the modules=n case 69262306a36Sopenharmony_ci * in which case "m" becomes "y". 69362306a36Sopenharmony_ci * If the symbol does not have any default then fallback 69462306a36Sopenharmony_ci * to the fixed default values. 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_ciconst char *sym_get_string_default(struct symbol *sym) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct property *prop; 69962306a36Sopenharmony_ci struct symbol *ds; 70062306a36Sopenharmony_ci const char *str; 70162306a36Sopenharmony_ci tristate val; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci sym_calc_visibility(sym); 70462306a36Sopenharmony_ci sym_calc_value(modules_sym); 70562306a36Sopenharmony_ci val = symbol_no.curr.tri; 70662306a36Sopenharmony_ci str = symbol_empty.curr.val; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* If symbol has a default value look it up */ 70962306a36Sopenharmony_ci prop = sym_get_default_prop(sym); 71062306a36Sopenharmony_ci if (prop != NULL) { 71162306a36Sopenharmony_ci switch (sym->type) { 71262306a36Sopenharmony_ci case S_BOOLEAN: 71362306a36Sopenharmony_ci case S_TRISTATE: 71462306a36Sopenharmony_ci /* The visibility may limit the value from yes => mod */ 71562306a36Sopenharmony_ci val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci default: 71862306a36Sopenharmony_ci /* 71962306a36Sopenharmony_ci * The following fails to handle the situation 72062306a36Sopenharmony_ci * where a default value is further limited by 72162306a36Sopenharmony_ci * the valid range. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci ds = prop_get_symbol(prop); 72462306a36Sopenharmony_ci if (ds != NULL) { 72562306a36Sopenharmony_ci sym_calc_value(ds); 72662306a36Sopenharmony_ci str = (const char *)ds->curr.val; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Handle select statements */ 73262306a36Sopenharmony_ci val = EXPR_OR(val, sym->rev_dep.tri); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* transpose mod to yes if modules are not enabled */ 73562306a36Sopenharmony_ci if (val == mod) 73662306a36Sopenharmony_ci if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) 73762306a36Sopenharmony_ci val = yes; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci /* transpose mod to yes if type is bool */ 74062306a36Sopenharmony_ci if (sym->type == S_BOOLEAN && val == mod) 74162306a36Sopenharmony_ci val = yes; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci /* adjust the default value if this symbol is implied by another */ 74462306a36Sopenharmony_ci if (val < sym->implied.tri) 74562306a36Sopenharmony_ci val = sym->implied.tri; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci switch (sym->type) { 74862306a36Sopenharmony_ci case S_BOOLEAN: 74962306a36Sopenharmony_ci case S_TRISTATE: 75062306a36Sopenharmony_ci switch (val) { 75162306a36Sopenharmony_ci case no: return "n"; 75262306a36Sopenharmony_ci case mod: return "m"; 75362306a36Sopenharmony_ci case yes: return "y"; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci case S_INT: 75662306a36Sopenharmony_ci case S_HEX: 75762306a36Sopenharmony_ci return str; 75862306a36Sopenharmony_ci case S_STRING: 75962306a36Sopenharmony_ci return str; 76062306a36Sopenharmony_ci case S_UNKNOWN: 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci return ""; 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ciconst char *sym_get_string_value(struct symbol *sym) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci tristate val; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci switch (sym->type) { 77162306a36Sopenharmony_ci case S_BOOLEAN: 77262306a36Sopenharmony_ci case S_TRISTATE: 77362306a36Sopenharmony_ci val = sym_get_tristate_value(sym); 77462306a36Sopenharmony_ci switch (val) { 77562306a36Sopenharmony_ci case no: 77662306a36Sopenharmony_ci return "n"; 77762306a36Sopenharmony_ci case mod: 77862306a36Sopenharmony_ci sym_calc_value(modules_sym); 77962306a36Sopenharmony_ci return (modules_sym->curr.tri == no) ? "n" : "m"; 78062306a36Sopenharmony_ci case yes: 78162306a36Sopenharmony_ci return "y"; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci break; 78462306a36Sopenharmony_ci default: 78562306a36Sopenharmony_ci ; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci return (const char *)sym->curr.val; 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cibool sym_is_changeable(struct symbol *sym) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci return sym->visible > sym->rev_dep.tri; 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic unsigned strhash(const char *s) 79662306a36Sopenharmony_ci{ 79762306a36Sopenharmony_ci /* fnv32 hash */ 79862306a36Sopenharmony_ci unsigned hash = 2166136261U; 79962306a36Sopenharmony_ci for (; *s; s++) 80062306a36Sopenharmony_ci hash = (hash ^ *s) * 0x01000193; 80162306a36Sopenharmony_ci return hash; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistruct symbol *sym_lookup(const char *name, int flags) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct symbol *symbol; 80762306a36Sopenharmony_ci char *new_name; 80862306a36Sopenharmony_ci int hash; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (name) { 81162306a36Sopenharmony_ci if (name[0] && !name[1]) { 81262306a36Sopenharmony_ci switch (name[0]) { 81362306a36Sopenharmony_ci case 'y': return &symbol_yes; 81462306a36Sopenharmony_ci case 'm': return &symbol_mod; 81562306a36Sopenharmony_ci case 'n': return &symbol_no; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci hash = strhash(name) % SYMBOL_HASHSIZE; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 82162306a36Sopenharmony_ci if (symbol->name && 82262306a36Sopenharmony_ci !strcmp(symbol->name, name) && 82362306a36Sopenharmony_ci (flags ? symbol->flags & flags 82462306a36Sopenharmony_ci : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) 82562306a36Sopenharmony_ci return symbol; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci new_name = xstrdup(name); 82862306a36Sopenharmony_ci } else { 82962306a36Sopenharmony_ci new_name = NULL; 83062306a36Sopenharmony_ci hash = 0; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci symbol = xmalloc(sizeof(*symbol)); 83462306a36Sopenharmony_ci memset(symbol, 0, sizeof(*symbol)); 83562306a36Sopenharmony_ci symbol->name = new_name; 83662306a36Sopenharmony_ci symbol->type = S_UNKNOWN; 83762306a36Sopenharmony_ci symbol->flags = flags; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci symbol->next = symbol_hash[hash]; 84062306a36Sopenharmony_ci symbol_hash[hash] = symbol; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci return symbol; 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistruct symbol *sym_find(const char *name) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci struct symbol *symbol = NULL; 84862306a36Sopenharmony_ci int hash = 0; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (!name) 85162306a36Sopenharmony_ci return NULL; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (name[0] && !name[1]) { 85462306a36Sopenharmony_ci switch (name[0]) { 85562306a36Sopenharmony_ci case 'y': return &symbol_yes; 85662306a36Sopenharmony_ci case 'm': return &symbol_mod; 85762306a36Sopenharmony_ci case 'n': return &symbol_no; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci hash = strhash(name) % SYMBOL_HASHSIZE; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 86362306a36Sopenharmony_ci if (symbol->name && 86462306a36Sopenharmony_ci !strcmp(symbol->name, name) && 86562306a36Sopenharmony_ci !(symbol->flags & SYMBOL_CONST)) 86662306a36Sopenharmony_ci break; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci return symbol; 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistruct sym_match { 87362306a36Sopenharmony_ci struct symbol *sym; 87462306a36Sopenharmony_ci off_t so, eo; 87562306a36Sopenharmony_ci}; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/* Compare matched symbols as thus: 87862306a36Sopenharmony_ci * - first, symbols that match exactly 87962306a36Sopenharmony_ci * - then, alphabetical sort 88062306a36Sopenharmony_ci */ 88162306a36Sopenharmony_cistatic int sym_rel_comp(const void *sym1, const void *sym2) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci const struct sym_match *s1 = sym1; 88462306a36Sopenharmony_ci const struct sym_match *s2 = sym2; 88562306a36Sopenharmony_ci int exact1, exact2; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Exact match: 88862306a36Sopenharmony_ci * - if matched length on symbol s1 is the length of that symbol, 88962306a36Sopenharmony_ci * then this symbol should come first; 89062306a36Sopenharmony_ci * - if matched length on symbol s2 is the length of that symbol, 89162306a36Sopenharmony_ci * then this symbol should come first. 89262306a36Sopenharmony_ci * Note: since the search can be a regexp, both symbols may match 89362306a36Sopenharmony_ci * exactly; if this is the case, we can't decide which comes first, 89462306a36Sopenharmony_ci * and we fallback to sorting alphabetically. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); 89762306a36Sopenharmony_ci exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); 89862306a36Sopenharmony_ci if (exact1 && !exact2) 89962306a36Sopenharmony_ci return -1; 90062306a36Sopenharmony_ci if (!exact1 && exact2) 90162306a36Sopenharmony_ci return 1; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci /* As a fallback, sort symbols alphabetically */ 90462306a36Sopenharmony_ci return strcmp(s1->sym->name, s2->sym->name); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistruct symbol **sym_re_search(const char *pattern) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct symbol *sym, **sym_arr = NULL; 91062306a36Sopenharmony_ci struct sym_match *sym_match_arr = NULL; 91162306a36Sopenharmony_ci int i, cnt, size; 91262306a36Sopenharmony_ci regex_t re; 91362306a36Sopenharmony_ci regmatch_t match[1]; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci cnt = size = 0; 91662306a36Sopenharmony_ci /* Skip if empty */ 91762306a36Sopenharmony_ci if (strlen(pattern) == 0) 91862306a36Sopenharmony_ci return NULL; 91962306a36Sopenharmony_ci if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) 92062306a36Sopenharmony_ci return NULL; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci for_all_symbols(i, sym) { 92362306a36Sopenharmony_ci if (sym->flags & SYMBOL_CONST || !sym->name) 92462306a36Sopenharmony_ci continue; 92562306a36Sopenharmony_ci if (regexec(&re, sym->name, 1, match, 0)) 92662306a36Sopenharmony_ci continue; 92762306a36Sopenharmony_ci if (cnt >= size) { 92862306a36Sopenharmony_ci void *tmp; 92962306a36Sopenharmony_ci size += 16; 93062306a36Sopenharmony_ci tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); 93162306a36Sopenharmony_ci if (!tmp) 93262306a36Sopenharmony_ci goto sym_re_search_free; 93362306a36Sopenharmony_ci sym_match_arr = tmp; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci sym_calc_value(sym); 93662306a36Sopenharmony_ci /* As regexec returned 0, we know we have a match, so 93762306a36Sopenharmony_ci * we can use match[0].rm_[se]o without further checks 93862306a36Sopenharmony_ci */ 93962306a36Sopenharmony_ci sym_match_arr[cnt].so = match[0].rm_so; 94062306a36Sopenharmony_ci sym_match_arr[cnt].eo = match[0].rm_eo; 94162306a36Sopenharmony_ci sym_match_arr[cnt++].sym = sym; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci if (sym_match_arr) { 94462306a36Sopenharmony_ci qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); 94562306a36Sopenharmony_ci sym_arr = malloc((cnt+1) * sizeof(struct symbol *)); 94662306a36Sopenharmony_ci if (!sym_arr) 94762306a36Sopenharmony_ci goto sym_re_search_free; 94862306a36Sopenharmony_ci for (i = 0; i < cnt; i++) 94962306a36Sopenharmony_ci sym_arr[i] = sym_match_arr[i].sym; 95062306a36Sopenharmony_ci sym_arr[cnt] = NULL; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_cisym_re_search_free: 95362306a36Sopenharmony_ci /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ 95462306a36Sopenharmony_ci free(sym_match_arr); 95562306a36Sopenharmony_ci regfree(&re); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return sym_arr; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci/* 96162306a36Sopenharmony_ci * When we check for recursive dependencies we use a stack to save 96262306a36Sopenharmony_ci * current state so we can print out relevant info to user. 96362306a36Sopenharmony_ci * The entries are located on the call stack so no need to free memory. 96462306a36Sopenharmony_ci * Note insert() remove() must always match to properly clear the stack. 96562306a36Sopenharmony_ci */ 96662306a36Sopenharmony_cistatic struct dep_stack { 96762306a36Sopenharmony_ci struct dep_stack *prev, *next; 96862306a36Sopenharmony_ci struct symbol *sym; 96962306a36Sopenharmony_ci struct property *prop; 97062306a36Sopenharmony_ci struct expr **expr; 97162306a36Sopenharmony_ci} *check_top; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_cistatic void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci memset(stack, 0, sizeof(*stack)); 97662306a36Sopenharmony_ci if (check_top) 97762306a36Sopenharmony_ci check_top->next = stack; 97862306a36Sopenharmony_ci stack->prev = check_top; 97962306a36Sopenharmony_ci stack->sym = sym; 98062306a36Sopenharmony_ci check_top = stack; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic void dep_stack_remove(void) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci check_top = check_top->prev; 98662306a36Sopenharmony_ci if (check_top) 98762306a36Sopenharmony_ci check_top->next = NULL; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* 99162306a36Sopenharmony_ci * Called when we have detected a recursive dependency. 99262306a36Sopenharmony_ci * check_top point to the top of the stact so we use 99362306a36Sopenharmony_ci * the ->prev pointer to locate the bottom of the stack. 99462306a36Sopenharmony_ci */ 99562306a36Sopenharmony_cistatic void sym_check_print_recursive(struct symbol *last_sym) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct dep_stack *stack; 99862306a36Sopenharmony_ci struct symbol *sym, *next_sym; 99962306a36Sopenharmony_ci struct menu *menu = NULL; 100062306a36Sopenharmony_ci struct property *prop; 100162306a36Sopenharmony_ci struct dep_stack cv_stack; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (sym_is_choice_value(last_sym)) { 100462306a36Sopenharmony_ci dep_stack_insert(&cv_stack, last_sym); 100562306a36Sopenharmony_ci last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci for (stack = check_top; stack != NULL; stack = stack->prev) 100962306a36Sopenharmony_ci if (stack->sym == last_sym) 101062306a36Sopenharmony_ci break; 101162306a36Sopenharmony_ci if (!stack) { 101262306a36Sopenharmony_ci fprintf(stderr, "unexpected recursive dependency error\n"); 101362306a36Sopenharmony_ci return; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci for (; stack; stack = stack->next) { 101762306a36Sopenharmony_ci sym = stack->sym; 101862306a36Sopenharmony_ci next_sym = stack->next ? stack->next->sym : last_sym; 101962306a36Sopenharmony_ci prop = stack->prop; 102062306a36Sopenharmony_ci if (prop == NULL) 102162306a36Sopenharmony_ci prop = stack->sym->prop; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* for choice values find the menu entry (used below) */ 102462306a36Sopenharmony_ci if (sym_is_choice(sym) || sym_is_choice_value(sym)) { 102562306a36Sopenharmony_ci for (prop = sym->prop; prop; prop = prop->next) { 102662306a36Sopenharmony_ci menu = prop->menu; 102762306a36Sopenharmony_ci if (prop->menu) 102862306a36Sopenharmony_ci break; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci if (stack->sym == last_sym) 103262306a36Sopenharmony_ci fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", 103362306a36Sopenharmony_ci prop->file->name, prop->lineno); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci if (sym_is_choice(sym)) { 103662306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", 103762306a36Sopenharmony_ci menu->file->name, menu->lineno, 103862306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 103962306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 104062306a36Sopenharmony_ci } else if (sym_is_choice_value(sym)) { 104162306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", 104262306a36Sopenharmony_ci menu->file->name, menu->lineno, 104362306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 104462306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 104562306a36Sopenharmony_ci } else if (stack->expr == &sym->dir_dep.expr) { 104662306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", 104762306a36Sopenharmony_ci prop->file->name, prop->lineno, 104862306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 104962306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 105062306a36Sopenharmony_ci } else if (stack->expr == &sym->rev_dep.expr) { 105162306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", 105262306a36Sopenharmony_ci prop->file->name, prop->lineno, 105362306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 105462306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 105562306a36Sopenharmony_ci } else if (stack->expr == &sym->implied.expr) { 105662306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", 105762306a36Sopenharmony_ci prop->file->name, prop->lineno, 105862306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 105962306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 106062306a36Sopenharmony_ci } else if (stack->expr) { 106162306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", 106262306a36Sopenharmony_ci prop->file->name, prop->lineno, 106362306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 106462306a36Sopenharmony_ci prop_get_type_name(prop->type), 106562306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 106662306a36Sopenharmony_ci } else { 106762306a36Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", 106862306a36Sopenharmony_ci prop->file->name, prop->lineno, 106962306a36Sopenharmony_ci sym->name ? sym->name : "<choice>", 107062306a36Sopenharmony_ci prop_get_type_name(prop->type), 107162306a36Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 107262306a36Sopenharmony_ci } 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci fprintf(stderr, 107662306a36Sopenharmony_ci "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n" 107762306a36Sopenharmony_ci "subsection \"Kconfig recursive dependency limitations\"\n" 107862306a36Sopenharmony_ci "\n"); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (check_top == &cv_stack) 108162306a36Sopenharmony_ci dep_stack_remove(); 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic struct symbol *sym_check_expr_deps(struct expr *e) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct symbol *sym; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (!e) 108962306a36Sopenharmony_ci return NULL; 109062306a36Sopenharmony_ci switch (e->type) { 109162306a36Sopenharmony_ci case E_OR: 109262306a36Sopenharmony_ci case E_AND: 109362306a36Sopenharmony_ci sym = sym_check_expr_deps(e->left.expr); 109462306a36Sopenharmony_ci if (sym) 109562306a36Sopenharmony_ci return sym; 109662306a36Sopenharmony_ci return sym_check_expr_deps(e->right.expr); 109762306a36Sopenharmony_ci case E_NOT: 109862306a36Sopenharmony_ci return sym_check_expr_deps(e->left.expr); 109962306a36Sopenharmony_ci case E_EQUAL: 110062306a36Sopenharmony_ci case E_GEQ: 110162306a36Sopenharmony_ci case E_GTH: 110262306a36Sopenharmony_ci case E_LEQ: 110362306a36Sopenharmony_ci case E_LTH: 110462306a36Sopenharmony_ci case E_UNEQUAL: 110562306a36Sopenharmony_ci sym = sym_check_deps(e->left.sym); 110662306a36Sopenharmony_ci if (sym) 110762306a36Sopenharmony_ci return sym; 110862306a36Sopenharmony_ci return sym_check_deps(e->right.sym); 110962306a36Sopenharmony_ci case E_SYMBOL: 111062306a36Sopenharmony_ci return sym_check_deps(e->left.sym); 111162306a36Sopenharmony_ci default: 111262306a36Sopenharmony_ci break; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci fprintf(stderr, "Oops! How to check %d?\n", e->type); 111562306a36Sopenharmony_ci return NULL; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci/* return NULL when dependencies are OK */ 111962306a36Sopenharmony_cistatic struct symbol *sym_check_sym_deps(struct symbol *sym) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci struct symbol *sym2; 112262306a36Sopenharmony_ci struct property *prop; 112362306a36Sopenharmony_ci struct dep_stack stack; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci dep_stack_insert(&stack, sym); 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci stack.expr = &sym->dir_dep.expr; 112862306a36Sopenharmony_ci sym2 = sym_check_expr_deps(sym->dir_dep.expr); 112962306a36Sopenharmony_ci if (sym2) 113062306a36Sopenharmony_ci goto out; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci stack.expr = &sym->rev_dep.expr; 113362306a36Sopenharmony_ci sym2 = sym_check_expr_deps(sym->rev_dep.expr); 113462306a36Sopenharmony_ci if (sym2) 113562306a36Sopenharmony_ci goto out; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci stack.expr = &sym->implied.expr; 113862306a36Sopenharmony_ci sym2 = sym_check_expr_deps(sym->implied.expr); 113962306a36Sopenharmony_ci if (sym2) 114062306a36Sopenharmony_ci goto out; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci stack.expr = NULL; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci for (prop = sym->prop; prop; prop = prop->next) { 114562306a36Sopenharmony_ci if (prop->type == P_CHOICE || prop->type == P_SELECT || 114662306a36Sopenharmony_ci prop->type == P_IMPLY) 114762306a36Sopenharmony_ci continue; 114862306a36Sopenharmony_ci stack.prop = prop; 114962306a36Sopenharmony_ci sym2 = sym_check_expr_deps(prop->visible.expr); 115062306a36Sopenharmony_ci if (sym2) 115162306a36Sopenharmony_ci break; 115262306a36Sopenharmony_ci if (prop->type != P_DEFAULT || sym_is_choice(sym)) 115362306a36Sopenharmony_ci continue; 115462306a36Sopenharmony_ci stack.expr = &prop->expr; 115562306a36Sopenharmony_ci sym2 = sym_check_expr_deps(prop->expr); 115662306a36Sopenharmony_ci if (sym2) 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci stack.expr = NULL; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ciout: 116262306a36Sopenharmony_ci dep_stack_remove(); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci return sym2; 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_cistatic struct symbol *sym_check_choice_deps(struct symbol *choice) 116862306a36Sopenharmony_ci{ 116962306a36Sopenharmony_ci struct symbol *sym, *sym2; 117062306a36Sopenharmony_ci struct property *prop; 117162306a36Sopenharmony_ci struct expr *e; 117262306a36Sopenharmony_ci struct dep_stack stack; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci dep_stack_insert(&stack, choice); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci prop = sym_get_choice_prop(choice); 117762306a36Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, sym) 117862306a36Sopenharmony_ci sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 118162306a36Sopenharmony_ci sym2 = sym_check_sym_deps(choice); 118262306a36Sopenharmony_ci choice->flags &= ~SYMBOL_CHECK; 118362306a36Sopenharmony_ci if (sym2) 118462306a36Sopenharmony_ci goto out; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, sym) { 118762306a36Sopenharmony_ci sym2 = sym_check_sym_deps(sym); 118862306a36Sopenharmony_ci if (sym2) 118962306a36Sopenharmony_ci break; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ciout: 119262306a36Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, sym) 119362306a36Sopenharmony_ci sym->flags &= ~SYMBOL_CHECK; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (sym2 && sym_is_choice_value(sym2) && 119662306a36Sopenharmony_ci prop_get_symbol(sym_get_choice_prop(sym2)) == choice) 119762306a36Sopenharmony_ci sym2 = choice; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci dep_stack_remove(); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci return sym2; 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_cistruct symbol *sym_check_deps(struct symbol *sym) 120562306a36Sopenharmony_ci{ 120662306a36Sopenharmony_ci struct symbol *sym2; 120762306a36Sopenharmony_ci struct property *prop; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (sym->flags & SYMBOL_CHECK) { 121062306a36Sopenharmony_ci sym_check_print_recursive(sym); 121162306a36Sopenharmony_ci return sym; 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci if (sym->flags & SYMBOL_CHECKED) 121462306a36Sopenharmony_ci return NULL; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci if (sym_is_choice_value(sym)) { 121762306a36Sopenharmony_ci struct dep_stack stack; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* for choice groups start the check with main choice symbol */ 122062306a36Sopenharmony_ci dep_stack_insert(&stack, sym); 122162306a36Sopenharmony_ci prop = sym_get_choice_prop(sym); 122262306a36Sopenharmony_ci sym2 = sym_check_deps(prop_get_symbol(prop)); 122362306a36Sopenharmony_ci dep_stack_remove(); 122462306a36Sopenharmony_ci } else if (sym_is_choice(sym)) { 122562306a36Sopenharmony_ci sym2 = sym_check_choice_deps(sym); 122662306a36Sopenharmony_ci } else { 122762306a36Sopenharmony_ci sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 122862306a36Sopenharmony_ci sym2 = sym_check_sym_deps(sym); 122962306a36Sopenharmony_ci sym->flags &= ~SYMBOL_CHECK; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci return sym2; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistruct symbol *prop_get_symbol(struct property *prop) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci if (prop->expr && (prop->expr->type == E_SYMBOL || 123862306a36Sopenharmony_ci prop->expr->type == E_LIST)) 123962306a36Sopenharmony_ci return prop->expr->left.sym; 124062306a36Sopenharmony_ci return NULL; 124162306a36Sopenharmony_ci} 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ciconst char *prop_get_type_name(enum prop_type type) 124462306a36Sopenharmony_ci{ 124562306a36Sopenharmony_ci switch (type) { 124662306a36Sopenharmony_ci case P_PROMPT: 124762306a36Sopenharmony_ci return "prompt"; 124862306a36Sopenharmony_ci case P_COMMENT: 124962306a36Sopenharmony_ci return "comment"; 125062306a36Sopenharmony_ci case P_MENU: 125162306a36Sopenharmony_ci return "menu"; 125262306a36Sopenharmony_ci case P_DEFAULT: 125362306a36Sopenharmony_ci return "default"; 125462306a36Sopenharmony_ci case P_CHOICE: 125562306a36Sopenharmony_ci return "choice"; 125662306a36Sopenharmony_ci case P_SELECT: 125762306a36Sopenharmony_ci return "select"; 125862306a36Sopenharmony_ci case P_IMPLY: 125962306a36Sopenharmony_ci return "imply"; 126062306a36Sopenharmony_ci case P_RANGE: 126162306a36Sopenharmony_ci return "range"; 126262306a36Sopenharmony_ci case P_SYMBOL: 126362306a36Sopenharmony_ci return "symbol"; 126462306a36Sopenharmony_ci case P_UNKNOWN: 126562306a36Sopenharmony_ci break; 126662306a36Sopenharmony_ci } 126762306a36Sopenharmony_ci return "unknown"; 126862306a36Sopenharmony_ci} 1269