18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <ctype.h> 78c2ecf20Sopenharmony_ci#include <stdlib.h> 88c2ecf20Sopenharmony_ci#include <string.h> 98c2ecf20Sopenharmony_ci#include <regex.h> 108c2ecf20Sopenharmony_ci#include <sys/utsname.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "lkc.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistruct symbol symbol_yes = { 158c2ecf20Sopenharmony_ci .name = "y", 168c2ecf20Sopenharmony_ci .curr = { "y", yes }, 178c2ecf20Sopenharmony_ci .flags = SYMBOL_CONST|SYMBOL_VALID, 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct symbol symbol_mod = { 218c2ecf20Sopenharmony_ci .name = "m", 228c2ecf20Sopenharmony_ci .curr = { "m", mod }, 238c2ecf20Sopenharmony_ci .flags = SYMBOL_CONST|SYMBOL_VALID, 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistruct symbol symbol_no = { 278c2ecf20Sopenharmony_ci .name = "n", 288c2ecf20Sopenharmony_ci .curr = { "n", no }, 298c2ecf20Sopenharmony_ci .flags = SYMBOL_CONST|SYMBOL_VALID, 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct symbol symbol_empty = { 338c2ecf20Sopenharmony_ci .name = "", 348c2ecf20Sopenharmony_ci .curr = { "", no }, 358c2ecf20Sopenharmony_ci .flags = SYMBOL_VALID, 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct symbol *sym_defconfig_list; 398c2ecf20Sopenharmony_cistruct symbol *modules_sym; 408c2ecf20Sopenharmony_cistatic tristate modules_val; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cienum symbol_type sym_get_type(struct symbol *sym) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci enum symbol_type type = sym->type; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (type == S_TRISTATE) { 478c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym) && sym->visible == yes) 488c2ecf20Sopenharmony_ci type = S_BOOLEAN; 498c2ecf20Sopenharmony_ci else if (modules_val == no) 508c2ecf20Sopenharmony_ci type = S_BOOLEAN; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci return type; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciconst char *sym_type_name(enum symbol_type type) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci switch (type) { 588c2ecf20Sopenharmony_ci case S_BOOLEAN: 598c2ecf20Sopenharmony_ci return "bool"; 608c2ecf20Sopenharmony_ci case S_TRISTATE: 618c2ecf20Sopenharmony_ci return "tristate"; 628c2ecf20Sopenharmony_ci case S_INT: 638c2ecf20Sopenharmony_ci return "integer"; 648c2ecf20Sopenharmony_ci case S_HEX: 658c2ecf20Sopenharmony_ci return "hex"; 668c2ecf20Sopenharmony_ci case S_STRING: 678c2ecf20Sopenharmony_ci return "string"; 688c2ecf20Sopenharmony_ci case S_UNKNOWN: 698c2ecf20Sopenharmony_ci return "unknown"; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci return "???"; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct property *sym_get_choice_prop(struct symbol *sym) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct property *prop; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci for_all_choices(sym, prop) 798c2ecf20Sopenharmony_ci return prop; 808c2ecf20Sopenharmony_ci return NULL; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic struct property *sym_get_default_prop(struct symbol *sym) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct property *prop; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci for_all_defaults(sym, prop) { 888c2ecf20Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 898c2ecf20Sopenharmony_ci if (prop->visible.tri != no) 908c2ecf20Sopenharmony_ci return prop; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistruct property *sym_get_range_prop(struct symbol *sym) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci struct property *prop; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci for_all_properties(sym, prop, P_RANGE) { 1008c2ecf20Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 1018c2ecf20Sopenharmony_ci if (prop->visible.tri != no) 1028c2ecf20Sopenharmony_ci return prop; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci return NULL; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic long long sym_get_range_val(struct symbol *sym, int base) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci sym_calc_value(sym); 1108c2ecf20Sopenharmony_ci switch (sym->type) { 1118c2ecf20Sopenharmony_ci case S_INT: 1128c2ecf20Sopenharmony_ci base = 10; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci case S_HEX: 1158c2ecf20Sopenharmony_ci base = 16; 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci default: 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci return strtoll(sym->curr.val, NULL, base); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic void sym_validate_range(struct symbol *sym) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct property *prop; 1268c2ecf20Sopenharmony_ci struct symbol *range_sym; 1278c2ecf20Sopenharmony_ci int base; 1288c2ecf20Sopenharmony_ci long long val, val2; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch (sym->type) { 1318c2ecf20Sopenharmony_ci case S_INT: 1328c2ecf20Sopenharmony_ci base = 10; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case S_HEX: 1358c2ecf20Sopenharmony_ci base = 16; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci default: 1388c2ecf20Sopenharmony_ci return; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci prop = sym_get_range_prop(sym); 1418c2ecf20Sopenharmony_ci if (!prop) 1428c2ecf20Sopenharmony_ci return; 1438c2ecf20Sopenharmony_ci val = strtoll(sym->curr.val, NULL, base); 1448c2ecf20Sopenharmony_ci range_sym = prop->expr->left.sym; 1458c2ecf20Sopenharmony_ci val2 = sym_get_range_val(range_sym, base); 1468c2ecf20Sopenharmony_ci if (val >= val2) { 1478c2ecf20Sopenharmony_ci range_sym = prop->expr->right.sym; 1488c2ecf20Sopenharmony_ci val2 = sym_get_range_val(range_sym, base); 1498c2ecf20Sopenharmony_ci if (val <= val2) 1508c2ecf20Sopenharmony_ci return; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci sym->curr.val = range_sym->curr.val; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic void sym_set_changed(struct symbol *sym) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct property *prop; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_CHANGED; 1608c2ecf20Sopenharmony_ci for (prop = sym->prop; prop; prop = prop->next) { 1618c2ecf20Sopenharmony_ci if (prop->menu) 1628c2ecf20Sopenharmony_ci prop->menu->flags |= MENU_CHANGED; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void sym_set_all_changed(void) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct symbol *sym; 1698c2ecf20Sopenharmony_ci int i; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci for_all_symbols(i, sym) 1728c2ecf20Sopenharmony_ci sym_set_changed(sym); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic void sym_calc_visibility(struct symbol *sym) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct property *prop; 1788c2ecf20Sopenharmony_ci struct symbol *choice_sym = NULL; 1798c2ecf20Sopenharmony_ci tristate tri; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* any prompt visible? */ 1828c2ecf20Sopenharmony_ci tri = no; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym)) 1858c2ecf20Sopenharmony_ci choice_sym = prop_get_symbol(sym_get_choice_prop(sym)); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci for_all_prompts(sym, prop) { 1888c2ecf20Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * Tristate choice_values with visibility 'mod' are 1918c2ecf20Sopenharmony_ci * not visible if the corresponding choice's value is 1928c2ecf20Sopenharmony_ci * 'yes'. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci if (choice_sym && sym->type == S_TRISTATE && 1958c2ecf20Sopenharmony_ci prop->visible.tri == mod && choice_sym->curr.tri == yes) 1968c2ecf20Sopenharmony_ci prop->visible.tri = no; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci tri = EXPR_OR(tri, prop->visible.tri); 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) 2018c2ecf20Sopenharmony_ci tri = yes; 2028c2ecf20Sopenharmony_ci if (sym->visible != tri) { 2038c2ecf20Sopenharmony_ci sym->visible = tri; 2048c2ecf20Sopenharmony_ci sym_set_changed(sym); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym)) 2078c2ecf20Sopenharmony_ci return; 2088c2ecf20Sopenharmony_ci /* defaulting to "yes" if no explicit "depends on" are given */ 2098c2ecf20Sopenharmony_ci tri = yes; 2108c2ecf20Sopenharmony_ci if (sym->dir_dep.expr) 2118c2ecf20Sopenharmony_ci tri = expr_calc_value(sym->dir_dep.expr); 2128c2ecf20Sopenharmony_ci if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 2138c2ecf20Sopenharmony_ci tri = yes; 2148c2ecf20Sopenharmony_ci if (sym->dir_dep.tri != tri) { 2158c2ecf20Sopenharmony_ci sym->dir_dep.tri = tri; 2168c2ecf20Sopenharmony_ci sym_set_changed(sym); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci tri = no; 2198c2ecf20Sopenharmony_ci if (sym->rev_dep.expr) 2208c2ecf20Sopenharmony_ci tri = expr_calc_value(sym->rev_dep.expr); 2218c2ecf20Sopenharmony_ci if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 2228c2ecf20Sopenharmony_ci tri = yes; 2238c2ecf20Sopenharmony_ci if (sym->rev_dep.tri != tri) { 2248c2ecf20Sopenharmony_ci sym->rev_dep.tri = tri; 2258c2ecf20Sopenharmony_ci sym_set_changed(sym); 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci tri = no; 2288c2ecf20Sopenharmony_ci if (sym->implied.expr) 2298c2ecf20Sopenharmony_ci tri = expr_calc_value(sym->implied.expr); 2308c2ecf20Sopenharmony_ci if (tri == mod && sym_get_type(sym) == S_BOOLEAN) 2318c2ecf20Sopenharmony_ci tri = yes; 2328c2ecf20Sopenharmony_ci if (sym->implied.tri != tri) { 2338c2ecf20Sopenharmony_ci sym->implied.tri = tri; 2348c2ecf20Sopenharmony_ci sym_set_changed(sym); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci/* 2398c2ecf20Sopenharmony_ci * Find the default symbol for a choice. 2408c2ecf20Sopenharmony_ci * First try the default values for the choice symbol 2418c2ecf20Sopenharmony_ci * Next locate the first visible choice value 2428c2ecf20Sopenharmony_ci * Return NULL if none was found 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistruct symbol *sym_choice_default(struct symbol *sym) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct symbol *def_sym; 2478c2ecf20Sopenharmony_ci struct property *prop; 2488c2ecf20Sopenharmony_ci struct expr *e; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci /* any of the defaults visible? */ 2518c2ecf20Sopenharmony_ci for_all_defaults(sym, prop) { 2528c2ecf20Sopenharmony_ci prop->visible.tri = expr_calc_value(prop->visible.expr); 2538c2ecf20Sopenharmony_ci if (prop->visible.tri == no) 2548c2ecf20Sopenharmony_ci continue; 2558c2ecf20Sopenharmony_ci def_sym = prop_get_symbol(prop); 2568c2ecf20Sopenharmony_ci if (def_sym->visible != no) 2578c2ecf20Sopenharmony_ci return def_sym; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* just get the first visible value */ 2618c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(sym); 2628c2ecf20Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, def_sym) 2638c2ecf20Sopenharmony_ci if (def_sym->visible != no) 2648c2ecf20Sopenharmony_ci return def_sym; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* failed to locate any defaults */ 2678c2ecf20Sopenharmony_ci return NULL; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic struct symbol *sym_calc_choice(struct symbol *sym) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct symbol *def_sym; 2738c2ecf20Sopenharmony_ci struct property *prop; 2748c2ecf20Sopenharmony_ci struct expr *e; 2758c2ecf20Sopenharmony_ci int flags; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* first calculate all choice values' visibilities */ 2788c2ecf20Sopenharmony_ci flags = sym->flags; 2798c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(sym); 2808c2ecf20Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, def_sym) { 2818c2ecf20Sopenharmony_ci sym_calc_visibility(def_sym); 2828c2ecf20Sopenharmony_ci if (def_sym->visible != no) 2838c2ecf20Sopenharmony_ci flags &= def_sym->flags; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci sym->flags &= flags | ~SYMBOL_DEF_USER; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* is the user choice visible? */ 2898c2ecf20Sopenharmony_ci def_sym = sym->def[S_DEF_USER].val; 2908c2ecf20Sopenharmony_ci if (def_sym && def_sym->visible != no) 2918c2ecf20Sopenharmony_ci return def_sym; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci def_sym = sym_choice_default(sym); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (def_sym == NULL) 2968c2ecf20Sopenharmony_ci /* no choice? reset tristate value */ 2978c2ecf20Sopenharmony_ci sym->curr.tri = no; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return def_sym; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void sym_warn_unmet_dep(struct symbol *sym) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct gstr gs = str_new(); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci str_printf(&gs, 3078c2ecf20Sopenharmony_ci "\nWARNING: unmet direct dependencies detected for %s\n", 3088c2ecf20Sopenharmony_ci sym->name); 3098c2ecf20Sopenharmony_ci str_printf(&gs, 3108c2ecf20Sopenharmony_ci " Depends on [%c]: ", 3118c2ecf20Sopenharmony_ci sym->dir_dep.tri == mod ? 'm' : 'n'); 3128c2ecf20Sopenharmony_ci expr_gstr_print(sym->dir_dep.expr, &gs); 3138c2ecf20Sopenharmony_ci str_printf(&gs, "\n"); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes, 3168c2ecf20Sopenharmony_ci " Selected by [y]:\n"); 3178c2ecf20Sopenharmony_ci expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod, 3188c2ecf20Sopenharmony_ci " Selected by [m]:\n"); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci fputs(str_get(&gs), stderr); 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_civoid sym_calc_value(struct symbol *sym) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct symbol_value newval, oldval; 3268c2ecf20Sopenharmony_ci struct property *prop; 3278c2ecf20Sopenharmony_ci struct expr *e; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!sym) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_VALID) 3338c2ecf20Sopenharmony_ci return; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym) && 3368c2ecf20Sopenharmony_ci sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { 3378c2ecf20Sopenharmony_ci sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; 3388c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(sym); 3398c2ecf20Sopenharmony_ci sym_calc_value(prop_get_symbol(prop)); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_VALID; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci oldval = sym->curr; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci switch (sym->type) { 3478c2ecf20Sopenharmony_ci case S_INT: 3488c2ecf20Sopenharmony_ci case S_HEX: 3498c2ecf20Sopenharmony_ci case S_STRING: 3508c2ecf20Sopenharmony_ci newval = symbol_empty.curr; 3518c2ecf20Sopenharmony_ci break; 3528c2ecf20Sopenharmony_ci case S_BOOLEAN: 3538c2ecf20Sopenharmony_ci case S_TRISTATE: 3548c2ecf20Sopenharmony_ci newval = symbol_no.curr; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci default: 3578c2ecf20Sopenharmony_ci sym->curr.val = sym->name; 3588c2ecf20Sopenharmony_ci sym->curr.tri = no; 3598c2ecf20Sopenharmony_ci return; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci sym->flags &= ~SYMBOL_WRITE; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci sym_calc_visibility(sym); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (sym->visible != no) 3668c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* set default if recursively called */ 3698c2ecf20Sopenharmony_ci sym->curr = newval; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci switch (sym_get_type(sym)) { 3728c2ecf20Sopenharmony_ci case S_BOOLEAN: 3738c2ecf20Sopenharmony_ci case S_TRISTATE: 3748c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym) && sym->visible == yes) { 3758c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(sym); 3768c2ecf20Sopenharmony_ci newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; 3778c2ecf20Sopenharmony_ci } else { 3788c2ecf20Sopenharmony_ci if (sym->visible != no) { 3798c2ecf20Sopenharmony_ci /* if the symbol is visible use the user value 3808c2ecf20Sopenharmony_ci * if available, otherwise try the default value 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci if (sym_has_value(sym)) { 3838c2ecf20Sopenharmony_ci newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, 3848c2ecf20Sopenharmony_ci sym->visible); 3858c2ecf20Sopenharmony_ci goto calc_newval; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci if (sym->rev_dep.tri != no) 3898c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 3908c2ecf20Sopenharmony_ci if (!sym_is_choice(sym)) { 3918c2ecf20Sopenharmony_ci prop = sym_get_default_prop(sym); 3928c2ecf20Sopenharmony_ci if (prop) { 3938c2ecf20Sopenharmony_ci newval.tri = EXPR_AND(expr_calc_value(prop->expr), 3948c2ecf20Sopenharmony_ci prop->visible.tri); 3958c2ecf20Sopenharmony_ci if (newval.tri != no) 3968c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci if (sym->implied.tri != no) { 3998c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 4008c2ecf20Sopenharmony_ci newval.tri = EXPR_OR(newval.tri, sym->implied.tri); 4018c2ecf20Sopenharmony_ci newval.tri = EXPR_AND(newval.tri, 4028c2ecf20Sopenharmony_ci sym->dir_dep.tri); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci calc_newval: 4068c2ecf20Sopenharmony_ci if (sym->dir_dep.tri < sym->rev_dep.tri) 4078c2ecf20Sopenharmony_ci sym_warn_unmet_dep(sym); 4088c2ecf20Sopenharmony_ci newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) 4118c2ecf20Sopenharmony_ci newval.tri = yes; 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case S_STRING: 4148c2ecf20Sopenharmony_ci case S_HEX: 4158c2ecf20Sopenharmony_ci case S_INT: 4168c2ecf20Sopenharmony_ci if (sym->visible != no && sym_has_value(sym)) { 4178c2ecf20Sopenharmony_ci newval.val = sym->def[S_DEF_USER].val; 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci prop = sym_get_default_prop(sym); 4218c2ecf20Sopenharmony_ci if (prop) { 4228c2ecf20Sopenharmony_ci struct symbol *ds = prop_get_symbol(prop); 4238c2ecf20Sopenharmony_ci if (ds) { 4248c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_WRITE; 4258c2ecf20Sopenharmony_ci sym_calc_value(ds); 4268c2ecf20Sopenharmony_ci newval.val = ds->curr.val; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci default: 4318c2ecf20Sopenharmony_ci ; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci sym->curr = newval; 4358c2ecf20Sopenharmony_ci if (sym_is_choice(sym) && newval.tri == yes) 4368c2ecf20Sopenharmony_ci sym->curr.val = sym_calc_choice(sym); 4378c2ecf20Sopenharmony_ci sym_validate_range(sym); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { 4408c2ecf20Sopenharmony_ci sym_set_changed(sym); 4418c2ecf20Sopenharmony_ci if (modules_sym == sym) { 4428c2ecf20Sopenharmony_ci sym_set_all_changed(); 4438c2ecf20Sopenharmony_ci modules_val = modules_sym->curr.tri; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (sym_is_choice(sym)) { 4488c2ecf20Sopenharmony_ci struct symbol *choice_sym; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(sym); 4518c2ecf20Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, choice_sym) { 4528c2ecf20Sopenharmony_ci if ((sym->flags & SYMBOL_WRITE) && 4538c2ecf20Sopenharmony_ci choice_sym->visible != no) 4548c2ecf20Sopenharmony_ci choice_sym->flags |= SYMBOL_WRITE; 4558c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_CHANGED) 4568c2ecf20Sopenharmony_ci sym_set_changed(choice_sym); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_NO_WRITE) 4618c2ecf20Sopenharmony_ci sym->flags &= ~SYMBOL_WRITE; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) 4648c2ecf20Sopenharmony_ci set_all_choice_values(sym); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_civoid sym_clear_all_valid(void) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci struct symbol *sym; 4708c2ecf20Sopenharmony_ci int i; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci for_all_symbols(i, sym) 4738c2ecf20Sopenharmony_ci sym->flags &= ~SYMBOL_VALID; 4748c2ecf20Sopenharmony_ci sym_add_change_count(1); 4758c2ecf20Sopenharmony_ci sym_calc_value(modules_sym); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cibool sym_tristate_within_range(struct symbol *sym, tristate val) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci int type = sym_get_type(sym); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if (sym->visible == no) 4838c2ecf20Sopenharmony_ci return false; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (type != S_BOOLEAN && type != S_TRISTATE) 4868c2ecf20Sopenharmony_ci return false; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (type == S_BOOLEAN && val == mod) 4898c2ecf20Sopenharmony_ci return false; 4908c2ecf20Sopenharmony_ci if (sym->visible <= sym->rev_dep.tri) 4918c2ecf20Sopenharmony_ci return false; 4928c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym) && sym->visible == yes) 4938c2ecf20Sopenharmony_ci return val == yes; 4948c2ecf20Sopenharmony_ci return val >= sym->rev_dep.tri && val <= sym->visible; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cibool sym_set_tristate_value(struct symbol *sym, tristate val) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci tristate oldval = sym_get_tristate_value(sym); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (oldval != val && !sym_tristate_within_range(sym, val)) 5028c2ecf20Sopenharmony_ci return false; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (!(sym->flags & SYMBOL_DEF_USER)) { 5058c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_DEF_USER; 5068c2ecf20Sopenharmony_ci sym_set_changed(sym); 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci /* 5098c2ecf20Sopenharmony_ci * setting a choice value also resets the new flag of the choice 5108c2ecf20Sopenharmony_ci * symbol and all other choice values. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym) && val == yes) { 5138c2ecf20Sopenharmony_ci struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); 5148c2ecf20Sopenharmony_ci struct property *prop; 5158c2ecf20Sopenharmony_ci struct expr *e; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci cs->def[S_DEF_USER].val = sym; 5188c2ecf20Sopenharmony_ci cs->flags |= SYMBOL_DEF_USER; 5198c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(cs); 5208c2ecf20Sopenharmony_ci for (e = prop->expr; e; e = e->left.expr) { 5218c2ecf20Sopenharmony_ci if (e->right.sym->visible != no) 5228c2ecf20Sopenharmony_ci e->right.sym->flags |= SYMBOL_DEF_USER; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci sym->def[S_DEF_USER].tri = val; 5278c2ecf20Sopenharmony_ci if (oldval != val) 5288c2ecf20Sopenharmony_ci sym_clear_all_valid(); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return true; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_citristate sym_toggle_tristate_value(struct symbol *sym) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci tristate oldval, newval; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci oldval = newval = sym_get_tristate_value(sym); 5388c2ecf20Sopenharmony_ci do { 5398c2ecf20Sopenharmony_ci switch (newval) { 5408c2ecf20Sopenharmony_ci case no: 5418c2ecf20Sopenharmony_ci newval = mod; 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci case mod: 5448c2ecf20Sopenharmony_ci newval = yes; 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci case yes: 5478c2ecf20Sopenharmony_ci newval = no; 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci if (sym_set_tristate_value(sym, newval)) 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci } while (oldval != newval); 5538c2ecf20Sopenharmony_ci return newval; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_cibool sym_string_valid(struct symbol *sym, const char *str) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci signed char ch; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci switch (sym->type) { 5618c2ecf20Sopenharmony_ci case S_STRING: 5628c2ecf20Sopenharmony_ci return true; 5638c2ecf20Sopenharmony_ci case S_INT: 5648c2ecf20Sopenharmony_ci ch = *str++; 5658c2ecf20Sopenharmony_ci if (ch == '-') 5668c2ecf20Sopenharmony_ci ch = *str++; 5678c2ecf20Sopenharmony_ci if (!isdigit(ch)) 5688c2ecf20Sopenharmony_ci return false; 5698c2ecf20Sopenharmony_ci if (ch == '0' && *str != 0) 5708c2ecf20Sopenharmony_ci return false; 5718c2ecf20Sopenharmony_ci while ((ch = *str++)) { 5728c2ecf20Sopenharmony_ci if (!isdigit(ch)) 5738c2ecf20Sopenharmony_ci return false; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci return true; 5768c2ecf20Sopenharmony_ci case S_HEX: 5778c2ecf20Sopenharmony_ci if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) 5788c2ecf20Sopenharmony_ci str += 2; 5798c2ecf20Sopenharmony_ci ch = *str++; 5808c2ecf20Sopenharmony_ci do { 5818c2ecf20Sopenharmony_ci if (!isxdigit(ch)) 5828c2ecf20Sopenharmony_ci return false; 5838c2ecf20Sopenharmony_ci } while ((ch = *str++)); 5848c2ecf20Sopenharmony_ci return true; 5858c2ecf20Sopenharmony_ci case S_BOOLEAN: 5868c2ecf20Sopenharmony_ci case S_TRISTATE: 5878c2ecf20Sopenharmony_ci switch (str[0]) { 5888c2ecf20Sopenharmony_ci case 'y': case 'Y': 5898c2ecf20Sopenharmony_ci case 'm': case 'M': 5908c2ecf20Sopenharmony_ci case 'n': case 'N': 5918c2ecf20Sopenharmony_ci return true; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci return false; 5948c2ecf20Sopenharmony_ci default: 5958c2ecf20Sopenharmony_ci return false; 5968c2ecf20Sopenharmony_ci } 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cibool sym_string_within_range(struct symbol *sym, const char *str) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct property *prop; 6028c2ecf20Sopenharmony_ci long long val; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci switch (sym->type) { 6058c2ecf20Sopenharmony_ci case S_STRING: 6068c2ecf20Sopenharmony_ci return sym_string_valid(sym, str); 6078c2ecf20Sopenharmony_ci case S_INT: 6088c2ecf20Sopenharmony_ci if (!sym_string_valid(sym, str)) 6098c2ecf20Sopenharmony_ci return false; 6108c2ecf20Sopenharmony_ci prop = sym_get_range_prop(sym); 6118c2ecf20Sopenharmony_ci if (!prop) 6128c2ecf20Sopenharmony_ci return true; 6138c2ecf20Sopenharmony_ci val = strtoll(str, NULL, 10); 6148c2ecf20Sopenharmony_ci return val >= sym_get_range_val(prop->expr->left.sym, 10) && 6158c2ecf20Sopenharmony_ci val <= sym_get_range_val(prop->expr->right.sym, 10); 6168c2ecf20Sopenharmony_ci case S_HEX: 6178c2ecf20Sopenharmony_ci if (!sym_string_valid(sym, str)) 6188c2ecf20Sopenharmony_ci return false; 6198c2ecf20Sopenharmony_ci prop = sym_get_range_prop(sym); 6208c2ecf20Sopenharmony_ci if (!prop) 6218c2ecf20Sopenharmony_ci return true; 6228c2ecf20Sopenharmony_ci val = strtoll(str, NULL, 16); 6238c2ecf20Sopenharmony_ci return val >= sym_get_range_val(prop->expr->left.sym, 16) && 6248c2ecf20Sopenharmony_ci val <= sym_get_range_val(prop->expr->right.sym, 16); 6258c2ecf20Sopenharmony_ci case S_BOOLEAN: 6268c2ecf20Sopenharmony_ci case S_TRISTATE: 6278c2ecf20Sopenharmony_ci switch (str[0]) { 6288c2ecf20Sopenharmony_ci case 'y': case 'Y': 6298c2ecf20Sopenharmony_ci return sym_tristate_within_range(sym, yes); 6308c2ecf20Sopenharmony_ci case 'm': case 'M': 6318c2ecf20Sopenharmony_ci return sym_tristate_within_range(sym, mod); 6328c2ecf20Sopenharmony_ci case 'n': case 'N': 6338c2ecf20Sopenharmony_ci return sym_tristate_within_range(sym, no); 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci return false; 6368c2ecf20Sopenharmony_ci default: 6378c2ecf20Sopenharmony_ci return false; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cibool sym_set_string_value(struct symbol *sym, const char *newval) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci const char *oldval; 6448c2ecf20Sopenharmony_ci char *val; 6458c2ecf20Sopenharmony_ci int size; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci switch (sym->type) { 6488c2ecf20Sopenharmony_ci case S_BOOLEAN: 6498c2ecf20Sopenharmony_ci case S_TRISTATE: 6508c2ecf20Sopenharmony_ci switch (newval[0]) { 6518c2ecf20Sopenharmony_ci case 'y': case 'Y': 6528c2ecf20Sopenharmony_ci return sym_set_tristate_value(sym, yes); 6538c2ecf20Sopenharmony_ci case 'm': case 'M': 6548c2ecf20Sopenharmony_ci return sym_set_tristate_value(sym, mod); 6558c2ecf20Sopenharmony_ci case 'n': case 'N': 6568c2ecf20Sopenharmony_ci return sym_set_tristate_value(sym, no); 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci return false; 6598c2ecf20Sopenharmony_ci default: 6608c2ecf20Sopenharmony_ci ; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (!sym_string_within_range(sym, newval)) 6648c2ecf20Sopenharmony_ci return false; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci if (!(sym->flags & SYMBOL_DEF_USER)) { 6678c2ecf20Sopenharmony_ci sym->flags |= SYMBOL_DEF_USER; 6688c2ecf20Sopenharmony_ci sym_set_changed(sym); 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci oldval = sym->def[S_DEF_USER].val; 6728c2ecf20Sopenharmony_ci size = strlen(newval) + 1; 6738c2ecf20Sopenharmony_ci if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { 6748c2ecf20Sopenharmony_ci size += 2; 6758c2ecf20Sopenharmony_ci sym->def[S_DEF_USER].val = val = xmalloc(size); 6768c2ecf20Sopenharmony_ci *val++ = '0'; 6778c2ecf20Sopenharmony_ci *val++ = 'x'; 6788c2ecf20Sopenharmony_ci } else if (!oldval || strcmp(oldval, newval)) 6798c2ecf20Sopenharmony_ci sym->def[S_DEF_USER].val = val = xmalloc(size); 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci return true; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci strcpy(val, newval); 6848c2ecf20Sopenharmony_ci free((void *)oldval); 6858c2ecf20Sopenharmony_ci sym_clear_all_valid(); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return true; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci/* 6918c2ecf20Sopenharmony_ci * Find the default value associated to a symbol. 6928c2ecf20Sopenharmony_ci * For tristate symbol handle the modules=n case 6938c2ecf20Sopenharmony_ci * in which case "m" becomes "y". 6948c2ecf20Sopenharmony_ci * If the symbol does not have any default then fallback 6958c2ecf20Sopenharmony_ci * to the fixed default values. 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ciconst char *sym_get_string_default(struct symbol *sym) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct property *prop; 7008c2ecf20Sopenharmony_ci struct symbol *ds; 7018c2ecf20Sopenharmony_ci const char *str; 7028c2ecf20Sopenharmony_ci tristate val; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci sym_calc_visibility(sym); 7058c2ecf20Sopenharmony_ci sym_calc_value(modules_sym); 7068c2ecf20Sopenharmony_ci val = symbol_no.curr.tri; 7078c2ecf20Sopenharmony_ci str = symbol_empty.curr.val; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* If symbol has a default value look it up */ 7108c2ecf20Sopenharmony_ci prop = sym_get_default_prop(sym); 7118c2ecf20Sopenharmony_ci if (prop != NULL) { 7128c2ecf20Sopenharmony_ci switch (sym->type) { 7138c2ecf20Sopenharmony_ci case S_BOOLEAN: 7148c2ecf20Sopenharmony_ci case S_TRISTATE: 7158c2ecf20Sopenharmony_ci /* The visibility may limit the value from yes => mod */ 7168c2ecf20Sopenharmony_ci val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); 7178c2ecf20Sopenharmony_ci break; 7188c2ecf20Sopenharmony_ci default: 7198c2ecf20Sopenharmony_ci /* 7208c2ecf20Sopenharmony_ci * The following fails to handle the situation 7218c2ecf20Sopenharmony_ci * where a default value is further limited by 7228c2ecf20Sopenharmony_ci * the valid range. 7238c2ecf20Sopenharmony_ci */ 7248c2ecf20Sopenharmony_ci ds = prop_get_symbol(prop); 7258c2ecf20Sopenharmony_ci if (ds != NULL) { 7268c2ecf20Sopenharmony_ci sym_calc_value(ds); 7278c2ecf20Sopenharmony_ci str = (const char *)ds->curr.val; 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* Handle select statements */ 7338c2ecf20Sopenharmony_ci val = EXPR_OR(val, sym->rev_dep.tri); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci /* transpose mod to yes if modules are not enabled */ 7368c2ecf20Sopenharmony_ci if (val == mod) 7378c2ecf20Sopenharmony_ci if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) 7388c2ecf20Sopenharmony_ci val = yes; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci /* transpose mod to yes if type is bool */ 7418c2ecf20Sopenharmony_ci if (sym->type == S_BOOLEAN && val == mod) 7428c2ecf20Sopenharmony_ci val = yes; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci /* adjust the default value if this symbol is implied by another */ 7458c2ecf20Sopenharmony_ci if (val < sym->implied.tri) 7468c2ecf20Sopenharmony_ci val = sym->implied.tri; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci switch (sym->type) { 7498c2ecf20Sopenharmony_ci case S_BOOLEAN: 7508c2ecf20Sopenharmony_ci case S_TRISTATE: 7518c2ecf20Sopenharmony_ci switch (val) { 7528c2ecf20Sopenharmony_ci case no: return "n"; 7538c2ecf20Sopenharmony_ci case mod: return "m"; 7548c2ecf20Sopenharmony_ci case yes: return "y"; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci case S_INT: 7578c2ecf20Sopenharmony_ci case S_HEX: 7588c2ecf20Sopenharmony_ci return str; 7598c2ecf20Sopenharmony_ci case S_STRING: 7608c2ecf20Sopenharmony_ci return str; 7618c2ecf20Sopenharmony_ci case S_UNKNOWN: 7628c2ecf20Sopenharmony_ci break; 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci return ""; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ciconst char *sym_get_string_value(struct symbol *sym) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci tristate val; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci switch (sym->type) { 7728c2ecf20Sopenharmony_ci case S_BOOLEAN: 7738c2ecf20Sopenharmony_ci case S_TRISTATE: 7748c2ecf20Sopenharmony_ci val = sym_get_tristate_value(sym); 7758c2ecf20Sopenharmony_ci switch (val) { 7768c2ecf20Sopenharmony_ci case no: 7778c2ecf20Sopenharmony_ci return "n"; 7788c2ecf20Sopenharmony_ci case mod: 7798c2ecf20Sopenharmony_ci sym_calc_value(modules_sym); 7808c2ecf20Sopenharmony_ci return (modules_sym->curr.tri == no) ? "n" : "m"; 7818c2ecf20Sopenharmony_ci case yes: 7828c2ecf20Sopenharmony_ci return "y"; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci break; 7858c2ecf20Sopenharmony_ci default: 7868c2ecf20Sopenharmony_ci ; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci return (const char *)sym->curr.val; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cibool sym_is_changeable(struct symbol *sym) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci return sym->visible > sym->rev_dep.tri; 7948c2ecf20Sopenharmony_ci} 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic unsigned strhash(const char *s) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci /* fnv32 hash */ 7998c2ecf20Sopenharmony_ci unsigned hash = 2166136261U; 8008c2ecf20Sopenharmony_ci for (; *s; s++) 8018c2ecf20Sopenharmony_ci hash = (hash ^ *s) * 0x01000193; 8028c2ecf20Sopenharmony_ci return hash; 8038c2ecf20Sopenharmony_ci} 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_cistruct symbol *sym_lookup(const char *name, int flags) 8068c2ecf20Sopenharmony_ci{ 8078c2ecf20Sopenharmony_ci struct symbol *symbol; 8088c2ecf20Sopenharmony_ci char *new_name; 8098c2ecf20Sopenharmony_ci int hash; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (name) { 8128c2ecf20Sopenharmony_ci if (name[0] && !name[1]) { 8138c2ecf20Sopenharmony_ci switch (name[0]) { 8148c2ecf20Sopenharmony_ci case 'y': return &symbol_yes; 8158c2ecf20Sopenharmony_ci case 'm': return &symbol_mod; 8168c2ecf20Sopenharmony_ci case 'n': return &symbol_no; 8178c2ecf20Sopenharmony_ci } 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci hash = strhash(name) % SYMBOL_HASHSIZE; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 8228c2ecf20Sopenharmony_ci if (symbol->name && 8238c2ecf20Sopenharmony_ci !strcmp(symbol->name, name) && 8248c2ecf20Sopenharmony_ci (flags ? symbol->flags & flags 8258c2ecf20Sopenharmony_ci : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) 8268c2ecf20Sopenharmony_ci return symbol; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci new_name = xstrdup(name); 8298c2ecf20Sopenharmony_ci } else { 8308c2ecf20Sopenharmony_ci new_name = NULL; 8318c2ecf20Sopenharmony_ci hash = 0; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci symbol = xmalloc(sizeof(*symbol)); 8358c2ecf20Sopenharmony_ci memset(symbol, 0, sizeof(*symbol)); 8368c2ecf20Sopenharmony_ci symbol->name = new_name; 8378c2ecf20Sopenharmony_ci symbol->type = S_UNKNOWN; 8388c2ecf20Sopenharmony_ci symbol->flags = flags; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci symbol->next = symbol_hash[hash]; 8418c2ecf20Sopenharmony_ci symbol_hash[hash] = symbol; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return symbol; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistruct symbol *sym_find(const char *name) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci struct symbol *symbol = NULL; 8498c2ecf20Sopenharmony_ci int hash = 0; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci if (!name) 8528c2ecf20Sopenharmony_ci return NULL; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci if (name[0] && !name[1]) { 8558c2ecf20Sopenharmony_ci switch (name[0]) { 8568c2ecf20Sopenharmony_ci case 'y': return &symbol_yes; 8578c2ecf20Sopenharmony_ci case 'm': return &symbol_mod; 8588c2ecf20Sopenharmony_ci case 'n': return &symbol_no; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci hash = strhash(name) % SYMBOL_HASHSIZE; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { 8648c2ecf20Sopenharmony_ci if (symbol->name && 8658c2ecf20Sopenharmony_ci !strcmp(symbol->name, name) && 8668c2ecf20Sopenharmony_ci !(symbol->flags & SYMBOL_CONST)) 8678c2ecf20Sopenharmony_ci break; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci return symbol; 8718c2ecf20Sopenharmony_ci} 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ciconst char *sym_escape_string_value(const char *in) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci const char *p; 8768c2ecf20Sopenharmony_ci size_t reslen; 8778c2ecf20Sopenharmony_ci char *res; 8788c2ecf20Sopenharmony_ci size_t l; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci reslen = strlen(in) + strlen("\"\"") + 1; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci p = in; 8838c2ecf20Sopenharmony_ci for (;;) { 8848c2ecf20Sopenharmony_ci l = strcspn(p, "\"\\"); 8858c2ecf20Sopenharmony_ci p += l; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci if (p[0] == '\0') 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci reslen++; 8918c2ecf20Sopenharmony_ci p++; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci res = xmalloc(reslen); 8958c2ecf20Sopenharmony_ci res[0] = '\0'; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci strcat(res, "\""); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci p = in; 9008c2ecf20Sopenharmony_ci for (;;) { 9018c2ecf20Sopenharmony_ci l = strcspn(p, "\"\\"); 9028c2ecf20Sopenharmony_ci strncat(res, p, l); 9038c2ecf20Sopenharmony_ci p += l; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci if (p[0] == '\0') 9068c2ecf20Sopenharmony_ci break; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci strcat(res, "\\"); 9098c2ecf20Sopenharmony_ci strncat(res, p++, 1); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci strcat(res, "\""); 9138c2ecf20Sopenharmony_ci return res; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistruct sym_match { 9178c2ecf20Sopenharmony_ci struct symbol *sym; 9188c2ecf20Sopenharmony_ci off_t so, eo; 9198c2ecf20Sopenharmony_ci}; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci/* Compare matched symbols as thus: 9228c2ecf20Sopenharmony_ci * - first, symbols that match exactly 9238c2ecf20Sopenharmony_ci * - then, alphabetical sort 9248c2ecf20Sopenharmony_ci */ 9258c2ecf20Sopenharmony_cistatic int sym_rel_comp(const void *sym1, const void *sym2) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci const struct sym_match *s1 = sym1; 9288c2ecf20Sopenharmony_ci const struct sym_match *s2 = sym2; 9298c2ecf20Sopenharmony_ci int exact1, exact2; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* Exact match: 9328c2ecf20Sopenharmony_ci * - if matched length on symbol s1 is the length of that symbol, 9338c2ecf20Sopenharmony_ci * then this symbol should come first; 9348c2ecf20Sopenharmony_ci * - if matched length on symbol s2 is the length of that symbol, 9358c2ecf20Sopenharmony_ci * then this symbol should come first. 9368c2ecf20Sopenharmony_ci * Note: since the search can be a regexp, both symbols may match 9378c2ecf20Sopenharmony_ci * exactly; if this is the case, we can't decide which comes first, 9388c2ecf20Sopenharmony_ci * and we fallback to sorting alphabetically. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); 9418c2ecf20Sopenharmony_ci exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); 9428c2ecf20Sopenharmony_ci if (exact1 && !exact2) 9438c2ecf20Sopenharmony_ci return -1; 9448c2ecf20Sopenharmony_ci if (!exact1 && exact2) 9458c2ecf20Sopenharmony_ci return 1; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* As a fallback, sort symbols alphabetically */ 9488c2ecf20Sopenharmony_ci return strcmp(s1->sym->name, s2->sym->name); 9498c2ecf20Sopenharmony_ci} 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistruct symbol **sym_re_search(const char *pattern) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci struct symbol *sym, **sym_arr = NULL; 9548c2ecf20Sopenharmony_ci struct sym_match *sym_match_arr = NULL; 9558c2ecf20Sopenharmony_ci int i, cnt, size; 9568c2ecf20Sopenharmony_ci regex_t re; 9578c2ecf20Sopenharmony_ci regmatch_t match[1]; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci cnt = size = 0; 9608c2ecf20Sopenharmony_ci /* Skip if empty */ 9618c2ecf20Sopenharmony_ci if (strlen(pattern) == 0) 9628c2ecf20Sopenharmony_ci return NULL; 9638c2ecf20Sopenharmony_ci if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) 9648c2ecf20Sopenharmony_ci return NULL; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci for_all_symbols(i, sym) { 9678c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_CONST || !sym->name) 9688c2ecf20Sopenharmony_ci continue; 9698c2ecf20Sopenharmony_ci if (regexec(&re, sym->name, 1, match, 0)) 9708c2ecf20Sopenharmony_ci continue; 9718c2ecf20Sopenharmony_ci if (cnt >= size) { 9728c2ecf20Sopenharmony_ci void *tmp; 9738c2ecf20Sopenharmony_ci size += 16; 9748c2ecf20Sopenharmony_ci tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); 9758c2ecf20Sopenharmony_ci if (!tmp) 9768c2ecf20Sopenharmony_ci goto sym_re_search_free; 9778c2ecf20Sopenharmony_ci sym_match_arr = tmp; 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci sym_calc_value(sym); 9808c2ecf20Sopenharmony_ci /* As regexec returned 0, we know we have a match, so 9818c2ecf20Sopenharmony_ci * we can use match[0].rm_[se]o without further checks 9828c2ecf20Sopenharmony_ci */ 9838c2ecf20Sopenharmony_ci sym_match_arr[cnt].so = match[0].rm_so; 9848c2ecf20Sopenharmony_ci sym_match_arr[cnt].eo = match[0].rm_eo; 9858c2ecf20Sopenharmony_ci sym_match_arr[cnt++].sym = sym; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci if (sym_match_arr) { 9888c2ecf20Sopenharmony_ci qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); 9898c2ecf20Sopenharmony_ci sym_arr = malloc((cnt+1) * sizeof(struct symbol *)); 9908c2ecf20Sopenharmony_ci if (!sym_arr) 9918c2ecf20Sopenharmony_ci goto sym_re_search_free; 9928c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) 9938c2ecf20Sopenharmony_ci sym_arr[i] = sym_match_arr[i].sym; 9948c2ecf20Sopenharmony_ci sym_arr[cnt] = NULL; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_cisym_re_search_free: 9978c2ecf20Sopenharmony_ci /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ 9988c2ecf20Sopenharmony_ci free(sym_match_arr); 9998c2ecf20Sopenharmony_ci regfree(&re); 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return sym_arr; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/* 10058c2ecf20Sopenharmony_ci * When we check for recursive dependencies we use a stack to save 10068c2ecf20Sopenharmony_ci * current state so we can print out relevant info to user. 10078c2ecf20Sopenharmony_ci * The entries are located on the call stack so no need to free memory. 10088c2ecf20Sopenharmony_ci * Note insert() remove() must always match to properly clear the stack. 10098c2ecf20Sopenharmony_ci */ 10108c2ecf20Sopenharmony_cistatic struct dep_stack { 10118c2ecf20Sopenharmony_ci struct dep_stack *prev, *next; 10128c2ecf20Sopenharmony_ci struct symbol *sym; 10138c2ecf20Sopenharmony_ci struct property *prop; 10148c2ecf20Sopenharmony_ci struct expr **expr; 10158c2ecf20Sopenharmony_ci} *check_top; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci memset(stack, 0, sizeof(*stack)); 10208c2ecf20Sopenharmony_ci if (check_top) 10218c2ecf20Sopenharmony_ci check_top->next = stack; 10228c2ecf20Sopenharmony_ci stack->prev = check_top; 10238c2ecf20Sopenharmony_ci stack->sym = sym; 10248c2ecf20Sopenharmony_ci check_top = stack; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic void dep_stack_remove(void) 10288c2ecf20Sopenharmony_ci{ 10298c2ecf20Sopenharmony_ci check_top = check_top->prev; 10308c2ecf20Sopenharmony_ci if (check_top) 10318c2ecf20Sopenharmony_ci check_top->next = NULL; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci/* 10358c2ecf20Sopenharmony_ci * Called when we have detected a recursive dependency. 10368c2ecf20Sopenharmony_ci * check_top point to the top of the stact so we use 10378c2ecf20Sopenharmony_ci * the ->prev pointer to locate the bottom of the stack. 10388c2ecf20Sopenharmony_ci */ 10398c2ecf20Sopenharmony_cistatic void sym_check_print_recursive(struct symbol *last_sym) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci struct dep_stack *stack; 10428c2ecf20Sopenharmony_ci struct symbol *sym, *next_sym; 10438c2ecf20Sopenharmony_ci struct menu *menu = NULL; 10448c2ecf20Sopenharmony_ci struct property *prop; 10458c2ecf20Sopenharmony_ci struct dep_stack cv_stack; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (sym_is_choice_value(last_sym)) { 10488c2ecf20Sopenharmony_ci dep_stack_insert(&cv_stack, last_sym); 10498c2ecf20Sopenharmony_ci last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci for (stack = check_top; stack != NULL; stack = stack->prev) 10538c2ecf20Sopenharmony_ci if (stack->sym == last_sym) 10548c2ecf20Sopenharmony_ci break; 10558c2ecf20Sopenharmony_ci if (!stack) { 10568c2ecf20Sopenharmony_ci fprintf(stderr, "unexpected recursive dependency error\n"); 10578c2ecf20Sopenharmony_ci return; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci for (; stack; stack = stack->next) { 10618c2ecf20Sopenharmony_ci sym = stack->sym; 10628c2ecf20Sopenharmony_ci next_sym = stack->next ? stack->next->sym : last_sym; 10638c2ecf20Sopenharmony_ci prop = stack->prop; 10648c2ecf20Sopenharmony_ci if (prop == NULL) 10658c2ecf20Sopenharmony_ci prop = stack->sym->prop; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci /* for choice values find the menu entry (used below) */ 10688c2ecf20Sopenharmony_ci if (sym_is_choice(sym) || sym_is_choice_value(sym)) { 10698c2ecf20Sopenharmony_ci for (prop = sym->prop; prop; prop = prop->next) { 10708c2ecf20Sopenharmony_ci menu = prop->menu; 10718c2ecf20Sopenharmony_ci if (prop->menu) 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci if (stack->sym == last_sym) 10768c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", 10778c2ecf20Sopenharmony_ci prop->file->name, prop->lineno); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (sym_is_choice(sym)) { 10808c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", 10818c2ecf20Sopenharmony_ci menu->file->name, menu->lineno, 10828c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 10838c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 10848c2ecf20Sopenharmony_ci } else if (sym_is_choice_value(sym)) { 10858c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", 10868c2ecf20Sopenharmony_ci menu->file->name, menu->lineno, 10878c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 10888c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 10898c2ecf20Sopenharmony_ci } else if (stack->expr == &sym->dir_dep.expr) { 10908c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", 10918c2ecf20Sopenharmony_ci prop->file->name, prop->lineno, 10928c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 10938c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 10948c2ecf20Sopenharmony_ci } else if (stack->expr == &sym->rev_dep.expr) { 10958c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", 10968c2ecf20Sopenharmony_ci prop->file->name, prop->lineno, 10978c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 10988c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 10998c2ecf20Sopenharmony_ci } else if (stack->expr == &sym->implied.expr) { 11008c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n", 11018c2ecf20Sopenharmony_ci prop->file->name, prop->lineno, 11028c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 11038c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 11048c2ecf20Sopenharmony_ci } else if (stack->expr) { 11058c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", 11068c2ecf20Sopenharmony_ci prop->file->name, prop->lineno, 11078c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 11088c2ecf20Sopenharmony_ci prop_get_type_name(prop->type), 11098c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 11108c2ecf20Sopenharmony_ci } else { 11118c2ecf20Sopenharmony_ci fprintf(stderr, "%s:%d:\tsymbol %s %s is visible depending on %s\n", 11128c2ecf20Sopenharmony_ci prop->file->name, prop->lineno, 11138c2ecf20Sopenharmony_ci sym->name ? sym->name : "<choice>", 11148c2ecf20Sopenharmony_ci prop_get_type_name(prop->type), 11158c2ecf20Sopenharmony_ci next_sym->name ? next_sym->name : "<choice>"); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci fprintf(stderr, 11208c2ecf20Sopenharmony_ci "For a resolution refer to Documentation/kbuild/kconfig-language.rst\n" 11218c2ecf20Sopenharmony_ci "subsection \"Kconfig recursive dependency limitations\"\n" 11228c2ecf20Sopenharmony_ci "\n"); 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (check_top == &cv_stack) 11258c2ecf20Sopenharmony_ci dep_stack_remove(); 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic struct symbol *sym_check_expr_deps(struct expr *e) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct symbol *sym; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci if (!e) 11338c2ecf20Sopenharmony_ci return NULL; 11348c2ecf20Sopenharmony_ci switch (e->type) { 11358c2ecf20Sopenharmony_ci case E_OR: 11368c2ecf20Sopenharmony_ci case E_AND: 11378c2ecf20Sopenharmony_ci sym = sym_check_expr_deps(e->left.expr); 11388c2ecf20Sopenharmony_ci if (sym) 11398c2ecf20Sopenharmony_ci return sym; 11408c2ecf20Sopenharmony_ci return sym_check_expr_deps(e->right.expr); 11418c2ecf20Sopenharmony_ci case E_NOT: 11428c2ecf20Sopenharmony_ci return sym_check_expr_deps(e->left.expr); 11438c2ecf20Sopenharmony_ci case E_EQUAL: 11448c2ecf20Sopenharmony_ci case E_GEQ: 11458c2ecf20Sopenharmony_ci case E_GTH: 11468c2ecf20Sopenharmony_ci case E_LEQ: 11478c2ecf20Sopenharmony_ci case E_LTH: 11488c2ecf20Sopenharmony_ci case E_UNEQUAL: 11498c2ecf20Sopenharmony_ci sym = sym_check_deps(e->left.sym); 11508c2ecf20Sopenharmony_ci if (sym) 11518c2ecf20Sopenharmony_ci return sym; 11528c2ecf20Sopenharmony_ci return sym_check_deps(e->right.sym); 11538c2ecf20Sopenharmony_ci case E_SYMBOL: 11548c2ecf20Sopenharmony_ci return sym_check_deps(e->left.sym); 11558c2ecf20Sopenharmony_ci default: 11568c2ecf20Sopenharmony_ci break; 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci fprintf(stderr, "Oops! How to check %d?\n", e->type); 11598c2ecf20Sopenharmony_ci return NULL; 11608c2ecf20Sopenharmony_ci} 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci/* return NULL when dependencies are OK */ 11638c2ecf20Sopenharmony_cistatic struct symbol *sym_check_sym_deps(struct symbol *sym) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci struct symbol *sym2; 11668c2ecf20Sopenharmony_ci struct property *prop; 11678c2ecf20Sopenharmony_ci struct dep_stack stack; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci dep_stack_insert(&stack, sym); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci stack.expr = &sym->dir_dep.expr; 11728c2ecf20Sopenharmony_ci sym2 = sym_check_expr_deps(sym->dir_dep.expr); 11738c2ecf20Sopenharmony_ci if (sym2) 11748c2ecf20Sopenharmony_ci goto out; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci stack.expr = &sym->rev_dep.expr; 11778c2ecf20Sopenharmony_ci sym2 = sym_check_expr_deps(sym->rev_dep.expr); 11788c2ecf20Sopenharmony_ci if (sym2) 11798c2ecf20Sopenharmony_ci goto out; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci stack.expr = &sym->implied.expr; 11828c2ecf20Sopenharmony_ci sym2 = sym_check_expr_deps(sym->implied.expr); 11838c2ecf20Sopenharmony_ci if (sym2) 11848c2ecf20Sopenharmony_ci goto out; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci stack.expr = NULL; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci for (prop = sym->prop; prop; prop = prop->next) { 11898c2ecf20Sopenharmony_ci if (prop->type == P_CHOICE || prop->type == P_SELECT || 11908c2ecf20Sopenharmony_ci prop->type == P_IMPLY) 11918c2ecf20Sopenharmony_ci continue; 11928c2ecf20Sopenharmony_ci stack.prop = prop; 11938c2ecf20Sopenharmony_ci sym2 = sym_check_expr_deps(prop->visible.expr); 11948c2ecf20Sopenharmony_ci if (sym2) 11958c2ecf20Sopenharmony_ci break; 11968c2ecf20Sopenharmony_ci if (prop->type != P_DEFAULT || sym_is_choice(sym)) 11978c2ecf20Sopenharmony_ci continue; 11988c2ecf20Sopenharmony_ci stack.expr = &prop->expr; 11998c2ecf20Sopenharmony_ci sym2 = sym_check_expr_deps(prop->expr); 12008c2ecf20Sopenharmony_ci if (sym2) 12018c2ecf20Sopenharmony_ci break; 12028c2ecf20Sopenharmony_ci stack.expr = NULL; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ciout: 12068c2ecf20Sopenharmony_ci dep_stack_remove(); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return sym2; 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic struct symbol *sym_check_choice_deps(struct symbol *choice) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci struct symbol *sym, *sym2; 12148c2ecf20Sopenharmony_ci struct property *prop; 12158c2ecf20Sopenharmony_ci struct expr *e; 12168c2ecf20Sopenharmony_ci struct dep_stack stack; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci dep_stack_insert(&stack, choice); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(choice); 12218c2ecf20Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, sym) 12228c2ecf20Sopenharmony_ci sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 12258c2ecf20Sopenharmony_ci sym2 = sym_check_sym_deps(choice); 12268c2ecf20Sopenharmony_ci choice->flags &= ~SYMBOL_CHECK; 12278c2ecf20Sopenharmony_ci if (sym2) 12288c2ecf20Sopenharmony_ci goto out; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, sym) { 12318c2ecf20Sopenharmony_ci sym2 = sym_check_sym_deps(sym); 12328c2ecf20Sopenharmony_ci if (sym2) 12338c2ecf20Sopenharmony_ci break; 12348c2ecf20Sopenharmony_ci } 12358c2ecf20Sopenharmony_ciout: 12368c2ecf20Sopenharmony_ci expr_list_for_each_sym(prop->expr, e, sym) 12378c2ecf20Sopenharmony_ci sym->flags &= ~SYMBOL_CHECK; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (sym2 && sym_is_choice_value(sym2) && 12408c2ecf20Sopenharmony_ci prop_get_symbol(sym_get_choice_prop(sym2)) == choice) 12418c2ecf20Sopenharmony_ci sym2 = choice; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci dep_stack_remove(); 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci return sym2; 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_cistruct symbol *sym_check_deps(struct symbol *sym) 12498c2ecf20Sopenharmony_ci{ 12508c2ecf20Sopenharmony_ci struct symbol *sym2; 12518c2ecf20Sopenharmony_ci struct property *prop; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_CHECK) { 12548c2ecf20Sopenharmony_ci sym_check_print_recursive(sym); 12558c2ecf20Sopenharmony_ci return sym; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci if (sym->flags & SYMBOL_CHECKED) 12588c2ecf20Sopenharmony_ci return NULL; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci if (sym_is_choice_value(sym)) { 12618c2ecf20Sopenharmony_ci struct dep_stack stack; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* for choice groups start the check with main choice symbol */ 12648c2ecf20Sopenharmony_ci dep_stack_insert(&stack, sym); 12658c2ecf20Sopenharmony_ci prop = sym_get_choice_prop(sym); 12668c2ecf20Sopenharmony_ci sym2 = sym_check_deps(prop_get_symbol(prop)); 12678c2ecf20Sopenharmony_ci dep_stack_remove(); 12688c2ecf20Sopenharmony_ci } else if (sym_is_choice(sym)) { 12698c2ecf20Sopenharmony_ci sym2 = sym_check_choice_deps(sym); 12708c2ecf20Sopenharmony_ci } else { 12718c2ecf20Sopenharmony_ci sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); 12728c2ecf20Sopenharmony_ci sym2 = sym_check_sym_deps(sym); 12738c2ecf20Sopenharmony_ci sym->flags &= ~SYMBOL_CHECK; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci return sym2; 12778c2ecf20Sopenharmony_ci} 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistruct symbol *prop_get_symbol(struct property *prop) 12808c2ecf20Sopenharmony_ci{ 12818c2ecf20Sopenharmony_ci if (prop->expr && (prop->expr->type == E_SYMBOL || 12828c2ecf20Sopenharmony_ci prop->expr->type == E_LIST)) 12838c2ecf20Sopenharmony_ci return prop->expr->left.sym; 12848c2ecf20Sopenharmony_ci return NULL; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ciconst char *prop_get_type_name(enum prop_type type) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci switch (type) { 12908c2ecf20Sopenharmony_ci case P_PROMPT: 12918c2ecf20Sopenharmony_ci return "prompt"; 12928c2ecf20Sopenharmony_ci case P_COMMENT: 12938c2ecf20Sopenharmony_ci return "comment"; 12948c2ecf20Sopenharmony_ci case P_MENU: 12958c2ecf20Sopenharmony_ci return "menu"; 12968c2ecf20Sopenharmony_ci case P_DEFAULT: 12978c2ecf20Sopenharmony_ci return "default"; 12988c2ecf20Sopenharmony_ci case P_CHOICE: 12998c2ecf20Sopenharmony_ci return "choice"; 13008c2ecf20Sopenharmony_ci case P_SELECT: 13018c2ecf20Sopenharmony_ci return "select"; 13028c2ecf20Sopenharmony_ci case P_IMPLY: 13038c2ecf20Sopenharmony_ci return "imply"; 13048c2ecf20Sopenharmony_ci case P_RANGE: 13058c2ecf20Sopenharmony_ci return "range"; 13068c2ecf20Sopenharmony_ci case P_SYMBOL: 13078c2ecf20Sopenharmony_ci return "symbol"; 13088c2ecf20Sopenharmony_ci case P_UNKNOWN: 13098c2ecf20Sopenharmony_ci break; 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci return "unknown"; 13128c2ecf20Sopenharmony_ci} 1313