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