diff options
Diffstat (limited to 'extra/config/symbol.c')
-rw-r--r-- | extra/config/symbol.c | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/extra/config/symbol.c b/extra/config/symbol.c new file mode 100644 index 000000000..59c88d253 --- /dev/null +++ b/extra/config/symbol.c @@ -0,0 +1,618 @@ +/* + * 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); + + 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("KERNELRELEASE", 0); + sym->type = S_STRING; + sym->flags |= SYMBOL_AUTO; + p = getenv("KERNELRELEASE"); + 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); +} + +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(ch)) + return false; + if (ch == '0' && *str != 0) + return false; + while ((ch = *str++)) { + if (!isdigit(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(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"; + } +} |