| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 | /* * 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 <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;void sym_add_default(struct symbol *sym, const char *def){	struct property *prop = create_prop(P_DEFAULT);	struct property **propp;	prop->sym = sym;	prop->def = sym_lookup(def, 1);	/* append property to the prop list of symbol */	if (prop->sym) {		for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)			;		*propp = prop;	}}void sym_init(void){	struct symbol *sym;	struct utsname uts;	char *p;	static bool inited = false;	if (inited)		return;	inited = true;	uname(&uts);#if 0	sym = sym_lookup("ARCH", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	p = getenv("ARCH");	if (p)		sym_add_default(sym, p);#endif	sym = sym_lookup("VERSION", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	p = getenv("VERSION");	if (p)		sym_add_default(sym, p);#if 0	sym = sym_lookup("UNAME_RELEASE", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	sym_add_default(sym, uts.release);#endif	sym = sym_lookup("TARGET_ARCH", 0);	sym->type = S_STRING;	sym->flags |= SYMBOL_AUTO;	p = getenv("TARGET_ARCH");	if (p)		sym_add_default(sym, p);}int sym_get_type(struct symbol *sym){	int type = sym->type;	if (type == S_TRISTATE) {		if (sym_is_choice_value(sym) && sym->visible == yes)			type = S_BOOLEAN;		else {			sym_calc_value(modules_sym);			if (S_TRI(modules_sym->curr) == no)				type = S_BOOLEAN;		}	}	return type;}const char *sym_type_name(int 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";	}	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;	tristate visible;	for_all_defaults(sym, prop) {		visible = E_CALC(prop->visible);		if (visible != no)			return prop;	}	return NULL;}void sym_calc_visibility(struct symbol *sym){	struct property *prop;	tristate visible, oldvisible;	/* any prompt visible? */	oldvisible = sym->visible;	visible = no;	for_all_prompts(sym, prop)		visible = E_OR(visible, E_CALC(prop->visible));	if (oldvisible != visible) {		sym->visible = visible;		sym->flags |= SYMBOL_CHANGED;	}}void sym_calc_value(struct symbol *sym){	struct symbol_value newval, oldval;	struct property *prop, *def_prop;	struct symbol *def_sym;	struct expr *e;	if (sym->flags & SYMBOL_VALID)		return;	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:		S_VAL(newval) = sym->name;		S_TRI(newval) = no;		if (sym->flags & SYMBOL_CONST) {			goto out;		}		//newval = symbol_empty.curr;		// generate warning somewhere here later		//S_TRI(newval) = yes;		goto out;	}	sym->flags |= SYMBOL_VALID;	if (!sym_is_choice_value(sym))		sym->flags &= ~SYMBOL_WRITE;	sym_calc_visibility(sym);	/* set default if recursively called */	sym->curr = newval;	if (sym->visible != no) {		sym->flags |= SYMBOL_WRITE;		if (!sym_has_value(sym)) {			if (!sym_is_choice(sym)) {				prop = sym_get_default_prop(sym);				if (prop) {					sym_calc_value(prop->def);					newval = prop->def->curr;				}			}		} else			newval = sym->def;		S_TRI(newval) = E_AND(S_TRI(newval), sym->visible);		/* if the symbol is visible and not optionial,		 * possibly ignore old user choice. */		if (!sym_is_optional(sym) && S_TRI(newval) == no)			S_TRI(newval) = sym->visible;		if (sym_is_choice_value(sym) && sym->visible == yes) {			prop = sym_get_choice_prop(sym);			S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no;		}	} else {		prop = sym_get_default_prop(sym);		if (prop) {			sym->flags |= SYMBOL_WRITE;			sym_calc_value(prop->def);			newval = prop->def->curr;		}	}	switch (sym_get_type(sym)) {	case S_TRISTATE:		if (S_TRI(newval) != mod)			break;		sym_calc_value(modules_sym);		if (S_TRI(modules_sym->curr) == no)			S_TRI(newval) = yes;		break;	case S_BOOLEAN:		if (S_TRI(newval) == mod)			S_TRI(newval) = yes;	}out:	sym->curr = newval;	if (sym_is_choice(sym) && S_TRI(newval) == yes) {		def_sym = S_VAL(sym->def);		if (def_sym) {			sym_calc_visibility(def_sym);			if (def_sym->visible == no)				def_sym = NULL;		}		if (!def_sym) {			for_all_defaults(sym, def_prop) {				if (E_CALC(def_prop->visible) == no)					continue;				sym_calc_visibility(def_prop->def);				if (def_prop->def->visible != no) {					def_sym = def_prop->def;					break;				}			}		}		if (!def_sym) {			prop = sym_get_choice_prop(sym);			for (e = prop->dep; e; e = e->left.expr) {				sym_calc_visibility(e->right.sym);				if (e->right.sym->visible != no) {					def_sym = e->right.sym;					break;				}			}		}		S_VAL(newval) = def_sym;	}	if (memcmp(&oldval, &newval, sizeof(newval)))		sym->flags |= SYMBOL_CHANGED;	sym->curr = newval;	if (sym_is_choice(sym)) {		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);		prop = sym_get_choice_prop(sym);		for (e = prop->dep; e; e = e->left.expr)			e->right.sym->flags |= flags;	}}void sym_clear_all_valid(void){	struct symbol *sym;	int i;	for_all_symbols(i, sym)		sym->flags &= ~SYMBOL_VALID;	sym_change_count++;}void sym_set_all_changed(void){	struct symbol *sym;	int i;	for_all_symbols(i, sym)		sym->flags |= SYMBOL_CHANGED;}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;	switch (val) {	case no:		if (sym_is_choice_value(sym) && sym->visible == yes)			return false;		return sym_is_optional(sym);	case mod:		if (sym_is_choice_value(sym) && sym->visible == yes)			return false;		return type == S_TRISTATE;	case yes:		return type == S_BOOLEAN || sym->visible == yes;	}	return false;}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->flags |= SYMBOL_CHANGED;	}	if (sym_is_choice_value(sym) && val == yes) {		struct property *prop = sym_get_choice_prop(sym);		S_VAL(prop->def->def) = sym;		prop->def->flags &= ~SYMBOL_NEW;	}	S_TRI(sym->def) = 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){	char ch;	switch (sym->type) {	case S_STRING:		return true;	case S_INT:		ch = *str++;		if (ch == '-')			ch = *str++;		if (!isdigit((int)ch))			return false;		if (ch == '0' && *str != 0)			return false;		while ((ch = *str++)) {			if (!isdigit((int)ch))				return false;		}		return true;	case S_HEX:		if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))			str += 2;		ch = *str++;		do {			if (!isxdigit((int)ch))				return false;		} while ((ch = *str++));		return true;	case S_BOOLEAN:	case S_TRISTATE:		switch (str[0]) {		case 'y':		case 'Y':			return sym_tristate_within_range(sym, yes);		case 'm':		case 'M':			return sym_tristate_within_range(sym, mod);		case 'n':		case 'N':			return sym_tristate_within_range(sym, no);		}		return false;	default:		return false;	}}bool sym_set_string_value(struct symbol *sym, const char *newval){	const char *oldval;	char *val;	int size;	switch (sym->type) {	case S_BOOLEAN:	case S_TRISTATE:		switch (newval[0]) {		case 'y':		case 'Y':			return sym_set_tristate_value(sym, yes);		case 'm':		case 'M':			return sym_set_tristate_value(sym, mod);		case 'n':		case 'N':			return sym_set_tristate_value(sym, no);		}		return false;	default:		;	}	if (!sym_string_valid(sym, newval))		return false;	if (sym->flags & SYMBOL_NEW) {		sym->flags &= ~SYMBOL_NEW;		sym->flags |= SYMBOL_CHANGED;	}	oldval = S_VAL(sym->def);	size = strlen(newval) + 1;	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {		size += 2;		S_VAL(sym->def) = val = malloc(size);		*val++ = '0';		*val++ = 'x';	} else if (!oldval || strcmp(oldval, newval))		S_VAL(sym->def) = val = malloc(size);	else		return true;	strcpy(val, newval);	free((void *)oldval);	sym_clear_all_valid();	return true;}const char *sym_get_string_value(struct symbol *sym){	tristate val;	switch (sym->type) {	case S_BOOLEAN:	case S_TRISTATE:		val = sym_get_tristate_value(sym);		switch (val) {		case no:			return "n";		case mod:			return "m";		case yes:			return "y";		}		break;	default:		;	}	return (const char *)S_VAL(sym->curr);}bool sym_is_changable(struct symbol *sym){	if (sym->visible == no)		return false;	/* at least 'n' and 'y'/'m' is selectable */	if (sym_is_optional(sym))		return true;	/* no 'n', so 'y' and 'm' must be selectable */	if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)		return true;	return false;}struct symbol *sym_lookup(const char *name, int isconst){	struct symbol *symbol;	const char *ptr;	char *new_name;	int hash = 0;	//printf("lookup: %s -> ", name);	if (name) {		if (name[0] && !name[1]) {			switch (name[0]) {			case 'y': return &symbol_yes;			case 'm': return &symbol_mod;			case 'n': return &symbol_no;			}		}		for (ptr = name; *ptr; ptr++)			hash += *ptr;		hash &= 0xff;		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {			if (!strcmp(symbol->name, name)) {				if ((isconst && symbol->flags & SYMBOL_CONST) ||				    (!isconst && !(symbol->flags & SYMBOL_CONST))) {					//printf("h:%p\n", symbol);					return symbol;				}			}		}		new_name = strdup(name);	} else {		new_name = NULL;		hash = 256;	}	symbol = malloc(sizeof(*symbol));	memset(symbol, 0, sizeof(*symbol));	symbol->name = new_name;	symbol->type = S_UNKNOWN;	symbol->flags = SYMBOL_NEW;	if (isconst)		symbol->flags |= SYMBOL_CONST;	symbol->next = symbol_hash[hash];	symbol_hash[hash] = symbol;	//printf("n:%p\n", symbol);	return symbol;}struct symbol *sym_find(const char *name){	struct symbol *symbol = NULL;	const char *ptr;	int hash = 0;	if (!name)		return NULL;	if (name[0] && !name[1]) {		switch (name[0]) {		case 'y': return &symbol_yes;		case 'm': return &symbol_mod;		case 'n': return &symbol_no;		}	}	for (ptr = name; *ptr; ptr++)		hash += *ptr;	hash &= 0xff;	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {		if (!strcmp(symbol->name, name) &&		    !(symbol->flags & SYMBOL_CONST))				break;	}	return symbol;}const char *prop_get_type_name(enum prop_type type){	switch (type) {	case P_PROMPT:		return "prompt";	case P_COMMENT:		return "comment";	case P_MENU:		return "menu";	case P_ROOTMENU:		return "rootmenu";	case P_DEFAULT:		return "default";	case P_CHOICE:		return "choice";	default:		return "unknown";	}}
 |