1366 lines · 29.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> */ #include <sys/types.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <regex.h> #include <hash.h>#include <xalloc.h>#include "internal.h"#include "lkc.h" struct symbol symbol_yes = {	.name = "y",	.type = S_TRISTATE,	.curr = { "y", yes },	.menus = LIST_HEAD_INIT(symbol_yes.menus),	.flags = SYMBOL_CONST|SYMBOL_VALID,}; struct symbol symbol_mod = {	.name = "m",	.type = S_TRISTATE,	.curr = { "m", mod },	.menus = LIST_HEAD_INIT(symbol_mod.menus),	.flags = SYMBOL_CONST|SYMBOL_VALID,}; struct symbol symbol_no = {	.name = "n",	.type = S_TRISTATE,	.curr = { "n", no },	.menus = LIST_HEAD_INIT(symbol_no.menus),	.flags = SYMBOL_CONST|SYMBOL_VALID,}; struct symbol *modules_sym;static tristate modules_val;static int sym_warnings; enum symbol_type sym_get_type(const struct symbol *sym){	enum symbol_type type = sym->type; 	if (type == S_TRISTATE && modules_val == no)		type = S_BOOLEAN;	return type;} const char *sym_type_name(enum symbol_type type){	switch (type) {	case S_BOOLEAN:		return "bool";	case S_TRISTATE:		return "tristate";	case S_INT:		return "integer";	case S_HEX:		return "hex";	case S_STRING:		return "string";	case S_UNKNOWN:		return "unknown";	}	return "???";} /** * sym_get_prompt_menu - get the menu entry with a prompt * * @sym: a symbol pointer * * Return: the menu entry with a prompt. */struct menu *sym_get_prompt_menu(const struct symbol *sym){	struct menu *m; 	list_for_each_entry(m, &sym->menus, link)		if (m->prompt)			return m; 	return NULL;} /** * sym_get_choice_menu - get the parent choice menu if present * * @sym: a symbol pointer * * Return: a choice menu if this function is called against a choice member. */struct menu *sym_get_choice_menu(const struct symbol *sym){	struct menu *menu = NULL; 	/*	 * Choice members must have a prompt. Find a menu entry with a prompt,	 * and assume it resides inside a choice block.	 */	menu = sym_get_prompt_menu(sym);	if (!menu)		return NULL; 	do {		menu = menu->parent;	} while (menu && !menu->sym); 	if (menu && menu->sym && sym_is_choice(menu->sym))		return menu; 	return NULL;} static struct property *sym_get_default_prop(struct symbol *sym){	struct property *prop; 	for_all_defaults(sym, prop) {		prop->visible.tri = expr_calc_value(prop->visible.expr);		if (prop->visible.tri != no)			return prop;	}	return NULL;} struct property *sym_get_range_prop(struct symbol *sym){	struct property *prop; 	for_all_properties(sym, prop, P_RANGE) {		prop->visible.tri = expr_calc_value(prop->visible.expr);		if (prop->visible.tri != no)			return prop;	}	return NULL;} static long long sym_get_range_val(struct symbol *sym, int base){	sym_calc_value(sym);	switch (sym->type) {	case S_INT:		base = 10;		break;	case S_HEX:		base = 16;		break;	default:		break;	}	return strtoll(sym->curr.val, NULL, base);} static void sym_validate_range(struct symbol *sym){	struct property *prop;	struct symbol *range_sym;	int base;	long long val, val2; 	switch (sym->type) {	case S_INT:		base = 10;		break;	case S_HEX:		base = 16;		break;	default:		return;	}	prop = sym_get_range_prop(sym);	if (!prop)		return;	val = strtoll(sym->curr.val, NULL, base);	range_sym = prop->expr->left.sym;	val2 = sym_get_range_val(range_sym, base);	if (val >= val2) {		range_sym = prop->expr->right.sym;		val2 = sym_get_range_val(range_sym, base);		if (val <= val2)			return;	}	sym->curr.val = range_sym->curr.val;} static void sym_set_changed(struct symbol *sym){	struct menu *menu; 	list_for_each_entry(menu, &sym->menus, link)		menu->flags |= MENU_CHANGED; 	menu = sym_get_choice_menu(sym);	if (menu)		menu->flags |= MENU_CHANGED;} static void sym_set_all_changed(void){	struct symbol *sym; 	for_all_symbols(sym)		sym_set_changed(sym);} static void sym_calc_visibility(struct symbol *sym){	struct property *prop;	tristate tri; 	if (sym->flags & SYMBOL_TRANS) {		sym->visible = yes;		return;	} 	/* any prompt visible? */	tri = no;	for_all_prompts(sym, prop) {		prop->visible.tri = expr_calc_value(prop->visible.expr);		tri = EXPR_OR(tri, prop->visible.tri);	}	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))		tri = yes;	if (sym->visible != tri) {		sym->visible = tri;		sym_set_changed(sym);	}	if (sym_is_choice_value(sym))		return;	/* defaulting to "yes" if no explicit "depends on" are given */	tri = yes;	if (sym->dir_dep.expr)		tri = expr_calc_value(sym->dir_dep.expr);	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)		tri = yes;	if (sym->dir_dep.tri != tri) {		sym->dir_dep.tri = tri;		sym_set_changed(sym);	}	tri = no;	if (sym->rev_dep.expr)		tri = expr_calc_value(sym->rev_dep.expr);	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)		tri = yes;	if (sym->rev_dep.tri != tri) {		sym->rev_dep.tri = tri;		sym_set_changed(sym);	}	tri = no;	if (sym->implied.expr)		tri = expr_calc_value(sym->implied.expr);	if (tri == mod && sym_get_type(sym) == S_BOOLEAN)		tri = yes;	if (sym->implied.tri != tri) {		sym->implied.tri = tri;		sym_set_changed(sym);	}} /* * Find the default symbol for a choice. * First try the default values for the choice symbol * Next locate the first visible choice value * Return NULL if none was found */struct symbol *sym_choice_default(struct menu *choice){	struct menu *menu;	struct symbol *def_sym;	struct property *prop; 	/* any of the defaults visible? */	for_all_defaults(choice->sym, prop) {		prop->visible.tri = expr_calc_value(prop->visible.expr);		if (prop->visible.tri == no)			continue;		def_sym = prop_get_symbol(prop);		if (def_sym->visible != no)			return def_sym;	} 	/* just get the first visible value */	menu_for_each_sub_entry(menu, choice)		if (menu->sym && menu->sym->visible != no)			return menu->sym; 	/* failed to locate any defaults */	return NULL;} /* * sym_calc_choice - calculate symbol values in a choice * * @choice: a menu of the choice * * Return: a chosen symbol */struct symbol *sym_calc_choice(struct menu *choice){	struct symbol *res = NULL;	struct symbol *sym;	struct menu *menu; 	/* Traverse the list of choice members in the priority order. */	list_for_each_entry(sym, &choice->choice_members, choice_link) {		sym_calc_visibility(sym);		if (sym->visible == no)			continue; 		/* The first visible symble with the user value 'y'. */		if (sym_has_value(sym) && sym->def[S_DEF_USER].tri == yes) {			res = sym;			break;		}	} 	/*	 * If 'y' is not found in the user input, use the default, unless it is	 * explicitly set to 'n'.	 */	if (!res) {		res = sym_choice_default(choice);		if (res && sym_has_value(res) && res->def[S_DEF_USER].tri == no)			res = NULL;	} 	/* Still not found. Pick up the first visible, user-unspecified symbol. */	if (!res) {		menu_for_each_sub_entry(menu, choice) {			sym = menu->sym; 			if (!sym || sym->visible == no || sym_has_value(sym))				continue; 			res = sym;			break;		}	} 	/*	 * Still not found. Traverse the linked list in the _reverse_ order to	 * pick up the least prioritized 'n'.	 */	if (!res) {		list_for_each_entry_reverse(sym, &choice->choice_members,					    choice_link) {			if (sym->visible == no)				continue; 			res = sym;			break;		}	} 	menu_for_each_sub_entry(menu, choice) {		tristate val; 		sym = menu->sym; 		if (!sym || sym->visible == no)			continue; 		val = sym == res ? yes : no; 		if (sym->curr.tri != val)			sym_set_changed(sym); 		sym->curr.tri = val;		sym->flags |= SYMBOL_VALID | SYMBOL_WRITE;	} 	return res;} static void sym_warn_unmet_dep(const struct symbol *sym){	struct gstr gs = str_new(); 	str_printf(&gs,		   "\nWARNING: unmet direct dependencies detected for %s\n",		   sym->name);	str_printf(&gs,		   "  Depends on [%c]: ",		   sym->dir_dep.tri == mod ? 'm' : 'n');	expr_gstr_print(sym->dir_dep.expr, &gs);	str_printf(&gs, "\n"); 	expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,			       "  Selected by [y]:\n");	expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,			       "  Selected by [m]:\n"); 	fputs(str_get(&gs), stderr);	str_free(&gs);	sym_warnings++;} bool sym_dep_errors(void){	if (sym_warnings)		return getenv("KCONFIG_WERROR");	return false;} void sym_calc_value(struct symbol *sym){	struct symbol_value newval, oldval;	struct property *prop = NULL;	struct menu *choice_menu; 	if (!sym)		return; 	if (sym->flags & SYMBOL_VALID)		return; 	sym->flags |= SYMBOL_VALID; 	oldval = sym->curr; 	newval.tri = no; 	switch (sym->type) {	case S_INT:		newval.val = "0";		break;	case S_HEX:		newval.val = "0x0";		break;	case S_STRING:		newval.val = "";		break;	case S_BOOLEAN:	case S_TRISTATE:		newval.val = "n";		break;	default:		sym->curr.val = sym->name;		sym->curr.tri = no;		return;	}	sym->flags &= ~SYMBOL_WRITE; 	sym_calc_visibility(sym); 	if (sym->visible != no)		sym->flags |= SYMBOL_WRITE; 	/* set default if recursively called */	sym->curr = newval; 	switch (sym_get_type(sym)) {	case S_BOOLEAN:	case S_TRISTATE:		choice_menu = sym_get_choice_menu(sym); 		if (choice_menu) {			sym_calc_choice(choice_menu);			newval.tri = sym->curr.tri;		} else {			if (sym->visible != no) {				/* if the symbol is visible use the user value				 * if available, otherwise try the default value				 */				if (sym_has_value(sym)) {					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,							      sym->visible);					goto calc_newval;				}			}			if (sym->rev_dep.tri != no)				sym->flags |= SYMBOL_WRITE;			if (!sym_is_choice(sym)) {				prop = sym_get_default_prop(sym);				if (prop) {					newval.tri = EXPR_AND(expr_calc_value(prop->expr),							      prop->visible.tri);					if (newval.tri != no)						sym->flags |= SYMBOL_WRITE;				}				if (sym->implied.tri != no) {					sym->flags |= SYMBOL_WRITE;					newval.tri = EXPR_OR(newval.tri, sym->implied.tri);					newval.tri = EXPR_AND(newval.tri,							      sym->dir_dep.tri);				}			}		calc_newval:			if (sym->dir_dep.tri < sym->rev_dep.tri)				sym_warn_unmet_dep(sym);			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);		}		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)			newval.tri = yes;

Lines 1–500 of 1366.