1310 lines · 27.2 KB · C
RawDownload
/* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ #include <ctype.h>#include <stdlib.h>#include <string.h>#include <regex.h>#include <sys/utsname.h> #include "lkc.h" struct symbol symbol_yes = {	.name = "y",	.curr = { "y", yes },	.flags = SYMBOL_CONST|SYMBOL_VALID,}, symbol_mod = {	.name = "m",	.curr = { "m", mod },	.flags = SYMBOL_CONST|SYMBOL_VALID,}, symbol_no = {	.name = "n",	.curr = { "n", no },	.flags = SYMBOL_CONST|SYMBOL_VALID,}, symbol_empty = {	.name = "",	.curr = { "", no },	.flags = SYMBOL_VALID,}; struct symbol *sym_defconfig_list;struct symbol *modules_sym;tristate modules_val; struct expr *sym_env_list; static void sym_add_default(struct symbol *sym, const char *def){	struct property *prop = prop_alloc(P_DEFAULT, sym); 	prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));} void sym_init(void){	struct symbol *sym;	struct utsname uts;	static bool inited = false; 	if (inited)		return;	inited = true; 	uname(&uts); 	sym = sym_lookup("UNAME_RELEASE", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	sym_add_default(sym, uts.release);} enum symbol_type sym_get_type(struct symbol *sym){	enum symbol_type type = sym->type; 	if (type == S_TRISTATE) {		if (sym_is_choice_value(sym) && sym->visible == yes)			type = S_BOOLEAN;		else if (modules_val == no)			type = S_BOOLEAN;	}	return type;} const char *sym_type_name(enum symbol_type type){	switch (type) {	case S_BOOLEAN:		return "boolean";	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";	case S_OTHER:		break;	}	return "???";} struct property *sym_get_choice_prop(struct symbol *sym){	struct property *prop; 	for_all_choices(sym, prop)		return prop;	return NULL;} struct property *sym_get_env_prop(struct symbol *sym){	struct property *prop; 	for_all_properties(sym, prop, P_ENV)		return prop;	return NULL;} 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;} static 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 int 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 strtol(sym->curr.val, NULL, base);} static void sym_validate_range(struct symbol *sym){	struct property *prop;	int base, val, val2;	char str[64]; 	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 = strtol(sym->curr.val, NULL, base);	val2 = sym_get_range_val(prop->expr->left.sym, base);	if (val >= val2) {		val2 = sym_get_range_val(prop->expr->right.sym, base);		if (val <= val2)			return;	}	if (sym->type == S_INT)		sprintf(str, "%d", val2);	else		sprintf(str, "0x%x", val2);	sym->curr.val = strdup(str);} static void sym_calc_visibility(struct symbol *sym){	struct property *prop;	tristate tri; 	/* 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)		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);	}} /* * 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 symbol *sym){	struct symbol *def_sym;	struct property *prop;	struct expr *e; 	/* any of the defaults visible? */	for_all_defaults(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 */	prop = sym_get_choice_prop(sym);	expr_list_for_each_sym(prop->expr, e, def_sym)		if (def_sym->visible != no)			return def_sym; 	/* failed to locate any defaults */	return NULL;} static struct symbol *sym_calc_choice(struct symbol *sym){	struct symbol *def_sym;	struct property *prop;	struct expr *e;	int flags; 	/* first calculate all choice values' visibilities */	flags = sym->flags;	prop = sym_get_choice_prop(sym);	expr_list_for_each_sym(prop->expr, e, def_sym) {		sym_calc_visibility(def_sym);		if (def_sym->visible != no)			flags &= def_sym->flags;	} 	sym->flags &= flags | ~SYMBOL_DEF_USER; 	/* is the user choice visible? */	def_sym = sym->def[S_DEF_USER].val;	if (def_sym && def_sym->visible != no)		return def_sym; 	def_sym = sym_choice_default(sym); 	if (def_sym == NULL)		/* no choice? reset tristate value */		sym->curr.tri = no; 	return def_sym;} void sym_calc_value(struct symbol *sym){	struct symbol_value newval, oldval;	struct property *prop;	struct expr *e; 	if (!sym)		return; 	if (sym->flags & SYMBOL_VALID)		return;	sym->flags |= SYMBOL_VALID; 	oldval = sym->curr; 	switch (sym->type) {	case S_INT:	case S_HEX:	case S_STRING:		newval = symbol_empty.curr;		break;	case S_BOOLEAN:	case S_TRISTATE:		newval = symbol_no.curr;		break;	default:		sym->curr.val = sym->name;		sym->curr.tri = no;		return;	}	if (!sym_is_choice_value(sym))		sym->flags &= ~SYMBOL_WRITE; 	sym_calc_visibility(sym); 	/* set default if recursively called */	sym->curr = newval; 	switch (sym_get_type(sym)) {	case S_BOOLEAN:	case S_TRISTATE:		if (sym_is_choice_value(sym) && sym->visible == yes) {			prop = sym_get_choice_prop(sym);			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;		} else {			if (sym->visible != no) {				/* if the symbol is visible use the user value				 * if available, otherwise try the default value				 */				sym->flags |= SYMBOL_WRITE;				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) {					sym->flags |= SYMBOL_WRITE;					newval.tri = EXPR_AND(expr_calc_value(prop->expr),							      prop->visible.tri);				}			}		calc_newval:			if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {				struct expr *e;				e = expr_simplify_unmet_dep(sym->rev_dep.expr,				    sym->dir_dep.expr);				fprintf(stderr, "warning: (");				expr_fprint(e, stderr);				fprintf(stderr, ") selects %s which has unmet direct dependencies (",					sym->name);				expr_fprint(sym->dir_dep.expr, stderr);				fprintf(stderr, ")\n");				expr_free(e);			}			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);		}		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)			newval.tri = yes;		break;	case S_STRING:	case S_HEX:	case S_INT:		if (sym->visible != no) {			sym->flags |= SYMBOL_WRITE;			if (sym_has_value(sym)) {				newval.val = sym->def[S_DEF_USER].val;				break;			}		}		prop = sym_get_default_prop(sym);		if (prop) {			struct symbol *ds = prop_get_symbol(prop);			if (ds) {				sym->flags |= SYMBOL_WRITE;				sym_calc_value(ds);				newval.val = ds->curr.val;			}		}		break;	default:		;	} 	sym->curr = newval;	if (sym_is_choice(sym) && newval.tri == yes)		sym->curr.val = sym_calc_choice(sym);	sym_validate_range(sym); 	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {		sym_set_changed(sym);		if (modules_sym == sym) {			sym_set_all_changed();			modules_val = modules_sym->curr.tri;		}	} 	if (sym_is_choice(sym)) {		struct symbol *choice_sym; 		prop = sym_get_choice_prop(sym);		expr_list_for_each_sym(prop->expr, e, choice_sym) {			if ((sym->flags & SYMBOL_WRITE) &&			    choice_sym->visible != no)				choice_sym->flags |= SYMBOL_WRITE;			if (sym->flags & SYMBOL_CHANGED)				sym_set_changed(choice_sym);		}	} 	if (sym->flags & SYMBOL_AUTO)		sym->flags &= ~SYMBOL_WRITE;} void sym_clear_all_valid(void){	struct symbol *sym;	int i; 	for_all_symbols(i, sym)		sym->flags &= ~SYMBOL_VALID;	sym_add_change_count(1);	if (modules_sym)		sym_calc_value(modules_sym);} void sym_set_changed(struct symbol *sym){	struct property *prop; 	sym->flags |= SYMBOL_CHANGED;	for (prop = sym->prop; prop; prop = prop->next) {		if (prop->menu)			prop->menu->flags |= MENU_CHANGED;	}} void sym_set_all_changed(void){	struct symbol *sym;	int i; 	for_all_symbols(i, sym)		sym_set_changed(sym);} bool sym_tristate_within_range(struct symbol *sym, tristate val){	int type = sym_get_type(sym); 	if (sym->visible == no)		return false; 	if (type != S_BOOLEAN && type != S_TRISTATE)		return false; 	if (type == S_BOOLEAN && val == mod)		return false;	if (sym->visible <= sym->rev_dep.tri)		return false;	if (sym_is_choice_value(sym) && sym->visible == yes)		return val == yes;	return val >= sym->rev_dep.tri && val <= sym->visible;} bool sym_set_tristate_value(struct symbol *sym, tristate val){	tristate oldval = sym_get_tristate_value(sym); 	if (oldval != val && !sym_tristate_within_range(sym, val))		return false; 	if (!(sym->flags & SYMBOL_DEF_USER)) {		sym->flags |= SYMBOL_DEF_USER;		sym_set_changed(sym);	}	/*	 * setting a choice value also resets the new flag of the choice	 * symbol and all other choice values.	 */	if (sym_is_choice_value(sym) && val == yes) {		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));		struct property *prop;		struct expr *e; 

Lines 1–500 of 1310.