882 lines · 17.3 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> #define LKC_DIRECT_LINK#include "lkc.h" struct symbol symbol_yes = {	.name = "y",	.curr = { "y", yes },	.flags = SYMBOL_YES|SYMBOL_VALID,}, symbol_mod = {	.name = "m",	.curr = { "m", mod },	.flags = SYMBOL_MOD|SYMBOL_VALID,}, symbol_no = {	.name = "n",	.curr = { "n", no },	.flags = SYMBOL_NO|SYMBOL_VALID,}, symbol_empty = {	.name = "",	.curr = { "", no },	.flags = SYMBOL_VALID,}; int sym_change_count;struct symbol *modules_sym;tristate modules_val; 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, 1));} void sym_init(void){	struct symbol *sym;	struct utsname uts;	char *p;	static bool inited = false; 	if (inited)		return;	inited = true; 	uname(&uts); 	sym = sym_lookup("ARCH", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	p = getenv("ARCH");	if (p)		sym_add_default(sym, p); 	sym = sym_lookup("KERNELVERSION", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	p = getenv("KERNELVERSION");	if (p)		sym_add_default(sym, p); 	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_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 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 = E_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;	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);	}} static struct symbol *sym_calc_choice(struct symbol *sym){	struct symbol *def_sym;	struct property *prop;	struct expr *e; 	/* is the user choice visible? */	def_sym = sym->user.val;	if (def_sym) {		sym_calc_visibility(def_sym);		if (def_sym->visible != no)			return def_sym;	} 	/* 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);		sym_calc_visibility(def_sym);		if (def_sym->visible != no)			return def_sym;	} 	/* just get the first visible value */	prop = sym_get_choice_prop(sym);	for (e = prop->expr; e; e = e->left.expr) {		def_sym = e->right.sym;		sym_calc_visibility(def_sym);		if (def_sym->visible != no)			return def_sym;	} 	/* no choice? reset tristate value */	sym->curr.tri = no;	return NULL;} 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 (E_OR(sym->visible, sym->rev_dep.tri) != no) {			sym->flags |= SYMBOL_WRITE;			if (sym_has_value(sym))				newval.tri = sym->user.tri;			else if (!sym_is_choice(sym)) {				prop = sym_get_default_prop(sym);				if (prop)					newval.tri = expr_calc_value(prop->expr);			}			newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);		} else if (!sym_is_choice(sym)) {			prop = sym_get_default_prop(sym);			if (prop) {				sym->flags |= SYMBOL_WRITE;				newval.tri = expr_calc_value(prop->expr);			}		}		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->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)		modules_val = modules_sym->curr.tri; 	if (sym_is_choice(sym)) {		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);		prop = sym_get_choice_prop(sym);		for (e = prop->expr; e; e = e->left.expr) {			e->right.sym->flags |= flags;			if (flags & SYMBOL_CHANGED)				sym_set_changed(e->right.sym);		}	}} void sym_clear_all_valid(void){	struct symbol *sym;	int i; 	for_all_symbols(i, sym)		sym->flags &= ~SYMBOL_VALID;	sym_change_count++;	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_NEW) {		sym->flags &= ~SYMBOL_NEW;		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; 		cs->user.val = sym;		cs->flags &= ~SYMBOL_NEW;		prop = sym_get_choice_prop(cs);		for (e = prop->expr; e; e = e->left.expr) {			if (e->right.sym->visible != no)				e->right.sym->flags &= ~SYMBOL_NEW;		}	} 	sym->user.tri = val;	if (oldval != val) {		sym_clear_all_valid();		if (sym == modules_sym)			sym_set_all_changed();	} 	return true;} tristate sym_toggle_tristate_value(struct symbol *sym){	tristate oldval, newval; 	oldval = newval = sym_get_tristate_value(sym);	do {		switch (newval) {		case no:			newval = mod;			break;		case mod:			newval = yes;			break;		case yes:			newval = no;			break;		}		if (sym_set_tristate_value(sym, newval))			break;	} while (oldval != newval);	return newval;} bool sym_string_valid(struct symbol *sym, const char *str){	signed char ch; 	switch (sym->type) {	case S_STRING:		return true;	case S_INT:		ch = *str++;		if (ch == '-')			ch = *str++;		if (!isdigit(ch))			return false;		if (ch == '0' && *str != 0)			return false;		while ((ch = *str++)) {			if (!isdigit(ch))

Lines 1–500 of 882.