diff options
| author | Karel Kočí <cynerd@email.cz> | 2014-12-14 19:28:28 +0100 | 
|---|---|---|
| committer | Karel Kočí <cynerd@email.cz> | 2014-12-14 19:28:28 +0100 | 
| commit | 4ec68e612e5d6670a154677b4c8914f22153b122 (patch) | |
| tree | 7fa4379e01336d0ac4e3613bb6b4d6ea7e66a04e /programs/src/kconfig | |
| parent | 5b99a9efbdd7026185266d71fca9615e124a6132 (diff) | |
| download | linux-conf-perf-4ec68e612e5d6670a154677b4c8914f22153b122.tar.gz linux-conf-perf-4ec68e612e5d6670a154677b4c8914f22153b122.tar.bz2 linux-conf-perf-4ec68e612e5d6670a154677b4c8914f22153b122.zip | |
Add kconfig_parser
kconfig_parser is placed to new folder tree. In folder "programs" will be all programs.
Files in folder programs/src/kconfig/kconfig are taken from kernel v3.18-rc3. In future, they should be updated if new changes will be added to kernel.
Diffstat (limited to 'programs/src/kconfig')
23 files changed, 11999 insertions, 0 deletions
| diff --git a/programs/src/kconfig/Makefile b/programs/src/kconfig/Makefile new file mode 100644 index 0000000..cc86499 --- /dev/null +++ b/programs/src/kconfig/Makefile @@ -0,0 +1,26 @@ +.SUFFIXES: + +all: kconfig_parser + + +clean: +	rm -f kconfig/zconf.tab.c kconfig/zconf.lex.c kconfig/zconf.hash.c +	rm -f ../../kconfig_parser + +INPUT_FILES  = kconfig_parser.c +INPUT_FILES += kconfig/zconf.tab.c \ +			   boolexp.c \ +			   symlist.c \ +			   output.c + +kconfig_parser: $(INPUT_FILES) kconfig/zconf.lex.c kconfig/zconf.hash.c +	gcc -O0 -w -ggdb -o ../../$@ $(INPUT_FILES) + +%.hash.c: %.gperf +	gperf -t --output-file $@ -a -C -E -g -k '1,3,$$' -p -t $< + +%.lex.c: %.l +	flex -o $@  -L -P zconf $< + +%.tab.c: %.y kconfig/zconf.lex.c kconfig/zconf.hash.c +	bison -o $@ $< -p zconf -t -l diff --git a/programs/src/kconfig/boolexp.c b/programs/src/kconfig/boolexp.c new file mode 100644 index 0000000..a41937a --- /dev/null +++ b/programs/src/kconfig/boolexp.c @@ -0,0 +1,141 @@ +#include "boolexp.h" + +struct boolexp *copy_kconfig_dep(struct symlist *sl, struct expr *expr) { +    struct boolexp *w; +    switch (expr->type) { +    case E_SYMBOL: +        w = malloc(sizeof(struct boolexp)); +        w->type = BE_LEAF; +        struct symlist_el *sel; +        sel = symlist_find(sl, expr->left.sym->name); +        if (sel == NULL) +            return NULL; +        w->left.id = sel->id; +        return w; +    case E_AND: +    case E_OR: +        w = malloc(sizeof(struct boolexp)); +        switch (expr->type) { +        case E_AND: +            w->type = BE_AND; +            break; +        case E_OR: +            w->type = BE_OR; +            break; +        } +        w->left.be = copy_kconfig_dep(sl, expr->left.expr); +        if (w->left.be == NULL) { +            free(w); +            return copy_kconfig_dep(sl, expr->right.expr); +        } +        w->right.be = copy_kconfig_dep(sl, expr->right.expr); +        if (w->right.be == NULL) { +            struct boolexp *ret = w->left.be; +            free(w); +            return ret; +        } +        return w; +    case E_EQUAL: +    case E_UNEQUAL: +        return NULL; +    case E_NOT: +        w = malloc(sizeof(struct boolexp)); +        w->type = BE_NOT; +        w->left.be = copy_kconfig_dep(sl, expr->left.expr); +        if (w->left.be == NULL) { +            free(w); +            return NULL; +        } +        return w; +    default: +        fprintf(stderr, "Error (%d): %s\n", expr->type, +                sym_type_name(expr->type)); +        return NULL; +    } +} + +// This function is leaking memory! TODO +struct boolexp *boolexp_cnf(struct boolexp *be) { +    if (be->type == BE_NOT) { +        if (be->left.be->type == BE_OR || be->left.be->type == BE_AND) { +            struct boolexp *root, *nleft, *nright; +            root = malloc(sizeof(struct boolexp)); +            nleft = malloc(sizeof(struct boolexp)); +            nright = malloc(sizeof(struct boolexp)); +            if (be->left.be->type == BE_OR) +                root->type = BE_AND; +            else if (be->left.be->type == BE_AND) +                root->type = BE_OR; +            nleft->type = BE_NOT; +            nright->type = BE_NOT; +            root->left.be = nleft; +            root->right.be = nright; +            nleft->left.be = be->left.be; +            nright->left.be = be->right.be; +            be = root; +        } +    } else if (be->type == BE_OR) +        if (be->left.be->type == BE_AND) { +            struct boolexp *root, *nleft, *nright; +            root = malloc(sizeof(struct boolexp)); +            nleft = malloc(sizeof(struct boolexp)); +            nright = malloc(sizeof(struct boolexp)); +            root->type = BE_AND; +            nleft->type = BE_OR; +            nright->type = BE_OR; +            root->left.be = nleft; +            root->right.be = nright; +            nleft->left.be = be->left.be->left.be; +            nleft->right.be = be->right.be; +            nright->left.be = be->left.be->right.be; +            nright->right.be = be->right.be; +            be = root; +        } else if (be->right.be->type == BE_AND) { +            struct boolexp *root, *nleft, *nright; +            root = malloc(sizeof(struct boolexp)); +            nleft = malloc(sizeof(struct boolexp)); +            nright = malloc(sizeof(struct boolexp)); +            root->type = BE_AND; +            nleft->type = BE_OR; +            nright->type = BE_OR; +            root->left.be = nleft; +            root->right.be = nright; +            nleft->left.be = be->left.be; +            nleft->right.be = be->right.be->left.be; +            nright->left.be = be->left.be; +            nright->right.be = be->right.be->right.be; +            be = root; +        } +    if (be->type == BE_OR || be->type == BE_AND || be->type == BE_NOT) +        be->left.be = boolexp_cnf(be->left.be); +    if (be->type == BE_OR || be->type == BE_AND) +        be->right.be = boolexp_cnf(be->right.be); +    return be; +} + +void boolexp_print(struct boolexp *be) { +    if (be != NULL) +        switch (be->type) { +        case BE_LEAF: +            printf("%d", be->left.id); +            break; +        case BE_AND: +            //printf("("); +            boolexp_print(be->left.be); +            printf(" and "); +            boolexp_print(be->right.be); +            //printf(")"); +            break; +        case BE_OR: +            printf("("); +            boolexp_print(be->left.be); +            printf(" or "); +            boolexp_print(be->right.be); +            printf(")"); +            break; +        case BE_NOT: +            printf("-"); +            boolexp_print(be->left.be); +            break; +        } +} diff --git a/programs/src/kconfig/boolexp.h b/programs/src/kconfig/boolexp.h new file mode 100644 index 0000000..f03fc33 --- /dev/null +++ b/programs/src/kconfig/boolexp.h @@ -0,0 +1,27 @@ +#ifndef _BOOLEXP_H_ +#define _BOOLEXP_H_ + +#include <stdbool.h> +#include "symlist.h" +#include "kconfig/lkc.h" + +enum boolexp_type { +    BE_OR, BE_AND, BE_NOT, BE_LEAF +}; + +struct boolexp; +union boolexp_data { +    struct boolexp *be; +    unsigned int id; +}; + +struct boolexp { +    enum boolexp_type type; +    union boolexp_data left, right; +}; + +struct boolexp *copy_kconfig_dep(struct symlist *sl, struct expr *expr); +struct boolexp *boolexp_cnf(struct boolexp *be); +void boolexp_print(struct boolexp *be); + +#endif /* _BOOLEXP_H_ */ diff --git a/programs/src/kconfig/kconfig/confdata.c b/programs/src/kconfig/kconfig/confdata.c new file mode 100644 index 0000000..f88d90f --- /dev/null +++ b/programs/src/kconfig/kconfig/confdata.c @@ -0,0 +1,1242 @@ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <sys/stat.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "lkc.h" + +static void conf_warning(const char *fmt, ...) +	__attribute__ ((format (printf, 1, 2))); + +static void conf_message(const char *fmt, ...) +	__attribute__ ((format (printf, 1, 2))); + +static const char *conf_filename; +static int conf_lineno, conf_warnings, conf_unsaved; + +const char conf_defname[] = "arch/$ARCH/defconfig"; + +static void conf_warning(const char *fmt, ...) +{ +	va_list ap; +	va_start(ap, fmt); +	fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); +	vfprintf(stderr, fmt, ap); +	fprintf(stderr, "\n"); +	va_end(ap); +	conf_warnings++; +} + +static void conf_default_message_callback(const char *fmt, va_list ap) +{ +	printf("#\n# "); +	vprintf(fmt, ap); +	printf("\n#\n"); +} + +static void (*conf_message_callback) (const char *fmt, va_list ap) = +	conf_default_message_callback; +void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) +{ +	conf_message_callback = fn; +} + +static void conf_message(const char *fmt, ...) +{ +	va_list ap; + +	va_start(ap, fmt); +	if (conf_message_callback) +		conf_message_callback(fmt, ap); +} + +const char *conf_get_configname(void) +{ +	char *name = getenv("KCONFIG_CONFIG"); + +	return name ? name : ".config"; +} + +const char *conf_get_autoconfig_name(void) +{ +	char *name = getenv("KCONFIG_AUTOCONFIG"); + +	return name ? name : "include/config/auto.conf"; +} + +static char *conf_expand_value(const char *in) +{ +	struct symbol *sym; +	const char *src; +	static char res_value[SYMBOL_MAXLENGTH]; +	char *dst, name[SYMBOL_MAXLENGTH]; + +	res_value[0] = 0; +	dst = name; +	while ((src = strchr(in, '$'))) { +		strncat(res_value, in, src - in); +		src++; +		dst = name; +		while (isalnum(*src) || *src == '_') +			*dst++ = *src++; +		*dst = 0; +		sym = sym_lookup(name, 0); +		sym_calc_value(sym); +		strcat(res_value, sym_get_string_value(sym)); +		in = src; +	} +	strcat(res_value, in); + +	return res_value; +} + +char *conf_get_default_confname(void) +{ +	struct stat buf; +	static char fullname[PATH_MAX+1]; +	char *env, *name; + +	name = conf_expand_value(conf_defname); +	env = getenv(SRCTREE); +	if (env) { +		sprintf(fullname, "%s/%s", env, name); +		if (!stat(fullname, &buf)) +			return fullname; +	} +	return name; +} + +static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) +{ +	char *p2; + +	switch (sym->type) { +	case S_TRISTATE: +		if (p[0] == 'm') { +			sym->def[def].tri = mod; +			sym->flags |= def_flags; +			break; +		} +		/* fall through */ +	case S_BOOLEAN: +		if (p[0] == 'y') { +			sym->def[def].tri = yes; +			sym->flags |= def_flags; +			break; +		} +		if (p[0] == 'n') { +			sym->def[def].tri = no; +			sym->flags |= def_flags; +			break; +		} +		if (def != S_DEF_AUTO) +			conf_warning("symbol value '%s' invalid for %s", +				     p, sym->name); +		return 1; +	case S_OTHER: +		if (*p != '"') { +			for (p2 = p; *p2 && !isspace(*p2); p2++) +				; +			sym->type = S_STRING; +			goto done; +		} +		/* fall through */ +	case S_STRING: +		if (*p++ != '"') +			break; +		for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { +			if (*p2 == '"') { +				*p2 = 0; +				break; +			} +			memmove(p2, p2 + 1, strlen(p2)); +		} +		if (!p2) { +			if (def != S_DEF_AUTO) +				conf_warning("invalid string found"); +			return 1; +		} +		/* fall through */ +	case S_INT: +	case S_HEX: +	done: +		if (sym_string_valid(sym, p)) { +			sym->def[def].val = strdup(p); +			sym->flags |= def_flags; +		} else { +			if (def != S_DEF_AUTO) +				conf_warning("symbol value '%s' invalid for %s", +					     p, sym->name); +			return 1; +		} +		break; +	default: +		; +	} +	return 0; +} + +#define LINE_GROWTH 16 +static int add_byte(int c, char **lineptr, size_t slen, size_t *n) +{ +	char *nline; +	size_t new_size = slen + 1; +	if (new_size > *n) { +		new_size += LINE_GROWTH - 1; +		new_size *= 2; +		nline = realloc(*lineptr, new_size); +		if (!nline) +			return -1; + +		*lineptr = nline; +		*n = new_size; +	} + +	(*lineptr)[slen] = c; + +	return 0; +} + +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) +{ +	char *line = *lineptr; +	size_t slen = 0; + +	for (;;) { +		int c = getc(stream); + +		switch (c) { +		case '\n': +			if (add_byte(c, &line, slen, n) < 0) +				goto e_out; +			slen++; +			/* fall through */ +		case EOF: +			if (add_byte('\0', &line, slen, n) < 0) +				goto e_out; +			*lineptr = line; +			if (slen == 0) +				return -1; +			return slen; +		default: +			if (add_byte(c, &line, slen, n) < 0) +				goto e_out; +			slen++; +		} +	} + +e_out: +	line[slen-1] = '\0'; +	*lineptr = line; +	return -1; +} + +int conf_read_simple(const char *name, int def) +{ +	FILE *in = NULL; +	char   *line = NULL; +	size_t  line_asize = 0; +	char *p, *p2; +	struct symbol *sym; +	int i, def_flags; + +	if (name) { +		in = zconf_fopen(name); +	} else { +		struct property *prop; + +		name = conf_get_configname(); +		in = zconf_fopen(name); +		if (in) +			goto load; +		sym_add_change_count(1); +		if (!sym_defconfig_list) { +			if (modules_sym) +				sym_calc_value(modules_sym); +			return 1; +		} + +		for_all_defaults(sym_defconfig_list, prop) { +			if (expr_calc_value(prop->visible.expr) == no || +			    prop->expr->type != E_SYMBOL) +				continue; +			name = conf_expand_value(prop->expr->left.sym->name); +			in = zconf_fopen(name); +			if (in) { +				conf_message(_("using defaults found in %s"), +					 name); +				goto load; +			} +		} +	} +	if (!in) +		return 1; + +load: +	conf_filename = name; +	conf_lineno = 0; +	conf_warnings = 0; +	conf_unsaved = 0; + +	def_flags = SYMBOL_DEF << def; +	for_all_symbols(i, sym) { +		sym->flags |= SYMBOL_CHANGED; +		sym->flags &= ~(def_flags|SYMBOL_VALID); +		if (sym_is_choice(sym)) +			sym->flags |= def_flags; +		switch (sym->type) { +		case S_INT: +		case S_HEX: +		case S_STRING: +			if (sym->def[def].val) +				free(sym->def[def].val); +			/* fall through */ +		default: +			sym->def[def].val = NULL; +			sym->def[def].tri = no; +		} +	} + +	while (compat_getline(&line, &line_asize, in) != -1) { +		conf_lineno++; +		sym = NULL; +		if (line[0] == '#') { +			if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) +				continue; +			p = strchr(line + 2 + strlen(CONFIG_), ' '); +			if (!p) +				continue; +			*p++ = 0; +			if (strncmp(p, "is not set", 10)) +				continue; +			if (def == S_DEF_USER) { +				sym = sym_find(line + 2 + strlen(CONFIG_)); +				if (!sym) { +					sym_add_change_count(1); +					goto setsym; +				} +			} else { +				sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); +				if (sym->type == S_UNKNOWN) +					sym->type = S_BOOLEAN; +			} +			if (sym->flags & def_flags) { +				conf_warning("override: reassigning to symbol %s", sym->name); +			} +			switch (sym->type) { +			case S_BOOLEAN: +			case S_TRISTATE: +				sym->def[def].tri = no; +				sym->flags |= def_flags; +				break; +			default: +				; +			} +		} else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { +			p = strchr(line + strlen(CONFIG_), '='); +			if (!p) +				continue; +			*p++ = 0; +			p2 = strchr(p, '\n'); +			if (p2) { +				*p2-- = 0; +				if (*p2 == '\r') +					*p2 = 0; +			} +			if (def == S_DEF_USER) { +				sym = sym_find(line + strlen(CONFIG_)); +				if (!sym) { +					sym_add_change_count(1); +					goto setsym; +				} +			} else { +				sym = sym_lookup(line + strlen(CONFIG_), 0); +				if (sym->type == S_UNKNOWN) +					sym->type = S_OTHER; +			} +			if (sym->flags & def_flags) { +				conf_warning("override: reassigning to symbol %s", sym->name); +			} +			if (conf_set_sym_val(sym, def, def_flags, p)) +				continue; +		} else { +			if (line[0] != '\r' && line[0] != '\n') +				conf_warning("unexpected data"); +			continue; +		} +setsym: +		if (sym && sym_is_choice_value(sym)) { +			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); +			switch (sym->def[def].tri) { +			case no: +				break; +			case mod: +				if (cs->def[def].tri == yes) { +					conf_warning("%s creates inconsistent choice state", sym->name); +					cs->flags &= ~def_flags; +				} +				break; +			case yes: +				if (cs->def[def].tri != no) +					conf_warning("override: %s changes choice state", sym->name); +				cs->def[def].val = sym; +				break; +			} +			cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); +		} +	} +	free(line); +	fclose(in); + +	if (modules_sym) +		sym_calc_value(modules_sym); +	return 0; +} + +int conf_read(const char *name) +{ +	struct symbol *sym; +	int i; + +	sym_set_change_count(0); + +	if (conf_read_simple(name, S_DEF_USER)) +		return 1; + +	for_all_symbols(i, sym) { +		sym_calc_value(sym); +		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) +			continue; +		if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { +			/* check that calculated value agrees with saved value */ +			switch (sym->type) { +			case S_BOOLEAN: +			case S_TRISTATE: +				if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) +					break; +				if (!sym_is_choice(sym)) +					continue; +				/* fall through */ +			default: +				if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) +					continue; +				break; +			} +		} else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) +			/* no previous value and not saved */ +			continue; +		conf_unsaved++; +		/* maybe print value in verbose mode... */ +	} + +	for_all_symbols(i, sym) { +		if (sym_has_value(sym) && !sym_is_choice_value(sym)) { +			/* Reset values of generates values, so they'll appear +			 * as new, if they should become visible, but that +			 * doesn't quite work if the Kconfig and the saved +			 * configuration disagree. +			 */ +			if (sym->visible == no && !conf_unsaved) +				sym->flags &= ~SYMBOL_DEF_USER; +			switch (sym->type) { +			case S_STRING: +			case S_INT: +			case S_HEX: +				/* Reset a string value if it's out of range */ +				if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) +					break; +				sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); +				conf_unsaved++; +				break; +			default: +				break; +			} +		} +	} + +	sym_add_change_count(conf_warnings || conf_unsaved); + +	return 0; +} + +/* + * Kconfig configuration printer + * + * This printer is used when generating the resulting configuration after + * kconfig invocation and `defconfig' files. Unset symbol might be omitted by + * passing a non-NULL argument to the printer. + * + */ +static void +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + +	switch (sym->type) { +	case S_BOOLEAN: +	case S_TRISTATE: +		if (*value == 'n') { +			bool skip_unset = (arg != NULL); + +			if (!skip_unset) +				fprintf(fp, "# %s%s is not set\n", +				    CONFIG_, sym->name); +			return; +		} +		break; +	default: +		break; +	} + +	fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); +} + +static void +kconfig_print_comment(FILE *fp, const char *value, void *arg) +{ +	const char *p = value; +	size_t l; + +	for (;;) { +		l = strcspn(p, "\n"); +		fprintf(fp, "#"); +		if (l) { +			fprintf(fp, " "); +			xfwrite(p, l, 1, fp); +			p += l; +		} +		fprintf(fp, "\n"); +		if (*p++ == '\0') +			break; +	} +} + +static struct conf_printer kconfig_printer_cb = +{ +	.print_symbol = kconfig_print_symbol, +	.print_comment = kconfig_print_comment, +}; + +/* + * Header printer + * + * This printer is used when generating the `include/generated/autoconf.h' file. + */ +static void +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + +	switch (sym->type) { +	case S_BOOLEAN: +	case S_TRISTATE: { +		const char *suffix = ""; + +		switch (*value) { +		case 'n': +			break; +		case 'm': +			suffix = "_MODULE"; +			/* fall through */ +		default: +			fprintf(fp, "#define %s%s%s 1\n", +			    CONFIG_, sym->name, suffix); +		} +		break; +	} +	case S_HEX: { +		const char *prefix = ""; + +		if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) +			prefix = "0x"; +		fprintf(fp, "#define %s%s %s%s\n", +		    CONFIG_, sym->name, prefix, value); +		break; +	} +	case S_STRING: +	case S_INT: +		fprintf(fp, "#define %s%s %s\n", +		    CONFIG_, sym->name, value); +		break; +	default: +		break; +	} + +} + +static void +header_print_comment(FILE *fp, const char *value, void *arg) +{ +	const char *p = value; +	size_t l; + +	fprintf(fp, "/*\n"); +	for (;;) { +		l = strcspn(p, "\n"); +		fprintf(fp, " *"); +		if (l) { +			fprintf(fp, " "); +			xfwrite(p, l, 1, fp); +			p += l; +		} +		fprintf(fp, "\n"); +		if (*p++ == '\0') +			break; +	} +	fprintf(fp, " */\n"); +} + +static struct conf_printer header_printer_cb = +{ +	.print_symbol = header_print_symbol, +	.print_comment = header_print_comment, +}; + +/* + * Tristate printer + * + * This printer is used when generating the `include/config/tristate.conf' file. + */ +static void +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) +{ + +	if (sym->type == S_TRISTATE && *value != 'n') +		fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); +} + +static struct conf_printer tristate_printer_cb = +{ +	.print_symbol = tristate_print_symbol, +	.print_comment = kconfig_print_comment, +}; + +static void conf_write_symbol(FILE *fp, struct symbol *sym, +			      struct conf_printer *printer, void *printer_arg) +{ +	const char *str; + +	switch (sym->type) { +	case S_OTHER: +	case S_UNKNOWN: +		break; +	case S_STRING: +		str = sym_get_string_value(sym); +		str = sym_escape_string_value(str); +		printer->print_symbol(fp, sym, str, printer_arg); +		free((void *)str); +		break; +	default: +		str = sym_get_string_value(sym); +		printer->print_symbol(fp, sym, str, printer_arg); +	} +} + +static void +conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) +{ +	char buf[256]; + +	snprintf(buf, sizeof(buf), +	    "\n" +	    "Automatically generated file; DO NOT EDIT.\n" +	    "%s\n", +	    rootmenu.prompt->text); + +	printer->print_comment(fp, buf, printer_arg); +} + +/* + * Write out a minimal config. + * All values that has default values are skipped as this is redundant. + */ +int conf_write_defconfig(const char *filename) +{ +	struct symbol *sym; +	struct menu *menu; +	FILE *out; + +	out = fopen(filename, "w"); +	if (!out) +		return 1; + +	sym_clear_all_valid(); + +	/* Traverse all menus to find all relevant symbols */ +	menu = rootmenu.list; + +	while (menu != NULL) +	{ +		sym = menu->sym; +		if (sym == NULL) { +			if (!menu_is_visible(menu)) +				goto next_menu; +		} else if (!sym_is_choice(sym)) { +			sym_calc_value(sym); +			if (!(sym->flags & SYMBOL_WRITE)) +				goto next_menu; +			sym->flags &= ~SYMBOL_WRITE; +			/* If we cannot change the symbol - skip */ +			if (!sym_is_changable(sym)) +				goto next_menu; +			/* If symbol equals to default value - skip */ +			if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) +				goto next_menu; + +			/* +			 * If symbol is a choice value and equals to the +			 * default for a choice - skip. +			 * But only if value is bool and equal to "y" and +			 * choice is not "optional". +			 * (If choice is "optional" then all values can be "n") +			 */ +			if (sym_is_choice_value(sym)) { +				struct symbol *cs; +				struct symbol *ds; + +				cs = prop_get_symbol(sym_get_choice_prop(sym)); +				ds = sym_choice_default(cs); +				if (!sym_is_optional(cs) && sym == ds) { +					if ((sym->type == S_BOOLEAN) && +					    sym_get_tristate_value(sym) == yes) +						goto next_menu; +				} +			} +			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); +		} +next_menu: +		if (menu->list != NULL) { +			menu = menu->list; +		} +		else if (menu->next != NULL) { +			menu = menu->next; +		} else { +			while ((menu = menu->parent)) { +				if (menu->next != NULL) { +					menu = menu->next; +					break; +				} +			} +		} +	} +	fclose(out); +	return 0; +} + +int conf_write(const char *name) +{ +	FILE *out; +	struct symbol *sym; +	struct menu *menu; +	const char *basename; +	const char *str; +	char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; +	char *env; + +	dirname[0] = 0; +	if (name && name[0]) { +		struct stat st; +		char *slash; + +		if (!stat(name, &st) && S_ISDIR(st.st_mode)) { +			strcpy(dirname, name); +			strcat(dirname, "/"); +			basename = conf_get_configname(); +		} else if ((slash = strrchr(name, '/'))) { +			int size = slash - name + 1; +			memcpy(dirname, name, size); +			dirname[size] = 0; +			if (slash[1]) +				basename = slash + 1; +			else +				basename = conf_get_configname(); +		} else +			basename = name; +	} else +		basename = conf_get_configname(); + +	sprintf(newname, "%s%s", dirname, basename); +	env = getenv("KCONFIG_OVERWRITECONFIG"); +	if (!env || !*env) { +		sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); +		out = fopen(tmpname, "w"); +	} else { +		*tmpname = 0; +		out = fopen(newname, "w"); +	} +	if (!out) +		return 1; + +	conf_write_heading(out, &kconfig_printer_cb, NULL); + +	if (!conf_get_changed()) +		sym_clear_all_valid(); + +	menu = rootmenu.list; +	while (menu) { +		sym = menu->sym; +		if (!sym) { +			if (!menu_is_visible(menu)) +				goto next; +			str = menu_get_prompt(menu); +			fprintf(out, "\n" +				     "#\n" +				     "# %s\n" +				     "#\n", str); +		} else if (!(sym->flags & SYMBOL_CHOICE)) { +			sym_calc_value(sym); +			if (!(sym->flags & SYMBOL_WRITE)) +				goto next; +			sym->flags &= ~SYMBOL_WRITE; + +			conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); +		} + +next: +		if (menu->list) { +			menu = menu->list; +			continue; +		} +		if (menu->next) +			menu = menu->next; +		else while ((menu = menu->parent)) { +			if (menu->next) { +				menu = menu->next; +				break; +			} +		} +	} +	fclose(out); + +	if (*tmpname) { +		strcat(dirname, basename); +		strcat(dirname, ".old"); +		rename(newname, dirname); +		if (rename(tmpname, newname)) +			return 1; +	} + +	conf_message(_("configuration written to %s"), newname); + +	sym_set_change_count(0); + +	return 0; +} + +static int conf_split_config(void) +{ +	const char *name; +	char path[PATH_MAX+1]; +	char *s, *d, c; +	struct symbol *sym; +	struct stat sb; +	int res, i, fd; + +	name = conf_get_autoconfig_name(); +	conf_read_simple(name, S_DEF_AUTO); + +	if (chdir("include/config")) +		return 1; + +	res = 0; +	for_all_symbols(i, sym) { +		sym_calc_value(sym); +		if ((sym->flags & SYMBOL_AUTO) || !sym->name) +			continue; +		if (sym->flags & SYMBOL_WRITE) { +			if (sym->flags & SYMBOL_DEF_AUTO) { +				/* +				 * symbol has old and new value, +				 * so compare them... +				 */ +				switch (sym->type) { +				case S_BOOLEAN: +				case S_TRISTATE: +					if (sym_get_tristate_value(sym) == +					    sym->def[S_DEF_AUTO].tri) +						continue; +					break; +				case S_STRING: +				case S_HEX: +				case S_INT: +					if (!strcmp(sym_get_string_value(sym), +						    sym->def[S_DEF_AUTO].val)) +						continue; +					break; +				default: +					break; +				} +			} else { +				/* +				 * If there is no old value, only 'no' (unset) +				 * is allowed as new value. +				 */ +				switch (sym->type) { +				case S_BOOLEAN: +				case S_TRISTATE: +					if (sym_get_tristate_value(sym) == no) +						continue; +					break; +				default: +					break; +				} +			} +		} else if (!(sym->flags & SYMBOL_DEF_AUTO)) +			/* There is neither an old nor a new value. */ +			continue; +		/* else +		 *	There is an old value, but no new value ('no' (unset) +		 *	isn't saved in auto.conf, so the old value is always +		 *	different from 'no'). +		 */ + +		/* Replace all '_' and append ".h" */ +		s = sym->name; +		d = path; +		while ((c = *s++)) { +			c = tolower(c); +			*d++ = (c == '_') ? '/' : c; +		} +		strcpy(d, ".h"); + +		/* Assume directory path already exists. */ +		fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); +		if (fd == -1) { +			if (errno != ENOENT) { +				res = 1; +				break; +			} +			/* +			 * Create directory components, +			 * unless they exist already. +			 */ +			d = path; +			while ((d = strchr(d, '/'))) { +				*d = 0; +				if (stat(path, &sb) && mkdir(path, 0755)) { +					res = 1; +					goto out; +				} +				*d++ = '/'; +			} +			/* Try it again. */ +			fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); +			if (fd == -1) { +				res = 1; +				break; +			} +		} +		close(fd); +	} +out: +	if (chdir("../..")) +		return 1; + +	return res; +} + +int conf_write_autoconf(void) +{ +	struct symbol *sym; +	const char *name; +	FILE *out, *tristate, *out_h; +	int i; + +	sym_clear_all_valid(); + +	file_write_dep("include/config/auto.conf.cmd"); + +	if (conf_split_config()) +		return 1; + +	out = fopen(".tmpconfig", "w"); +	if (!out) +		return 1; + +	tristate = fopen(".tmpconfig_tristate", "w"); +	if (!tristate) { +		fclose(out); +		return 1; +	} + +	out_h = fopen(".tmpconfig.h", "w"); +	if (!out_h) { +		fclose(out); +		fclose(tristate); +		return 1; +	} + +	conf_write_heading(out, &kconfig_printer_cb, NULL); + +	conf_write_heading(tristate, &tristate_printer_cb, NULL); + +	conf_write_heading(out_h, &header_printer_cb, NULL); + +	for_all_symbols(i, sym) { +		sym_calc_value(sym); +		if (!(sym->flags & SYMBOL_WRITE) || !sym->name) +			continue; + +		/* write symbol to auto.conf, tristate and header files */ +		conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); + +		conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); + +		conf_write_symbol(out_h, sym, &header_printer_cb, NULL); +	} +	fclose(out); +	fclose(tristate); +	fclose(out_h); + +	name = getenv("KCONFIG_AUTOHEADER"); +	if (!name) +		name = "include/generated/autoconf.h"; +	if (rename(".tmpconfig.h", name)) +		return 1; +	name = getenv("KCONFIG_TRISTATE"); +	if (!name) +		name = "include/config/tristate.conf"; +	if (rename(".tmpconfig_tristate", name)) +		return 1; +	name = conf_get_autoconfig_name(); +	/* +	 * This must be the last step, kbuild has a dependency on auto.conf +	 * and this marks the successful completion of the previous steps. +	 */ +	if (rename(".tmpconfig", name)) +		return 1; + +	return 0; +} + +static int sym_change_count; +static void (*conf_changed_callback)(void); + +void sym_set_change_count(int count) +{ +	int _sym_change_count = sym_change_count; +	sym_change_count = count; +	if (conf_changed_callback && +	    (bool)_sym_change_count != (bool)count) +		conf_changed_callback(); +} + +void sym_add_change_count(int count) +{ +	sym_set_change_count(count + sym_change_count); +} + +bool conf_get_changed(void) +{ +	return sym_change_count; +} + +void conf_set_changed_callback(void (*fn)(void)) +{ +	conf_changed_callback = fn; +} + +static bool randomize_choice_values(struct symbol *csym) +{ +	struct property *prop; +	struct symbol *sym; +	struct expr *e; +	int cnt, def; + +	/* +	 * If choice is mod then we may have more items selected +	 * and if no then no-one. +	 * In both cases stop. +	 */ +	if (csym->curr.tri != yes) +		return false; + +	prop = sym_get_choice_prop(csym); + +	/* count entries in choice block */ +	cnt = 0; +	expr_list_for_each_sym(prop->expr, e, sym) +		cnt++; + +	/* +	 * find a random value and set it to yes, +	 * set the rest to no so we have only one set +	 */ +	def = (rand() % cnt); + +	cnt = 0; +	expr_list_for_each_sym(prop->expr, e, sym) { +		if (def == cnt++) { +			sym->def[S_DEF_USER].tri = yes; +			csym->def[S_DEF_USER].val = sym; +		} +		else { +			sym->def[S_DEF_USER].tri = no; +		} +		sym->flags |= SYMBOL_DEF_USER; +		/* clear VALID to get value calculated */ +		sym->flags &= ~SYMBOL_VALID; +	} +	csym->flags |= SYMBOL_DEF_USER; +	/* clear VALID to get value calculated */ +	csym->flags &= ~(SYMBOL_VALID); + +	return true; +} + +void set_all_choice_values(struct symbol *csym) +{ +	struct property *prop; +	struct symbol *sym; +	struct expr *e; + +	prop = sym_get_choice_prop(csym); + +	/* +	 * Set all non-assinged choice values to no +	 */ +	expr_list_for_each_sym(prop->expr, e, sym) { +		if (!sym_has_value(sym)) +			sym->def[S_DEF_USER].tri = no; +	} +	csym->flags |= SYMBOL_DEF_USER; +	/* clear VALID to get value calculated */ +	csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); +} + +bool conf_set_all_new_symbols(enum conf_def_mode mode) +{ +	struct symbol *sym, *csym; +	int i, cnt, pby, pty, ptm;	/* pby: probability of boolean  = y +					 * pty: probability of tristate = y +					 * ptm: probability of tristate = m +					 */ + +	pby = 50; pty = ptm = 33; /* can't go as the default in switch-case +				   * below, otherwise gcc whines about +				   * -Wmaybe-uninitialized */ +	if (mode == def_random) { +		int n, p[3]; +		char *env = getenv("KCONFIG_PROBABILITY"); +		n = 0; +		while( env && *env ) { +			char *endp; +			int tmp = strtol( env, &endp, 10 ); +			if( tmp >= 0 && tmp <= 100 ) { +				p[n++] = tmp; +			} else { +				errno = ERANGE; +				perror( "KCONFIG_PROBABILITY" ); +				exit( 1 ); +			} +			env = (*endp == ':') ? endp+1 : endp; +			if( n >=3 ) { +				break; +			} +		} +		switch( n ) { +		case 1: +			pby = p[0]; ptm = pby/2; pty = pby-ptm; +			break; +		case 2: +			pty = p[0]; ptm = p[1]; pby = pty + ptm; +			break; +		case 3: +			pby = p[0]; pty = p[1]; ptm = p[2]; +			break; +		} + +		if( pty+ptm > 100 ) { +			errno = ERANGE; +			perror( "KCONFIG_PROBABILITY" ); +			exit( 1 ); +		} +	} +	bool has_changed = false; + +	for_all_symbols(i, sym) { +		if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) +			continue; +		switch (sym_get_type(sym)) { +		case S_BOOLEAN: +		case S_TRISTATE: +			has_changed = true; +			switch (mode) { +			case def_yes: +				sym->def[S_DEF_USER].tri = yes; +				break; +			case def_mod: +				sym->def[S_DEF_USER].tri = mod; +				break; +			case def_no: +				if (sym->flags & SYMBOL_ALLNOCONFIG_Y) +					sym->def[S_DEF_USER].tri = yes; +				else +					sym->def[S_DEF_USER].tri = no; +				break; +			case def_random: +				sym->def[S_DEF_USER].tri = no; +				cnt = rand() % 100; +				if (sym->type == S_TRISTATE) { +					if (cnt < pty) +						sym->def[S_DEF_USER].tri = yes; +					else if (cnt < (pty+ptm)) +						sym->def[S_DEF_USER].tri = mod; +				} else if (cnt < pby) +					sym->def[S_DEF_USER].tri = yes; +				break; +			default: +				continue; +			} +			if (!(sym_is_choice(sym) && mode == def_random)) +				sym->flags |= SYMBOL_DEF_USER; +			break; +		default: +			break; +		} + +	} + +	sym_clear_all_valid(); + +	/* +	 * We have different type of choice blocks. +	 * If curr.tri equals to mod then we can select several +	 * choice symbols in one block. +	 * In this case we do nothing. +	 * If curr.tri equals yes then only one symbol can be +	 * selected in a choice block and we set it to yes, +	 * and the rest to no. +	 */ +	if (mode != def_random) { +		for_all_symbols(i, csym) { +			if ((sym_is_choice(csym) && !sym_has_value(csym)) || +			    sym_is_choice_value(csym)) +				csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; +		} +	} + +	for_all_symbols(i, csym) { +		if (sym_has_value(csym) || !sym_is_choice(csym)) +			continue; + +		sym_calc_value(csym); +		if (mode == def_random) +			has_changed = randomize_choice_values(csym); +		else { +			set_all_choice_values(csym); +			has_changed = true; +		} +	} + +	return has_changed; +} diff --git a/programs/src/kconfig/kconfig/expr.c b/programs/src/kconfig/kconfig/expr.c new file mode 100644 index 0000000..d662652 --- /dev/null +++ b/programs/src/kconfig/kconfig/expr.c @@ -0,0 +1,1168 @@ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "lkc.h" + +#define DEBUG_EXPR	0 + +struct expr *expr_alloc_symbol(struct symbol *sym) +{ +	struct expr *e = xcalloc(1, sizeof(*e)); +	e->type = E_SYMBOL; +	e->left.sym = sym; +	return e; +} + +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) +{ +	struct expr *e = xcalloc(1, sizeof(*e)); +	e->type = type; +	e->left.expr = ce; +	return e; +} + +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) +{ +	struct expr *e = xcalloc(1, sizeof(*e)); +	e->type = type; +	e->left.expr = e1; +	e->right.expr = e2; +	return e; +} + +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) +{ +	struct expr *e = xcalloc(1, sizeof(*e)); +	e->type = type; +	e->left.sym = s1; +	e->right.sym = s2; +	return e; +} + +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) +{ +	if (!e1) +		return e2; +	return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; +} + +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) +{ +	if (!e1) +		return e2; +	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; +} + +struct expr *expr_copy(const struct expr *org) +{ +	struct expr *e; + +	if (!org) +		return NULL; + +	e = xmalloc(sizeof(*org)); +	memcpy(e, org, sizeof(*org)); +	switch (org->type) { +	case E_SYMBOL: +		e->left = org->left; +		break; +	case E_NOT: +		e->left.expr = expr_copy(org->left.expr); +		break; +	case E_EQUAL: +	case E_UNEQUAL: +		e->left.sym = org->left.sym; +		e->right.sym = org->right.sym; +		break; +	case E_AND: +	case E_OR: +	case E_LIST: +		e->left.expr = expr_copy(org->left.expr); +		e->right.expr = expr_copy(org->right.expr); +		break; +	default: +		printf("can't copy type %d\n", e->type); +		free(e); +		e = NULL; +		break; +	} + +	return e; +} + +void expr_free(struct expr *e) +{ +	if (!e) +		return; + +	switch (e->type) { +	case E_SYMBOL: +		break; +	case E_NOT: +		expr_free(e->left.expr); +		return; +	case E_EQUAL: +	case E_UNEQUAL: +		break; +	case E_OR: +	case E_AND: +		expr_free(e->left.expr); +		expr_free(e->right.expr); +		break; +	default: +		printf("how to free type %d?\n", e->type); +		break; +	} +	free(e); +} + +static int trans_count; + +#define e1 (*ep1) +#define e2 (*ep2) + +static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +	if (e1->type == type) { +		__expr_eliminate_eq(type, &e1->left.expr, &e2); +		__expr_eliminate_eq(type, &e1->right.expr, &e2); +		return; +	} +	if (e2->type == type) { +		__expr_eliminate_eq(type, &e1, &e2->left.expr); +		__expr_eliminate_eq(type, &e1, &e2->right.expr); +		return; +	} +	if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && +	    e1->left.sym == e2->left.sym && +	    (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) +		return; +	if (!expr_eq(e1, e2)) +		return; +	trans_count++; +	expr_free(e1); expr_free(e2); +	switch (type) { +	case E_OR: +		e1 = expr_alloc_symbol(&symbol_no); +		e2 = expr_alloc_symbol(&symbol_no); +		break; +	case E_AND: +		e1 = expr_alloc_symbol(&symbol_yes); +		e2 = expr_alloc_symbol(&symbol_yes); +		break; +	default: +		; +	} +} + +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) +{ +	if (!e1 || !e2) +		return; +	switch (e1->type) { +	case E_OR: +	case E_AND: +		__expr_eliminate_eq(e1->type, ep1, ep2); +	default: +		; +	} +	if (e1->type != e2->type) switch (e2->type) { +	case E_OR: +	case E_AND: +		__expr_eliminate_eq(e2->type, ep1, ep2); +	default: +		; +	} +	e1 = expr_eliminate_yn(e1); +	e2 = expr_eliminate_yn(e2); +} + +#undef e1 +#undef e2 + +int expr_eq(struct expr *e1, struct expr *e2) +{ +	int res, old_count; + +	if (e1->type != e2->type) +		return 0; +	switch (e1->type) { +	case E_EQUAL: +	case E_UNEQUAL: +		return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; +	case E_SYMBOL: +		return e1->left.sym == e2->left.sym; +	case E_NOT: +		return expr_eq(e1->left.expr, e2->left.expr); +	case E_AND: +	case E_OR: +		e1 = expr_copy(e1); +		e2 = expr_copy(e2); +		old_count = trans_count; +		expr_eliminate_eq(&e1, &e2); +		res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && +		       e1->left.sym == e2->left.sym); +		expr_free(e1); +		expr_free(e2); +		trans_count = old_count; +		return res; +	case E_LIST: +	case E_RANGE: +	case E_NONE: +		/* panic */; +	} + +	if (DEBUG_EXPR) { +		expr_fprint(e1, stdout); +		printf(" = "); +		expr_fprint(e2, stdout); +		printf(" ?\n"); +	} + +	return 0; +} + +struct expr *expr_eliminate_yn(struct expr *e) +{ +	struct expr *tmp; + +	if (e) switch (e->type) { +	case E_AND: +		e->left.expr = expr_eliminate_yn(e->left.expr); +		e->right.expr = expr_eliminate_yn(e->right.expr); +		if (e->left.expr->type == E_SYMBOL) { +			if (e->left.expr->left.sym == &symbol_no) { +				expr_free(e->left.expr); +				expr_free(e->right.expr); +				e->type = E_SYMBOL; +				e->left.sym = &symbol_no; +				e->right.expr = NULL; +				return e; +			} else if (e->left.expr->left.sym == &symbol_yes) { +				free(e->left.expr); +				tmp = e->right.expr; +				*e = *(e->right.expr); +				free(tmp); +				return e; +			} +		} +		if (e->right.expr->type == E_SYMBOL) { +			if (e->right.expr->left.sym == &symbol_no) { +				expr_free(e->left.expr); +				expr_free(e->right.expr); +				e->type = E_SYMBOL; +				e->left.sym = &symbol_no; +				e->right.expr = NULL; +				return e; +			} else if (e->right.expr->left.sym == &symbol_yes) { +				free(e->right.expr); +				tmp = e->left.expr; +				*e = *(e->left.expr); +				free(tmp); +				return e; +			} +		} +		break; +	case E_OR: +		e->left.expr = expr_eliminate_yn(e->left.expr); +		e->right.expr = expr_eliminate_yn(e->right.expr); +		if (e->left.expr->type == E_SYMBOL) { +			if (e->left.expr->left.sym == &symbol_no) { +				free(e->left.expr); +				tmp = e->right.expr; +				*e = *(e->right.expr); +				free(tmp); +				return e; +			} else if (e->left.expr->left.sym == &symbol_yes) { +				expr_free(e->left.expr); +				expr_free(e->right.expr); +				e->type = E_SYMBOL; +				e->left.sym = &symbol_yes; +				e->right.expr = NULL; +				return e; +			} +		} +		if (e->right.expr->type == E_SYMBOL) { +			if (e->right.expr->left.sym == &symbol_no) { +				free(e->right.expr); +				tmp = e->left.expr; +				*e = *(e->left.expr); +				free(tmp); +				return e; +			} else if (e->right.expr->left.sym == &symbol_yes) { +				expr_free(e->left.expr); +				expr_free(e->right.expr); +				e->type = E_SYMBOL; +				e->left.sym = &symbol_yes; +				e->right.expr = NULL; +				return e; +			} +		} +		break; +	default: +		; +	} +	return e; +} + +/* + * bool FOO!=n => FOO + */ +struct expr *expr_trans_bool(struct expr *e) +{ +	if (!e) +		return NULL; +	switch (e->type) { +	case E_AND: +	case E_OR: +	case E_NOT: +		e->left.expr = expr_trans_bool(e->left.expr); +		e->right.expr = expr_trans_bool(e->right.expr); +		break; +	case E_UNEQUAL: +		// FOO!=n -> FOO +		if (e->left.sym->type == S_TRISTATE) { +			if (e->right.sym == &symbol_no) { +				e->type = E_SYMBOL; +				e->right.sym = NULL; +			} +		} +		break; +	default: +		; +	} +	return e; +} + +/* + * e1 || e2 -> ? + */ +static struct expr *expr_join_or(struct expr *e1, struct expr *e2) +{ +	struct expr *tmp; +	struct symbol *sym1, *sym2; + +	if (expr_eq(e1, e2)) +		return expr_copy(e1); +	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) +		return NULL; +	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) +		return NULL; +	if (e1->type == E_NOT) { +		tmp = e1->left.expr; +		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) +			return NULL; +		sym1 = tmp->left.sym; +	} else +		sym1 = e1->left.sym; +	if (e2->type == E_NOT) { +		if (e2->left.expr->type != E_SYMBOL) +			return NULL; +		sym2 = e2->left.expr->left.sym; +	} else +		sym2 = e2->left.sym; +	if (sym1 != sym2) +		return NULL; +	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) +		return NULL; +	if (sym1->type == S_TRISTATE) { +		if (e1->type == E_EQUAL && e2->type == E_EQUAL && +		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || +		     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { +			// (a='y') || (a='m') -> (a!='n') +			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); +		} +		if (e1->type == E_EQUAL && e2->type == E_EQUAL && +		    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || +		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { +			// (a='y') || (a='n') -> (a!='m') +			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); +		} +		if (e1->type == E_EQUAL && e2->type == E_EQUAL && +		    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || +		     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { +			// (a='m') || (a='n') -> (a!='y') +			return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); +		} +	} +	if (sym1->type == S_BOOLEAN && sym1 == sym2) { +		if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || +		    (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) +			return expr_alloc_symbol(&symbol_yes); +	} + +	if (DEBUG_EXPR) { +		printf("optimize ("); +		expr_fprint(e1, stdout); +		printf(") || ("); +		expr_fprint(e2, stdout); +		printf(")?\n"); +	} +	return NULL; +} + +static struct expr *expr_join_and(struct expr *e1, struct expr *e2) +{ +	struct expr *tmp; +	struct symbol *sym1, *sym2; + +	if (expr_eq(e1, e2)) +		return expr_copy(e1); +	if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) +		return NULL; +	if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) +		return NULL; +	if (e1->type == E_NOT) { +		tmp = e1->left.expr; +		if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) +			return NULL; +		sym1 = tmp->left.sym; +	} else +		sym1 = e1->left.sym; +	if (e2->type == E_NOT) { +		if (e2->left.expr->type != E_SYMBOL) +			return NULL; +		sym2 = e2->left.expr->left.sym; +	} else +		sym2 = e2->left.sym; +	if (sym1 != sym2) +		return NULL; +	if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) +		return NULL; + +	if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || +	    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) +		// (a) && (a='y') -> (a='y') +		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + +	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || +	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) +		// (a) && (a!='n') -> (a) +		return expr_alloc_symbol(sym1); + +	if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || +	    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) +		// (a) && (a!='m') -> (a='y') +		return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + +	if (sym1->type == S_TRISTATE) { +		if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { +			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' +			sym2 = e1->right.sym; +			if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) +				return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) +							     : expr_alloc_symbol(&symbol_no); +		} +		if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { +			// (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' +			sym2 = e2->right.sym; +			if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) +				return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) +							     : expr_alloc_symbol(&symbol_no); +		} +		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && +			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || +			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) +			// (a!='y') && (a!='n') -> (a='m') +			return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); + +		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && +			   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || +			    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) +			// (a!='y') && (a!='m') -> (a='n') +			return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); + +		if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && +			   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || +			    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) +			// (a!='m') && (a!='n') -> (a='m') +			return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); + +		if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || +		    (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || +		    (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || +		    (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) +			return NULL; +	} + +	if (DEBUG_EXPR) { +		printf("optimize ("); +		expr_fprint(e1, stdout); +		printf(") && ("); +		expr_fprint(e2, stdout); +		printf(")?\n"); +	} +	return NULL; +} + +static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) +	struct expr *tmp; + +	if (e1->type == type) { +		expr_eliminate_dups1(type, &e1->left.expr, &e2); +		expr_eliminate_dups1(type, &e1->right.expr, &e2); +		return; +	} +	if (e2->type == type) { +		expr_eliminate_dups1(type, &e1, &e2->left.expr); +		expr_eliminate_dups1(type, &e1, &e2->right.expr); +		return; +	} +	if (e1 == e2) +		return; + +	switch (e1->type) { +	case E_OR: case E_AND: +		expr_eliminate_dups1(e1->type, &e1, &e1); +	default: +		; +	} + +	switch (type) { +	case E_OR: +		tmp = expr_join_or(e1, e2); +		if (tmp) { +			expr_free(e1); expr_free(e2); +			e1 = expr_alloc_symbol(&symbol_no); +			e2 = tmp; +			trans_count++; +		} +		break; +	case E_AND: +		tmp = expr_join_and(e1, e2); +		if (tmp) { +			expr_free(e1); expr_free(e2); +			e1 = expr_alloc_symbol(&symbol_yes); +			e2 = tmp; +			trans_count++; +		} +		break; +	default: +		; +	} +#undef e1 +#undef e2 +} + +static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) +	struct expr *tmp, *tmp1, *tmp2; + +	if (e1->type == type) { +		expr_eliminate_dups2(type, &e1->left.expr, &e2); +		expr_eliminate_dups2(type, &e1->right.expr, &e2); +		return; +	} +	if (e2->type == type) { +		expr_eliminate_dups2(type, &e1, &e2->left.expr); +		expr_eliminate_dups2(type, &e1, &e2->right.expr); +	} +	if (e1 == e2) +		return; + +	switch (e1->type) { +	case E_OR: +		expr_eliminate_dups2(e1->type, &e1, &e1); +		// (FOO || BAR) && (!FOO && !BAR) -> n +		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); +		tmp2 = expr_copy(e2); +		tmp = expr_extract_eq_and(&tmp1, &tmp2); +		if (expr_is_yes(tmp1)) { +			expr_free(e1); +			e1 = expr_alloc_symbol(&symbol_no); +			trans_count++; +		} +		expr_free(tmp2); +		expr_free(tmp1); +		expr_free(tmp); +		break; +	case E_AND: +		expr_eliminate_dups2(e1->type, &e1, &e1); +		// (FOO && BAR) || (!FOO || !BAR) -> y +		tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1))); +		tmp2 = expr_copy(e2); +		tmp = expr_extract_eq_or(&tmp1, &tmp2); +		if (expr_is_no(tmp1)) { +			expr_free(e1); +			e1 = expr_alloc_symbol(&symbol_yes); +			trans_count++; +		} +		expr_free(tmp2); +		expr_free(tmp1); +		expr_free(tmp); +		break; +	default: +		; +	} +#undef e1 +#undef e2 +} + +struct expr *expr_eliminate_dups(struct expr *e) +{ +	int oldcount; +	if (!e) +		return e; + +	oldcount = trans_count; +	while (1) { +		trans_count = 0; +		switch (e->type) { +		case E_OR: case E_AND: +			expr_eliminate_dups1(e->type, &e, &e); +			expr_eliminate_dups2(e->type, &e, &e); +		default: +			; +		} +		if (!trans_count) +			break; +		e = expr_eliminate_yn(e); +	} +	trans_count = oldcount; +	return e; +} + +struct expr *expr_transform(struct expr *e) +{ +	struct expr *tmp; + +	if (!e) +		return NULL; +	switch (e->type) { +	case E_EQUAL: +	case E_UNEQUAL: +	case E_SYMBOL: +	case E_LIST: +		break; +	default: +		e->left.expr = expr_transform(e->left.expr); +		e->right.expr = expr_transform(e->right.expr); +	} + +	switch (e->type) { +	case E_EQUAL: +		if (e->left.sym->type != S_BOOLEAN) +			break; +		if (e->right.sym == &symbol_no) { +			e->type = E_NOT; +			e->left.expr = expr_alloc_symbol(e->left.sym); +			e->right.sym = NULL; +			break; +		} +		if (e->right.sym == &symbol_mod) { +			printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); +			e->type = E_SYMBOL; +			e->left.sym = &symbol_no; +			e->right.sym = NULL; +			break; +		} +		if (e->right.sym == &symbol_yes) { +			e->type = E_SYMBOL; +			e->right.sym = NULL; +			break; +		} +		break; +	case E_UNEQUAL: +		if (e->left.sym->type != S_BOOLEAN) +			break; +		if (e->right.sym == &symbol_no) { +			e->type = E_SYMBOL; +			e->right.sym = NULL; +			break; +		} +		if (e->right.sym == &symbol_mod) { +			printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); +			e->type = E_SYMBOL; +			e->left.sym = &symbol_yes; +			e->right.sym = NULL; +			break; +		} +		if (e->right.sym == &symbol_yes) { +			e->type = E_NOT; +			e->left.expr = expr_alloc_symbol(e->left.sym); +			e->right.sym = NULL; +			break; +		} +		break; +	case E_NOT: +		switch (e->left.expr->type) { +		case E_NOT: +			// !!a -> a +			tmp = e->left.expr->left.expr; +			free(e->left.expr); +			free(e); +			e = tmp; +			e = expr_transform(e); +			break; +		case E_EQUAL: +		case E_UNEQUAL: +			// !a='x' -> a!='x' +			tmp = e->left.expr; +			free(e); +			e = tmp; +			e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; +			break; +		case E_OR: +			// !(a || b) -> !a && !b +			tmp = e->left.expr; +			e->type = E_AND; +			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); +			tmp->type = E_NOT; +			tmp->right.expr = NULL; +			e = expr_transform(e); +			break; +		case E_AND: +			// !(a && b) -> !a || !b +			tmp = e->left.expr; +			e->type = E_OR; +			e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); +			tmp->type = E_NOT; +			tmp->right.expr = NULL; +			e = expr_transform(e); +			break; +		case E_SYMBOL: +			if (e->left.expr->left.sym == &symbol_yes) { +				// !'y' -> 'n' +				tmp = e->left.expr; +				free(e); +				e = tmp; +				e->type = E_SYMBOL; +				e->left.sym = &symbol_no; +				break; +			} +			if (e->left.expr->left.sym == &symbol_mod) { +				// !'m' -> 'm' +				tmp = e->left.expr; +				free(e); +				e = tmp; +				e->type = E_SYMBOL; +				e->left.sym = &symbol_mod; +				break; +			} +			if (e->left.expr->left.sym == &symbol_no) { +				// !'n' -> 'y' +				tmp = e->left.expr; +				free(e); +				e = tmp; +				e->type = E_SYMBOL; +				e->left.sym = &symbol_yes; +				break; +			} +			break; +		default: +			; +		} +		break; +	default: +		; +	} +	return e; +} + +int expr_contains_symbol(struct expr *dep, struct symbol *sym) +{ +	if (!dep) +		return 0; + +	switch (dep->type) { +	case E_AND: +	case E_OR: +		return expr_contains_symbol(dep->left.expr, sym) || +		       expr_contains_symbol(dep->right.expr, sym); +	case E_SYMBOL: +		return dep->left.sym == sym; +	case E_EQUAL: +	case E_UNEQUAL: +		return dep->left.sym == sym || +		       dep->right.sym == sym; +	case E_NOT: +		return expr_contains_symbol(dep->left.expr, sym); +	default: +		; +	} +	return 0; +} + +bool expr_depends_symbol(struct expr *dep, struct symbol *sym) +{ +	if (!dep) +		return false; + +	switch (dep->type) { +	case E_AND: +		return expr_depends_symbol(dep->left.expr, sym) || +		       expr_depends_symbol(dep->right.expr, sym); +	case E_SYMBOL: +		return dep->left.sym == sym; +	case E_EQUAL: +		if (dep->left.sym == sym) { +			if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) +				return true; +		} +		break; +	case E_UNEQUAL: +		if (dep->left.sym == sym) { +			if (dep->right.sym == &symbol_no) +				return true; +		} +		break; +	default: +		; +	} + 	return false; +} + +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2) +{ +	struct expr *tmp = NULL; +	expr_extract_eq(E_AND, &tmp, ep1, ep2); +	if (tmp) { +		*ep1 = expr_eliminate_yn(*ep1); +		*ep2 = expr_eliminate_yn(*ep2); +	} +	return tmp; +} + +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2) +{ +	struct expr *tmp = NULL; +	expr_extract_eq(E_OR, &tmp, ep1, ep2); +	if (tmp) { +		*ep1 = expr_eliminate_yn(*ep1); +		*ep2 = expr_eliminate_yn(*ep2); +	} +	return tmp; +} + +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2) +{ +#define e1 (*ep1) +#define e2 (*ep2) +	if (e1->type == type) { +		expr_extract_eq(type, ep, &e1->left.expr, &e2); +		expr_extract_eq(type, ep, &e1->right.expr, &e2); +		return; +	} +	if (e2->type == type) { +		expr_extract_eq(type, ep, ep1, &e2->left.expr); +		expr_extract_eq(type, ep, ep1, &e2->right.expr); +		return; +	} +	if (expr_eq(e1, e2)) { +		*ep = *ep ? expr_alloc_two(type, *ep, e1) : e1; +		expr_free(e2); +		if (type == E_AND) { +			e1 = expr_alloc_symbol(&symbol_yes); +			e2 = expr_alloc_symbol(&symbol_yes); +		} else if (type == E_OR) { +			e1 = expr_alloc_symbol(&symbol_no); +			e2 = expr_alloc_symbol(&symbol_no); +		} +	} +#undef e1 +#undef e2 +} + +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) +{ +	struct expr *e1, *e2; + +	if (!e) { +		e = expr_alloc_symbol(sym); +		if (type == E_UNEQUAL) +			e = expr_alloc_one(E_NOT, e); +		return e; +	} +	switch (e->type) { +	case E_AND: +		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); +		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); +		if (sym == &symbol_yes) +			e = expr_alloc_two(E_AND, e1, e2); +		if (sym == &symbol_no) +			e = expr_alloc_two(E_OR, e1, e2); +		if (type == E_UNEQUAL) +			e = expr_alloc_one(E_NOT, e); +		return e; +	case E_OR: +		e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); +		e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); +		if (sym == &symbol_yes) +			e = expr_alloc_two(E_OR, e1, e2); +		if (sym == &symbol_no) +			e = expr_alloc_two(E_AND, e1, e2); +		if (type == E_UNEQUAL) +			e = expr_alloc_one(E_NOT, e); +		return e; +	case E_NOT: +		return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); +	case E_UNEQUAL: +	case E_EQUAL: +		if (type == E_EQUAL) { +			if (sym == &symbol_yes) +				return expr_copy(e); +			if (sym == &symbol_mod) +				return expr_alloc_symbol(&symbol_no); +			if (sym == &symbol_no) +				return expr_alloc_one(E_NOT, expr_copy(e)); +		} else { +			if (sym == &symbol_yes) +				return expr_alloc_one(E_NOT, expr_copy(e)); +			if (sym == &symbol_mod) +				return expr_alloc_symbol(&symbol_yes); +			if (sym == &symbol_no) +				return expr_copy(e); +		} +		break; +	case E_SYMBOL: +		return expr_alloc_comp(type, e->left.sym, sym); +	case E_LIST: +	case E_RANGE: +	case E_NONE: +		/* panic */; +	} +	return NULL; +} + +tristate expr_calc_value(struct expr *e) +{ +	tristate val1, val2; +	const char *str1, *str2; + +	if (!e) +		return yes; + +	switch (e->type) { +	case E_SYMBOL: +		sym_calc_value(e->left.sym); +		return e->left.sym->curr.tri; +	case E_AND: +		val1 = expr_calc_value(e->left.expr); +		val2 = expr_calc_value(e->right.expr); +		return EXPR_AND(val1, val2); +	case E_OR: +		val1 = expr_calc_value(e->left.expr); +		val2 = expr_calc_value(e->right.expr); +		return EXPR_OR(val1, val2); +	case E_NOT: +		val1 = expr_calc_value(e->left.expr); +		return EXPR_NOT(val1); +	case E_EQUAL: +		sym_calc_value(e->left.sym); +		sym_calc_value(e->right.sym); +		str1 = sym_get_string_value(e->left.sym); +		str2 = sym_get_string_value(e->right.sym); +		return !strcmp(str1, str2) ? yes : no; +	case E_UNEQUAL: +		sym_calc_value(e->left.sym); +		sym_calc_value(e->right.sym); +		str1 = sym_get_string_value(e->left.sym); +		str2 = sym_get_string_value(e->right.sym); +		return !strcmp(str1, str2) ? no : yes; +	default: +		printf("expr_calc_value: %d?\n", e->type); +		return no; +	} +} + +int expr_compare_type(enum expr_type t1, enum expr_type t2) +{ +#if 0 +	return 1; +#else +	if (t1 == t2) +		return 0; +	switch (t1) { +	case E_EQUAL: +	case E_UNEQUAL: +		if (t2 == E_NOT) +			return 1; +	case E_NOT: +		if (t2 == E_AND) +			return 1; +	case E_AND: +		if (t2 == E_OR) +			return 1; +	case E_OR: +		if (t2 == E_LIST) +			return 1; +	case E_LIST: +		if (t2 == 0) +			return 1; +	default: +		return -1; +	} +	printf("[%dgt%d?]", t1, t2); +	return 0; +#endif +} + +static inline struct expr * +expr_get_leftmost_symbol(const struct expr *e) +{ + +	if (e == NULL) +		return NULL; + +	while (e->type != E_SYMBOL) +		e = e->left.expr; + +	return expr_copy(e); +} + +/* + * Given expression `e1' and `e2', returns the leaf of the longest + * sub-expression of `e1' not containing 'e2. + */ +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) +{ +	struct expr *ret; + +	switch (e1->type) { +	case E_OR: +		return expr_alloc_and( +		    expr_simplify_unmet_dep(e1->left.expr, e2), +		    expr_simplify_unmet_dep(e1->right.expr, e2)); +	case E_AND: { +		struct expr *e; +		e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); +		e = expr_eliminate_dups(e); +		ret = (!expr_eq(e, e1)) ? e1 : NULL; +		expr_free(e); +		break; +		} +	default: +		ret = e1; +		break; +	} + +	return expr_get_leftmost_symbol(ret); +} + +void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) +{ +	if (!e) { +		fn(data, NULL, "y"); +		return; +	} + +	if (expr_compare_type(prevtoken, e->type) > 0) +		fn(data, NULL, "("); +	switch (e->type) { +	case E_SYMBOL: +		if (e->left.sym->name) +			fn(data, e->left.sym, e->left.sym->name); +		else +			fn(data, NULL, "<choice>"); +		break; +	case E_NOT: +		fn(data, NULL, "!"); +		expr_print(e->left.expr, fn, data, E_NOT); +		break; +	case E_EQUAL: +		if (e->left.sym->name) +			fn(data, e->left.sym, e->left.sym->name); +		else +			fn(data, NULL, "<choice>"); +		fn(data, NULL, "="); +		fn(data, e->right.sym, e->right.sym->name); +		break; +	case E_UNEQUAL: +		if (e->left.sym->name) +			fn(data, e->left.sym, e->left.sym->name); +		else +			fn(data, NULL, "<choice>"); +		fn(data, NULL, "!="); +		fn(data, e->right.sym, e->right.sym->name); +		break; +	case E_OR: +		expr_print(e->left.expr, fn, data, E_OR); +		fn(data, NULL, " || "); +		expr_print(e->right.expr, fn, data, E_OR); +		break; +	case E_AND: +		expr_print(e->left.expr, fn, data, E_AND); +		fn(data, NULL, " && "); +		expr_print(e->right.expr, fn, data, E_AND); +		break; +	case E_LIST: +		fn(data, e->right.sym, e->right.sym->name); +		if (e->left.expr) { +			fn(data, NULL, " ^ "); +			expr_print(e->left.expr, fn, data, E_LIST); +		} +		break; +	case E_RANGE: +		fn(data, NULL, "["); +		fn(data, e->left.sym, e->left.sym->name); +		fn(data, NULL, " "); +		fn(data, e->right.sym, e->right.sym->name); +		fn(data, NULL, "]"); +		break; +	default: +	  { +		char buf[32]; +		sprintf(buf, "<unknown type %d>", e->type); +		fn(data, NULL, buf); +		break; +	  } +	} +	if (expr_compare_type(prevtoken, e->type) > 0) +		fn(data, NULL, ")"); +} + +static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) +{ +	xfwrite(str, strlen(str), 1, data); +} + +void expr_fprint(struct expr *e, FILE *out) +{ +	expr_print(e, expr_print_file_helper, out, E_NONE); +} + +static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) +{ +	struct gstr *gs = (struct gstr*)data; +	const char *sym_str = NULL; + +	if (sym) +		sym_str = sym_get_string_value(sym); + +	if (gs->max_width) { +		unsigned extra_length = strlen(str); +		const char *last_cr = strrchr(gs->s, '\n'); +		unsigned last_line_length; + +		if (sym_str) +			extra_length += 4 + strlen(sym_str); + +		if (!last_cr) +			last_cr = gs->s; + +		last_line_length = strlen(gs->s) - (last_cr - gs->s); + +		if ((last_line_length + extra_length) > gs->max_width) +			str_append(gs, "\\\n"); +	} + +	str_append(gs, str); +	if (sym && sym->type != S_UNKNOWN) +		str_printf(gs, " [=%s]", sym_str); +} + +void expr_gstr_print(struct expr *e, struct gstr *gs) +{ +	expr_print(e, expr_print_gstr_helper, gs, E_NONE); +} diff --git a/programs/src/kconfig/kconfig/expr.h b/programs/src/kconfig/kconfig/expr.h new file mode 100644 index 0000000..412ea8a --- /dev/null +++ b/programs/src/kconfig/kconfig/expr.h @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef EXPR_H +#define EXPR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <stdio.h> +#include "list.h" +#ifndef __cplusplus +#include <stdbool.h> +#endif + +struct file { +	struct file *next; +	struct file *parent; +	const char *name; +	int lineno; +}; + +typedef enum tristate { +	no, mod, yes +} tristate; + +enum expr_type { +	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE +}; + +union expr_data { +	struct expr *expr; +	struct symbol *sym; +}; + +struct expr { +	enum expr_type type; +	union expr_data left, right; +}; + +#define EXPR_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2)) +#define EXPR_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2)) +#define EXPR_NOT(dep)		(2-(dep)) + +#define expr_list_for_each_sym(l, e, s) \ +	for (e = (l); e && (s = e->right.sym); e = e->left.expr) + +struct expr_value { +	struct expr *expr; +	tristate tri; +}; + +struct symbol_value { +	void *val; +	tristate tri; +}; + +enum symbol_type { +	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER +}; + +/* enum values are used as index to symbol.def[] */ +enum { +	S_DEF_USER,		/* main user value */ +	S_DEF_AUTO,		/* values read from auto.conf */ +	S_DEF_DEF3,		/* Reserved for UI usage */ +	S_DEF_DEF4,		/* Reserved for UI usage */ +	S_DEF_COUNT +}; + +struct symbol { +	struct symbol *next; +	char *name; +	enum symbol_type type; +	struct symbol_value curr; +	struct symbol_value def[S_DEF_COUNT]; +	tristate visible; +	int flags; +	struct property *prop; +	struct expr_value dir_dep; +	struct expr_value rev_dep; +}; + +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) + +#define SYMBOL_CONST      0x0001  /* symbol is const */ +#define SYMBOL_CHECK      0x0008  /* used during dependency checking */ +#define SYMBOL_CHOICE     0x0010  /* start of a choice block (null name) */ +#define SYMBOL_CHOICEVAL  0x0020  /* used as a value in a choice block */ +#define SYMBOL_VALID      0x0080  /* set when symbol.curr is calculated */ +#define SYMBOL_OPTIONAL   0x0100  /* choice is optional - values can be 'n' */ +#define SYMBOL_WRITE      0x0200  /* write symbol to file (KCONFIG_CONFIG) */ +#define SYMBOL_CHANGED    0x0400  /* ? */ +#define SYMBOL_AUTO       0x1000  /* value from environment variable */ +#define SYMBOL_CHECKED    0x2000  /* used during dependency checking */ +#define SYMBOL_WARNED     0x8000  /* warning has been issued */ + +/* Set when symbol.def[] is used */ +#define SYMBOL_DEF        0x10000  /* First bit of SYMBOL_DEF */ +#define SYMBOL_DEF_USER   0x10000  /* symbol.def[S_DEF_USER] is valid */ +#define SYMBOL_DEF_AUTO   0x20000  /* symbol.def[S_DEF_AUTO] is valid */ +#define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */ +#define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */ + +/* choice values need to be set before calculating this symbol value */ +#define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000 + +/* Set symbol to y if allnoconfig; used for symbols that hide others */ +#define SYMBOL_ALLNOCONFIG_Y 0x200000 + +#define SYMBOL_MAXLENGTH	256 +#define SYMBOL_HASHSIZE		9973 + +/* A property represent the config options that can be associated + * with a config "symbol". + * Sample: + * config FOO + *         default y + *         prompt "foo prompt" + *         select BAR + * config BAZ + *         int "BAZ Value" + *         range 1..255 + */ +enum prop_type { +	P_UNKNOWN, +	P_PROMPT,   /* prompt "foo prompt" or "BAZ Value" */ +	P_COMMENT,  /* text associated with a comment */ +	P_MENU,     /* prompt associated with a menuconfig option */ +	P_DEFAULT,  /* default y */ +	P_CHOICE,   /* choice value */ +	P_SELECT,   /* select BAR */ +	P_RANGE,    /* range 7..100 (for a symbol) */ +	P_ENV,      /* value from environment variable */ +	P_SYMBOL,   /* where a symbol is defined */ +}; + +struct property { +	struct property *next;     /* next property - null if last */ +	struct symbol *sym;        /* the symbol for which the property is associated */ +	enum prop_type type;       /* type of property */ +	const char *text;          /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ +	struct expr_value visible; +	struct expr *expr;         /* the optional conditional part of the property */ +	struct menu *menu;         /* the menu the property are associated with +	                            * valid for: P_SELECT, P_RANGE, P_CHOICE, +	                            * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ +	struct file *file;         /* what file was this property defined */ +	int lineno;                /* what lineno was this property defined */ +}; + +#define for_all_properties(sym, st, tok) \ +	for (st = sym->prop; st; st = st->next) \ +		if (st->type == (tok)) +#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) +#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) +#define for_all_prompts(sym, st) \ +	for (st = sym->prop; st; st = st->next) \ +		if (st->text) + +struct menu { +	struct menu *next; +	struct menu *parent; +	struct menu *list; +	struct symbol *sym; +	struct property *prompt; +	struct expr *visibility; +	struct expr *dep; +	unsigned int flags; +	char *help; +	struct file *file; +	int lineno; +	void *data; +}; + +#define MENU_CHANGED		0x0001 +#define MENU_ROOT		0x0002 + +struct jump_key { +	struct list_head entries; +	size_t offset; +	struct menu *target; +	int index; +}; + +#define JUMP_NB			9 + +extern struct file *file_list; +extern struct file *current_file; +struct file *lookup_file(const char *name); + +extern struct symbol symbol_yes, symbol_no, symbol_mod; +extern struct symbol *modules_sym; +extern struct symbol *sym_defconfig_list; +extern int cdebug; +struct expr *expr_alloc_symbol(struct symbol *sym); +struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); +struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); +struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); +struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); +struct expr *expr_copy(const struct expr *org); +void expr_free(struct expr *e); +int expr_eq(struct expr *e1, struct expr *e2); +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); +tristate expr_calc_value(struct expr *e); +struct expr *expr_eliminate_yn(struct expr *e); +struct expr *expr_trans_bool(struct expr *e); +struct expr *expr_eliminate_dups(struct expr *e); +struct expr *expr_transform(struct expr *e); +int expr_contains_symbol(struct expr *dep, struct symbol *sym); +bool expr_depends_symbol(struct expr *dep, struct symbol *sym); +struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); +struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); +void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); +struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); +struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); + +void expr_fprint(struct expr *e, FILE *out); +struct gstr; /* forward */ +void expr_gstr_print(struct expr *e, struct gstr *gs); + +static inline int expr_is_yes(struct expr *e) +{ +	return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); +} + +static inline int expr_is_no(struct expr *e) +{ +	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); +} + +#ifdef __cplusplus +} +#endif + +#endif /* EXPR_H */ diff --git a/programs/src/kconfig/kconfig/list.h b/programs/src/kconfig/kconfig/list.h new file mode 100644 index 0000000..685d80e --- /dev/null +++ b/programs/src/kconfig/kconfig/list.h @@ -0,0 +1,131 @@ +#ifndef LIST_H +#define LIST_H + +/* + * Copied from include/linux/... + */ + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr:        the pointer to the member. + * @type:       the type of the container struct this is embedded in. + * @member:     the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({                      \ +	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \ +	(type *)( (char *)__mptr - offsetof(type,member) );}) + + +struct list_head { +	struct list_head *next, *prev; +}; + + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ +	struct list_head name = LIST_HEAD_INIT(name) + +/** + * list_entry - get the struct for this entry + * @ptr:	the &struct list_head pointer. + * @type:	the type of the struct this is embedded in. + * @member:	the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ +	container_of(ptr, type, member) + +/** + * list_for_each_entry	-	iterate over list of given type + * @pos:	the type * to use as a loop cursor. + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + */ +#define list_for_each_entry(pos, head, member)				\ +	for (pos = list_entry((head)->next, typeof(*pos), member);	\ +	     &pos->member != (head); 	\ +	     pos = list_entry(pos->member.next, typeof(*pos), member)) + +/** + * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @pos:	the type * to use as a loop cursor. + * @n:		another type * to use as temporary storage + * @head:	the head for your list. + * @member:	the name of the list_struct within the struct. + */ +#define list_for_each_entry_safe(pos, n, head, member)			\ +	for (pos = list_entry((head)->next, typeof(*pos), member),	\ +		n = list_entry(pos->member.next, typeof(*pos), member);	\ +	     &pos->member != (head);					\ +	     pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +/** + * list_empty - tests whether a list is empty + * @head: the list to test. + */ +static inline int list_empty(const struct list_head *head) +{ +	return head->next == head; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *_new, +			      struct list_head *prev, +			      struct list_head *next) +{ +	next->prev = _new; +	_new->next = next; +	_new->prev = prev; +	prev->next = _new; +} + +/** + * list_add_tail - add a new entry + * @new: new entry to be added + * @head: list head to add it before + * + * Insert a new entry before the specified head. + * This is useful for implementing queues. + */ +static inline void list_add_tail(struct list_head *_new, struct list_head *head) +{ +	__list_add(_new, head->prev, head); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head *prev, struct list_head *next) +{ +	next->prev = prev; +	prev->next = next; +} + +#define LIST_POISON1  ((void *) 0x00100100) +#define LIST_POISON2  ((void *) 0x00200200) +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void list_del(struct list_head *entry) +{ +	__list_del(entry->prev, entry->next); +	entry->next = (struct list_head*)LIST_POISON1; +	entry->prev = (struct list_head*)LIST_POISON2; +} +#endif diff --git a/programs/src/kconfig/kconfig/lkc.h b/programs/src/kconfig/kconfig/lkc.h new file mode 100644 index 0000000..d5daa7a --- /dev/null +++ b/programs/src/kconfig/kconfig/lkc.h @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#ifndef LKC_H +#define LKC_H + +#include "expr.h" + +#ifndef KBUILD_NO_NLS +# include <libintl.h> +#else +static inline const char *gettext(const char *txt) { return txt; } +static inline void textdomain(const char *domainname) {} +static inline void bindtextdomain(const char *name, const char *dir) {} +static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define P(name,type,arg)	extern type name arg +#include "lkc_proto.h" +#undef P + +#define SRCTREE "srctree" + +#ifndef PACKAGE +#define PACKAGE "linux" +#endif + +#define LOCALEDIR "/usr/share/locale" + +#define _(text) gettext(text) +#define N_(text) (text) + +#ifndef CONFIG_ +#define CONFIG_ "CONFIG_" +#endif +static inline const char *CONFIG_prefix(void) +{ +	return getenv( "CONFIG_" ) ?: CONFIG_; +} +#undef CONFIG_ +#define CONFIG_ CONFIG_prefix() + +#define TF_COMMAND	0x0001 +#define TF_PARAM	0x0002 +#define TF_OPTION	0x0004 + +enum conf_def_mode { +	def_default, +	def_yes, +	def_mod, +	def_no, +	def_random +}; + +#define T_OPT_MODULES		1 +#define T_OPT_DEFCONFIG_LIST	2 +#define T_OPT_ENV		3 +#define T_OPT_ALLNOCONFIG_Y	4 + +struct kconf_id { +	int name; +	int token; +	unsigned int flags; +	enum symbol_type stype; +}; + +extern int zconfdebug; + +int zconfparse(void); +void zconfdump(FILE *out); +void zconf_starthelp(void); +FILE *zconf_fopen(const char *name); +void zconf_initscan(const char *name); +void zconf_nextfile(const char *name); +int zconf_lineno(void); +const char *zconf_curname(void); + +/* confdata.c */ +const char *conf_get_configname(void); +const char *conf_get_autoconfig_name(void); +char *conf_get_default_confname(void); +void sym_set_change_count(int count); +void sym_add_change_count(int count); +bool conf_set_all_new_symbols(enum conf_def_mode mode); +void set_all_choice_values(struct symbol *csym); + +struct conf_printer { +	void (*print_symbol)(FILE *, struct symbol *, const char *, void *); +	void (*print_comment)(FILE *, const char *, void *); +}; + +/* confdata.c and expr.c */ +static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) +{ +	assert(len != 0); + +	if (fwrite(str, len, count, out) != count) +		fprintf(stderr, "Error in writing or end of file.\n"); +} + +/* menu.c */ +void _menu_init(void); +void menu_warn(struct menu *menu, const char *fmt, ...); +struct menu *menu_add_menu(void); +void menu_end_menu(void); +void menu_add_entry(struct symbol *sym); +void menu_end_entry(void); +void menu_add_dep(struct expr *dep); +void menu_add_visibility(struct expr *dep); +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); +void menu_add_option(int token, char *arg); +void menu_finalize(struct menu *parent); +void menu_set_type(int type); + +/* util.c */ +struct file *file_lookup(const char *name); +int file_write_dep(const char *name); +void *xmalloc(size_t size); +void *xcalloc(size_t nmemb, size_t size); + +struct gstr { +	size_t len; +	char  *s; +	/* +	* when max_width is not zero long lines in string s (if any) get +	* wrapped not to exceed the max_width value +	*/ +	int max_width; +}; +struct gstr str_new(void); +struct gstr str_assign(const char *s); +void str_free(struct gstr *gs); +void str_append(struct gstr *gs, const char *s); +void str_printf(struct gstr *gs, const char *fmt, ...); +const char *str_get(struct gstr *gs); + +/* symbol.c */ +extern struct expr *sym_env_list; + +void sym_init(void); +void sym_clear_all_valid(void); +void sym_set_all_changed(void); +void sym_set_changed(struct symbol *sym); +struct symbol *sym_choice_default(struct symbol *sym); +const char *sym_get_string_default(struct symbol *sym); +struct symbol *sym_check_deps(struct symbol *sym); +struct property *prop_alloc(enum prop_type type, struct symbol *sym); +struct symbol *prop_get_symbol(struct property *prop); +struct property *sym_get_env_prop(struct symbol *sym); + +static inline tristate sym_get_tristate_value(struct symbol *sym) +{ +	return sym->curr.tri; +} + + +static inline struct symbol *sym_get_choice_value(struct symbol *sym) +{ +	return (struct symbol *)sym->curr.val; +} + +static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) +{ +	return sym_set_tristate_value(chval, yes); +} + +static inline bool sym_is_choice(struct symbol *sym) +{ +	return sym->flags & SYMBOL_CHOICE ? true : false; +} + +static inline bool sym_is_choice_value(struct symbol *sym) +{ +	return sym->flags & SYMBOL_CHOICEVAL ? true : false; +} + +static inline bool sym_is_optional(struct symbol *sym) +{ +	return sym->flags & SYMBOL_OPTIONAL ? true : false; +} + +static inline bool sym_has_value(struct symbol *sym) +{ +	return sym->flags & SYMBOL_DEF_USER ? true : false; +} + +#ifdef __cplusplus +} +#endif + +#endif /* LKC_H */ diff --git a/programs/src/kconfig/kconfig/lkc_proto.h b/programs/src/kconfig/kconfig/lkc_proto.h new file mode 100644 index 0000000..ecdb965 --- /dev/null +++ b/programs/src/kconfig/kconfig/lkc_proto.h @@ -0,0 +1,57 @@ +#include <stdarg.h> + +/* confdata.c */ +P(conf_parse,void,(const char *name)); +P(conf_read,int,(const char *name)); +P(conf_read_simple,int,(const char *name, int)); +P(conf_write_defconfig,int,(const char *name)); +P(conf_write,int,(const char *name)); +P(conf_write_autoconf,int,(void)); +P(conf_get_changed,bool,(void)); +P(conf_set_changed_callback, void,(void (*fn)(void))); +P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap))); + +/* menu.c */ +P(rootmenu,struct menu,); + +P(menu_is_empty, bool, (struct menu *menu)); +P(menu_is_visible, bool, (struct menu *menu)); +P(menu_has_prompt, bool, (struct menu *menu)); +P(menu_get_prompt,const char *,(struct menu *menu)); +P(menu_get_root_menu,struct menu *,(struct menu *menu)); +P(menu_get_parent_menu,struct menu *,(struct menu *menu)); +P(menu_has_help,bool,(struct menu *menu)); +P(menu_get_help,const char *,(struct menu *menu)); +P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head +			 *head)); +P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head +				   *head)); +P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); + +/* symbol.c */ +P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); + +P(sym_lookup,struct symbol *,(const char *name, int flags)); +P(sym_find,struct symbol *,(const char *name)); +P(sym_expand_string_value,const char *,(const char *in)); +P(sym_escape_string_value, const char *,(const char *in)); +P(sym_re_search,struct symbol **,(const char *pattern)); +P(sym_type_name,const char *,(enum symbol_type type)); +P(sym_calc_value,void,(struct symbol *sym)); +P(sym_get_type,enum symbol_type,(struct symbol *sym)); +P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); +P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); +P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); +P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); +P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); +P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); +P(sym_is_changable,bool,(struct symbol *sym)); +P(sym_get_choice_prop,struct property *,(struct symbol *sym)); +P(sym_get_default_prop,struct property *,(struct symbol *sym)); +P(sym_get_string_value,const char *,(struct symbol *sym)); + +P(prop_get_type_name,const char *,(enum prop_type type)); + +/* expr.c */ +P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); +P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); diff --git a/programs/src/kconfig/kconfig/menu.c b/programs/src/kconfig/kconfig/menu.c new file mode 100644 index 0000000..a26cc5d --- /dev/null +++ b/programs/src/kconfig/kconfig/menu.c @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#include "lkc.h" + +static const char nohelp_text[] = "There is no help available for this option."; + +struct menu rootmenu; +static struct menu **last_entry_ptr; + +struct file *file_list; +struct file *current_file; + +void menu_warn(struct menu *menu, const char *fmt, ...) +{ +	va_list ap; +	va_start(ap, fmt); +	fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); +	vfprintf(stderr, fmt, ap); +	fprintf(stderr, "\n"); +	va_end(ap); +} + +static void prop_warn(struct property *prop, const char *fmt, ...) +{ +	va_list ap; +	va_start(ap, fmt); +	fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); +	vfprintf(stderr, fmt, ap); +	fprintf(stderr, "\n"); +	va_end(ap); +} + +void _menu_init(void) +{ +	current_entry = current_menu = &rootmenu; +	last_entry_ptr = &rootmenu.list; +} + +void menu_add_entry(struct symbol *sym) +{ +	struct menu *menu; + +	menu = xmalloc(sizeof(*menu)); +	memset(menu, 0, sizeof(*menu)); +	menu->sym = sym; +	menu->parent = current_menu; +	menu->file = current_file; +	menu->lineno = zconf_lineno(); + +	*last_entry_ptr = menu; +	last_entry_ptr = &menu->next; +	current_entry = menu; +	if (sym) +		menu_add_symbol(P_SYMBOL, sym, NULL); +} + +void menu_end_entry(void) +{ +} + +struct menu *menu_add_menu(void) +{ +	menu_end_entry(); +	last_entry_ptr = ¤t_entry->list; +	return current_menu = current_entry; +} + +void menu_end_menu(void) +{ +	last_entry_ptr = ¤t_menu->next; +	current_menu = current_menu->parent; +} + +static struct expr *menu_check_dep(struct expr *e) +{ +	if (!e) +		return e; + +	switch (e->type) { +	case E_NOT: +		e->left.expr = menu_check_dep(e->left.expr); +		break; +	case E_OR: +	case E_AND: +		e->left.expr = menu_check_dep(e->left.expr); +		e->right.expr = menu_check_dep(e->right.expr); +		break; +	case E_SYMBOL: +		/* change 'm' into 'm' && MODULES */ +		if (e->left.sym == &symbol_mod) +			return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); +		break; +	default: +		break; +	} +	return e; +} + +void menu_add_dep(struct expr *dep) +{ +	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); +} + +void menu_set_type(int type) +{ +	struct symbol *sym = current_entry->sym; + +	if (sym->type == type) +		return; +	if (sym->type == S_UNKNOWN) { +		sym->type = type; +		return; +	} +	menu_warn(current_entry, +		"ignoring type redefinition of '%s' from '%s' to '%s'", +		sym->name ? sym->name : "<choice>", +		sym_type_name(sym->type), sym_type_name(type)); +} + +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) +{ +	struct property *prop = prop_alloc(type, current_entry->sym); + +	prop->menu = current_entry; +	prop->expr = expr; +	prop->visible.expr = menu_check_dep(dep); + +	if (prompt) { +		if (isspace(*prompt)) { +			prop_warn(prop, "leading whitespace ignored"); +			while (isspace(*prompt)) +				prompt++; +		} +		if (current_entry->prompt && current_entry != &rootmenu) +			prop_warn(prop, "prompt redefined"); + +		/* Apply all upper menus' visibilities to actual prompts. */ +		if(type == P_PROMPT) { +			struct menu *menu = current_entry; + +			while ((menu = menu->parent) != NULL) { +				struct expr *dup_expr; + +				if (!menu->visibility) +					continue; +				/* +				 * Do not add a reference to the +				 * menu's visibility expression but +				 * use a copy of it.  Otherwise the +				 * expression reduction functions +				 * will modify expressions that have +				 * multiple references which can +				 * cause unwanted side effects. +				 */ +				dup_expr = expr_copy(menu->visibility); + +				prop->visible.expr +					= expr_alloc_and(prop->visible.expr, +							 dup_expr); +			} +		} + +		current_entry->prompt = prop; +	} +	prop->text = prompt; + +	return prop; +} + +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) +{ +	return menu_add_prop(type, prompt, NULL, dep); +} + +void menu_add_visibility(struct expr *expr) +{ +	current_entry->visibility = expr_alloc_and(current_entry->visibility, +	    expr); +} + +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) +{ +	menu_add_prop(type, NULL, expr, dep); +} + +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) +{ +	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); +} + +void menu_add_option(int token, char *arg) +{ +	switch (token) { +	case T_OPT_MODULES: +		if (modules_sym) +			zconf_error("symbol '%s' redefines option 'modules'" +				    " already defined by symbol '%s'", +				    current_entry->sym->name, +				    modules_sym->name +				    ); +		modules_sym = current_entry->sym; +		break; +	case T_OPT_DEFCONFIG_LIST: +		if (!sym_defconfig_list) +			sym_defconfig_list = current_entry->sym; +		else if (sym_defconfig_list != current_entry->sym) +			zconf_error("trying to redefine defconfig symbol"); +		break; +	case T_OPT_ENV: +		prop_add_env(arg); +		break; +	case T_OPT_ALLNOCONFIG_Y: +		current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; +		break; +	} +} + +static int menu_validate_number(struct symbol *sym, struct symbol *sym2) +{ +	return sym2->type == S_INT || sym2->type == S_HEX || +	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); +} + +static void sym_check_prop(struct symbol *sym) +{ +	struct property *prop; +	struct symbol *sym2; +	for (prop = sym->prop; prop; prop = prop->next) { +		switch (prop->type) { +		case P_DEFAULT: +			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && +			    prop->expr->type != E_SYMBOL) +				prop_warn(prop, +				    "default for config symbol '%s'" +				    " must be a single symbol", sym->name); +			if (prop->expr->type != E_SYMBOL) +				break; +			sym2 = prop_get_symbol(prop); +			if (sym->type == S_HEX || sym->type == S_INT) { +				if (!menu_validate_number(sym, sym2)) +					prop_warn(prop, +					    "'%s': number is invalid", +					    sym->name); +			} +			break; +		case P_SELECT: +			sym2 = prop_get_symbol(prop); +			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) +				prop_warn(prop, +				    "config symbol '%s' uses select, but is " +				    "not boolean or tristate", sym->name); +			else if (sym2->type != S_UNKNOWN && +				 sym2->type != S_BOOLEAN && +				 sym2->type != S_TRISTATE) +				prop_warn(prop, +				    "'%s' has wrong type. 'select' only " +				    "accept arguments of boolean and " +				    "tristate type", sym2->name); +			break; +		case P_RANGE: +			if (sym->type != S_INT && sym->type != S_HEX) +				prop_warn(prop, "range is only allowed " +						"for int or hex symbols"); +			if (!menu_validate_number(sym, prop->expr->left.sym) || +			    !menu_validate_number(sym, prop->expr->right.sym)) +				prop_warn(prop, "range is invalid"); +			break; +		default: +			; +		} +	} +} + +void menu_finalize(struct menu *parent) +{ +	struct menu *menu, *last_menu; +	struct symbol *sym; +	struct property *prop; +	struct expr *parentdep, *basedep, *dep, *dep2, **ep; + +	sym = parent->sym; +	if (parent->list) { +		if (sym && sym_is_choice(sym)) { +			if (sym->type == S_UNKNOWN) { +				/* find the first choice value to find out choice type */ +				current_entry = parent; +				for (menu = parent->list; menu; menu = menu->next) { +					if (menu->sym && menu->sym->type != S_UNKNOWN) { +						menu_set_type(menu->sym->type); +						break; +					} +				} +			} +			/* set the type of the remaining choice values */ +			for (menu = parent->list; menu; menu = menu->next) { +				current_entry = menu; +				if (menu->sym && menu->sym->type == S_UNKNOWN) +					menu_set_type(sym->type); +			} +			parentdep = expr_alloc_symbol(sym); +		} else if (parent->prompt) +			parentdep = parent->prompt->visible.expr; +		else +			parentdep = parent->dep; + +		for (menu = parent->list; menu; menu = menu->next) { +			basedep = expr_transform(menu->dep); +			basedep = expr_alloc_and(expr_copy(parentdep), basedep); +			basedep = expr_eliminate_dups(basedep); +			menu->dep = basedep; +			if (menu->sym) +				prop = menu->sym->prop; +			else +				prop = menu->prompt; +			for (; prop; prop = prop->next) { +				if (prop->menu != menu) +					continue; +				dep = expr_transform(prop->visible.expr); +				dep = expr_alloc_and(expr_copy(basedep), dep); +				dep = expr_eliminate_dups(dep); +				if (menu->sym && menu->sym->type != S_TRISTATE) +					dep = expr_trans_bool(dep); +				prop->visible.expr = dep; +				if (prop->type == P_SELECT) { +					struct symbol *es = prop_get_symbol(prop); +					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, +							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); +				} +			} +		} +		for (menu = parent->list; menu; menu = menu->next) +			menu_finalize(menu); +	} else if (sym) { +		basedep = parent->prompt ? parent->prompt->visible.expr : NULL; +		basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); +		basedep = expr_eliminate_dups(expr_transform(basedep)); +		last_menu = NULL; +		for (menu = parent->next; menu; menu = menu->next) { +			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; +			if (!expr_contains_symbol(dep, sym)) +				break; +			if (expr_depends_symbol(dep, sym)) +				goto next; +			dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); +			dep = expr_eliminate_dups(expr_transform(dep)); +			dep2 = expr_copy(basedep); +			expr_eliminate_eq(&dep, &dep2); +			expr_free(dep); +			if (!expr_is_yes(dep2)) { +				expr_free(dep2); +				break; +			} +			expr_free(dep2); +		next: +			menu_finalize(menu); +			menu->parent = parent; +			last_menu = menu; +		} +		if (last_menu) { +			parent->list = parent->next; +			parent->next = last_menu->next; +			last_menu->next = NULL; +		} + +		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); +	} +	for (menu = parent->list; menu; menu = menu->next) { +		if (sym && sym_is_choice(sym) && +		    menu->sym && !sym_is_choice_value(menu->sym)) { +			current_entry = menu; +			menu->sym->flags |= SYMBOL_CHOICEVAL; +			if (!menu->prompt) +				menu_warn(menu, "choice value must have a prompt"); +			for (prop = menu->sym->prop; prop; prop = prop->next) { +				if (prop->type == P_DEFAULT) +					prop_warn(prop, "defaults for choice " +						  "values not supported"); +				if (prop->menu == menu) +					continue; +				if (prop->type == P_PROMPT && +				    prop->menu->parent->sym != sym) +					prop_warn(prop, "choice value used outside its choice group"); +			} +			/* Non-tristate choice values of tristate choices must +			 * depend on the choice being set to Y. The choice +			 * values' dependencies were propagated to their +			 * properties above, so the change here must be re- +			 * propagated. +			 */ +			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { +				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); +				menu->dep = expr_alloc_and(basedep, menu->dep); +				for (prop = menu->sym->prop; prop; prop = prop->next) { +					if (prop->menu != menu) +						continue; +					prop->visible.expr = expr_alloc_and(expr_copy(basedep), +									    prop->visible.expr); +				} +			} +			menu_add_symbol(P_CHOICE, sym, NULL); +			prop = sym_get_choice_prop(sym); +			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) +				; +			*ep = expr_alloc_one(E_LIST, NULL); +			(*ep)->right.sym = menu->sym; +		} +		if (menu->list && (!menu->prompt || !menu->prompt->text)) { +			for (last_menu = menu->list; ; last_menu = last_menu->next) { +				last_menu->parent = parent; +				if (!last_menu->next) +					break; +			} +			last_menu->next = menu->next; +			menu->next = menu->list; +			menu->list = NULL; +		} +	} + +	if (sym && !(sym->flags & SYMBOL_WARNED)) { +		if (sym->type == S_UNKNOWN) +			menu_warn(parent, "config symbol defined without type"); + +		if (sym_is_choice(sym) && !parent->prompt) +			menu_warn(parent, "choice must have a prompt"); + +		/* Check properties connected to this symbol */ +		sym_check_prop(sym); +		sym->flags |= SYMBOL_WARNED; +	} + +	if (sym && !sym_is_optional(sym) && parent->prompt) { +		sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, +				expr_alloc_and(parent->prompt->visible.expr, +					expr_alloc_symbol(&symbol_mod))); +	} +} + +bool menu_has_prompt(struct menu *menu) +{ +	if (!menu->prompt) +		return false; +	return true; +} + +/* + * Determine if a menu is empty. + * A menu is considered empty if it contains no or only + * invisible entries. + */ +bool menu_is_empty(struct menu *menu) +{ +	struct menu *child; + +	for (child = menu->list; child; child = child->next) { +		if (menu_is_visible(child)) +			return(false); +	} +	return(true); +} + +bool menu_is_visible(struct menu *menu) +{ +	struct menu *child; +	struct symbol *sym; +	tristate visible; + +	if (!menu->prompt) +		return false; + +	if (menu->visibility) { +		if (expr_calc_value(menu->visibility) == no) +			return no; +	} + +	sym = menu->sym; +	if (sym) { +		sym_calc_value(sym); +		visible = menu->prompt->visible.tri; +	} else +		visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); + +	if (visible != no) +		return true; + +	if (!sym || sym_get_tristate_value(menu->sym) == no) +		return false; + +	for (child = menu->list; child; child = child->next) { +		if (menu_is_visible(child)) { +			if (sym) +				sym->flags |= SYMBOL_DEF_USER; +			return true; +		} +	} + +	return false; +} + +const char *menu_get_prompt(struct menu *menu) +{ +	if (menu->prompt) +		return menu->prompt->text; +	else if (menu->sym) +		return menu->sym->name; +	return NULL; +} + +struct menu *menu_get_root_menu(struct menu *menu) +{ +	return &rootmenu; +} + +struct menu *menu_get_parent_menu(struct menu *menu) +{ +	enum prop_type type; + +	for (; menu != &rootmenu; menu = menu->parent) { +		type = menu->prompt ? menu->prompt->type : 0; +		if (type == P_MENU) +			break; +	} +	return menu; +} + +bool menu_has_help(struct menu *menu) +{ +	return menu->help != NULL; +} + +const char *menu_get_help(struct menu *menu) +{ +	if (menu->help) +		return menu->help; +	else +		return ""; +} + +static void get_prompt_str(struct gstr *r, struct property *prop, +			   struct list_head *head) +{ +	int i, j; +	struct menu *submenu[8], *menu, *location = NULL; +	struct jump_key *jump; + +	str_printf(r, _("Prompt: %s\n"), _(prop->text)); +	menu = prop->menu->parent; +	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { +		bool accessible = menu_is_visible(menu); + +		submenu[i++] = menu; +		if (location == NULL && accessible) +			location = menu; +	} +	if (head && location) { +		jump = xmalloc(sizeof(struct jump_key)); + +		if (menu_is_visible(prop->menu)) { +			/* +			 * There is not enough room to put the hint at the +			 * beginning of the "Prompt" line. Put the hint on the +			 * last "Location" line even when it would belong on +			 * the former. +			 */ +			jump->target = prop->menu; +		} else +			jump->target = location; + +		if (list_empty(head)) +			jump->index = 0; +		else +			jump->index = list_entry(head->prev, struct jump_key, +						 entries)->index + 1; + +		list_add_tail(&jump->entries, head); +	} + +	if (i > 0) { +		str_printf(r, _("  Location:\n")); +		for (j = 4; --i >= 0; j += 2) { +			menu = submenu[i]; +			if (head && location && menu == location) +				jump->offset = strlen(r->s); +			str_printf(r, "%*c-> %s", j, ' ', +				   _(menu_get_prompt(menu))); +			if (menu->sym) { +				str_printf(r, " (%s [=%s])", menu->sym->name ? +					menu->sym->name : _("<choice>"), +					sym_get_string_value(menu->sym)); +			} +			str_append(r, "\n"); +		} +	} +} + +/* + * get property of type P_SYMBOL + */ +static struct property *get_symbol_prop(struct symbol *sym) +{ +	struct property *prop = NULL; + +	for_all_properties(sym, prop, P_SYMBOL) +		break; +	return prop; +} + +/* + * head is optional and may be NULL + */ +void get_symbol_str(struct gstr *r, struct symbol *sym, +		    struct list_head *head) +{ +	bool hit; +	struct property *prop; + +	if (sym && sym->name) { +		str_printf(r, "Symbol: %s [=%s]\n", sym->name, +			   sym_get_string_value(sym)); +		str_printf(r, "Type  : %s\n", sym_type_name(sym->type)); +		if (sym->type == S_INT || sym->type == S_HEX) { +			prop = sym_get_range_prop(sym); +			if (prop) { +				str_printf(r, "Range : "); +				expr_gstr_print(prop->expr, r); +				str_append(r, "\n"); +			} +		} +	} +	for_all_prompts(sym, prop) +		get_prompt_str(r, prop, head); + +	prop = get_symbol_prop(sym); +	if (prop) { +		str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name, +			prop->menu->lineno); +		if (!expr_is_yes(prop->visible.expr)) { +			str_append(r, _("  Depends on: ")); +			expr_gstr_print(prop->visible.expr, r); +			str_append(r, "\n"); +		} +	} + +	hit = false; +	for_all_properties(sym, prop, P_SELECT) { +		if (!hit) { +			str_append(r, "  Selects: "); +			hit = true; +		} else +			str_printf(r, " && "); +		expr_gstr_print(prop->expr, r); +	} +	if (hit) +		str_append(r, "\n"); +	if (sym->rev_dep.expr) { +		str_append(r, _("  Selected by: ")); +		expr_gstr_print(sym->rev_dep.expr, r); +		str_append(r, "\n"); +	} +	str_append(r, "\n\n"); +} + +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) +{ +	struct symbol *sym; +	struct gstr res = str_new(); +	int i; + +	for (i = 0; sym_arr && (sym = sym_arr[i]); i++) +		get_symbol_str(&res, sym, head); +	if (!i) +		str_append(&res, _("No matches found.\n")); +	return res; +} + + +void menu_get_ext_help(struct menu *menu, struct gstr *help) +{ +	struct symbol *sym = menu->sym; +	const char *help_text = nohelp_text; + +	if (menu_has_help(menu)) { +		if (sym->name) +			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); +		help_text = menu_get_help(menu); +	} +	str_printf(help, "%s\n", _(help_text)); +	if (sym) +		get_symbol_str(help, sym, NULL); +} diff --git a/programs/src/kconfig/kconfig/symbol.c b/programs/src/kconfig/kconfig/symbol.c new file mode 100644 index 0000000..7caabdb --- /dev/null +++ b/programs/src/kconfig/kconfig/symbol.c @@ -0,0 +1,1373 @@ +/* + * 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 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; +	int base; +	long long 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 = strtoll(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, "%lld", val2); +	else +		sprintf(str, "0x%llx", 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; + +	if (sym_is_choice_value(sym) && +	    sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { +		sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; +		prop = sym_get_choice_prop(sym); +		sym_calc_value(prop_get_symbol(prop)); +	} + +	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; + +	if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) +		set_all_choice_values(sym); +} + +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; + +		cs->def[S_DEF_USER].val = sym; +		cs->flags |= SYMBOL_DEF_USER; +		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_DEF_USER; +		} +	} + +	sym->def[S_DEF_USER].tri = val; +	if (oldval != val) +		sym_clear_all_valid(); + +	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)) +				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': +		case 'm': case 'M': +		case 'n': case 'N': +			return true; +		} +		return false; +	default: +		return false; +	} +} + +bool sym_string_within_range(struct symbol *sym, const char *str) +{ +	struct property *prop; +	long long val; + +	switch (sym->type) { +	case S_STRING: +		return sym_string_valid(sym, str); +	case S_INT: +		if (!sym_string_valid(sym, str)) +			return false; +		prop = sym_get_range_prop(sym); +		if (!prop) +			return true; +		val = strtoll(str, NULL, 10); +		return val >= sym_get_range_val(prop->expr->left.sym, 10) && +		       val <= sym_get_range_val(prop->expr->right.sym, 10); +	case S_HEX: +		if (!sym_string_valid(sym, str)) +			return false; +		prop = sym_get_range_prop(sym); +		if (!prop) +			return true; +		val = strtoll(str, NULL, 16); +		return val >= sym_get_range_val(prop->expr->left.sym, 16) && +		       val <= sym_get_range_val(prop->expr->right.sym, 16); +	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_within_range(sym, newval)) +		return false; + +	if (!(sym->flags & SYMBOL_DEF_USER)) { +		sym->flags |= SYMBOL_DEF_USER; +		sym_set_changed(sym); +	} + +	oldval = sym->def[S_DEF_USER].val; +	size = strlen(newval) + 1; +	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { +		size += 2; +		sym->def[S_DEF_USER].val = val = xmalloc(size); +		*val++ = '0'; +		*val++ = 'x'; +	} else if (!oldval || strcmp(oldval, newval)) +		sym->def[S_DEF_USER].val = val = xmalloc(size); +	else +		return true; + +	strcpy(val, newval); +	free((void *)oldval); +	sym_clear_all_valid(); + +	return true; +} + +/* + * Find the default value associated to a symbol. + * For tristate symbol handle the modules=n case + * in which case "m" becomes "y". + * If the symbol does not have any default then fallback + * to the fixed default values. + */ +const char *sym_get_string_default(struct symbol *sym) +{ +	struct property *prop; +	struct symbol *ds; +	const char *str; +	tristate val; + +	sym_calc_visibility(sym); +	sym_calc_value(modules_sym); +	val = symbol_no.curr.tri; +	str = symbol_empty.curr.val; + +	/* If symbol has a default value look it up */ +	prop = sym_get_default_prop(sym); +	if (prop != NULL) { +		switch (sym->type) { +		case S_BOOLEAN: +		case S_TRISTATE: +			/* The visibility may limit the value from yes => mod */ +			val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); +			break; +		default: +			/* +			 * The following fails to handle the situation +			 * where a default value is further limited by +			 * the valid range. +			 */ +			ds = prop_get_symbol(prop); +			if (ds != NULL) { +				sym_calc_value(ds); +				str = (const char *)ds->curr.val; +			} +		} +	} + +	/* Handle select statements */ +	val = EXPR_OR(val, sym->rev_dep.tri); + +	/* transpose mod to yes if modules are not enabled */ +	if (val == mod) +		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) +			val = yes; + +	/* transpose mod to yes if type is bool */ +	if (sym->type == S_BOOLEAN && val == mod) +		val = yes; + +	switch (sym->type) { +	case S_BOOLEAN: +	case S_TRISTATE: +		switch (val) { +		case no: return "n"; +		case mod: return "m"; +		case yes: return "y"; +		} +	case S_INT: +	case S_HEX: +		return str; +	case S_STRING: +		return str; +	case S_OTHER: +	case S_UNKNOWN: +		break; +	} +	return ""; +} + +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: +			sym_calc_value(modules_sym); +			return (modules_sym->curr.tri == no) ? "n" : "m"; +		case yes: +			return "y"; +		} +		break; +	default: +		; +	} +	return (const char *)sym->curr.val; +} + +bool sym_is_changable(struct symbol *sym) +{ +	return sym->visible > sym->rev_dep.tri; +} + +static unsigned strhash(const char *s) +{ +	/* fnv32 hash */ +	unsigned hash = 2166136261U; +	for (; *s; s++) +		hash = (hash ^ *s) * 0x01000193; +	return hash; +} + +struct symbol *sym_lookup(const char *name, int flags) +{ +	struct symbol *symbol; +	char *new_name; +	int hash; + +	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; +			} +		} +		hash = strhash(name) % SYMBOL_HASHSIZE; + +		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { +			if (symbol->name && +			    !strcmp(symbol->name, name) && +			    (flags ? symbol->flags & flags +				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) +				return symbol; +		} +		new_name = strdup(name); +	} else { +		new_name = NULL; +		hash = 0; +	} + +	symbol = xmalloc(sizeof(*symbol)); +	memset(symbol, 0, sizeof(*symbol)); +	symbol->name = new_name; +	symbol->type = S_UNKNOWN; +	symbol->flags |= flags; + +	symbol->next = symbol_hash[hash]; +	symbol_hash[hash] = symbol; + +	return symbol; +} + +struct symbol *sym_find(const char *name) +{ +	struct symbol *symbol = NULL; +	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; +		} +	} +	hash = strhash(name) % SYMBOL_HASHSIZE; + +	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { +		if (symbol->name && +		    !strcmp(symbol->name, name) && +		    !(symbol->flags & SYMBOL_CONST)) +				break; +	} + +	return symbol; +} + +/* + * Expand symbol's names embedded in the string given in argument. Symbols' + * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to + * the empty string. + */ +const char *sym_expand_string_value(const char *in) +{ +	const char *src; +	char *res; +	size_t reslen; + +	reslen = strlen(in) + 1; +	res = xmalloc(reslen); +	res[0] = '\0'; + +	while ((src = strchr(in, '$'))) { +		char *p, name[SYMBOL_MAXLENGTH]; +		const char *symval = ""; +		struct symbol *sym; +		size_t newlen; + +		strncat(res, in, src - in); +		src++; + +		p = name; +		while (isalnum(*src) || *src == '_') +			*p++ = *src++; +		*p = '\0'; + +		sym = sym_find(name); +		if (sym != NULL) { +			sym_calc_value(sym); +			symval = sym_get_string_value(sym); +		} + +		newlen = strlen(res) + strlen(symval) + strlen(src) + 1; +		if (newlen > reslen) { +			reslen = newlen; +			res = realloc(res, reslen); +		} + +		strcat(res, symval); +		in = src; +	} +	strcat(res, in); + +	return res; +} + +const char *sym_escape_string_value(const char *in) +{ +	const char *p; +	size_t reslen; +	char *res; +	size_t l; + +	reslen = strlen(in) + strlen("\"\"") + 1; + +	p = in; +	for (;;) { +		l = strcspn(p, "\"\\"); +		p += l; + +		if (p[0] == '\0') +			break; + +		reslen++; +		p++; +	} + +	res = xmalloc(reslen); +	res[0] = '\0'; + +	strcat(res, "\""); + +	p = in; +	for (;;) { +		l = strcspn(p, "\"\\"); +		strncat(res, p, l); +		p += l; + +		if (p[0] == '\0') +			break; + +		strcat(res, "\\"); +		strncat(res, p++, 1); +	} + +	strcat(res, "\""); +	return res; +} + +struct sym_match { +	struct symbol	*sym; +	off_t		so, eo; +}; + +/* Compare matched symbols as thus: + * - first, symbols that match exactly + * - then, alphabetical sort + */ +static int sym_rel_comp(const void *sym1, const void *sym2) +{ +	const struct sym_match *s1 = sym1; +	const struct sym_match *s2 = sym2; +	int exact1, exact2; + +	/* Exact match: +	 * - if matched length on symbol s1 is the length of that symbol, +	 *   then this symbol should come first; +	 * - if matched length on symbol s2 is the length of that symbol, +	 *   then this symbol should come first. +	 * Note: since the search can be a regexp, both symbols may match +	 * exactly; if this is the case, we can't decide which comes first, +	 * and we fallback to sorting alphabetically. +	 */ +	exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); +	exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); +	if (exact1 && !exact2) +		return -1; +	if (!exact1 && exact2) +		return 1; + +	/* As a fallback, sort symbols alphabetically */ +	return strcmp(s1->sym->name, s2->sym->name); +} + +struct symbol **sym_re_search(const char *pattern) +{ +	struct symbol *sym, **sym_arr = NULL; +	struct sym_match *sym_match_arr = NULL; +	int i, cnt, size; +	regex_t re; +	regmatch_t match[1]; + +	cnt = size = 0; +	/* Skip if empty */ +	if (strlen(pattern) == 0) +		return NULL; +	if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) +		return NULL; + +	for_all_symbols(i, sym) { +		if (sym->flags & SYMBOL_CONST || !sym->name) +			continue; +		if (regexec(&re, sym->name, 1, match, 0)) +			continue; +		if (cnt >= size) { +			void *tmp; +			size += 16; +			tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); +			if (!tmp) +				goto sym_re_search_free; +			sym_match_arr = tmp; +		} +		sym_calc_value(sym); +		/* As regexec returned 0, we know we have a match, so +		 * we can use match[0].rm_[se]o without further checks +		 */ +		sym_match_arr[cnt].so = match[0].rm_so; +		sym_match_arr[cnt].eo = match[0].rm_eo; +		sym_match_arr[cnt++].sym = sym; +	} +	if (sym_match_arr) { +		qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); +		sym_arr = malloc((cnt+1) * sizeof(struct symbol)); +		if (!sym_arr) +			goto sym_re_search_free; +		for (i = 0; i < cnt; i++) +			sym_arr[i] = sym_match_arr[i].sym; +		sym_arr[cnt] = NULL; +	} +sym_re_search_free: +	/* sym_match_arr can be NULL if no match, but free(NULL) is OK */ +	free(sym_match_arr); +	regfree(&re); + +	return sym_arr; +} + +/* + * When we check for recursive dependencies we use a stack to save + * current state so we can print out relevant info to user. + * The entries are located on the call stack so no need to free memory. + * Note insert() remove() must always match to properly clear the stack. + */ +static struct dep_stack { +	struct dep_stack *prev, *next; +	struct symbol *sym; +	struct property *prop; +	struct expr *expr; +} *check_top; + +static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) +{ +	memset(stack, 0, sizeof(*stack)); +	if (check_top) +		check_top->next = stack; +	stack->prev = check_top; +	stack->sym = sym; +	check_top = stack; +} + +static void dep_stack_remove(void) +{ +	check_top = check_top->prev; +	if (check_top) +		check_top->next = NULL; +} + +/* + * Called when we have detected a recursive dependency. + * check_top point to the top of the stact so we use + * the ->prev pointer to locate the bottom of the stack. + */ +static void sym_check_print_recursive(struct symbol *last_sym) +{ +	struct dep_stack *stack; +	struct symbol *sym, *next_sym; +	struct menu *menu = NULL; +	struct property *prop; +	struct dep_stack cv_stack; + +	if (sym_is_choice_value(last_sym)) { +		dep_stack_insert(&cv_stack, last_sym); +		last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); +	} + +	for (stack = check_top; stack != NULL; stack = stack->prev) +		if (stack->sym == last_sym) +			break; +	if (!stack) { +		fprintf(stderr, "unexpected recursive dependency error\n"); +		return; +	} + +	for (; stack; stack = stack->next) { +		sym = stack->sym; +		next_sym = stack->next ? stack->next->sym : last_sym; +		prop = stack->prop; +		if (prop == NULL) +			prop = stack->sym->prop; + +		/* for choice values find the menu entry (used below) */ +		if (sym_is_choice(sym) || sym_is_choice_value(sym)) { +			for (prop = sym->prop; prop; prop = prop->next) { +				menu = prop->menu; +				if (prop->menu) +					break; +			} +		} +		if (stack->sym == last_sym) +			fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", +				prop->file->name, prop->lineno); +		if (stack->expr) { +			fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", +				prop->file->name, prop->lineno, +				sym->name ? sym->name : "<choice>", +				prop_get_type_name(prop->type), +				next_sym->name ? next_sym->name : "<choice>"); +		} else if (stack->prop) { +			fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", +				prop->file->name, prop->lineno, +				sym->name ? sym->name : "<choice>", +				next_sym->name ? next_sym->name : "<choice>"); +		} else if (sym_is_choice(sym)) { +			fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", +				menu->file->name, menu->lineno, +				sym->name ? sym->name : "<choice>", +				next_sym->name ? next_sym->name : "<choice>"); +		} else if (sym_is_choice_value(sym)) { +			fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", +				menu->file->name, menu->lineno, +				sym->name ? sym->name : "<choice>", +				next_sym->name ? next_sym->name : "<choice>"); +		} else { +			fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", +				prop->file->name, prop->lineno, +				sym->name ? sym->name : "<choice>", +				next_sym->name ? next_sym->name : "<choice>"); +		} +	} + +	if (check_top == &cv_stack) +		dep_stack_remove(); +} + +static struct symbol *sym_check_expr_deps(struct expr *e) +{ +	struct symbol *sym; + +	if (!e) +		return NULL; +	switch (e->type) { +	case E_OR: +	case E_AND: +		sym = sym_check_expr_deps(e->left.expr); +		if (sym) +			return sym; +		return sym_check_expr_deps(e->right.expr); +	case E_NOT: +		return sym_check_expr_deps(e->left.expr); +	case E_EQUAL: +	case E_UNEQUAL: +		sym = sym_check_deps(e->left.sym); +		if (sym) +			return sym; +		return sym_check_deps(e->right.sym); +	case E_SYMBOL: +		return sym_check_deps(e->left.sym); +	default: +		break; +	} +	printf("Oops! How to check %d?\n", e->type); +	return NULL; +} + +/* return NULL when dependencies are OK */ +static struct symbol *sym_check_sym_deps(struct symbol *sym) +{ +	struct symbol *sym2; +	struct property *prop; +	struct dep_stack stack; + +	dep_stack_insert(&stack, sym); + +	sym2 = sym_check_expr_deps(sym->rev_dep.expr); +	if (sym2) +		goto out; + +	for (prop = sym->prop; prop; prop = prop->next) { +		if (prop->type == P_CHOICE || prop->type == P_SELECT) +			continue; +		stack.prop = prop; +		sym2 = sym_check_expr_deps(prop->visible.expr); +		if (sym2) +			break; +		if (prop->type != P_DEFAULT || sym_is_choice(sym)) +			continue; +		stack.expr = prop->expr; +		sym2 = sym_check_expr_deps(prop->expr); +		if (sym2) +			break; +		stack.expr = NULL; +	} + +out: +	dep_stack_remove(); + +	return sym2; +} + +static struct symbol *sym_check_choice_deps(struct symbol *choice) +{ +	struct symbol *sym, *sym2; +	struct property *prop; +	struct expr *e; +	struct dep_stack stack; + +	dep_stack_insert(&stack, choice); + +	prop = sym_get_choice_prop(choice); +	expr_list_for_each_sym(prop->expr, e, sym) +		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + +	choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); +	sym2 = sym_check_sym_deps(choice); +	choice->flags &= ~SYMBOL_CHECK; +	if (sym2) +		goto out; + +	expr_list_for_each_sym(prop->expr, e, sym) { +		sym2 = sym_check_sym_deps(sym); +		if (sym2) +			break; +	} +out: +	expr_list_for_each_sym(prop->expr, e, sym) +		sym->flags &= ~SYMBOL_CHECK; + +	if (sym2 && sym_is_choice_value(sym2) && +	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice) +		sym2 = choice; + +	dep_stack_remove(); + +	return sym2; +} + +struct symbol *sym_check_deps(struct symbol *sym) +{ +	struct symbol *sym2; +	struct property *prop; + +	if (sym->flags & SYMBOL_CHECK) { +		sym_check_print_recursive(sym); +		return sym; +	} +	if (sym->flags & SYMBOL_CHECKED) +		return NULL; + +	if (sym_is_choice_value(sym)) { +		struct dep_stack stack; + +		/* for choice groups start the check with main choice symbol */ +		dep_stack_insert(&stack, sym); +		prop = sym_get_choice_prop(sym); +		sym2 = sym_check_deps(prop_get_symbol(prop)); +		dep_stack_remove(); +	} else if (sym_is_choice(sym)) { +		sym2 = sym_check_choice_deps(sym); +	} else { +		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); +		sym2 = sym_check_sym_deps(sym); +		sym->flags &= ~SYMBOL_CHECK; +	} + +	if (sym2 && sym2 == sym) +		sym2 = NULL; + +	return sym2; +} + +struct property *prop_alloc(enum prop_type type, struct symbol *sym) +{ +	struct property *prop; +	struct property **propp; + +	prop = xmalloc(sizeof(*prop)); +	memset(prop, 0, sizeof(*prop)); +	prop->type = type; +	prop->sym = sym; +	prop->file = current_file; +	prop->lineno = zconf_lineno(); + +	/* append property to the prop list of symbol */ +	if (sym) { +		for (propp = &sym->prop; *propp; propp = &(*propp)->next) +			; +		*propp = prop; +	} + +	return prop; +} + +struct symbol *prop_get_symbol(struct property *prop) +{ +	if (prop->expr && (prop->expr->type == E_SYMBOL || +			   prop->expr->type == E_LIST)) +		return prop->expr->left.sym; +	return NULL; +} + +const char *prop_get_type_name(enum prop_type type) +{ +	switch (type) { +	case P_PROMPT: +		return "prompt"; +	case P_ENV: +		return "env"; +	case P_COMMENT: +		return "comment"; +	case P_MENU: +		return "menu"; +	case P_DEFAULT: +		return "default"; +	case P_CHOICE: +		return "choice"; +	case P_SELECT: +		return "select"; +	case P_RANGE: +		return "range"; +	case P_SYMBOL: +		return "symbol"; +	case P_UNKNOWN: +		break; +	} +	return "unknown"; +} + +static void prop_add_env(const char *env) +{ +	struct symbol *sym, *sym2; +	struct property *prop; +	char *p; + +	sym = current_entry->sym; +	sym->flags |= SYMBOL_AUTO; +	for_all_properties(sym, prop, P_ENV) { +		sym2 = prop_get_symbol(prop); +		if (strcmp(sym2->name, env)) +			menu_warn(current_entry, "redefining environment symbol from %s", +				  sym2->name); +		return; +	} + +	prop = prop_alloc(P_ENV, sym); +	prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); + +	sym_env_list = expr_alloc_one(E_LIST, sym_env_list); +	sym_env_list->right.sym = sym; + +	p = getenv(env); +	if (p) +		sym_add_default(sym, p); +	else +		menu_warn(current_entry, "environment variable %s undefined", env); +} diff --git a/programs/src/kconfig/kconfig/util.c b/programs/src/kconfig/kconfig/util.c new file mode 100644 index 0000000..94f9c83 --- /dev/null +++ b/programs/src/kconfig/kconfig/util.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2002-2005 Roman Zippel <zippel@linux-m68k.org> + * Copyright (C) 2002-2005 Sam Ravnborg <sam@ravnborg.org> + * + * Released under the terms of the GNU GPL v2.0. + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include "lkc.h" + +/* file already present in list? If not add it */ +struct file *file_lookup(const char *name) +{ +	struct file *file; +	const char *file_name = sym_expand_string_value(name); + +	for (file = file_list; file; file = file->next) { +		if (!strcmp(name, file->name)) { +			free((void *)file_name); +			return file; +		} +	} + +	file = xmalloc(sizeof(*file)); +	memset(file, 0, sizeof(*file)); +	file->name = file_name; +	file->next = file_list; +	file_list = file; +	return file; +} + +/* write a dependency file as used by kbuild to track dependencies */ +int file_write_dep(const char *name) +{ +	struct symbol *sym, *env_sym; +	struct expr *e; +	struct file *file; +	FILE *out; + +	if (!name) +		name = ".kconfig.d"; +	out = fopen("..config.tmp", "w"); +	if (!out) +		return 1; +	fprintf(out, "deps_config := \\\n"); +	for (file = file_list; file; file = file->next) { +		if (file->next) +			fprintf(out, "\t%s \\\n", file->name); +		else +			fprintf(out, "\t%s\n", file->name); +	} +	fprintf(out, "\n%s: \\\n" +		     "\t$(deps_config)\n\n", conf_get_autoconfig_name()); + +	expr_list_for_each_sym(sym_env_list, e, sym) { +		struct property *prop; +		const char *value; + +		prop = sym_get_env_prop(sym); +		env_sym = prop_get_symbol(prop); +		if (!env_sym) +			continue; +		value = getenv(env_sym->name); +		if (!value) +			value = ""; +		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); +		fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); +		fprintf(out, "endif\n"); +	} + +	fprintf(out, "\n$(deps_config): ;\n"); +	fclose(out); +	rename("..config.tmp", name); +	return 0; +} + + +/* Allocate initial growable string */ +struct gstr str_new(void) +{ +	struct gstr gs; +	gs.s = xmalloc(sizeof(char) * 64); +	gs.len = 64; +	gs.max_width = 0; +	strcpy(gs.s, "\0"); +	return gs; +} + +/* Allocate and assign growable string */ +struct gstr str_assign(const char *s) +{ +	struct gstr gs; +	gs.s = strdup(s); +	gs.len = strlen(s) + 1; +	gs.max_width = 0; +	return gs; +} + +/* Free storage for growable string */ +void str_free(struct gstr *gs) +{ +	if (gs->s) +		free(gs->s); +	gs->s = NULL; +	gs->len = 0; +} + +/* Append to growable string */ +void str_append(struct gstr *gs, const char *s) +{ +	size_t l; +	if (s) { +		l = strlen(gs->s) + strlen(s) + 1; +		if (l > gs->len) { +			gs->s   = realloc(gs->s, l); +			gs->len = l; +		} +		strcat(gs->s, s); +	} +} + +/* Append printf formatted string to growable string */ +void str_printf(struct gstr *gs, const char *fmt, ...) +{ +	va_list ap; +	char s[10000]; /* big enough... */ +	va_start(ap, fmt); +	vsnprintf(s, sizeof(s), fmt, ap); +	str_append(gs, s); +	va_end(ap); +} + +/* Retrieve value of growable string */ +const char *str_get(struct gstr *gs) +{ +	return gs->s; +} + +void *xmalloc(size_t size) +{ +	void *p = malloc(size); +	if (p) +		return p; +	fprintf(stderr, "Out of memory.\n"); +	exit(1); +} + +void *xcalloc(size_t nmemb, size_t size) +{ +	void *p = calloc(nmemb, size); +	if (p) +		return p; +	fprintf(stderr, "Out of memory.\n"); +	exit(1); +} diff --git a/programs/src/kconfig/kconfig/zconf.gperf b/programs/src/kconfig/kconfig/zconf.gperf new file mode 100644 index 0000000..b6ac02d --- /dev/null +++ b/programs/src/kconfig/kconfig/zconf.gperf @@ -0,0 +1,48 @@ +%language=ANSI-C +%define hash-function-name kconf_id_hash +%define lookup-function-name kconf_id_lookup +%define string-pool-name kconf_id_strings +%compare-strncmp +%enum +%pic +%struct-type + +struct kconf_id; + +static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); + +%% +mainmenu,	T_MAINMENU,	TF_COMMAND +menu,		T_MENU,		TF_COMMAND +endmenu,	T_ENDMENU,	TF_COMMAND +source,		T_SOURCE,	TF_COMMAND +choice,		T_CHOICE,	TF_COMMAND +endchoice,	T_ENDCHOICE,	TF_COMMAND +comment,	T_COMMENT,	TF_COMMAND +config,		T_CONFIG,	TF_COMMAND +menuconfig,	T_MENUCONFIG,	TF_COMMAND +help,		T_HELP,		TF_COMMAND +if,		T_IF,		TF_COMMAND|TF_PARAM +endif,		T_ENDIF,	TF_COMMAND +depends,	T_DEPENDS,	TF_COMMAND +optional,	T_OPTIONAL,	TF_COMMAND +default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN +prompt,		T_PROMPT,	TF_COMMAND +tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE +def_tristate,	T_DEFAULT,	TF_COMMAND, S_TRISTATE +bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN +boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN +def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN +int,		T_TYPE,		TF_COMMAND, S_INT +hex,		T_TYPE,		TF_COMMAND, S_HEX +string,		T_TYPE,		TF_COMMAND, S_STRING +select,		T_SELECT,	TF_COMMAND +range,		T_RANGE,	TF_COMMAND +visible,	T_VISIBLE,	TF_COMMAND +option,		T_OPTION,	TF_COMMAND +on,		T_ON,		TF_PARAM +modules,	T_OPT_MODULES,	TF_OPTION +defconfig_list,	T_OPT_DEFCONFIG_LIST,TF_OPTION +env,		T_OPT_ENV,	TF_OPTION +allnoconfig_y,	T_OPT_ALLNOCONFIG_Y,TF_OPTION +%% diff --git a/programs/src/kconfig/kconfig/zconf.hash.c b/programs/src/kconfig/kconfig/zconf.hash.c new file mode 100644 index 0000000..b8c1dfb --- /dev/null +++ b/programs/src/kconfig/kconfig/zconf.hash.c @@ -0,0 +1,289 @@ +/* ANSI-C code produced by gperf version 3.0.4 */ +/* Command-line: gperf -t --output-file kconfig/zconf.hash.c -a -C -E -g -k '1,3,$' -p -t kconfig/zconf.gperf  */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ +      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ +      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ +      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ +      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ +      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ +      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ +      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ +      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ +      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ +      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ +      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ +      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ +      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ +      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ +      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ +      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ +      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ +      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ +      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ +      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ +      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ +      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646.  */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>." +#endif + +#line 10 "kconfig/zconf.gperf" +struct kconf_id; + +static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); +/* maximum key range = 71, duplicates = 0 */ + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +kconf_id_hash (register const char *str, register unsigned int len) +{ +  static const unsigned char asso_values[] = +    { +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73,  5, 25, 25, +       0,  0,  0,  5,  0,  0, 73, 73,  5,  0, +      10,  5, 45, 73, 20, 20,  0, 15, 15, 73, +      20,  5, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73, 73, 73, 73, 73, +      73, 73, 73, 73, 73, 73 +    }; +  register int hval = len; + +  switch (hval) +    { +      default: +        hval += asso_values[(unsigned char)str[2]]; +      /*FALLTHROUGH*/ +      case 2: +      case 1: +        hval += asso_values[(unsigned char)str[0]]; +        break; +    } +  return hval + asso_values[(unsigned char)str[len - 1]]; +} + +struct kconf_id_strings_t +  { +    char kconf_id_strings_str2[sizeof("if")]; +    char kconf_id_strings_str3[sizeof("int")]; +    char kconf_id_strings_str5[sizeof("endif")]; +    char kconf_id_strings_str7[sizeof("default")]; +    char kconf_id_strings_str8[sizeof("tristate")]; +    char kconf_id_strings_str9[sizeof("endchoice")]; +    char kconf_id_strings_str12[sizeof("def_tristate")]; +    char kconf_id_strings_str13[sizeof("def_bool")]; +    char kconf_id_strings_str14[sizeof("defconfig_list")]; +    char kconf_id_strings_str17[sizeof("on")]; +    char kconf_id_strings_str18[sizeof("optional")]; +    char kconf_id_strings_str21[sizeof("option")]; +    char kconf_id_strings_str22[sizeof("endmenu")]; +    char kconf_id_strings_str23[sizeof("mainmenu")]; +    char kconf_id_strings_str25[sizeof("menuconfig")]; +    char kconf_id_strings_str27[sizeof("modules")]; +    char kconf_id_strings_str28[sizeof("allnoconfig_y")]; +    char kconf_id_strings_str29[sizeof("menu")]; +    char kconf_id_strings_str31[sizeof("select")]; +    char kconf_id_strings_str32[sizeof("comment")]; +    char kconf_id_strings_str33[sizeof("env")]; +    char kconf_id_strings_str35[sizeof("range")]; +    char kconf_id_strings_str36[sizeof("choice")]; +    char kconf_id_strings_str39[sizeof("bool")]; +    char kconf_id_strings_str41[sizeof("source")]; +    char kconf_id_strings_str42[sizeof("visible")]; +    char kconf_id_strings_str43[sizeof("hex")]; +    char kconf_id_strings_str46[sizeof("config")]; +    char kconf_id_strings_str47[sizeof("boolean")]; +    char kconf_id_strings_str51[sizeof("string")]; +    char kconf_id_strings_str54[sizeof("help")]; +    char kconf_id_strings_str56[sizeof("prompt")]; +    char kconf_id_strings_str72[sizeof("depends")]; +  }; +static const struct kconf_id_strings_t kconf_id_strings_contents = +  { +    "if", +    "int", +    "endif", +    "default", +    "tristate", +    "endchoice", +    "def_tristate", +    "def_bool", +    "defconfig_list", +    "on", +    "optional", +    "option", +    "endmenu", +    "mainmenu", +    "menuconfig", +    "modules", +    "allnoconfig_y", +    "menu", +    "select", +    "comment", +    "env", +    "range", +    "choice", +    "bool", +    "source", +    "visible", +    "hex", +    "config", +    "boolean", +    "string", +    "help", +    "prompt", +    "depends" +  }; +#define kconf_id_strings ((const char *) &kconf_id_strings_contents) +#ifdef __GNUC__ +__inline +#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ +__attribute__ ((__gnu_inline__)) +#endif +#endif +const struct kconf_id * +kconf_id_lookup (register const char *str, register unsigned int len) +{ +  enum +    { +      TOTAL_KEYWORDS = 33, +      MIN_WORD_LENGTH = 2, +      MAX_WORD_LENGTH = 14, +      MIN_HASH_VALUE = 2, +      MAX_HASH_VALUE = 72 +    }; + +  static const struct kconf_id wordlist[] = +    { +      {-1}, {-1}, +#line 25 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_IF,		TF_COMMAND|TF_PARAM}, +#line 36 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_TYPE,		TF_COMMAND, S_INT}, +      {-1}, +#line 26 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND}, +      {-1}, +#line 29 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN}, +#line 31 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_TYPE,		TF_COMMAND, S_TRISTATE}, +#line 20 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND}, +      {-1}, {-1}, +#line 32 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_TRISTATE}, +#line 35 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN}, +#line 45 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,	T_OPT_DEFCONFIG_LIST,TF_OPTION}, +      {-1}, {-1}, +#line 43 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,		T_ON,		TF_PARAM}, +#line 28 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_OPTIONAL,	TF_COMMAND}, +      {-1}, {-1}, +#line 42 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_OPTION,	TF_COMMAND}, +#line 17 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,	T_ENDMENU,	TF_COMMAND}, +#line 15 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,	T_MAINMENU,	TF_COMMAND}, +      {-1}, +#line 23 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25,	T_MENUCONFIG,	TF_COMMAND}, +      {-1}, +#line 44 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION}, +#line 47 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_OPT_ALLNOCONFIG_Y,TF_OPTION}, +#line 16 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND}, +      {-1}, +#line 39 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SELECT,	TF_COMMAND}, +#line 21 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND}, +#line 46 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,		T_OPT_ENV,	TF_OPTION}, +      {-1}, +#line 40 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,		T_RANGE,	TF_COMMAND}, +#line 19 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_CHOICE,	TF_COMMAND}, +      {-1}, {-1}, +#line 33 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39,		T_TYPE,		TF_COMMAND, S_BOOLEAN}, +      {-1}, +#line 18 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_SOURCE,	TF_COMMAND}, +#line 41 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_VISIBLE,	TF_COMMAND}, +#line 37 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43,		T_TYPE,		TF_COMMAND, S_HEX}, +      {-1}, {-1}, +#line 22 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,		T_CONFIG,	TF_COMMAND}, +#line 34 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47,	T_TYPE,		TF_COMMAND, S_BOOLEAN}, +      {-1}, {-1}, {-1}, +#line 38 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51,		T_TYPE,		TF_COMMAND, S_STRING}, +      {-1}, {-1}, +#line 24 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54,		T_HELP,		TF_COMMAND}, +      {-1}, +#line 30 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56,		T_PROMPT,	TF_COMMAND}, +      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 27 "kconfig/zconf.gperf" +      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72,	T_DEPENDS,	TF_COMMAND} +    }; + +  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) +    { +      register int key = kconf_id_hash (str, len); + +      if (key <= MAX_HASH_VALUE && key >= 0) +        { +          register int o = wordlist[key].name; +          if (o >= 0) +            { +              register const char *s = o + kconf_id_strings; + +              if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') +                return &wordlist[key]; +            } +        } +    } +  return 0; +} +#line 48 "kconfig/zconf.gperf" + diff --git a/programs/src/kconfig/kconfig/zconf.l b/programs/src/kconfig/kconfig/zconf.l new file mode 100644 index 0000000..6c62d93 --- /dev/null +++ b/programs/src/kconfig/kconfig/zconf.l @@ -0,0 +1,363 @@ +%option nostdinit noyywrap never-interactive full ecs +%option 8bit nodefault perf-report perf-report +%option noinput +%x COMMAND HELP STRING PARAM +%{ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "lkc.h" + +#define START_STRSIZE	16 + +static struct { +	struct file *file; +	int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { +	struct buffer *parent; +	YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +static void new_string(void) +{ +	text = xmalloc(START_STRSIZE); +	text_asize = START_STRSIZE; +	text_size = 0; +	*text = 0; +} + +static void append_string(const char *str, int size) +{ +	int new_size = text_size + size + 1; +	if (new_size > text_asize) { +		new_size += START_STRSIZE - 1; +		new_size &= -START_STRSIZE; +		text = realloc(text, new_size); +		text_asize = new_size; +	} +	memcpy(text + text_size, str, size); +	text_size += size; +	text[text_size] = 0; +} + +static void alloc_string(const char *str, int size) +{ +	text = xmalloc(size + 1); +	memcpy(text, str, size); +	text[size] = 0; +} +%} + +n	[A-Za-z0-9_] + +%% +	int str = 0; +	int ts, i; + +[ \t]*#.*\n	| +[ \t]*\n	{ +	current_file->lineno++; +	return T_EOL; +} +[ \t]*#.* + + +[ \t]+	{ +	BEGIN(COMMAND); +} + +.	{ +	unput(yytext[0]); +	BEGIN(COMMAND); +} + + +<COMMAND>{ +	{n}+	{ +		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); +		BEGIN(PARAM); +		current_pos.file = current_file; +		current_pos.lineno = current_file->lineno; +		if (id && id->flags & TF_COMMAND) { +			zconflval.id = id; +			return id->token; +		} +		alloc_string(yytext, yyleng); +		zconflval.string = text; +		return T_WORD; +	} +	. +	\n	{ +		BEGIN(INITIAL); +		current_file->lineno++; +		return T_EOL; +	} +} + +<PARAM>{ +	"&&"	return T_AND; +	"||"	return T_OR; +	"("	return T_OPEN_PAREN; +	")"	return T_CLOSE_PAREN; +	"!"	return T_NOT; +	"="	return T_EQUAL; +	"!="	return T_UNEQUAL; +	\"|\'	{ +		str = yytext[0]; +		new_string(); +		BEGIN(STRING); +	} +	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL; +	---	/* ignore */ +	({n}|[-/.])+	{ +		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng); +		if (id && id->flags & TF_PARAM) { +			zconflval.id = id; +			return id->token; +		} +		alloc_string(yytext, yyleng); +		zconflval.string = text; +		return T_WORD; +	} +	#.*	/* comment */ +	\\\n	current_file->lineno++; +	. +	<<EOF>> { +		BEGIN(INITIAL); +	} +} + +<STRING>{ +	[^'"\\\n]+/\n	{ +		append_string(yytext, yyleng); +		zconflval.string = text; +		return T_WORD_QUOTE; +	} +	[^'"\\\n]+	{ +		append_string(yytext, yyleng); +	} +	\\.?/\n	{ +		append_string(yytext + 1, yyleng - 1); +		zconflval.string = text; +		return T_WORD_QUOTE; +	} +	\\.?	{ +		append_string(yytext + 1, yyleng - 1); +	} +	\'|\"	{ +		if (str == yytext[0]) { +			BEGIN(PARAM); +			zconflval.string = text; +			return T_WORD_QUOTE; +		} else +			append_string(yytext, 1); +	} +	\n	{ +		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); +		current_file->lineno++; +		BEGIN(INITIAL); +		return T_EOL; +	} +	<<EOF>>	{ +		BEGIN(INITIAL); +	} +} + +<HELP>{ +	[ \t]+	{ +		ts = 0; +		for (i = 0; i < yyleng; i++) { +			if (yytext[i] == '\t') +				ts = (ts & ~7) + 8; +			else +				ts++; +		} +		last_ts = ts; +		if (first_ts) { +			if (ts < first_ts) { +				zconf_endhelp(); +				return T_HELPTEXT; +			} +			ts -= first_ts; +			while (ts > 8) { +				append_string("        ", 8); +				ts -= 8; +			} +			append_string("        ", ts); +		} +	} +	[ \t]*\n/[^ \t\n] { +		current_file->lineno++; +		zconf_endhelp(); +		return T_HELPTEXT; +	} +	[ \t]*\n	{ +		current_file->lineno++; +		append_string("\n", 1); +	} +	[^ \t\n].* { +		while (yyleng) { +			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) +				break; +			yyleng--; +		} +		append_string(yytext, yyleng); +		if (!first_ts) +			first_ts = last_ts; +	} +	<<EOF>>	{ +		zconf_endhelp(); +		return T_HELPTEXT; +	} +} + +<<EOF>>	{ +	if (current_file) { +		zconf_endfile(); +		return T_EOL; +	} +	fclose(yyin); +	yyterminate(); +} + +%% +void zconf_starthelp(void) +{ +	new_string(); +	last_ts = first_ts = 0; +	BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ +	zconflval.string = text; +	BEGIN(INITIAL); +} + + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ +	char *env, fullname[PATH_MAX+1]; +	FILE *f; + +	f = fopen(name, "r"); +	if (!f && name != NULL && name[0] != '/') { +		env = getenv(SRCTREE); +		if (env) { +			sprintf(fullname, "%s/%s", env, name); +			f = fopen(fullname, "r"); +		} +	} +	return f; +} + +void zconf_initscan(const char *name) +{ +	yyin = zconf_fopen(name); +	if (!yyin) { +		printf("can't find file %s\n", name); +		exit(1); +	} + +	current_buf = xmalloc(sizeof(*current_buf)); +	memset(current_buf, 0, sizeof(*current_buf)); + +	current_file = file_lookup(name); +	current_file->lineno = 1; +} + +void zconf_nextfile(const char *name) +{ +	struct file *iter; +	struct file *file = file_lookup(name); +	struct buffer *buf = xmalloc(sizeof(*buf)); +	memset(buf, 0, sizeof(*buf)); + +	current_buf->state = YY_CURRENT_BUFFER; +	yyin = zconf_fopen(file->name); +	if (!yyin) { +		printf("%s:%d: can't open file \"%s\"\n", +		    zconf_curname(), zconf_lineno(), file->name); +		exit(1); +	} +	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); +	buf->parent = current_buf; +	current_buf = buf; + +	for (iter = current_file->parent; iter; iter = iter->parent ) { +		if (!strcmp(current_file->name,iter->name) ) { +			printf("%s:%d: recursive inclusion detected. " +			       "Inclusion path:\n  current file : '%s'\n", +			       zconf_curname(), zconf_lineno(), +			       zconf_curname()); +			iter = current_file->parent; +			while (iter && \ +			       strcmp(iter->name,current_file->name)) { +				printf("  included from: '%s:%d'\n", +				       iter->name, iter->lineno-1); +				iter = iter->parent; +			} +			if (iter) +				printf("  included from: '%s:%d'\n", +				       iter->name, iter->lineno+1); +			exit(1); +		} +	} +	file->lineno = 1; +	file->parent = current_file; +	current_file = file; +} + +static void zconf_endfile(void) +{ +	struct buffer *parent; + +	current_file = current_file->parent; + +	parent = current_buf->parent; +	if (parent) { +		fclose(yyin); +		yy_delete_buffer(YY_CURRENT_BUFFER); +		yy_switch_to_buffer(parent->state); +	} +	free(current_buf); +	current_buf = parent; +} + +int zconf_lineno(void) +{ +	return current_pos.lineno; +} + +const char *zconf_curname(void) +{ +	return current_pos.file ? current_pos.file->name : "<none>"; +} diff --git a/programs/src/kconfig/kconfig/zconf.lex.c b/programs/src/kconfig/kconfig/zconf.lex.c new file mode 100644 index 0000000..e3b33bd --- /dev/null +++ b/programs/src/kconfig/kconfig/zconf.lex.c @@ -0,0 +1,2421 @@ + +#line 3 "kconfig/zconf.lex.c" + +#define  YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer zconf_create_buffer +#define yy_delete_buffer zconf_delete_buffer +#define yy_flex_debug zconf_flex_debug +#define yy_init_buffer zconf_init_buffer +#define yy_flush_buffer zconf_flush_buffer +#define yy_load_buffer_state zconf_load_buffer_state +#define yy_switch_to_buffer zconf_switch_to_buffer +#define yyin zconfin +#define yyleng zconfleng +#define yylex zconflex +#define yylineno zconflineno +#define yyout zconfout +#define yyrestart zconfrestart +#define yytext zconftext +#define yywrap zconfwrap +#define yyalloc zconfalloc +#define yyrealloc zconfrealloc +#define yyfree zconffree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 37 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with  platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types.  + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t;  +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN               (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN              (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN              (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX               (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX              (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX              (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX              (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX             (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX             (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else	/* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif	/* defined (__STDC__) */ +#endif	/* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index.  If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition.  This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state.  The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE zconfrestart(zconfin  ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE 16384 +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern yy_size_t zconfleng; + +extern FILE *zconfin, *zconfout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +    #define YY_LESS_LINENO(n) +     +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ +	do \ +		{ \ +		/* Undo effects of setting up zconftext. */ \ +        int yyless_macro_arg = (n); \ +        YY_LESS_LINENO(yyless_macro_arg);\ +		*yy_cp = (yy_hold_char); \ +		YY_RESTORE_YY_MORE_OFFSET \ +		(yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ +		YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ +		} \ +	while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr)  ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state +	{ +	FILE *yy_input_file; + +	char *yy_ch_buf;		/* input buffer */ +	char *yy_buf_pos;		/* current position in input buffer */ + +	/* Size of input buffer in bytes, not including room for EOB +	 * characters. +	 */ +	yy_size_t yy_buf_size; + +	/* Number of characters read into yy_ch_buf, not including EOB +	 * characters. +	 */ +	yy_size_t yy_n_chars; + +	/* Whether we "own" the buffer - i.e., we know we created it, +	 * and can realloc() it to grow it, and should free() it to +	 * delete it. +	 */ +	int yy_is_our_buffer; + +	/* Whether this is an "interactive" input source; if so, and +	 * if we're using stdio for input, then we want to use getc() +	 * instead of fread(), to make sure we stop fetching input after +	 * each newline. +	 */ +	int yy_is_interactive; + +	/* Whether we're considered to be at the beginning of a line. +	 * If so, '^' rules will be active on the next match, otherwise +	 * not. +	 */ +	int yy_at_bol; + +    int yy_bs_lineno; /**< The line count. */ +    int yy_bs_column; /**< The column count. */ +     +	/* Whether to try to fill the input buffer when we reach the +	 * end of it. +	 */ +	int yy_fill_buffer; + +	int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 +	/* When an EOF's been seen but there's still some text to process +	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we +	 * shouldn't try reading from the input source any more.  We might +	 * still have a bunch of tokens to match, though, because of +	 * possible backing-up. +	 * +	 * When we actually see the EOF, we change the status to "new" +	 * (via zconfrestart()), so that the user can continue scanning by +	 * just pointing zconfin at a new input file. +	 */ +#define YY_BUFFER_EOF_PENDING 2 + +	}; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ +                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ +                          : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when zconftext is formed. */ +static char yy_hold_char; +static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */ +yy_size_t zconfleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0;		/* whether we need to initialize */ +static int yy_start = 0;	/* start state number */ + +/* Flag which is used to allow zconfwrap()'s to do buffer switches + * instead of setting up a fresh zconfin.  A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void zconfrestart (FILE *input_file  ); +void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer  ); +YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size  ); +void zconf_delete_buffer (YY_BUFFER_STATE b  ); +void zconf_flush_buffer (YY_BUFFER_STATE b  ); +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer  ); +void zconfpop_buffer_state (void ); + +static void zconfensure_buffer_stack (void ); +static void zconf_load_buffer_state (void ); +static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  ); + +#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  ); +YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  ); +YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,yy_size_t len  ); + +void *zconfalloc (yy_size_t  ); +void *zconfrealloc (void *,yy_size_t  ); +void zconffree (void *  ); + +#define yy_new_buffer zconf_create_buffer + +#define yy_set_interactive(is_interactive) \ +	{ \ +	if ( ! YY_CURRENT_BUFFER ){ \ +        zconfensure_buffer_stack (); \ +		YY_CURRENT_BUFFER_LVALUE =    \ +            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ +	} \ +	YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ +	} + +#define yy_set_bol(at_bol) \ +	{ \ +	if ( ! YY_CURRENT_BUFFER ){\ +        zconfensure_buffer_stack (); \ +		YY_CURRENT_BUFFER_LVALUE =    \ +            zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ +	} \ +	YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ +	} + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define zconfwrap() 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; + +typedef int yy_state_type; + +extern int zconflineno; + +int zconflineno = 1; + +extern char *zconftext; +#define yytext_ptr zconftext +static yyconst flex_int16_t yy_nxt[][17] = +    { +    { +        0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +        0,    0,    0,    0,    0,    0,    0 +    }, + +    { +       11,   12,   13,   14,   12,   12,   15,   12,   12,   12, +       12,   12,   12,   12,   12,   12,   12 +    }, + +    { +       11,   12,   13,   14,   12,   12,   15,   12,   12,   12, +       12,   12,   12,   12,   12,   12,   12 +    }, + +    { +       11,   16,   16,   17,   16,   16,   16,   16,   16,   16, +       16,   16,   16,   18,   16,   16,   16 +    }, + +    { +       11,   16,   16,   17,   16,   16,   16,   16,   16,   16, +       16,   16,   16,   18,   16,   16,   16 + +    }, + +    { +       11,   19,   20,   21,   19,   19,   19,   19,   19,   19, +       19,   19,   19,   19,   19,   19,   19 +    }, + +    { +       11,   19,   20,   21,   19,   19,   19,   19,   19,   19, +       19,   19,   19,   19,   19,   19,   19 +    }, + +    { +       11,   22,   22,   23,   22,   24,   22,   22,   24,   22, +       22,   22,   22,   22,   22,   25,   22 +    }, + +    { +       11,   22,   22,   23,   22,   24,   22,   22,   24,   22, +       22,   22,   22,   22,   22,   25,   22 +    }, + +    { +       11,   26,   26,   27,   28,   29,   30,   31,   29,   32, +       33,   34,   35,   35,   36,   37,   38 + +    }, + +    { +       11,   26,   26,   27,   28,   29,   30,   31,   29,   32, +       33,   34,   35,   35,   36,   37,   38 +    }, + +    { +      -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11,  -11, +      -11,  -11,  -11,  -11,  -11,  -11,  -11 +    }, + +    { +       11,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12,  -12, +      -12,  -12,  -12,  -12,  -12,  -12,  -12 +    }, + +    { +       11,  -13,   39,   40,  -13,  -13,   41,  -13,  -13,  -13, +      -13,  -13,  -13,  -13,  -13,  -13,  -13 +    }, + +    { +       11,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14, +      -14,  -14,  -14,  -14,  -14,  -14,  -14 + +    }, + +    { +       11,   42,   42,   43,   42,   42,   42,   42,   42,   42, +       42,   42,   42,   42,   42,   42,   42 +    }, + +    { +       11,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16, +      -16,  -16,  -16,  -16,  -16,  -16,  -16 +    }, + +    { +       11,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17,  -17, +      -17,  -17,  -17,  -17,  -17,  -17,  -17 +    }, + +    { +       11,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18, +      -18,  -18,  -18,   44,  -18,  -18,  -18 +    }, + +    { +       11,   45,   45,  -19,   45,   45,   45,   45,   45,   45, +       45,   45,   45,   45,   45,   45,   45 + +    }, + +    { +       11,  -20,   46,   47,  -20,  -20,  -20,  -20,  -20,  -20, +      -20,  -20,  -20,  -20,  -20,  -20,  -20 +    }, + +    { +       11,   48,  -21,  -21,   48,   48,   48,   48,   48,   48, +       48,   48,   48,   48,   48,   48,   48 +    }, + +    { +       11,   49,   49,   50,   49,  -22,   49,   49,  -22,   49, +       49,   49,   49,   49,   49,  -22,   49 +    }, + +    { +       11,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23,  -23, +      -23,  -23,  -23,  -23,  -23,  -23,  -23 +    }, + +    { +       11,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24, +      -24,  -24,  -24,  -24,  -24,  -24,  -24 + +    }, + +    { +       11,   51,   51,   52,   51,   51,   51,   51,   51,   51, +       51,   51,   51,   51,   51,   51,   51 +    }, + +    { +       11,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26,  -26, +      -26,  -26,  -26,  -26,  -26,  -26,  -26 +    }, + +    { +       11,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27, +      -27,  -27,  -27,  -27,  -27,  -27,  -27 +    }, + +    { +       11,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28,  -28, +      -28,  -28,  -28,  -28,   53,  -28,  -28 +    }, + +    { +       11,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29,  -29, +      -29,  -29,  -29,  -29,  -29,  -29,  -29 + +    }, + +    { +       11,   54,   54,  -30,   54,   54,   54,   54,   54,   54, +       54,   54,   54,   54,   54,   54,   54 +    }, + +    { +       11,  -31,  -31,  -31,  -31,  -31,  -31,   55,  -31,  -31, +      -31,  -31,  -31,  -31,  -31,  -31,  -31 +    }, + +    { +       11,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32,  -32, +      -32,  -32,  -32,  -32,  -32,  -32,  -32 +    }, + +    { +       11,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33,  -33, +      -33,  -33,  -33,  -33,  -33,  -33,  -33 +    }, + +    { +       11,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34, +      -34,   56,   57,   57,  -34,  -34,  -34 + +    }, + +    { +       11,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35, +      -35,   57,   57,   57,  -35,  -35,  -35 +    }, + +    { +       11,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36, +      -36,  -36,  -36,  -36,  -36,  -36,  -36 +    }, + +    { +       11,  -37,  -37,   58,  -37,  -37,  -37,  -37,  -37,  -37, +      -37,  -37,  -37,  -37,  -37,  -37,  -37 +    }, + +    { +       11,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38, +      -38,  -38,  -38,  -38,  -38,  -38,   59 +    }, + +    { +       11,  -39,   39,   40,  -39,  -39,   41,  -39,  -39,  -39, +      -39,  -39,  -39,  -39,  -39,  -39,  -39 + +    }, + +    { +       11,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40,  -40, +      -40,  -40,  -40,  -40,  -40,  -40,  -40 +    }, + +    { +       11,   42,   42,   43,   42,   42,   42,   42,   42,   42, +       42,   42,   42,   42,   42,   42,   42 +    }, + +    { +       11,   42,   42,   43,   42,   42,   42,   42,   42,   42, +       42,   42,   42,   42,   42,   42,   42 +    }, + +    { +       11,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43, +      -43,  -43,  -43,  -43,  -43,  -43,  -43 +    }, + +    { +       11,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44,  -44, +      -44,  -44,  -44,   44,  -44,  -44,  -44 + +    }, + +    { +       11,   45,   45,  -45,   45,   45,   45,   45,   45,   45, +       45,   45,   45,   45,   45,   45,   45 +    }, + +    { +       11,  -46,   46,   47,  -46,  -46,  -46,  -46,  -46,  -46, +      -46,  -46,  -46,  -46,  -46,  -46,  -46 +    }, + +    { +       11,   48,  -47,  -47,   48,   48,   48,   48,   48,   48, +       48,   48,   48,   48,   48,   48,   48 +    }, + +    { +       11,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48, +      -48,  -48,  -48,  -48,  -48,  -48,  -48 +    }, + +    { +       11,   49,   49,   50,   49,  -49,   49,   49,  -49,   49, +       49,   49,   49,   49,   49,  -49,   49 + +    }, + +    { +       11,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50,  -50, +      -50,  -50,  -50,  -50,  -50,  -50,  -50 +    }, + +    { +       11,  -51,  -51,   52,  -51,  -51,  -51,  -51,  -51,  -51, +      -51,  -51,  -51,  -51,  -51,  -51,  -51 +    }, + +    { +       11,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52, +      -52,  -52,  -52,  -52,  -52,  -52,  -52 +    }, + +    { +       11,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53, +      -53,  -53,  -53,  -53,  -53,  -53,  -53 +    }, + +    { +       11,   54,   54,  -54,   54,   54,   54,   54,   54,   54, +       54,   54,   54,   54,   54,   54,   54 + +    }, + +    { +       11,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55,  -55, +      -55,  -55,  -55,  -55,  -55,  -55,  -55 +    }, + +    { +       11,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56,  -56, +      -56,   60,   57,   57,  -56,  -56,  -56 +    }, + +    { +       11,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57, +      -57,   57,   57,   57,  -57,  -57,  -57 +    }, + +    { +       11,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58, +      -58,  -58,  -58,  -58,  -58,  -58,  -58 +    }, + +    { +       11,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59,  -59, +      -59,  -59,  -59,  -59,  -59,  -59,  -59 + +    }, + +    { +       11,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60, +      -60,   57,   57,   57,  -60,  -60,  -60 +    }, + +    } ; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state  ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[]  ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up zconftext. + */ +#define YY_DO_BEFORE_ACTION \ +	(yytext_ptr) = yy_bp; \ +	zconfleng = (size_t) (yy_cp - yy_bp); \ +	(yy_hold_char) = *yy_cp; \ +	*yy_cp = '\0'; \ +	(yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 33 +#define YY_END_OF_BUFFER 34 +/* This struct is not used in this scanner, +   but its presence is necessary. */ +struct yy_trans_info +	{ +	flex_int32_t yy_verify; +	flex_int32_t yy_nxt; +	}; +static yyconst flex_int16_t yy_accept[61] = +    {   0, +        0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +       34,    5,    4,    2,    3,    7,    8,    6,   32,   29, +       31,   24,   28,   27,   26,   22,   17,   13,   16,   20, +       22,   11,   12,   19,   19,   14,   22,   22,    4,    2, +        3,    3,    1,    6,   32,   29,   31,   30,   24,   23, +       26,   25,   15,   20,    9,   19,   19,   21,   10,   18 +    } ; + +static yyconst flex_int32_t yy_ec[256] = +    {   0, +        1,    1,    1,    1,    1,    1,    1,    1,    2,    3, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    2,    4,    5,    6,    1,    1,    7,    8,    9, +       10,    1,    1,    1,   11,   12,   12,   13,   13,   13, +       13,   13,   13,   13,   13,   13,   13,    1,    1,    1, +       14,    1,    1,    1,   13,   13,   13,   13,   13,   13, +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13, +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13, +        1,   15,    1,    1,   13,    1,   13,   13,   13,   13, + +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13, +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13, +       13,   13,    1,   16,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, + +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1, +        1,    1,    1,    1,    1 +    } ; + +extern int zconf_flex_debug; +int zconf_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *zconftext; +#define YY_NO_INPUT 1 + +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "lkc.h" + +#define START_STRSIZE	16 + +static struct { +	struct file *file; +	int lineno; +} current_pos; + +static char *text; +static int text_size, text_asize; + +struct buffer { +	struct buffer *parent; +	YY_BUFFER_STATE state; +}; + +struct buffer *current_buf; + +static int last_ts, first_ts; + +static void zconf_endhelp(void); +static void zconf_endfile(void); + +static void new_string(void) +{ +	text = xmalloc(START_STRSIZE); +	text_asize = START_STRSIZE; +	text_size = 0; +	*text = 0; +} + +static void append_string(const char *str, int size) +{ +	int new_size = text_size + size + 1; +	if (new_size > text_asize) { +		new_size += START_STRSIZE - 1; +		new_size &= -START_STRSIZE; +		text = realloc(text, new_size); +		text_asize = new_size; +	} +	memcpy(text + text_size, str, size); +	text_size += size; +	text[text_size] = 0; +} + +static void alloc_string(const char *str, int size) +{ +	text = xmalloc(size + 1); +	memcpy(text, str, size); +	text[size] = 0; +} + +#define INITIAL 0 +#define COMMAND 1 +#define HELP 2 +#define STRING 3 +#define PARAM 4 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. +   These are made visible to non-reentrant scanners for convenience. */ + +int zconflex_destroy (void ); + +int zconfget_debug (void ); + +void zconfset_debug (int debug_flag  ); + +YY_EXTRA_TYPE zconfget_extra (void ); + +void zconfset_extra (YY_EXTRA_TYPE user_defined  ); + +FILE *zconfget_in (void ); + +void zconfset_in  (FILE * in_str  ); + +FILE *zconfget_out (void ); + +void zconfset_out  (FILE * out_str  ); + +yy_size_t zconfget_leng (void ); + +char *zconfget_text (void ); + +int zconfget_lineno (void ); + +void zconfset_lineno (int line_number  ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int zconfwrap (void ); +#else +extern int zconfwrap (void ); +#endif +#endif + +    static void yyunput (int c,char *buf_ptr  ); +     +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ +	errno=0; \ +	while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ +	{ \ +		if( errno != EINTR) \ +		{ \ +			YY_FATAL_ERROR( "input in flex scanner failed" ); \ +			break; \ +		} \ +		errno=0; \ +		clearerr(zconfin); \ +	}\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int zconflex (void); + +#define YY_DECL int zconflex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after zconftext and zconfleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ +	YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ +	register yy_state_type yy_current_state; +	register char *yy_cp, *yy_bp; +	register int yy_act; +     +	int str = 0; +	int ts, i; + +	if ( !(yy_init) ) +		{ +		(yy_init) = 1; + +#ifdef YY_USER_INIT +		YY_USER_INIT; +#endif + +		if ( ! (yy_start) ) +			(yy_start) = 1;	/* first start state */ + +		if ( ! zconfin ) +			zconfin = stdin; + +		if ( ! zconfout ) +			zconfout = stdout; + +		if ( ! YY_CURRENT_BUFFER ) { +			zconfensure_buffer_stack (); +			YY_CURRENT_BUFFER_LVALUE = +				zconf_create_buffer(zconfin,YY_BUF_SIZE ); +		} + +		zconf_load_buffer_state( ); +		} + +	while ( 1 )		/* loops until end-of-file is reached */ +		{ +		yy_cp = (yy_c_buf_p); + +		/* Support of zconftext. */ +		*yy_cp = (yy_hold_char); + +		/* yy_bp points to the position in yy_ch_buf of the start of +		 * the current run. +		 */ +		yy_bp = yy_cp; + +		yy_current_state = (yy_start); +yy_match: +		while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 ) +			++yy_cp; + +		yy_current_state = -yy_current_state; + +yy_find_action: +		yy_act = yy_accept[yy_current_state]; + +		YY_DO_BEFORE_ACTION; + +do_action:	/* This label is used only to access EOF actions. */ + +		switch ( yy_act ) +	{ /* beginning of action switch */ +case 1: +/* rule 1 can match eol */ +case 2: +/* rule 2 can match eol */ +YY_RULE_SETUP +{ +	current_file->lineno++; +	return T_EOL; +} +	YY_BREAK +case 3: +YY_RULE_SETUP + +	YY_BREAK +case 4: +YY_RULE_SETUP +{ +	BEGIN(COMMAND); +} +	YY_BREAK +case 5: +YY_RULE_SETUP +{ +	unput(zconftext[0]); +	BEGIN(COMMAND); +} +	YY_BREAK + +case 6: +YY_RULE_SETUP +{ +		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); +		BEGIN(PARAM); +		current_pos.file = current_file; +		current_pos.lineno = current_file->lineno; +		if (id && id->flags & TF_COMMAND) { +			zconflval.id = id; +			return id->token; +		} +		alloc_string(zconftext, zconfleng); +		zconflval.string = text; +		return T_WORD; +	} +	YY_BREAK +case 7: +YY_RULE_SETUP + +	YY_BREAK +case 8: +/* rule 8 can match eol */ +YY_RULE_SETUP +{ +		BEGIN(INITIAL); +		current_file->lineno++; +		return T_EOL; +	} +	YY_BREAK + +case 9: +YY_RULE_SETUP +return T_AND; +	YY_BREAK +case 10: +YY_RULE_SETUP +return T_OR; +	YY_BREAK +case 11: +YY_RULE_SETUP +return T_OPEN_PAREN; +	YY_BREAK +case 12: +YY_RULE_SETUP +return T_CLOSE_PAREN; +	YY_BREAK +case 13: +YY_RULE_SETUP +return T_NOT; +	YY_BREAK +case 14: +YY_RULE_SETUP +return T_EQUAL; +	YY_BREAK +case 15: +YY_RULE_SETUP +return T_UNEQUAL; +	YY_BREAK +case 16: +YY_RULE_SETUP +{ +		str = zconftext[0]; +		new_string(); +		BEGIN(STRING); +	} +	YY_BREAK +case 17: +/* rule 17 can match eol */ +YY_RULE_SETUP +BEGIN(INITIAL); current_file->lineno++; return T_EOL; +	YY_BREAK +case 18: +YY_RULE_SETUP +/* ignore */ +	YY_BREAK +case 19: +YY_RULE_SETUP +{ +		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); +		if (id && id->flags & TF_PARAM) { +			zconflval.id = id; +			return id->token; +		} +		alloc_string(zconftext, zconfleng); +		zconflval.string = text; +		return T_WORD; +	} +	YY_BREAK +case 20: +YY_RULE_SETUP +/* comment */ +	YY_BREAK +case 21: +/* rule 21 can match eol */ +YY_RULE_SETUP +current_file->lineno++; +	YY_BREAK +case 22: +YY_RULE_SETUP + +	YY_BREAK +case YY_STATE_EOF(PARAM): +{ +		BEGIN(INITIAL); +	} +	YY_BREAK + +case 23: +/* rule 23 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ +		append_string(zconftext, zconfleng); +		zconflval.string = text; +		return T_WORD_QUOTE; +	} +	YY_BREAK +case 24: +YY_RULE_SETUP +{ +		append_string(zconftext, zconfleng); +	} +	YY_BREAK +case 25: +/* rule 25 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ +		append_string(zconftext + 1, zconfleng - 1); +		zconflval.string = text; +		return T_WORD_QUOTE; +	} +	YY_BREAK +case 26: +YY_RULE_SETUP +{ +		append_string(zconftext + 1, zconfleng - 1); +	} +	YY_BREAK +case 27: +YY_RULE_SETUP +{ +		if (str == zconftext[0]) { +			BEGIN(PARAM); +			zconflval.string = text; +			return T_WORD_QUOTE; +		} else +			append_string(zconftext, 1); +	} +	YY_BREAK +case 28: +/* rule 28 can match eol */ +YY_RULE_SETUP +{ +		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); +		current_file->lineno++; +		BEGIN(INITIAL); +		return T_EOL; +	} +	YY_BREAK +case YY_STATE_EOF(STRING): +{ +		BEGIN(INITIAL); +	} +	YY_BREAK + +case 29: +YY_RULE_SETUP +{ +		ts = 0; +		for (i = 0; i < zconfleng; i++) { +			if (zconftext[i] == '\t') +				ts = (ts & ~7) + 8; +			else +				ts++; +		} +		last_ts = ts; +		if (first_ts) { +			if (ts < first_ts) { +				zconf_endhelp(); +				return T_HELPTEXT; +			} +			ts -= first_ts; +			while (ts > 8) { +				append_string("        ", 8); +				ts -= 8; +			} +			append_string("        ", ts); +		} +	} +	YY_BREAK +case 30: +/* rule 30 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ +YY_RULE_SETUP +{ +		current_file->lineno++; +		zconf_endhelp(); +		return T_HELPTEXT; +	} +	YY_BREAK +case 31: +/* rule 31 can match eol */ +YY_RULE_SETUP +{ +		current_file->lineno++; +		append_string("\n", 1); +	} +	YY_BREAK +case 32: +YY_RULE_SETUP +{ +		while (zconfleng) { +			if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t')) +				break; +			zconfleng--; +		} +		append_string(zconftext, zconfleng); +		if (!first_ts) +			first_ts = last_ts; +	} +	YY_BREAK +case YY_STATE_EOF(HELP): +{ +		zconf_endhelp(); +		return T_HELPTEXT; +	} +	YY_BREAK + +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(COMMAND): +{ +	if (current_file) { +		zconf_endfile(); +		return T_EOL; +	} +	fclose(zconfin); +	yyterminate(); +} +	YY_BREAK +case 33: +YY_RULE_SETUP +YY_FATAL_ERROR( "flex scanner jammed" ); +	YY_BREAK + +	case YY_END_OF_BUFFER: +		{ +		/* Amount of text matched not including the EOB char. */ +		int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + +		/* Undo the effects of YY_DO_BEFORE_ACTION. */ +		*yy_cp = (yy_hold_char); +		YY_RESTORE_YY_MORE_OFFSET + +		if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) +			{ +			/* We're scanning a new file or input source.  It's +			 * possible that this happened because the user +			 * just pointed zconfin at a new source and called +			 * zconflex().  If so, then we have to assure +			 * consistency between YY_CURRENT_BUFFER and our +			 * globals.  Here is the right place to do so, because +			 * this is the first action (other than possibly a +			 * back-up) that will match for the new input source. +			 */ +			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; +			YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; +			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; +			} + +		/* Note that here we test for yy_c_buf_p "<=" to the position +		 * of the first EOB in the buffer, since yy_c_buf_p will +		 * already have been incremented past the NUL character +		 * (since all states make transitions on EOB to the +		 * end-of-buffer state).  Contrast this with the test +		 * in input(). +		 */ +		if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) +			{ /* This was really a NUL. */ +			yy_state_type yy_next_state; + +			(yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + +			yy_current_state = yy_get_previous_state(  ); + +			/* Okay, we're now positioned to make the NUL +			 * transition.  We couldn't have +			 * yy_get_previous_state() go ahead and do it +			 * for us because it doesn't know how to deal +			 * with the possibility of jamming (and we don't +			 * want to build jamming into it because then it +			 * will run more slowly). +			 */ + +			yy_next_state = yy_try_NUL_trans( yy_current_state ); + +			yy_bp = (yytext_ptr) + YY_MORE_ADJ; + +			if ( yy_next_state ) +				{ +				/* Consume the NUL. */ +				yy_cp = ++(yy_c_buf_p); +				yy_current_state = yy_next_state; +				goto yy_match; +				} + +			else +				{ +				yy_cp = (yy_c_buf_p); +				goto yy_find_action; +				} +			} + +		else switch ( yy_get_next_buffer(  ) ) +			{ +			case EOB_ACT_END_OF_FILE: +				{ +				(yy_did_buffer_switch_on_eof) = 0; + +				if ( zconfwrap( ) ) +					{ +					/* Note: because we've taken care in +					 * yy_get_next_buffer() to have set up +					 * zconftext, we can now set up +					 * yy_c_buf_p so that if some total +					 * hoser (like flex itself) wants to +					 * call the scanner after we return the +					 * YY_NULL, it'll still work - another +					 * YY_NULL will get returned. +					 */ +					(yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + +					yy_act = YY_STATE_EOF(YY_START); +					goto do_action; +					} + +				else +					{ +					if ( ! (yy_did_buffer_switch_on_eof) ) +						YY_NEW_FILE; +					} +				break; +				} + +			case EOB_ACT_CONTINUE_SCAN: +				(yy_c_buf_p) = +					(yytext_ptr) + yy_amount_of_matched_text; + +				yy_current_state = yy_get_previous_state(  ); + +				yy_cp = (yy_c_buf_p); +				yy_bp = (yytext_ptr) + YY_MORE_ADJ; +				goto yy_match; + +			case EOB_ACT_LAST_MATCH: +				(yy_c_buf_p) = +				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + +				yy_current_state = yy_get_previous_state(  ); + +				yy_cp = (yy_c_buf_p); +				yy_bp = (yytext_ptr) + YY_MORE_ADJ; +				goto yy_find_action; +			} +		break; +		} + +	default: +		YY_FATAL_ERROR( +			"fatal flex scanner internal error--no action found" ); +	} /* end of action switch */ +		} /* end of scanning one token */ +} /* end of zconflex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + *	EOB_ACT_LAST_MATCH - + *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position + *	EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ +    	register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; +	register char *source = (yytext_ptr); +	register int number_to_move, i; +	int ret_val; + +	if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) +		YY_FATAL_ERROR( +		"fatal flex scanner internal error--end of buffer missed" ); + +	if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) +		{ /* Don't try to fill the buffer, so this is an EOF. */ +		if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) +			{ +			/* We matched a single character, the EOB, so +			 * treat this as a final EOF. +			 */ +			return EOB_ACT_END_OF_FILE; +			} + +		else +			{ +			/* We matched some text prior to the EOB, first +			 * process it. +			 */ +			return EOB_ACT_LAST_MATCH; +			} +		} + +	/* Try to read more data. */ + +	/* First move last chars to start of buffer. */ +	number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + +	for ( i = 0; i < number_to_move; ++i ) +		*(dest++) = *(source++); + +	if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) +		/* don't do the read, it's not guaranteed to return an EOF, +		 * just force an EOF +		 */ +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + +	else +		{ +			yy_size_t num_to_read = +			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + +		while ( num_to_read <= 0 ) +			{ /* Not enough room in the buffer - grow it. */ + +			/* just a shorter name for the current buffer */ +			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + +			int yy_c_buf_p_offset = +				(int) ((yy_c_buf_p) - b->yy_ch_buf); + +			if ( b->yy_is_our_buffer ) +				{ +				yy_size_t new_size = b->yy_buf_size * 2; + +				if ( new_size <= 0 ) +					b->yy_buf_size += b->yy_buf_size / 8; +				else +					b->yy_buf_size *= 2; + +				b->yy_ch_buf = (char *) +					/* Include room in for 2 EOB chars. */ +					zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  ); +				} +			else +				/* Can't grow it, we don't own it. */ +				b->yy_ch_buf = 0; + +			if ( ! b->yy_ch_buf ) +				YY_FATAL_ERROR( +				"fatal error - scanner input buffer overflow" ); + +			(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + +			num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - +						number_to_move - 1; + +			} + +		if ( num_to_read > YY_READ_BUF_SIZE ) +			num_to_read = YY_READ_BUF_SIZE; + +		/* Read in more data. */ +		YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), +			(yy_n_chars), num_to_read ); + +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); +		} + +	if ( (yy_n_chars) == 0 ) +		{ +		if ( number_to_move == YY_MORE_ADJ ) +			{ +			ret_val = EOB_ACT_END_OF_FILE; +			zconfrestart(zconfin  ); +			} + +		else +			{ +			ret_val = EOB_ACT_LAST_MATCH; +			YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = +				YY_BUFFER_EOF_PENDING; +			} +		} + +	else +		ret_val = EOB_ACT_CONTINUE_SCAN; + +	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { +		/* Extend the array by 50%, plus the number we really need. */ +		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); +		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  ); +		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) +			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); +	} + +	(yy_n_chars) += number_to_move; +	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; +	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + +	(yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + +	return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +    static yy_state_type yy_get_previous_state (void) +{ +	register yy_state_type yy_current_state; +	register char *yy_cp; +     +	yy_current_state = (yy_start); + +	for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) +		{ +		yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; +		} + +	return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + *	next_state = yy_try_NUL_trans( current_state ); + */ +    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state ) +{ +	register int yy_is_jam; +     +	yy_current_state = yy_nxt[yy_current_state][1]; +	yy_is_jam = (yy_current_state <= 0); + +		return yy_is_jam ? 0 : yy_current_state; +} + +    static void yyunput (int c, register char * yy_bp ) +{ +	register char *yy_cp; +     +    yy_cp = (yy_c_buf_p); + +	/* undo effects of setting up zconftext */ +	*yy_cp = (yy_hold_char); + +	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) +		{ /* need to shift things up to make room */ +		/* +2 for EOB chars. */ +		register yy_size_t number_to_move = (yy_n_chars) + 2; +		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ +					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; +		register char *source = +				&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + +		while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) +			*--dest = *--source; + +		yy_cp += (int) (dest - source); +		yy_bp += (int) (dest - source); +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = +			(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + +		if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) +			YY_FATAL_ERROR( "flex scanner push-back overflow" ); +		} + +	*--yy_cp = (char) c; + +	(yytext_ptr) = yy_bp; +	(yy_hold_char) = *yy_cp; +	(yy_c_buf_p) = yy_cp; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +    static int yyinput (void) +#else +    static int input  (void) +#endif + +{ +	int c; +     +	*(yy_c_buf_p) = (yy_hold_char); + +	if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) +		{ +		/* yy_c_buf_p now points to the character we want to return. +		 * If this occurs *before* the EOB characters, then it's a +		 * valid NUL; if not, then we've hit the end of the buffer. +		 */ +		if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) +			/* This was really a NUL. */ +			*(yy_c_buf_p) = '\0'; + +		else +			{ /* need more input */ +			yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); +			++(yy_c_buf_p); + +			switch ( yy_get_next_buffer(  ) ) +				{ +				case EOB_ACT_LAST_MATCH: +					/* This happens because yy_g_n_b() +					 * sees that we've accumulated a +					 * token and flags that we need to +					 * try matching the token before +					 * proceeding.  But for input(), +					 * there's no matching to consider. +					 * So convert the EOB_ACT_LAST_MATCH +					 * to EOB_ACT_END_OF_FILE. +					 */ + +					/* Reset buffer status. */ +					zconfrestart(zconfin ); + +					/*FALLTHROUGH*/ + +				case EOB_ACT_END_OF_FILE: +					{ +					if ( zconfwrap( ) ) +						return EOF; + +					if ( ! (yy_did_buffer_switch_on_eof) ) +						YY_NEW_FILE; +#ifdef __cplusplus +					return yyinput(); +#else +					return input(); +#endif +					} + +				case EOB_ACT_CONTINUE_SCAN: +					(yy_c_buf_p) = (yytext_ptr) + offset; +					break; +				} +			} +		} + +	c = *(unsigned char *) (yy_c_buf_p);	/* cast for 8-bit char's */ +	*(yy_c_buf_p) = '\0';	/* preserve zconftext */ +	(yy_hold_char) = *++(yy_c_buf_p); + +	return c; +} +#endif	/* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + *  + * @note This function does not reset the start condition to @c INITIAL . + */ +    void zconfrestart  (FILE * input_file ) +{ +     +	if ( ! YY_CURRENT_BUFFER ){ +        zconfensure_buffer_stack (); +		YY_CURRENT_BUFFER_LVALUE = +            zconf_create_buffer(zconfin,YY_BUF_SIZE ); +	} + +	zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); +	zconf_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + *  + */ +    void zconf_switch_to_buffer  (YY_BUFFER_STATE  new_buffer ) +{ +     +	/* TODO. We should be able to replace this entire function body +	 * with +	 *		zconfpop_buffer_state(); +	 *		zconfpush_buffer_state(new_buffer); +     */ +	zconfensure_buffer_stack (); +	if ( YY_CURRENT_BUFFER == new_buffer ) +		return; + +	if ( YY_CURRENT_BUFFER ) +		{ +		/* Flush out information for old buffer. */ +		*(yy_c_buf_p) = (yy_hold_char); +		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); +		} + +	YY_CURRENT_BUFFER_LVALUE = new_buffer; +	zconf_load_buffer_state( ); + +	/* We don't actually know whether we did this switch during +	 * EOF (zconfwrap()) processing, but the only time this flag +	 * is looked at is after zconfwrap() is called, so it's safe +	 * to go ahead and always set it. +	 */ +	(yy_did_buffer_switch_on_eof) = 1; +} + +static void zconf_load_buffer_state  (void) +{ +    	(yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; +	(yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; +	zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; +	(yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + *  + * @return the allocated buffer state. + */ +    YY_BUFFER_STATE zconf_create_buffer  (FILE * file, int  size ) +{ +	YY_BUFFER_STATE b; +     +	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  ); +	if ( ! b ) +		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + +	b->yy_buf_size = size; + +	/* yy_ch_buf has to be 2 characters longer than the size given because +	 * we need to put in 2 end-of-buffer characters. +	 */ +	b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2  ); +	if ( ! b->yy_ch_buf ) +		YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); + +	b->yy_is_our_buffer = 1; + +	zconf_init_buffer(b,file ); + +	return b; +} + +/** Destroy the buffer. + * @param b a buffer created with zconf_create_buffer() + *  + */ +    void zconf_delete_buffer (YY_BUFFER_STATE  b ) +{ +     +	if ( ! b ) +		return; + +	if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ +		YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + +	if ( b->yy_is_our_buffer ) +		zconffree((void *) b->yy_ch_buf  ); + +	zconffree((void *) b  ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a zconfrestart() or at EOF. + */ +    static void zconf_init_buffer  (YY_BUFFER_STATE  b, FILE * file ) + +{ +	int oerrno = errno; +     +	zconf_flush_buffer(b ); + +	b->yy_input_file = file; +	b->yy_fill_buffer = 1; + +    /* If b is the current buffer, then zconf_init_buffer was _probably_ +     * called from zconfrestart() or through yy_get_next_buffer. +     * In that case, we don't want to reset the lineno or column. +     */ +    if (b != YY_CURRENT_BUFFER){ +        b->yy_bs_lineno = 1; +        b->yy_bs_column = 0; +    } + +        b->yy_is_interactive = 0; +     +	errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + *  + */ +    void zconf_flush_buffer (YY_BUFFER_STATE  b ) +{ +    	if ( ! b ) +		return; + +	b->yy_n_chars = 0; + +	/* We always need two end-of-buffer characters.  The first causes +	 * a transition to the end-of-buffer state.  The second causes +	 * a jam in that state. +	 */ +	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; +	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + +	b->yy_buf_pos = &b->yy_ch_buf[0]; + +	b->yy_at_bol = 1; +	b->yy_buffer_status = YY_BUFFER_NEW; + +	if ( b == YY_CURRENT_BUFFER ) +		zconf_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + *  the current state. This function will allocate the stack + *  if necessary. + *  @param new_buffer The new state. + *   + */ +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ +    	if (new_buffer == NULL) +		return; + +	zconfensure_buffer_stack(); + +	/* This block is copied from zconf_switch_to_buffer. */ +	if ( YY_CURRENT_BUFFER ) +		{ +		/* Flush out information for old buffer. */ +		*(yy_c_buf_p) = (yy_hold_char); +		YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); +		YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); +		} + +	/* Only push if top exists. Otherwise, replace top. */ +	if (YY_CURRENT_BUFFER) +		(yy_buffer_stack_top)++; +	YY_CURRENT_BUFFER_LVALUE = new_buffer; + +	/* copied from zconf_switch_to_buffer. */ +	zconf_load_buffer_state( ); +	(yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + *  The next element becomes the new top. + *   + */ +void zconfpop_buffer_state (void) +{ +    	if (!YY_CURRENT_BUFFER) +		return; + +	zconf_delete_buffer(YY_CURRENT_BUFFER ); +	YY_CURRENT_BUFFER_LVALUE = NULL; +	if ((yy_buffer_stack_top) > 0) +		--(yy_buffer_stack_top); + +	if (YY_CURRENT_BUFFER) { +		zconf_load_buffer_state( ); +		(yy_did_buffer_switch_on_eof) = 1; +	} +} + +/* Allocates the stack if it does not exist. + *  Guarantees space for at least one push. + */ +static void zconfensure_buffer_stack (void) +{ +	yy_size_t num_to_alloc; +     +	if (!(yy_buffer_stack)) { + +		/* First allocation is just for 2 elements, since we don't know if this +		 * scanner will even need a stack. We use 2 instead of 1 to avoid an +		 * immediate realloc on the next call. +         */ +		num_to_alloc = 1; +		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc +								(num_to_alloc * sizeof(struct yy_buffer_state*) +								); +		if ( ! (yy_buffer_stack) ) +			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); +								   +		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); +				 +		(yy_buffer_stack_max) = num_to_alloc; +		(yy_buffer_stack_top) = 0; +		return; +	} + +	if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + +		/* Increase the buffer to prepare for a possible push. */ +		int grow_size = 8 /* arbitrary grow size */; + +		num_to_alloc = (yy_buffer_stack_max) + grow_size; +		(yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc +								((yy_buffer_stack), +								num_to_alloc * sizeof(struct yy_buffer_state*) +								); +		if ( ! (yy_buffer_stack) ) +			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); + +		/* zero only the new slots.*/ +		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); +		(yy_buffer_stack_max) = num_to_alloc; +	} +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + *  + * @return the newly allocated buffer state object.  + */ +YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size ) +{ +	YY_BUFFER_STATE b; +     +	if ( size < 2 || +	     base[size-2] != YY_END_OF_BUFFER_CHAR || +	     base[size-1] != YY_END_OF_BUFFER_CHAR ) +		/* They forgot to leave room for the EOB's. */ +		return 0; + +	b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state )  ); +	if ( ! b ) +		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); + +	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */ +	b->yy_buf_pos = b->yy_ch_buf = base; +	b->yy_is_our_buffer = 0; +	b->yy_input_file = 0; +	b->yy_n_chars = b->yy_buf_size; +	b->yy_is_interactive = 0; +	b->yy_at_bol = 1; +	b->yy_fill_buffer = 0; +	b->yy_buffer_status = YY_BUFFER_NEW; + +	zconf_switch_to_buffer(b  ); + +	return b; +} + +/** Setup the input buffer state to scan a string. The next call to zconflex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + *  + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + *       zconf_scan_bytes() instead. + */ +YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr ) +{ +     +	return zconf_scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + *  + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len ) +{ +	YY_BUFFER_STATE b; +	char *buf; +	yy_size_t n; +	yy_size_t i; +     +	/* Get memory for full buffer, including space for trailing EOB's. */ +	n = _yybytes_len + 2; +	buf = (char *) zconfalloc(n  ); +	if ( ! buf ) +		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); + +	for ( i = 0; i < _yybytes_len; ++i ) +		buf[i] = yybytes[i]; + +	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + +	b = zconf_scan_buffer(buf,n ); +	if ( ! b ) +		YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); + +	/* It's okay to grow etc. this buffer, and we should throw it +	 * away when we're done. +	 */ +	b->yy_is_our_buffer = 1; + +	return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ +    	(void) fprintf( stderr, "%s\n", msg ); +	exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ +	do \ +		{ \ +		/* Undo effects of setting up zconftext. */ \ +        int yyless_macro_arg = (n); \ +        YY_LESS_LINENO(yyless_macro_arg);\ +		zconftext[zconfleng] = (yy_hold_char); \ +		(yy_c_buf_p) = zconftext + yyless_macro_arg; \ +		(yy_hold_char) = *(yy_c_buf_p); \ +		*(yy_c_buf_p) = '\0'; \ +		zconfleng = yyless_macro_arg; \ +		} \ +	while ( 0 ) + +/* Accessor  methods (get/set functions) to struct members. */ + +/** Get the current line number. + *  + */ +int zconfget_lineno  (void) +{ +         +    return zconflineno; +} + +/** Get the input stream. + *  + */ +FILE *zconfget_in  (void) +{ +        return zconfin; +} + +/** Get the output stream. + *  + */ +FILE *zconfget_out  (void) +{ +        return zconfout; +} + +/** Get the length of the current token. + *  + */ +yy_size_t zconfget_leng  (void) +{ +        return zconfleng; +} + +/** Get the current token. + *  + */ + +char *zconfget_text  (void) +{ +        return zconftext; +} + +/** Set the current line number. + * @param line_number + *  + */ +void zconfset_lineno (int  line_number ) +{ +     +    zconflineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + *  + * @see zconf_switch_to_buffer + */ +void zconfset_in (FILE *  in_str ) +{ +        zconfin = in_str ; +} + +void zconfset_out (FILE *  out_str ) +{ +        zconfout = out_str ; +} + +int zconfget_debug  (void) +{ +        return zconf_flex_debug; +} + +void zconfset_debug (int  bdebug ) +{ +        zconf_flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ +        /* Initialization is the same as for the non-reentrant scanner. +     * This function is called from zconflex_destroy(), so don't allocate here. +     */ + +    (yy_buffer_stack) = 0; +    (yy_buffer_stack_top) = 0; +    (yy_buffer_stack_max) = 0; +    (yy_c_buf_p) = (char *) 0; +    (yy_init) = 0; +    (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT +    zconfin = stdin; +    zconfout = stdout; +#else +    zconfin = (FILE *) 0; +    zconfout = (FILE *) 0; +#endif + +    /* For future reference: Set errno on error, since we are called by +     * zconflex_init() +     */ +    return 0; +} + +/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ +int zconflex_destroy  (void) +{ +     +    /* Pop the buffer stack, destroying each element. */ +	while(YY_CURRENT_BUFFER){ +		zconf_delete_buffer(YY_CURRENT_BUFFER  ); +		YY_CURRENT_BUFFER_LVALUE = NULL; +		zconfpop_buffer_state(); +	} + +	/* Destroy the stack itself. */ +	zconffree((yy_buffer_stack) ); +	(yy_buffer_stack) = NULL; + +    /* Reset the globals. This is important in a non-reentrant scanner so the next time +     * zconflex() is called, initialization will occur. */ +    yy_init_globals( ); + +    return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ +	register int i; +	for ( i = 0; i < n; ++i ) +		s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ +	register int n; +	for ( n = 0; s[n]; ++n ) +		; + +	return n; +} +#endif + +void *zconfalloc (yy_size_t  size ) +{ +	return (void *) malloc( size ); +} + +void *zconfrealloc  (void * ptr, yy_size_t  size ) +{ +	/* The cast to (char *) in the following accommodates both +	 * implementations that use char* generic pointers, and those +	 * that use void* generic pointers.  It works with the latter +	 * because both ANSI C and C++ allow castless assignment from +	 * any pointer type to void*, and deal with argument conversions +	 * as though doing an assignment. +	 */ +	return (void *) realloc( (char *) ptr, size ); +} + +void zconffree (void * ptr ) +{ +	free( (char *) ptr );	/* see zconfrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +void zconf_starthelp(void) +{ +	new_string(); +	last_ts = first_ts = 0; +	BEGIN(HELP); +} + +static void zconf_endhelp(void) +{ +	zconflval.string = text; +	BEGIN(INITIAL); +} + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ +	char *env, fullname[PATH_MAX+1]; +	FILE *f; + +	f = fopen(name, "r"); +	if (!f && name != NULL && name[0] != '/') { +		env = getenv(SRCTREE); +		if (env) { +			sprintf(fullname, "%s/%s", env, name); +			f = fopen(fullname, "r"); +		} +	} +	return f; +} + +void zconf_initscan(const char *name) +{ +	zconfin = zconf_fopen(name); +	if (!zconfin) { +		printf("can't find file %s\n", name); +		exit(1); +	} + +	current_buf = xmalloc(sizeof(*current_buf)); +	memset(current_buf, 0, sizeof(*current_buf)); + +	current_file = file_lookup(name); +	current_file->lineno = 1; +} + +void zconf_nextfile(const char *name) +{ +	struct file *iter; +	struct file *file = file_lookup(name); +	struct buffer *buf = xmalloc(sizeof(*buf)); +	memset(buf, 0, sizeof(*buf)); + +	current_buf->state = YY_CURRENT_BUFFER; +	zconfin = zconf_fopen(file->name); +	if (!zconfin) { +		printf("%s:%d: can't open file \"%s\"\n", +		    zconf_curname(), zconf_lineno(), file->name); +		exit(1); +	} +	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); +	buf->parent = current_buf; +	current_buf = buf; + +	for (iter = current_file->parent; iter; iter = iter->parent ) { +		if (!strcmp(current_file->name,iter->name) ) { +			printf("%s:%d: recursive inclusion detected. " +			       "Inclusion path:\n  current file : '%s'\n", +			       zconf_curname(), zconf_lineno(), +			       zconf_curname()); +			iter = current_file->parent; +			while (iter && \ +			       strcmp(iter->name,current_file->name)) { +				printf("  included from: '%s:%d'\n", +				       iter->name, iter->lineno-1); +				iter = iter->parent; +			} +			if (iter) +				printf("  included from: '%s:%d'\n", +				       iter->name, iter->lineno+1); +			exit(1); +		} +	} +	file->lineno = 1; +	file->parent = current_file; +	current_file = file; +} + +static void zconf_endfile(void) +{ +	struct buffer *parent; + +	current_file = current_file->parent; + +	parent = current_buf->parent; +	if (parent) { +		fclose(zconfin); +		zconf_delete_buffer(YY_CURRENT_BUFFER); +		zconf_switch_to_buffer(parent->state); +	} +	free(current_buf); +	current_buf = parent; +} + +int zconf_lineno(void) +{ +	return current_pos.lineno; +} + +const char *zconf_curname(void) +{ +	return current_pos.file ? current_pos.file->name : "<none>"; +} + diff --git a/programs/src/kconfig/kconfig/zconf.tab.c b/programs/src/kconfig/kconfig/zconf.tab.c new file mode 100644 index 0000000..0864c7d --- /dev/null +++ b/programs/src/kconfig/kconfig/zconf.tab.c @@ -0,0 +1,2416 @@ +/* A Bison parser, made by GNU Bison 3.0.2.  */ + +/* Bison implementation for Yacc-like parsers in C + +   Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. + +   This program is free software: you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation, either version 3 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ + +/* As a special exception, you may create a larger work that contains +   part or all of the Bison parser skeleton and distribute that work +   under terms of your choice, so long as that work isn't itself a +   parser generator using the skeleton or a modified version thereof +   as a parser skeleton.  Alternatively, if you modify or redistribute +   the parser skeleton itself, you may (at your option) remove this +   special exception, which will cause the skeleton and the resulting +   Bison output files to be licensed under the GNU General Public +   License without this special exception. + +   This special exception was added by the Free Software Foundation in +   version 2.2 of Bison.  */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by +   simplifying the original so-called "semantic" parser.  */ + +/* All symbols defined below should begin with yy or YY, to avoid +   infringing on user name space.  This should be done even for local +   variables, as they might otherwise be expanded by user macros. +   There are some unavoidable exceptions within include files to +   define necessary library symbols; they are noted "INFRINGES ON +   USER NAME SPACE" below.  */ + +/* Identify Bison output.  */ +#define YYBISON 1 + +/* Bison version.  */ +#define YYBISON_VERSION "3.0.2" + +/* Skeleton name.  */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers.  */ +#define YYPURE 0 + +/* Push parsers.  */ +#define YYPUSH 0 + +/* Pull parsers.  */ +#define YYPULL 1 + + +/* Substitute the variable and function names.  */ +#define yyparse         zconfparse +#define yylex           zconflex +#define yyerror         zconferror +#define yydebug         zconfdebug +#define yynerrs         zconfnerrs + +#define yylval          zconflval +#define yychar          zconfchar + +/* Copy the first part of user declarations.  */ + + +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD		0x0001 +#define DEBUG_PARSE	0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + + + + +# ifndef YY_NULLPTR +#  if defined __cplusplus && 201103L <= __cplusplus +#   define YY_NULLPTR nullptr +#  else +#   define YY_NULLPTR 0 +#  endif +# endif + +/* Enabling verbose error messages.  */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + + +/* Debug traces.  */ +#ifndef YYDEBUG +# define YYDEBUG 1 +#endif +#if YYDEBUG +extern int zconfdebug; +#endif + +/* Token type.  */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE +  enum yytokentype +  { +    T_MAINMENU = 258, +    T_MENU = 259, +    T_ENDMENU = 260, +    T_SOURCE = 261, +    T_CHOICE = 262, +    T_ENDCHOICE = 263, +    T_COMMENT = 264, +    T_CONFIG = 265, +    T_MENUCONFIG = 266, +    T_HELP = 267, +    T_HELPTEXT = 268, +    T_IF = 269, +    T_ENDIF = 270, +    T_DEPENDS = 271, +    T_OPTIONAL = 272, +    T_PROMPT = 273, +    T_TYPE = 274, +    T_DEFAULT = 275, +    T_SELECT = 276, +    T_RANGE = 277, +    T_VISIBLE = 278, +    T_OPTION = 279, +    T_ON = 280, +    T_WORD = 281, +    T_WORD_QUOTE = 282, +    T_UNEQUAL = 283, +    T_CLOSE_PAREN = 284, +    T_OPEN_PAREN = 285, +    T_EOL = 286, +    T_OR = 287, +    T_AND = 288, +    T_EQUAL = 289, +    T_NOT = 290 +  }; +#endif + +/* Value type.  */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE YYSTYPE; +union YYSTYPE +{ + + +	char *string; +	struct file *file; +	struct symbol *symbol; +	struct expr *expr; +	struct menu *menu; +	const struct kconf_id *id; + + +}; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE zconflval; + +int zconfparse (void); + + + +/* Copy the second part of user declarations.  */ + + +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +#  define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +#  define YYSIZE_T size_t +# elif ! defined YYSIZE_T +#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +#  define YYSIZE_T size_t +# else +#  define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +#  if ENABLE_NLS +#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +#   define YY_(Msgid) dgettext ("bison-runtime", Msgid) +#  endif +# endif +# ifndef YY_ +#  define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__                                               \ +      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \ +     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +#  define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +#  define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ +     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +#  define _Noreturn __declspec (noreturn) +# else +#  define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E.  */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized.  */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ +    _Pragma ("GCC diagnostic push") \ +    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ +    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ +    _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols.  */ + +# ifdef YYSTACK_USE_ALLOCA +#  if YYSTACK_USE_ALLOCA +#   ifdef __GNUC__ +#    define YYSTACK_ALLOC __builtin_alloca +#   elif defined __BUILTIN_VA_ARG_INCR +#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +#   elif defined _AIX +#    define YYSTACK_ALLOC __alloca +#   elif defined _MSC_VER +#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +#    define alloca _alloca +#   else +#    define YYSTACK_ALLOC alloca +#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */ +#     ifndef EXIT_SUCCESS +#      define EXIT_SUCCESS 0 +#     endif +#    endif +#   endif +#  endif +# endif + +# ifdef YYSTACK_ALLOC +   /* Pacify GCC's 'empty if-body' warning.  */ +#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +#  ifndef YYSTACK_ALLOC_MAXIMUM +    /* The OS might guarantee only one guard page at the bottom of the stack, +       and a page size can be as small as 4096 bytes.  So we cannot safely +       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number +       to allow for a few compiler-allocated temporary stack slots.  */ +#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +#  endif +# else +#  define YYSTACK_ALLOC YYMALLOC +#  define YYSTACK_FREE YYFREE +#  ifndef YYSTACK_ALLOC_MAXIMUM +#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +#  endif +#  if (defined __cplusplus && ! defined EXIT_SUCCESS \ +       && ! ((defined YYMALLOC || defined malloc) \ +             && (defined YYFREE || defined free))) +#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +#   ifndef EXIT_SUCCESS +#    define EXIT_SUCCESS 0 +#   endif +#  endif +#  ifndef YYMALLOC +#   define YYMALLOC malloc +#   if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +#   endif +#  endif +#  ifndef YYFREE +#   define YYFREE free +#   if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +#   endif +#  endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ +     && (! defined __cplusplus \ +         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member.  */ +union yyalloc +{ +  yytype_int16 yyss_alloc; +  YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next.  */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with +   N elements.  */ +# define YYSTACK_BYTES(N) \ +     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ +      + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one.  The +   local variables YYSIZE and YYSTACKSIZE give the old and new number of +   elements in the stack, and YYPTR gives the new location of the +   stack.  Advance YYPTR to a properly aligned location for the next +   stack.  */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \ +    do                                                                  \ +      {                                                                 \ +        YYSIZE_T yynewbytes;                                            \ +        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \ +        Stack = &yyptr->Stack_alloc;                                    \ +        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ +        yyptr += yynewbytes / sizeof (*yyptr);                          \ +      }                                                                 \ +    while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST.  The source and destination do +   not overlap.  */ +# ifndef YYCOPY +#  if defined __GNUC__ && 1 < __GNUC__ +#   define YYCOPY(Dst, Src, Count) \ +      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +#  else +#   define YYCOPY(Dst, Src, Count)              \ +      do                                        \ +        {                                       \ +          YYSIZE_T yyi;                         \ +          for (yyi = 0; yyi < (Count); yyi++)   \ +            (Dst)[yyi] = (Src)[yyi];            \ +        }                                       \ +      while (0) +#  endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state.  */ +#define YYFINAL  11 +/* YYLAST -- Last index in YYTABLE.  */ +#define YYLAST   290 + +/* YYNTOKENS -- Number of terminals.  */ +#define YYNTOKENS  36 +/* YYNNTS -- Number of nonterminals.  */ +#define YYNNTS  50 +/* YYNRULES -- Number of rules.  */ +#define YYNRULES  118 +/* YYNSTATES -- Number of states.  */ +#define YYNSTATES  191 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned +   by yylex, with out-of-bounds checking.  */ +#define YYUNDEFTOK  2 +#define YYMAXUTOK   290 + +#define YYTRANSLATE(YYX)                                                \ +  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM +   as returned by yylex, without out-of-bounds checking.  */ +static const yytype_uint8 yytranslate[] = +{ +       0,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2, +       2,     2,     2,     2,     2,     2,     1,     2,     3,     4, +       5,     6,     7,     8,     9,    10,    11,    12,    13,    14, +      15,    16,    17,    18,    19,    20,    21,    22,    23,    24, +      25,    26,    27,    28,    29,    30,    31,    32,    33,    34, +      35 +}; + +#if YYDEBUG +  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */ +static const yytype_uint16 yyrline[] = +{ +       0,   103,   103,   103,   105,   105,   107,   109,   110,   111, +     112,   113,   114,   118,   122,   122,   122,   122,   122,   122, +     122,   122,   126,   127,   128,   129,   130,   131,   135,   136, +     142,   150,   156,   164,   174,   176,   177,   178,   179,   180, +     181,   184,   192,   198,   208,   214,   220,   223,   225,   236, +     237,   242,   251,   256,   264,   267,   269,   270,   271,   272, +     273,   276,   282,   293,   299,   309,   311,   316,   324,   332, +     335,   337,   338,   339,   344,   351,   358,   363,   371,   374, +     376,   377,   378,   381,   389,   396,   403,   409,   416,   418, +     419,   420,   423,   431,   433,   434,   437,   444,   446,   451, +     452,   455,   456,   457,   461,   462,   465,   466,   469,   470, +     471,   472,   473,   474,   475,   478,   479,   482,   483 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. +   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */ +static const char *const yytname[] = +{ +  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", +  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", +  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", +  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", +  "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", +  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", +  "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", +  "common_stmt", "option_error", "config_entry_start", "config_stmt", +  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", +  "config_option", "symbol_option", "symbol_option_list", +  "symbol_option_arg", "choice", "choice_entry", "choice_end", +  "choice_stmt", "choice_option_list", "choice_option", "choice_block", +  "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", +  "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", +  "comment", "comment_stmt", "help_start", "help", "depends_list", +  "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", +  "end", "nl", "if_expr", "expr", "symbol", "word_opt", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the +   (internal) symbol number NUM (which must be that of a token).  */ +static const yytype_uint16 yytoknum[] = +{ +       0,   256,   257,   258,   259,   260,   261,   262,   263,   264, +     265,   266,   267,   268,   269,   270,   271,   272,   273,   274, +     275,   276,   277,   278,   279,   280,   281,   282,   283,   284, +     285,   286,   287,   288,   289,   290 +}; +# endif + +#define YYPACT_NINF -90 + +#define yypact_value_is_default(Yystate) \ +  (!!((Yystate) == (-90))) + +#define YYTABLE_NINF -86 + +#define yytable_value_is_error(Yytable_value) \ +  0 + +  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing +     STATE-NUM.  */ +static const yytype_int16 yypact[] = +{ +       4,    42,   -90,    96,   -90,   111,   -90,    15,   -90,   -90, +      75,   -90,    82,    42,   104,    42,   110,   107,    42,   115, +     125,    -4,   121,   -90,   -90,   -90,   -90,   -90,   -90,   -90, +     -90,   162,   -90,   163,   -90,   -90,   -90,   -90,   -90,   -90, +     -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90, +     -90,   139,   -90,   -90,   138,   -90,   142,   -90,   143,   -90, +     152,   -90,   164,   167,   168,   -90,   -90,    -4,    -4,    77, +     -18,   -90,   177,   185,    33,    71,   195,   247,   236,    -2, +     236,   171,   -90,   -90,   -90,   -90,   -90,   -90,    41,   -90, +      -4,    -4,   138,    97,    97,   -90,   -90,   186,   187,   194, +      42,    42,    -4,   196,    97,   -90,   219,   -90,   -90,   -90, +     -90,   210,   -90,   -90,   204,    42,    42,   199,   -90,   -90, +     -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90, +     -90,   222,   -90,   223,   -90,   -90,   -90,   -90,   -90,   -90, +     -90,   -90,   -90,   -90,   215,   -90,   -90,   -90,   -90,   -90, +      -4,   222,   228,   222,    -5,   222,    97,    35,   229,   -90, +     -90,   222,   232,   222,    -4,   -90,   135,   233,   -90,   -90, +     234,   235,   222,   240,   -90,   -90,   237,   -90,   239,   -13, +     -90,   -90,   -90,   -90,   244,    42,   -90,   -90,   -90,   -90, +     -90 +}; + +  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. +     Performed when YYTABLE does not specify something else to do.  Zero +     means the default is an error.  */ +static const yytype_uint8 yydefact[] = +{ +       6,     0,   104,     0,     3,     0,     6,     6,    99,   100, +       0,     1,     0,     0,     0,     0,   117,     0,     0,     0, +       0,     0,     0,    14,    18,    15,    16,    20,    17,    19, +      21,     0,    22,     0,     7,    34,    25,    34,    26,    55, +      65,     8,    70,    23,    93,    79,     9,    27,    88,    24, +      10,     0,   105,     2,    74,    13,     0,   101,     0,   118, +       0,   102,     0,     0,     0,   115,   116,     0,     0,     0, +     108,   103,     0,     0,     0,     0,     0,     0,     0,    88, +       0,     0,    75,    83,    51,    84,    30,    32,     0,   112, +       0,     0,    67,     0,     0,    11,    12,     0,     0,     0, +       0,    97,     0,     0,     0,    47,     0,    40,    39,    35, +      36,     0,    38,    37,     0,     0,    97,     0,    59,    60, +      56,    58,    57,    66,    54,    53,    71,    73,    69,    72, +      68,   106,    95,     0,    94,    80,    82,    78,    81,    77, +      90,    91,    89,   111,   113,   114,   110,   109,    29,    86, +       0,   106,     0,   106,   106,   106,     0,     0,     0,    87, +      63,   106,     0,   106,     0,    96,     0,     0,    41,    98, +       0,     0,   106,    49,    46,    28,     0,    62,     0,   107, +      92,    42,    43,    44,     0,     0,    48,    61,    64,    45, +      50 +}; + +  /* YYPGOTO[NTERM-NUM].  */ +static const yytype_int16 yypgoto[] = +{ +     -90,   -90,   269,   271,   -90,    23,   -70,   -90,   -90,   -90, +     -90,   243,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -48, +     -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90,   -90, +     -90,   -20,   -90,   -90,   -90,   -90,   -90,   206,   205,   -68, +     -90,   -90,   169,    -1,    27,    -7,   118,   -66,   -89,   -90 +}; + +  /* YYDEFGOTO[NTERM-NUM].  */ +static const yytype_int16 yydefgoto[] = +{ +      -1,     3,     4,     5,    33,    34,   108,    35,    36,    37, +      38,    74,   109,   110,   157,   186,    39,    40,   124,    41, +      76,   120,    77,    42,   128,    43,    78,     6,    44,    45, +     137,    46,    80,    47,    48,    49,   111,   112,    81,   113, +      79,   134,   152,   153,    50,     7,   165,    69,    70,    60 +}; + +  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If +     positive, shift that token.  If negative, reduce the rule whose +     number is the opposite.  If YYTABLE_NINF, syntax error.  */ +static const yytype_int16 yytable[] = +{ +      10,    88,    89,    54,   146,   147,   119,     1,   122,   164, +      93,   141,    56,   142,    58,   156,    94,    62,     1,    90, +      91,   131,    65,    66,   144,   145,    67,    90,    91,   132, +     127,    68,   136,   -31,    97,     2,   154,   -31,   -31,   -31, +     -31,   -31,   -31,   -31,   -31,    98,    52,   -31,   -31,    99, +     -31,   100,   101,   102,   103,   104,   -31,   105,   129,   106, +     138,   173,    92,   141,   107,   142,   174,   172,     8,     9, +     143,   -33,    97,    90,    91,   -33,   -33,   -33,   -33,   -33, +     -33,   -33,   -33,    98,   166,   -33,   -33,    99,   -33,   100, +     101,   102,   103,   104,   -33,   105,    11,   106,   179,   151, +     123,   126,   107,   135,   125,   130,     2,   139,     2,    90, +      91,    -5,    12,    55,   161,    13,    14,    15,    16,    17, +      18,    19,    20,    65,    66,    21,    22,    23,    24,    25, +      26,    27,    28,    29,    30,    57,    59,    31,    61,    -4, +      12,    63,    32,    13,    14,    15,    16,    17,    18,    19, +      20,    64,    71,    21,    22,    23,    24,    25,    26,    27, +      28,    29,    30,    72,    73,    31,   180,    90,    91,    52, +      32,   -85,    97,    82,    83,   -85,   -85,   -85,   -85,   -85, +     -85,   -85,   -85,    84,   190,   -85,   -85,    99,   -85,   -85, +     -85,   -85,   -85,   -85,   -85,    85,    97,   106,    86,    87, +     -52,   -52,   140,   -52,   -52,   -52,   -52,    98,    95,   -52, +     -52,    99,   114,   115,   116,   117,    96,   148,   149,   150, +     158,   106,   155,   159,    97,   163,   118,   -76,   -76,   -76, +     -76,   -76,   -76,   -76,   -76,   160,   164,   -76,   -76,    99, +      13,    14,    15,    16,    17,    18,    19,    20,    91,   106, +      21,    22,    14,    15,   140,    17,    18,    19,    20,   168, +     175,    21,    22,   177,   181,   182,   183,    32,   187,   167, +     188,   169,   170,   171,   185,   189,    53,    51,    32,   176, +      75,   178,   121,     0,   133,   162,     0,     0,     0,     0, +     184 +}; + +static const yytype_int16 yycheck[] = +{ +       1,    67,    68,    10,    93,    94,    76,     3,    76,    14, +      28,    81,    13,    81,    15,   104,    34,    18,     3,    32, +      33,    23,    26,    27,    90,    91,    30,    32,    33,    31, +      78,    35,    80,     0,     1,    31,   102,     4,     5,     6, +       7,     8,     9,    10,    11,    12,    31,    14,    15,    16, +      17,    18,    19,    20,    21,    22,    23,    24,    78,    26, +      80,    26,    69,   133,    31,   133,    31,   156,    26,    27, +      29,     0,     1,    32,    33,     4,     5,     6,     7,     8, +       9,    10,    11,    12,   150,    14,    15,    16,    17,    18, +      19,    20,    21,    22,    23,    24,     0,    26,   164,   100, +      77,    78,    31,    80,    77,    78,    31,    80,    31,    32, +      33,     0,     1,    31,   115,     4,     5,     6,     7,     8, +       9,    10,    11,    26,    27,    14,    15,    16,    17,    18, +      19,    20,    21,    22,    23,    31,    26,    26,    31,     0, +       1,    26,    31,     4,     5,     6,     7,     8,     9,    10, +      11,    26,    31,    14,    15,    16,    17,    18,    19,    20, +      21,    22,    23,     1,     1,    26,    31,    32,    33,    31, +      31,     0,     1,    31,    31,     4,     5,     6,     7,     8, +       9,    10,    11,    31,   185,    14,    15,    16,    17,    18, +      19,    20,    21,    22,    23,    31,     1,    26,    31,    31, +       5,     6,    31,     8,     9,    10,    11,    12,    31,    14, +      15,    16,    17,    18,    19,    20,    31,    31,    31,    25, +       1,    26,    26,    13,     1,    26,    31,     4,     5,     6, +       7,     8,     9,    10,    11,    31,    14,    14,    15,    16, +       4,     5,     6,     7,     8,     9,    10,    11,    33,    26, +      14,    15,     5,     6,    31,     8,     9,    10,    11,    31, +      31,    14,    15,    31,    31,    31,    31,    31,    31,   151, +      31,   153,   154,   155,    34,    31,     7,     6,    31,   161, +      37,   163,    76,    -1,    79,   116,    -1,    -1,    -1,    -1, +     172 +}; + +  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing +     symbol of state STATE-NUM.  */ +static const yytype_uint8 yystos[] = +{ +       0,     3,    31,    37,    38,    39,    63,    81,    26,    27, +      79,     0,     1,     4,     5,     6,     7,     8,     9,    10, +      11,    14,    15,    16,    17,    18,    19,    20,    21,    22, +      23,    26,    31,    40,    41,    43,    44,    45,    46,    52, +      53,    55,    59,    61,    64,    65,    67,    69,    70,    71, +      80,    39,    31,    38,    81,    31,    79,    31,    79,    26, +      85,    31,    79,    26,    26,    26,    27,    30,    35,    83, +      84,    31,     1,     1,    47,    47,    56,    58,    62,    76, +      68,    74,    31,    31,    31,    31,    31,    31,    83,    83, +      32,    33,    81,    28,    34,    31,    31,     1,    12,    16, +      18,    19,    20,    21,    22,    24,    26,    31,    42,    48, +      49,    72,    73,    75,    17,    18,    19,    20,    31,    42, +      57,    73,    75,    41,    54,    80,    41,    55,    60,    67, +      80,    23,    31,    74,    77,    41,    55,    66,    67,    80, +      31,    42,    75,    29,    83,    83,    84,    84,    31,    31, +      25,    79,    78,    79,    83,    26,    84,    50,     1,    13, +      31,    79,    78,    26,    14,    82,    83,    82,    31,    82, +      82,    82,    84,    26,    31,    31,    82,    31,    82,    83, +      31,    31,    31,    31,    82,    34,    51,    31,    31,    31, +      79 +}; + +  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */ +static const yytype_uint8 yyr1[] = +{ +       0,    36,    37,    37,    38,    38,    39,    39,    39,    39, +      39,    39,    39,    39,    40,    40,    40,    40,    40,    40, +      40,    40,    41,    41,    41,    41,    41,    41,    42,    42, +      43,    44,    45,    46,    47,    47,    47,    47,    47,    47, +      47,    48,    48,    48,    48,    48,    49,    50,    50,    51, +      51,    52,    53,    54,    55,    56,    56,    56,    56,    56, +      56,    57,    57,    57,    57,    58,    58,    59,    60,    61, +      62,    62,    62,    62,    63,    64,    65,    66,    67,    68, +      68,    68,    68,    69,    70,    71,    72,    73,    74,    74, +      74,    74,    75,    76,    76,    76,    77,    78,    78,    79, +      79,    80,    80,    80,    81,    81,    82,    82,    83,    83, +      83,    83,    83,    83,    83,    84,    84,    85,    85 +}; + +  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */ +static const yytype_uint8 yyr2[] = +{ +       0,     2,     2,     1,     2,     1,     0,     2,     2,     2, +       2,     4,     4,     3,     1,     1,     1,     1,     1,     1, +       1,     1,     1,     1,     1,     1,     1,     1,     3,     2, +       3,     2,     3,     2,     0,     2,     2,     2,     2,     2, +       2,     3,     4,     4,     4,     5,     3,     0,     3,     0, +       2,     3,     2,     1,     3,     0,     2,     2,     2,     2, +       2,     4,     3,     2,     4,     0,     2,     3,     1,     3, +       0,     2,     2,     2,     3,     3,     3,     1,     3,     0, +       2,     2,     2,     3,     3,     2,     2,     2,     0,     2, +       2,     2,     4,     0,     2,     2,     2,     0,     2,     1, +       1,     2,     2,     2,     1,     2,     0,     2,     1,     3, +       3,     3,     2,     3,     3,     1,     1,     0,     1 +}; + + +#define yyerrok         (yyerrstatus = 0) +#define yyclearin       (yychar = YYEMPTY) +#define YYEMPTY         (-2) +#define YYEOF           0 + +#define YYACCEPT        goto yyacceptlab +#define YYABORT         goto yyabortlab +#define YYERROR         goto yyerrorlab + + +#define YYRECOVERING()  (!!yyerrstatus) + +#define YYBACKUP(Token, Value)                                  \ +do                                                              \ +  if (yychar == YYEMPTY)                                        \ +    {                                                           \ +      yychar = (Token);                                         \ +      yylval = (Value);                                         \ +      YYPOPSTACK (yylen);                                       \ +      yystate = *yyssp;                                         \ +      goto yybackup;                                            \ +    }                                                           \ +  else                                                          \ +    {                                                           \ +      yyerror (YY_("syntax error: cannot back up")); \ +      YYERROR;                                                  \ +    }                                                           \ +while (0) + +/* Error token number */ +#define YYTERROR        1 +#define YYERRCODE       256 + + + +/* Enable debugging if requested.  */ +#if YYDEBUG + +# ifndef YYFPRINTF +#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +#  define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args)                        \ +do {                                            \ +  if (yydebug)                                  \ +    YYFPRINTF Args;                             \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \ +do {                                                                      \ +  if (yydebug)                                                            \ +    {                                                                     \ +      YYFPRINTF (stderr, "%s ", Title);                                   \ +      yy_symbol_print (stderr,                                            \ +                  Type, Value); \ +      YYFPRINTF (stderr, "\n");                                           \ +    }                                                                     \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT.  | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ +  FILE *yyo = yyoutput; +  YYUSE (yyo); +  if (!yyvaluep) +    return; +# ifdef YYPRINT +  if (yytype < YYNTOKENS) +    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif +  YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT.  | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +{ +  YYFPRINTF (yyoutput, "%s %s (", +             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + +  yy_symbol_value_print (yyoutput, yytype, yyvaluep); +  YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included).                                                   | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ +  YYFPRINTF (stderr, "Stack now"); +  for (; yybottom <= yytop; yybottom++) +    { +      int yybot = *yybottom; +      YYFPRINTF (stderr, " %d", yybot); +    } +  YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top)                            \ +do {                                                            \ +  if (yydebug)                                                  \ +    yy_stack_print ((Bottom), (Top));                           \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced.  | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) +{ +  unsigned long int yylno = yyrline[yyrule]; +  int yynrhs = yyr2[yyrule]; +  int yyi; +  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", +             yyrule - 1, yylno); +  /* The symbols being reduced.  */ +  for (yyi = 0; yyi < yynrhs; yyi++) +    { +      YYFPRINTF (stderr, "   $%d = ", yyi + 1); +      yy_symbol_print (stderr, +                       yystos[yyssp[yyi + 1 - yynrhs]], +                       &(yyvsp[(yyi + 1) - (yynrhs)]) +                                              ); +      YYFPRINTF (stderr, "\n"); +    } +} + +# define YY_REDUCE_PRINT(Rule)          \ +do {                                    \ +  if (yydebug)                          \ +    yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace.  It is left uninitialized so that +   multiple parsers can coexist.  */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks.  */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only +   if the built-in stack extension method is used). + +   Do not make this value too large; the results are undefined if +   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) +   evaluated with infinite-precision integer arithmetic.  */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +#  if defined __GLIBC__ && defined _STRING_H +#   define yystrlen strlen +#  else +/* Return the length of YYSTR.  */ +static YYSIZE_T +yystrlen (const char *yystr) +{ +  YYSIZE_T yylen; +  for (yylen = 0; yystr[yylen]; yylen++) +    continue; +  return yylen; +} +#  endif +# endif + +# ifndef yystpcpy +#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +#   define yystpcpy stpcpy +#  else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in +   YYDEST.  */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ +  char *yyd = yydest; +  const char *yys = yysrc; + +  while ((*yyd++ = *yys++) != '\0') +    continue; + +  return yyd - 1; +} +#  endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary +   quotes and backslashes, so that it's suitable for yyerror.  The +   heuristic is that double-quoting is unnecessary unless the string +   contains an apostrophe, a comma, or backslash (other than +   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is +   null, do not copy; instead, return the length of what the result +   would have been.  */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ +  if (*yystr == '"') +    { +      YYSIZE_T yyn = 0; +      char const *yyp = yystr; + +      for (;;) +        switch (*++yyp) +          { +          case '\'': +          case ',': +            goto do_not_strip_quotes; + +          case '\\': +            if (*++yyp != '\\') +              goto do_not_strip_quotes; +            /* Fall through.  */ +          default: +            if (yyres) +              yyres[yyn] = *yyp; +            yyn++; +            break; + +          case '"': +            if (yyres) +              yyres[yyn] = '\0'; +            return yyn; +          } +    do_not_strip_quotes: ; +    } + +  if (! yyres) +    return yystrlen (yystr); + +  return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message +   about the unexpected token YYTOKEN for the state stack whose top is +   YYSSP. + +   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is +   not large enough to hold the message.  In that case, also set +   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the +   required number of bytes is too large to store.  */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, +                yytype_int16 *yyssp, int yytoken) +{ +  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); +  YYSIZE_T yysize = yysize0; +  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; +  /* Internationalized format string. */ +  const char *yyformat = YY_NULLPTR; +  /* Arguments of yyformat. */ +  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; +  /* Number of reported tokens (one for the "unexpected", one per +     "expected"). */ +  int yycount = 0; + +  /* There are many possibilities here to consider: +     - If this state is a consistent state with a default action, then +       the only way this function was invoked is if the default action +       is an error action.  In that case, don't check for expected +       tokens because there are none. +     - The only way there can be no lookahead present (in yychar) is if +       this state is a consistent state with a default action.  Thus, +       detecting the absence of a lookahead is sufficient to determine +       that there is no unexpected or expected token to report.  In that +       case, just report a simple "syntax error". +     - Don't assume there isn't a lookahead just because this state is a +       consistent state with a default action.  There might have been a +       previous inconsistent state, consistent state with a non-default +       action, or user semantic action that manipulated yychar. +     - Of course, the expected token list depends on states to have +       correct lookahead information, and it depends on the parser not +       to perform extra reductions after fetching a lookahead from the +       scanner and before detecting a syntax error.  Thus, state merging +       (from LALR or IELR) and default reductions corrupt the expected +       token list.  However, the list is correct for canonical LR with +       one exception: it will still contain any token that will not be +       accepted due to an error action in a later state. +  */ +  if (yytoken != YYEMPTY) +    { +      int yyn = yypact[*yyssp]; +      yyarg[yycount++] = yytname[yytoken]; +      if (!yypact_value_is_default (yyn)) +        { +          /* Start YYX at -YYN if negative to avoid negative indexes in +             YYCHECK.  In other words, skip the first -YYN actions for +             this state because they are default actions.  */ +          int yyxbegin = yyn < 0 ? -yyn : 0; +          /* Stay within bounds of both yycheck and yytname.  */ +          int yychecklim = YYLAST - yyn + 1; +          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; +          int yyx; + +          for (yyx = yyxbegin; yyx < yyxend; ++yyx) +            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR +                && !yytable_value_is_error (yytable[yyx + yyn])) +              { +                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) +                  { +                    yycount = 1; +                    yysize = yysize0; +                    break; +                  } +                yyarg[yycount++] = yytname[yyx]; +                { +                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); +                  if (! (yysize <= yysize1 +                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) +                    return 2; +                  yysize = yysize1; +                } +              } +        } +    } + +  switch (yycount) +    { +# define YYCASE_(N, S)                      \ +      case N:                               \ +        yyformat = S;                       \ +      break +      YYCASE_(0, YY_("syntax error")); +      YYCASE_(1, YY_("syntax error, unexpected %s")); +      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); +      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); +      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); +      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ +    } + +  { +    YYSIZE_T yysize1 = yysize + yystrlen (yyformat); +    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) +      return 2; +    yysize = yysize1; +  } + +  if (*yymsg_alloc < yysize) +    { +      *yymsg_alloc = 2 * yysize; +      if (! (yysize <= *yymsg_alloc +             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) +        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; +      return 1; +    } + +  /* Avoid sprintf, as that infringes on the user's name space. +     Don't have undefined behavior even if the translation +     produced a string with the wrong number of "%s"s.  */ +  { +    char *yyp = *yymsg; +    int yyi = 0; +    while ((*yyp = *yyformat) != '\0') +      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) +        { +          yyp += yytnamerr (yyp, yyarg[yyi++]); +          yyformat += 2; +        } +      else +        { +          yyp++; +          yyformat++; +        } +  } +  return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol.  | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +{ +  YYUSE (yyvaluep); +  if (!yymsg) +    yymsg = "Deleting"; +  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + +  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +  switch (yytype) +    { +          case 53: /* choice_entry  */ + +      { +	fprintf(stderr, "%s:%d: missing end statement for this entry\n", +		((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno); +	if (current_menu == ((*yyvaluep).menu)) +		menu_end_menu(); +} + +        break; + +    case 59: /* if_entry  */ + +      { +	fprintf(stderr, "%s:%d: missing end statement for this entry\n", +		((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno); +	if (current_menu == ((*yyvaluep).menu)) +		menu_end_menu(); +} + +        break; + +    case 65: /* menu_entry  */ + +      { +	fprintf(stderr, "%s:%d: missing end statement for this entry\n", +		((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno); +	if (current_menu == ((*yyvaluep).menu)) +		menu_end_menu(); +} + +        break; + + +      default: +        break; +    } +  YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/* The lookahead symbol.  */ +int yychar; + +/* The semantic value of the lookahead symbol.  */ +YYSTYPE yylval; +/* Number of syntax errors so far.  */ +int yynerrs; + + +/*----------. +| yyparse.  | +`----------*/ + +int +yyparse (void) +{ +    int yystate; +    /* Number of tokens to shift before error messages enabled.  */ +    int yyerrstatus; + +    /* The stacks and their tools: +       'yyss': related to states. +       'yyvs': related to semantic values. + +       Refer to the stacks through separate pointers, to allow yyoverflow +       to reallocate them elsewhere.  */ + +    /* The state stack.  */ +    yytype_int16 yyssa[YYINITDEPTH]; +    yytype_int16 *yyss; +    yytype_int16 *yyssp; + +    /* The semantic value stack.  */ +    YYSTYPE yyvsa[YYINITDEPTH]; +    YYSTYPE *yyvs; +    YYSTYPE *yyvsp; + +    YYSIZE_T yystacksize; + +  int yyn; +  int yyresult; +  /* Lookahead token as an internal (translated) token number.  */ +  int yytoken = 0; +  /* The variables used to return semantic value and location from the +     action routines.  */ +  YYSTYPE yyval; + +#if YYERROR_VERBOSE +  /* Buffer for error messages, and its allocated size.  */ +  char yymsgbuf[128]; +  char *yymsg = yymsgbuf; +  YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N)) + +  /* The number of symbols on the RHS of the reduced rule. +     Keep to zero when no symbol should be popped.  */ +  int yylen = 0; + +  yyssp = yyss = yyssa; +  yyvsp = yyvs = yyvsa; +  yystacksize = YYINITDEPTH; + +  YYDPRINTF ((stderr, "Starting parse\n")); + +  yystate = 0; +  yyerrstatus = 0; +  yynerrs = 0; +  yychar = YYEMPTY; /* Cause a token to be read.  */ +  goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate.  | +`------------------------------------------------------------*/ + yynewstate: +  /* In all cases, when you get here, the value and location stacks +     have just been pushed.  So pushing a state here evens the stacks.  */ +  yyssp++; + + yysetstate: +  *yyssp = yystate; + +  if (yyss + yystacksize - 1 <= yyssp) +    { +      /* Get the current used size of the three stacks, in elements.  */ +      YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow +      { +        /* Give user a chance to reallocate the stack.  Use copies of +           these so that the &'s don't force the real ones into +           memory.  */ +        YYSTYPE *yyvs1 = yyvs; +        yytype_int16 *yyss1 = yyss; + +        /* Each stack pointer address is followed by the size of the +           data in use in that stack, in bytes.  This used to be a +           conditional around just the two extra args, but that might +           be undefined if yyoverflow is a macro.  */ +        yyoverflow (YY_("memory exhausted"), +                    &yyss1, yysize * sizeof (*yyssp), +                    &yyvs1, yysize * sizeof (*yyvsp), +                    &yystacksize); + +        yyss = yyss1; +        yyvs = yyvs1; +      } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE +      goto yyexhaustedlab; +# else +      /* Extend the stack our own way.  */ +      if (YYMAXDEPTH <= yystacksize) +        goto yyexhaustedlab; +      yystacksize *= 2; +      if (YYMAXDEPTH < yystacksize) +        yystacksize = YYMAXDEPTH; + +      { +        yytype_int16 *yyss1 = yyss; +        union yyalloc *yyptr = +          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); +        if (! yyptr) +          goto yyexhaustedlab; +        YYSTACK_RELOCATE (yyss_alloc, yyss); +        YYSTACK_RELOCATE (yyvs_alloc, yyvs); +#  undef YYSTACK_RELOCATE +        if (yyss1 != yyssa) +          YYSTACK_FREE (yyss1); +      } +# endif +#endif /* no yyoverflow */ + +      yyssp = yyss + yysize - 1; +      yyvsp = yyvs + yysize - 1; + +      YYDPRINTF ((stderr, "Stack size increased to %lu\n", +                  (unsigned long int) yystacksize)); + +      if (yyss + yystacksize - 1 <= yyssp) +        YYABORT; +    } + +  YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + +  if (yystate == YYFINAL) +    YYACCEPT; + +  goto yybackup; + +/*-----------. +| yybackup.  | +`-----------*/ +yybackup: + +  /* Do appropriate processing given the current state.  Read a +     lookahead token if we need one and don't already have one.  */ + +  /* First try to decide what to do without reference to lookahead token.  */ +  yyn = yypact[yystate]; +  if (yypact_value_is_default (yyn)) +    goto yydefault; + +  /* Not known => get a lookahead token if don't already have one.  */ + +  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */ +  if (yychar == YYEMPTY) +    { +      YYDPRINTF ((stderr, "Reading a token: ")); +      yychar = yylex (); +    } + +  if (yychar <= YYEOF) +    { +      yychar = yytoken = YYEOF; +      YYDPRINTF ((stderr, "Now at end of input.\n")); +    } +  else +    { +      yytoken = YYTRANSLATE (yychar); +      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); +    } + +  /* If the proper action on seeing token YYTOKEN is to reduce or to +     detect an error, take that action.  */ +  yyn += yytoken; +  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) +    goto yydefault; +  yyn = yytable[yyn]; +  if (yyn <= 0) +    { +      if (yytable_value_is_error (yyn)) +        goto yyerrlab; +      yyn = -yyn; +      goto yyreduce; +    } + +  /* Count tokens shifted since error; after three, turn off error +     status.  */ +  if (yyerrstatus) +    yyerrstatus--; + +  /* Shift the lookahead token.  */ +  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + +  /* Discard the shifted token.  */ +  yychar = YYEMPTY; + +  yystate = yyn; +  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +  *++yyvsp = yylval; +  YY_IGNORE_MAYBE_UNINITIALIZED_END + +  goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state.  | +`-----------------------------------------------------------*/ +yydefault: +  yyn = yydefact[yystate]; +  if (yyn == 0) +    goto yyerrlab; +  goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction.  | +`-----------------------------*/ +yyreduce: +  /* yyn is the number of a rule to reduce with.  */ +  yylen = yyr2[yyn]; + +  /* If YYLEN is nonzero, implement the default value of the action: +     '$$ = $1'. + +     Otherwise, the following line sets YYVAL to garbage. +     This behavior is undocumented and Bison +     users should not rely upon it.  Assigning to YYVAL +     unconditionally makes the parser a bit smaller, and it avoids a +     GCC warning that YYVAL may be used uninitialized.  */ +  yyval = yyvsp[1-yylen]; + + +  YY_REDUCE_PRINT (yyn); +  switch (yyn) +    { +        case 10: + +    { zconf_error("unexpected end statement"); } + +    break; + +  case 11: + +    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); } + +    break; + +  case 12: + +    { +	zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[-2].id)->name); +} + +    break; + +  case 13: + +    { zconf_error("invalid statement"); } + +    break; + +  case 28: + +    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); } + +    break; + +  case 29: + +    { zconf_error("invalid option"); } + +    break; + +  case 30: + +    { +	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0); +	sym->flags |= SYMBOL_OPTIONAL; +	menu_add_entry(sym); +	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string)); +} + +    break; + +  case 31: + +    { +	menu_end_entry(); +	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 32: + +    { +	struct symbol *sym = sym_lookup((yyvsp[-1].string), 0); +	sym->flags |= SYMBOL_OPTIONAL; +	menu_add_entry(sym); +	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string)); +} + +    break; + +  case 33: + +    { +	if (current_entry->prompt) +		current_entry->prompt->type = P_MENU; +	else +		zconfprint("warning: menuconfig statement without prompt"); +	menu_end_entry(); +	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 41: + +    { +	menu_set_type((yyvsp[-2].id)->stype); +	printd(DEBUG_PARSE, "%s:%d:type(%u)\n", +		zconf_curname(), zconf_lineno(), +		(yyvsp[-2].id)->stype); +} + +    break; + +  case 42: + +    { +	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr)); +	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 43: + +    { +	menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr)); +	if ((yyvsp[-3].id)->stype != S_UNKNOWN) +		menu_set_type((yyvsp[-3].id)->stype); +	printd(DEBUG_PARSE, "%s:%d:default(%u)\n", +		zconf_curname(), zconf_lineno(), +		(yyvsp[-3].id)->stype); +} + +    break; + +  case 44: + +    { +	menu_add_symbol(P_SELECT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr)); +	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 45: + +    { +	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), (yyvsp[-2].symbol)), (yyvsp[-1].expr)); +	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 48: + +    { +	const struct kconf_id *id = kconf_id_lookup((yyvsp[-1].string), strlen((yyvsp[-1].string))); +	if (id && id->flags & TF_OPTION) +		menu_add_option(id->token, (yyvsp[0].string)); +	else +		zconfprint("warning: ignoring unknown option %s", (yyvsp[-1].string)); +	free((yyvsp[-1].string)); +} + +    break; + +  case 49: + +    { (yyval.string) = NULL; } + +    break; + +  case 50: + +    { (yyval.string) = (yyvsp[0].string); } + +    break; + +  case 51: + +    { +	struct symbol *sym = sym_lookup((yyvsp[-1].string), SYMBOL_CHOICE); +	sym->flags |= SYMBOL_AUTO; +	menu_add_entry(sym); +	menu_add_expr(P_CHOICE, NULL, NULL); +	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 52: + +    { +	(yyval.menu) = menu_add_menu(); +} + +    break; + +  case 53: + +    { +	if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) { +		menu_end_menu(); +		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); +	} +} + +    break; + +  case 61: + +    { +	menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr)); +	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 62: + +    { +	if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == S_TRISTATE) { +		menu_set_type((yyvsp[-2].id)->stype); +		printd(DEBUG_PARSE, "%s:%d:type(%u)\n", +			zconf_curname(), zconf_lineno(), +			(yyvsp[-2].id)->stype); +	} else +		YYERROR; +} + +    break; + +  case 63: + +    { +	current_entry->sym->flags |= SYMBOL_OPTIONAL; +	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 64: + +    { +	if ((yyvsp[-3].id)->stype == S_UNKNOWN) { +		menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[-2].string), 0), (yyvsp[-1].expr)); +		printd(DEBUG_PARSE, "%s:%d:default\n", +			zconf_curname(), zconf_lineno()); +	} else +		YYERROR; +} + +    break; + +  case 67: + +    { +	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); +	menu_add_entry(NULL); +	menu_add_dep((yyvsp[-1].expr)); +	(yyval.menu) = menu_add_menu(); +} + +    break; + +  case 68: + +    { +	if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) { +		menu_end_menu(); +		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); +	} +} + +    break; + +  case 74: + +    { +	menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL); +} + +    break; + +  case 75: + +    { +	menu_add_entry(NULL); +	menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL); +	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 76: + +    { +	(yyval.menu) = menu_add_menu(); +} + +    break; + +  case 77: + +    { +	if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) { +		menu_end_menu(); +		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); +	} +} + +    break; + +  case 83: + +    { +	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[-1].string)); +	zconf_nextfile((yyvsp[-1].string)); +} + +    break; + +  case 84: + +    { +	menu_add_entry(NULL); +	menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL); +	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 85: + +    { +	menu_end_entry(); +} + +    break; + +  case 86: + +    { +	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); +	zconf_starthelp(); +} + +    break; + +  case 87: + +    { +	current_entry->help = (yyvsp[0].string); +} + +    break; + +  case 92: + +    { +	menu_add_dep((yyvsp[-1].expr)); +	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +} + +    break; + +  case 96: + +    { +	menu_add_visibility((yyvsp[0].expr)); +} + +    break; + +  case 98: + +    { +	menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr)); +} + +    break; + +  case 101: + +    { (yyval.id) = (yyvsp[-1].id); } + +    break; + +  case 102: + +    { (yyval.id) = (yyvsp[-1].id); } + +    break; + +  case 103: + +    { (yyval.id) = (yyvsp[-1].id); } + +    break; + +  case 106: + +    { (yyval.expr) = NULL; } + +    break; + +  case 107: + +    { (yyval.expr) = (yyvsp[0].expr); } + +    break; + +  case 108: + +    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); } + +    break; + +  case 109: + +    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); } + +    break; + +  case 110: + +    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), (yyvsp[0].symbol)); } + +    break; + +  case 111: + +    { (yyval.expr) = (yyvsp[-1].expr); } + +    break; + +  case 112: + +    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); } + +    break; + +  case 113: + +    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), (yyvsp[0].expr)); } + +    break; + +  case 114: + +    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), (yyvsp[0].expr)); } + +    break; + +  case 115: + +    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); free((yyvsp[0].string)); } + +    break; + +  case 116: + +    { (yyval.symbol) = sym_lookup((yyvsp[0].string), SYMBOL_CONST); free((yyvsp[0].string)); } + +    break; + +  case 117: + +    { (yyval.string) = NULL; } + +    break; + + + +      default: break; +    } +  /* User semantic actions sometimes alter yychar, and that requires +     that yytoken be updated with the new translation.  We take the +     approach of translating immediately before every use of yytoken. +     One alternative is translating here after every semantic action, +     but that translation would be missed if the semantic action invokes +     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or +     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an +     incorrect destructor might then be invoked immediately.  In the +     case of YYERROR or YYBACKUP, subsequent parser actions might lead +     to an incorrect destructor call or verbose syntax error message +     before the lookahead is translated.  */ +  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + +  YYPOPSTACK (yylen); +  yylen = 0; +  YY_STACK_PRINT (yyss, yyssp); + +  *++yyvsp = yyval; + +  /* Now 'shift' the result of the reduction.  Determine what state +     that goes to, based on the state we popped back to and the rule +     number reduced by.  */ + +  yyn = yyr1[yyn]; + +  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; +  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) +    yystate = yytable[yystate]; +  else +    yystate = yydefgoto[yyn - YYNTOKENS]; + +  goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error.  | +`--------------------------------------*/ +yyerrlab: +  /* Make sure we have latest lookahead translation.  See comments at +     user semantic actions for why this is necessary.  */ +  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + +  /* If not already recovering from an error, report this error.  */ +  if (!yyerrstatus) +    { +      ++yynerrs; +#if ! YYERROR_VERBOSE +      yyerror (YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ +                                        yyssp, yytoken) +      { +        char const *yymsgp = YY_("syntax error"); +        int yysyntax_error_status; +        yysyntax_error_status = YYSYNTAX_ERROR; +        if (yysyntax_error_status == 0) +          yymsgp = yymsg; +        else if (yysyntax_error_status == 1) +          { +            if (yymsg != yymsgbuf) +              YYSTACK_FREE (yymsg); +            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); +            if (!yymsg) +              { +                yymsg = yymsgbuf; +                yymsg_alloc = sizeof yymsgbuf; +                yysyntax_error_status = 2; +              } +            else +              { +                yysyntax_error_status = YYSYNTAX_ERROR; +                yymsgp = yymsg; +              } +          } +        yyerror (yymsgp); +        if (yysyntax_error_status == 2) +          goto yyexhaustedlab; +      } +# undef YYSYNTAX_ERROR +#endif +    } + + + +  if (yyerrstatus == 3) +    { +      /* If just tried and failed to reuse lookahead token after an +         error, discard it.  */ + +      if (yychar <= YYEOF) +        { +          /* Return failure if at end of input.  */ +          if (yychar == YYEOF) +            YYABORT; +        } +      else +        { +          yydestruct ("Error: discarding", +                      yytoken, &yylval); +          yychar = YYEMPTY; +        } +    } + +  /* Else will try to reuse lookahead token after shifting the error +     token.  */ +  goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR.  | +`---------------------------------------------------*/ +yyerrorlab: + +  /* Pacify compilers like GCC when the user code never invokes +     YYERROR and the label yyerrorlab therefore never appears in user +     code.  */ +  if (/*CONSTCOND*/ 0) +     goto yyerrorlab; + +  /* Do not reclaim the symbols of the rule whose action triggered +     this YYERROR.  */ +  YYPOPSTACK (yylen); +  yylen = 0; +  YY_STACK_PRINT (yyss, yyssp); +  yystate = *yyssp; +  goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR.  | +`-------------------------------------------------------------*/ +yyerrlab1: +  yyerrstatus = 3;      /* Each real token shifted decrements this.  */ + +  for (;;) +    { +      yyn = yypact[yystate]; +      if (!yypact_value_is_default (yyn)) +        { +          yyn += YYTERROR; +          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) +            { +              yyn = yytable[yyn]; +              if (0 < yyn) +                break; +            } +        } + +      /* Pop the current state because it cannot handle the error token.  */ +      if (yyssp == yyss) +        YYABORT; + + +      yydestruct ("Error: popping", +                  yystos[yystate], yyvsp); +      YYPOPSTACK (1); +      yystate = *yyssp; +      YY_STACK_PRINT (yyss, yyssp); +    } + +  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +  *++yyvsp = yylval; +  YY_IGNORE_MAYBE_UNINITIALIZED_END + + +  /* Shift the error token.  */ +  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + +  yystate = yyn; +  goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here.  | +`-------------------------------------*/ +yyacceptlab: +  yyresult = 0; +  goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here.  | +`-----------------------------------*/ +yyabortlab: +  yyresult = 1; +  goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here.  | +`-------------------------------------------------*/ +yyexhaustedlab: +  yyerror (YY_("memory exhausted")); +  yyresult = 2; +  /* Fall through.  */ +#endif + +yyreturn: +  if (yychar != YYEMPTY) +    { +      /* Make sure we have latest lookahead translation.  See comments at +         user semantic actions for why this is necessary.  */ +      yytoken = YYTRANSLATE (yychar); +      yydestruct ("Cleanup: discarding lookahead", +                  yytoken, &yylval); +    } +  /* Do not reclaim the symbols of the rule whose action triggered +     this YYABORT or YYACCEPT.  */ +  YYPOPSTACK (yylen); +  YY_STACK_PRINT (yyss, yyssp); +  while (yyssp != yyss) +    { +      yydestruct ("Cleanup: popping", +                  yystos[*yyssp], yyvsp); +      YYPOPSTACK (1); +    } +#ifndef yyoverflow +  if (yyss != yyssa) +    YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE +  if (yymsg != yymsgbuf) +    YYSTACK_FREE (yymsg); +#endif +  return yyresult; +} + + + +void conf_parse(const char *name) +{ +	struct symbol *sym; +	int i; + +	zconf_initscan(name); + +	sym_init(); +	_menu_init(); +	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +	if (getenv("ZCONF_DEBUG")) +		zconfdebug = 1; +	zconfparse(); +	if (zconfnerrs) +		exit(1); +	if (!modules_sym) +		modules_sym = sym_find( "n" ); + +	rootmenu.prompt->text = _(rootmenu.prompt->text); +	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + +	menu_finalize(&rootmenu); +	for_all_symbols(i, sym) { +		if (sym_check_deps(sym)) +			zconfnerrs++; +	} +	if (zconfnerrs) +		exit(1); +	sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ +	switch (token) { +	case T_MENU:		return "menu"; +	case T_ENDMENU:		return "endmenu"; +	case T_CHOICE:		return "choice"; +	case T_ENDCHOICE:	return "endchoice"; +	case T_IF:		return "if"; +	case T_ENDIF:		return "endif"; +	case T_DEPENDS:		return "depends"; +	case T_VISIBLE:		return "visible"; +	} +	return "<token>"; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ +	if (id->token != endtoken) { +		zconf_error("unexpected '%s' within %s block", +			kconf_id_strings + id->name, zconf_tokenname(starttoken)); +		zconfnerrs++; +		return false; +	} +	if (current_menu->file != current_file) { +		zconf_error("'%s' in different file than '%s'", +			kconf_id_strings + id->name, zconf_tokenname(starttoken)); +		fprintf(stderr, "%s:%d: location of the '%s'\n", +			current_menu->file->name, current_menu->lineno, +			zconf_tokenname(starttoken)); +		zconfnerrs++; +		return false; +	} +	return true; +} + +static void zconfprint(const char *err, ...) +{ +	va_list ap; + +	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); +	va_start(ap, err); +	vfprintf(stderr, err, ap); +	va_end(ap); +	fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ +	va_list ap; + +	zconfnerrs++; +	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); +	va_start(ap, err); +	vfprintf(stderr, err, ap); +	va_end(ap); +	fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ +	const char *p; +	int len; + +	putc('"', out); +	while ((p = strchr(str, '"'))) { +		len = p - str; +		if (len) +			fprintf(out, "%.*s", len, str); +		fputs("\\\"", out); +		str = p + 1; +	} +	fputs(str, out); +	putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ +	struct symbol *sym = menu->sym; +	struct property *prop; + +	if (sym_is_choice(sym)) +		fprintf(out, "\nchoice\n"); +	else +		fprintf(out, "\nconfig %s\n", sym->name); +	switch (sym->type) { +	case S_BOOLEAN: +		fputs("  boolean\n", out); +		break; +	case S_TRISTATE: +		fputs("  tristate\n", out); +		break; +	case S_STRING: +		fputs("  string\n", out); +		break; +	case S_INT: +		fputs("  integer\n", out); +		break; +	case S_HEX: +		fputs("  hex\n", out); +		break; +	default: +		fputs("  ???\n", out); +		break; +	} +	for (prop = sym->prop; prop; prop = prop->next) { +		if (prop->menu != menu) +			continue; +		switch (prop->type) { +		case P_PROMPT: +			fputs("  prompt ", out); +			print_quoted_string(out, prop->text); +			if (!expr_is_yes(prop->visible.expr)) { +				fputs(" if ", out); +				expr_fprint(prop->visible.expr, out); +			} +			fputc('\n', out); +			break; +		case P_DEFAULT: +			fputs( "  default ", out); +			expr_fprint(prop->expr, out); +			if (!expr_is_yes(prop->visible.expr)) { +				fputs(" if ", out); +				expr_fprint(prop->visible.expr, out); +			} +			fputc('\n', out); +			break; +		case P_CHOICE: +			fputs("  #choice value\n", out); +			break; +		case P_SELECT: +			fputs( "  select ", out); +			expr_fprint(prop->expr, out); +			fputc('\n', out); +			break; +		case P_RANGE: +			fputs( "  range ", out); +			expr_fprint(prop->expr, out); +			fputc('\n', out); +			break; +		case P_MENU: +			fputs( "  menu ", out); +			print_quoted_string(out, prop->text); +			fputc('\n', out); +			break; +		default: +			fprintf(out, "  unknown prop %d!\n", prop->type); +			break; +		} +	} +	if (menu->help) { +		int len = strlen(menu->help); +		while (menu->help[--len] == '\n') +			menu->help[len] = 0; +		fprintf(out, "  help\n%s\n", menu->help); +	} +} + +void zconfdump(FILE *out) +{ +	struct property *prop; +	struct symbol *sym; +	struct menu *menu; + +	menu = rootmenu.list; +	while (menu) { +		if ((sym = menu->sym)) +			print_symbol(out, menu); +		else if ((prop = menu->prompt)) { +			switch (prop->type) { +			case P_COMMENT: +				fputs("\ncomment ", out); +				print_quoted_string(out, prop->text); +				fputs("\n", out); +				break; +			case P_MENU: +				fputs("\nmenu ", out); +				print_quoted_string(out, prop->text); +				fputs("\n", out); +				break; +			default: +				; +			} +			if (!expr_is_yes(prop->visible.expr)) { +				fputs("  depends ", out); +				expr_fprint(prop->visible.expr, out); +				fputc('\n', out); +			} +		} + +		if (menu->list) +			menu = menu->list; +		else if (menu->next) +			menu = menu->next; +		else while ((menu = menu->parent)) { +			if (menu->prompt && menu->prompt->type == P_MENU) +				fputs("\nendmenu\n", out); +			if (menu->next) { +				menu = menu->next; +				break; +			} +		} +	} +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" diff --git a/programs/src/kconfig/kconfig/zconf.y b/programs/src/kconfig/kconfig/zconf.y new file mode 100644 index 0000000..0f683cf --- /dev/null +++ b/programs/src/kconfig/kconfig/zconf.y @@ -0,0 +1,733 @@ +%{ +/* + * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> + * Released under the terms of the GNU GPL v2.0. + */ + +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> + +#include "lkc.h" + +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) + +#define PRINTD		0x0001 +#define DEBUG_PARSE	0x0002 + +int cdebug = PRINTD; + +extern int zconflex(void); +static void zconfprint(const char *err, ...); +static void zconf_error(const char *err, ...); +static void zconferror(const char *err); +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); + +struct symbol *symbol_hash[SYMBOL_HASHSIZE]; + +static struct menu *current_menu, *current_entry; + +%} +%expect 30 + +%union +{ +	char *string; +	struct file *file; +	struct symbol *symbol; +	struct expr *expr; +	struct menu *menu; +	const struct kconf_id *id; +} + +%token <id>T_MAINMENU +%token <id>T_MENU +%token <id>T_ENDMENU +%token <id>T_SOURCE +%token <id>T_CHOICE +%token <id>T_ENDCHOICE +%token <id>T_COMMENT +%token <id>T_CONFIG +%token <id>T_MENUCONFIG +%token <id>T_HELP +%token <string> T_HELPTEXT +%token <id>T_IF +%token <id>T_ENDIF +%token <id>T_DEPENDS +%token <id>T_OPTIONAL +%token <id>T_PROMPT +%token <id>T_TYPE +%token <id>T_DEFAULT +%token <id>T_SELECT +%token <id>T_RANGE +%token <id>T_VISIBLE +%token <id>T_OPTION +%token <id>T_ON +%token <string> T_WORD +%token <string> T_WORD_QUOTE +%token T_UNEQUAL +%token T_CLOSE_PAREN +%token T_OPEN_PAREN +%token T_EOL + +%left T_OR +%left T_AND +%left T_EQUAL T_UNEQUAL +%nonassoc T_NOT + +%type <string> prompt +%type <symbol> symbol +%type <expr> expr +%type <expr> if_expr +%type <id> end +%type <id> option_name +%type <menu> if_entry menu_entry choice_entry +%type <string> symbol_option_arg word_opt + +%destructor { +	fprintf(stderr, "%s:%d: missing end statement for this entry\n", +		$$->file->name, $$->lineno); +	if (current_menu == $$) +		menu_end_menu(); +} if_entry menu_entry choice_entry + +%{ +/* Include zconf.hash.c here so it can see the token constants. */ +#include "zconf.hash.c" +%} + +%% +input: nl start | start; + +start: mainmenu_stmt stmt_list | stmt_list; + +stmt_list: +	  /* empty */ +	| stmt_list common_stmt +	| stmt_list choice_stmt +	| stmt_list menu_stmt +	| stmt_list end			{ zconf_error("unexpected end statement"); } +	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); } +	| stmt_list option_name error T_EOL +{ +	zconf_error("unexpected option \"%s\"", kconf_id_strings + $2->name); +} +	| stmt_list error T_EOL		{ zconf_error("invalid statement"); } +; + +option_name: +	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE +; + +common_stmt: +	  T_EOL +	| if_stmt +	| comment_stmt +	| config_stmt +	| menuconfig_stmt +	| source_stmt +; + +option_error: +	  T_WORD error T_EOL		{ zconf_error("unknown option \"%s\"", $1); } +	| error T_EOL			{ zconf_error("invalid option"); } +; + + +/* config/menuconfig entry */ + +config_entry_start: T_CONFIG T_WORD T_EOL +{ +	struct symbol *sym = sym_lookup($2, 0); +	sym->flags |= SYMBOL_OPTIONAL; +	menu_add_entry(sym); +	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +config_stmt: config_entry_start config_option_list +{ +	menu_end_entry(); +	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL +{ +	struct symbol *sym = sym_lookup($2, 0); +	sym->flags |= SYMBOL_OPTIONAL; +	menu_add_entry(sym); +	printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); +}; + +menuconfig_stmt: menuconfig_entry_start config_option_list +{ +	if (current_entry->prompt) +		current_entry->prompt->type = P_MENU; +	else +		zconfprint("warning: menuconfig statement without prompt"); +	menu_end_entry(); +	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); +}; + +config_option_list: +	  /* empty */ +	| config_option_list config_option +	| config_option_list symbol_option +	| config_option_list depends +	| config_option_list help +	| config_option_list option_error +	| config_option_list T_EOL +; + +config_option: T_TYPE prompt_stmt_opt T_EOL +{ +	menu_set_type($1->stype); +	printd(DEBUG_PARSE, "%s:%d:type(%u)\n", +		zconf_curname(), zconf_lineno(), +		$1->stype); +}; + +config_option: T_PROMPT prompt if_expr T_EOL +{ +	menu_add_prompt(P_PROMPT, $2, $3); +	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_DEFAULT expr if_expr T_EOL +{ +	menu_add_expr(P_DEFAULT, $2, $3); +	if ($1->stype != S_UNKNOWN) +		menu_set_type($1->stype); +	printd(DEBUG_PARSE, "%s:%d:default(%u)\n", +		zconf_curname(), zconf_lineno(), +		$1->stype); +}; + +config_option: T_SELECT T_WORD if_expr T_EOL +{ +	menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); +	printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ +	menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); +	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + +symbol_option: T_OPTION symbol_option_list T_EOL +; + +symbol_option_list: +	  /* empty */ +	| symbol_option_list T_WORD symbol_option_arg +{ +	const struct kconf_id *id = kconf_id_lookup($2, strlen($2)); +	if (id && id->flags & TF_OPTION) +		menu_add_option(id->token, $3); +	else +		zconfprint("warning: ignoring unknown option %s", $2); +	free($2); +}; + +symbol_option_arg: +	  /* empty */		{ $$ = NULL; } +	| T_EQUAL prompt	{ $$ = $2; } +; + +/* choice entry */ + +choice: T_CHOICE word_opt T_EOL +{ +	struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE); +	sym->flags |= SYMBOL_AUTO; +	menu_add_entry(sym); +	menu_add_expr(P_CHOICE, NULL, NULL); +	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); +}; + +choice_entry: choice choice_option_list +{ +	$$ = menu_add_menu(); +}; + +choice_end: end +{ +	if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { +		menu_end_menu(); +		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); +	} +}; + +choice_stmt: choice_entry choice_block choice_end +; + +choice_option_list: +	  /* empty */ +	| choice_option_list choice_option +	| choice_option_list depends +	| choice_option_list help +	| choice_option_list T_EOL +	| choice_option_list option_error +; + +choice_option: T_PROMPT prompt if_expr T_EOL +{ +	menu_add_prompt(P_PROMPT, $2, $3); +	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_TYPE prompt_stmt_opt T_EOL +{ +	if ($1->stype == S_BOOLEAN || $1->stype == S_TRISTATE) { +		menu_set_type($1->stype); +		printd(DEBUG_PARSE, "%s:%d:type(%u)\n", +			zconf_curname(), zconf_lineno(), +			$1->stype); +	} else +		YYERROR; +}; + +choice_option: T_OPTIONAL T_EOL +{ +	current_entry->sym->flags |= SYMBOL_OPTIONAL; +	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_DEFAULT T_WORD if_expr T_EOL +{ +	if ($1->stype == S_UNKNOWN) { +		menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); +		printd(DEBUG_PARSE, "%s:%d:default\n", +			zconf_curname(), zconf_lineno()); +	} else +		YYERROR; +}; + +choice_block: +	  /* empty */ +	| choice_block common_stmt +; + +/* if entry */ + +if_entry: T_IF expr nl +{ +	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); +	menu_add_entry(NULL); +	menu_add_dep($2); +	$$ = menu_add_menu(); +}; + +if_end: end +{ +	if (zconf_endtoken($1, T_IF, T_ENDIF)) { +		menu_end_menu(); +		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); +	} +}; + +if_stmt: if_entry if_block if_end +; + +if_block: +	  /* empty */ +	| if_block common_stmt +	| if_block menu_stmt +	| if_block choice_stmt +; + +/* mainmenu entry */ + +mainmenu_stmt: T_MAINMENU prompt nl +{ +	menu_add_prompt(P_MENU, $2, NULL); +}; + +/* menu entry */ + +menu: T_MENU prompt T_EOL +{ +	menu_add_entry(NULL); +	menu_add_prompt(P_MENU, $2, NULL); +	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); +}; + +menu_entry: menu visibility_list depends_list +{ +	$$ = menu_add_menu(); +}; + +menu_end: end +{ +	if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { +		menu_end_menu(); +		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); +	} +}; + +menu_stmt: menu_entry menu_block menu_end +; + +menu_block: +	  /* empty */ +	| menu_block common_stmt +	| menu_block menu_stmt +	| menu_block choice_stmt +; + +source_stmt: T_SOURCE prompt T_EOL +{ +	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); +	zconf_nextfile($2); +}; + +/* comment entry */ + +comment: T_COMMENT prompt T_EOL +{ +	menu_add_entry(NULL); +	menu_add_prompt(P_COMMENT, $2, NULL); +	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); +}; + +comment_stmt: comment depends_list +{ +	menu_end_entry(); +}; + +/* help option */ + +help_start: T_HELP T_EOL +{ +	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); +	zconf_starthelp(); +}; + +help: help_start T_HELPTEXT +{ +	current_entry->help = $2; +}; + +/* depends option */ + +depends_list: +	  /* empty */ +	| depends_list depends +	| depends_list T_EOL +	| depends_list option_error +; + +depends: T_DEPENDS T_ON expr T_EOL +{ +	menu_add_dep($3); +	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); +}; + +/* visibility option */ + +visibility_list: +	  /* empty */ +	| visibility_list visible +	| visibility_list T_EOL +; + +visible: T_VISIBLE if_expr +{ +	menu_add_visibility($2); +}; + +/* prompt statement */ + +prompt_stmt_opt: +	  /* empty */ +	| prompt if_expr +{ +	menu_add_prompt(P_PROMPT, $1, $2); +}; + +prompt:	  T_WORD +	| T_WORD_QUOTE +; + +end:	  T_ENDMENU T_EOL	{ $$ = $1; } +	| T_ENDCHOICE T_EOL	{ $$ = $1; } +	| T_ENDIF T_EOL		{ $$ = $1; } +; + +nl: +	  T_EOL +	| nl T_EOL +; + +if_expr:  /* empty */			{ $$ = NULL; } +	| T_IF expr			{ $$ = $2; } +; + +expr:	  symbol				{ $$ = expr_alloc_symbol($1); } +	| symbol T_EQUAL symbol			{ $$ = expr_alloc_comp(E_EQUAL, $1, $3); } +	| symbol T_UNEQUAL symbol		{ $$ = expr_alloc_comp(E_UNEQUAL, $1, $3); } +	| T_OPEN_PAREN expr T_CLOSE_PAREN	{ $$ = $2; } +	| T_NOT expr				{ $$ = expr_alloc_one(E_NOT, $2); } +	| expr T_OR expr			{ $$ = expr_alloc_two(E_OR, $1, $3); } +	| expr T_AND expr			{ $$ = expr_alloc_two(E_AND, $1, $3); } +; + +symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); } +	| T_WORD_QUOTE	{ $$ = sym_lookup($1, SYMBOL_CONST); free($1); } +; + +word_opt: /* empty */			{ $$ = NULL; } +	| T_WORD + +%% + +void conf_parse(const char *name) +{ +	struct symbol *sym; +	int i; + +	zconf_initscan(name); + +	sym_init(); +	_menu_init(); +	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); + +	if (getenv("ZCONF_DEBUG")) +		zconfdebug = 1; +	zconfparse(); +	if (zconfnerrs) +		exit(1); +	if (!modules_sym) +		modules_sym = sym_find( "n" ); + +	rootmenu.prompt->text = _(rootmenu.prompt->text); +	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); + +	menu_finalize(&rootmenu); +	for_all_symbols(i, sym) { +		if (sym_check_deps(sym)) +			zconfnerrs++; +	} +	if (zconfnerrs) +		exit(1); +	sym_set_change_count(1); +} + +static const char *zconf_tokenname(int token) +{ +	switch (token) { +	case T_MENU:		return "menu"; +	case T_ENDMENU:		return "endmenu"; +	case T_CHOICE:		return "choice"; +	case T_ENDCHOICE:	return "endchoice"; +	case T_IF:		return "if"; +	case T_ENDIF:		return "endif"; +	case T_DEPENDS:		return "depends"; +	case T_VISIBLE:		return "visible"; +	} +	return "<token>"; +} + +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) +{ +	if (id->token != endtoken) { +		zconf_error("unexpected '%s' within %s block", +			kconf_id_strings + id->name, zconf_tokenname(starttoken)); +		zconfnerrs++; +		return false; +	} +	if (current_menu->file != current_file) { +		zconf_error("'%s' in different file than '%s'", +			kconf_id_strings + id->name, zconf_tokenname(starttoken)); +		fprintf(stderr, "%s:%d: location of the '%s'\n", +			current_menu->file->name, current_menu->lineno, +			zconf_tokenname(starttoken)); +		zconfnerrs++; +		return false; +	} +	return true; +} + +static void zconfprint(const char *err, ...) +{ +	va_list ap; + +	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); +	va_start(ap, err); +	vfprintf(stderr, err, ap); +	va_end(ap); +	fprintf(stderr, "\n"); +} + +static void zconf_error(const char *err, ...) +{ +	va_list ap; + +	zconfnerrs++; +	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); +	va_start(ap, err); +	vfprintf(stderr, err, ap); +	va_end(ap); +	fprintf(stderr, "\n"); +} + +static void zconferror(const char *err) +{ +	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); +} + +static void print_quoted_string(FILE *out, const char *str) +{ +	const char *p; +	int len; + +	putc('"', out); +	while ((p = strchr(str, '"'))) { +		len = p - str; +		if (len) +			fprintf(out, "%.*s", len, str); +		fputs("\\\"", out); +		str = p + 1; +	} +	fputs(str, out); +	putc('"', out); +} + +static void print_symbol(FILE *out, struct menu *menu) +{ +	struct symbol *sym = menu->sym; +	struct property *prop; + +	if (sym_is_choice(sym)) +		fprintf(out, "\nchoice\n"); +	else +		fprintf(out, "\nconfig %s\n", sym->name); +	switch (sym->type) { +	case S_BOOLEAN: +		fputs("  boolean\n", out); +		break; +	case S_TRISTATE: +		fputs("  tristate\n", out); +		break; +	case S_STRING: +		fputs("  string\n", out); +		break; +	case S_INT: +		fputs("  integer\n", out); +		break; +	case S_HEX: +		fputs("  hex\n", out); +		break; +	default: +		fputs("  ???\n", out); +		break; +	} +	for (prop = sym->prop; prop; prop = prop->next) { +		if (prop->menu != menu) +			continue; +		switch (prop->type) { +		case P_PROMPT: +			fputs("  prompt ", out); +			print_quoted_string(out, prop->text); +			if (!expr_is_yes(prop->visible.expr)) { +				fputs(" if ", out); +				expr_fprint(prop->visible.expr, out); +			} +			fputc('\n', out); +			break; +		case P_DEFAULT: +			fputs( "  default ", out); +			expr_fprint(prop->expr, out); +			if (!expr_is_yes(prop->visible.expr)) { +				fputs(" if ", out); +				expr_fprint(prop->visible.expr, out); +			} +			fputc('\n', out); +			break; +		case P_CHOICE: +			fputs("  #choice value\n", out); +			break; +		case P_SELECT: +			fputs( "  select ", out); +			expr_fprint(prop->expr, out); +			fputc('\n', out); +			break; +		case P_RANGE: +			fputs( "  range ", out); +			expr_fprint(prop->expr, out); +			fputc('\n', out); +			break; +		case P_MENU: +			fputs( "  menu ", out); +			print_quoted_string(out, prop->text); +			fputc('\n', out); +			break; +		default: +			fprintf(out, "  unknown prop %d!\n", prop->type); +			break; +		} +	} +	if (menu->help) { +		int len = strlen(menu->help); +		while (menu->help[--len] == '\n') +			menu->help[len] = 0; +		fprintf(out, "  help\n%s\n", menu->help); +	} +} + +void zconfdump(FILE *out) +{ +	struct property *prop; +	struct symbol *sym; +	struct menu *menu; + +	menu = rootmenu.list; +	while (menu) { +		if ((sym = menu->sym)) +			print_symbol(out, menu); +		else if ((prop = menu->prompt)) { +			switch (prop->type) { +			case P_COMMENT: +				fputs("\ncomment ", out); +				print_quoted_string(out, prop->text); +				fputs("\n", out); +				break; +			case P_MENU: +				fputs("\nmenu ", out); +				print_quoted_string(out, prop->text); +				fputs("\n", out); +				break; +			default: +				; +			} +			if (!expr_is_yes(prop->visible.expr)) { +				fputs("  depends ", out); +				expr_fprint(prop->visible.expr, out); +				fputc('\n', out); +			} +		} + +		if (menu->list) +			menu = menu->list; +		else if (menu->next) +			menu = menu->next; +		else while ((menu = menu->parent)) { +			if (menu->prompt && menu->prompt->type == P_MENU) +				fputs("\nendmenu\n", out); +			if (menu->next) { +				menu = menu->next; +				break; +			} +		} +	} +} + +#include "zconf.lex.c" +#include "util.c" +#include "confdata.c" +#include "expr.c" +#include "symbol.c" +#include "menu.c" diff --git a/programs/src/kconfig/kconfig_parser.c b/programs/src/kconfig/kconfig_parser.c new file mode 100644 index 0000000..4fac8b2 --- /dev/null +++ b/programs/src/kconfig/kconfig_parser.c @@ -0,0 +1,100 @@ +#include <stdio.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <locale.h> +#include <stdbool.h> +#include "kconfig/lkc.h" +#include "symlist.h" +#include "boolexp.h" +#include "output.h" + +void kconfig_menu_walker(void (*solve) +                          (struct symbol * sym)); + +void solve_names(struct symbol *sym); +void solve_dep(struct symbol *sym); + +struct symlist *gsymlist; +int noname_num; + +int main(int argc, char **argv) { + +    if (argc < 2) { +        printf("No input file specified\n"); +        return; +    } + +    setlocale(LC_ALL, ""); +    bindtextdomain(PACKAGE, LOCALEDIR); +    textdomain(PACKAGE); + +    conf_parse(argv[1]); +    sym_clear_all_valid(); + +    gsymlist = symlist_create(); + +    kconfig_menu_walker(solve_names); +    kconfig_menu_walker(solve_dep); + +    //symlist_print(gsymlist); +	fprint_rules(gsymlist); +	fprint_linker(gsymlist); +} + +void kconfig_menu_walker(void (*solve) (struct symbol * sym)) { +    struct menu *menu; +    struct symbol *sym; +    menu = rootmenu.list; + +    while (menu != NULL) { +        sym = menu->sym; +        if (sym != NULL) { +            do { +                if (sym->type == S_BOOLEAN || sym->type == S_TRISTATE) { +                    solve(sym); +                } +            } while ((sym = sym->next) != NULL); +        } +        // switch to menu +        if (menu->list != NULL) { +            menu = menu->list; +        } else if (menu->next != NULL) { +            menu = menu->next; +        } else { +            while ((menu = menu->parent) != NULL) { +                if (menu->next != NULL) { +                    menu = menu->next; +                    break; +                } +            } +        } +    } +} + +void solve_names(struct symbol *sym) { +    if (sym->name != NULL) { +        if (symlist_find(gsymlist, sym->name) == NULL) +            symlist_add(gsymlist, sym->name); +    } else { +        sym->name = malloc((9 + 7) * sizeof(char)); +        sprintf(sym->name, "NONAMEGEN%d", noname_num++); +        symlist_add(gsymlist, sym->name); +    } +} + +void solve_dep(struct symbol *sym) { +    if (sym->dir_dep.expr != NULL) { +        struct symlist_el *el; +        el = symlist_find(gsymlist, sym->name); +        el->be = copy_kconfig_dep(gsymlist, sym->dir_dep.expr); +        if (el->be != NULL) +            el->be = boolexp_cnf(el->be); +    } +} diff --git a/programs/src/kconfig/output.c b/programs/src/kconfig/output.c new file mode 100644 index 0000000..ed9daec --- /dev/null +++ b/programs/src/kconfig/output.c @@ -0,0 +1,82 @@ +#include "output.h" + +void fprint_rules(struct symlist *sl) { +    FILE *f; +    f = fopen(RULES_FILE, "w"); +    if (f == NULL) { +        fprintf(stderr, "Can't create file: %s\n", RULES_FILE); +        return; +    } +    int i; +    struct symlist_el *el; +    struct boolexp *be; +    struct boolexp **stack; +    size_t stack_size = 2, stack_pos = 0; +    int count_or, count_and; +    stack = malloc(stack_size * sizeof(struct boolexp *)); +    for (i = 0; i < sl->pos; i++) { +        if (sl->array[i].be != NULL) { +            el = sl->array + i; +            be = el->be; +            stack_pos = 0; +            count_or = 0; +            count_and = 0; +            fprintf(f, "-%d ", el->id); +            while (be != NULL) { +                if (stack_pos >= stack_size) { +                    stack_size *= 2; +                    stack = +                        realloc(stack, +                                stack_size * sizeof(struct boolexp *)); +                } +                switch (be->type) { +                case BE_NOT: +                    fprintf(f, "-"); +                    be = be->left.be; +                    break; +                case BE_AND: +                    count_and++; +                    stack[stack_pos++] = be->right.be; +                    be = be->left.be; +                    break; +                case BE_OR: +                    count_or++; +                    stack[stack_pos++] = be->right.be; +                    be = be->left.be; +                    break; +                case BE_LEAF: +                    fprintf(f, "%d", be->left.id); +                    if (count_or > 0) { +                        fprintf(f, " "); +                        count_or--; +                    } else if (count_and > 0) { +                        fprintf(f, "\n-%d ", el->id); +                        count_and--; +                    } +                    if (stack_pos > 0) +                        be = stack[--stack_pos]; +                    else +                        be = NULL; +                    break; +                } +            } +            fprintf(f, "\n"); +        } +    } +    free(stack); +    fclose(f); +} + +void fprint_linker(struct symlist *sl) { +    FILE *f; +    f = fopen(LINKER_FILE, "w"); +    if (f == NULL) { +        fprintf(stderr, "Can't create file: %s\n", RULES_FILE); +        return; +    } +    int i; +    for (i = 0; i < sl->pos; i++) { +        fprintf(f, "%d:%s\n", sl->array[i].id, sl->array[i].name); +    } +    fclose(f); +} diff --git a/programs/src/kconfig/output.h b/programs/src/kconfig/output.h new file mode 100644 index 0000000..aefbc0f --- /dev/null +++ b/programs/src/kconfig/output.h @@ -0,0 +1,14 @@ +#ifndef _OUTPUT_H_ +#define _OUTPUT_H_ + +#include <stdlib.h> +#include <stdio.h> +#include "symlist.h" + +#define RULES_FILE "rules" +#define LINKER_FILE "linker" + +void fprint_rules(struct symlist *sl); +void fprint_linker(struct symlist *sl); + +#endif /* _OUTPUT_H_ */ diff --git a/programs/src/kconfig/symlist.c b/programs/src/kconfig/symlist.c new file mode 100644 index 0000000..7dcd2c6 --- /dev/null +++ b/programs/src/kconfig/symlist.c @@ -0,0 +1,49 @@ +#include "symlist.h" + +struct symlist *symlist_create() { +    struct symlist *ret; +    ret = malloc(sizeof(struct symlist)); +    ret->size = 2; +    ret->pos = 0; +    ret->array = malloc(ret->size * sizeof(struct symlist_el)); +    return ret; +} + +void symlist_add(struct symlist *sl, char *name) { +    if (sl->pos >= sl->size) { +        sl->size *= 2; +        sl->array = +            realloc(sl->array, sl->size * sizeof(struct symlist_el)); +    } +    sl->array[sl->pos].id = sl->pos + 1; +    sl->array[sl->pos].name = name; +    sl->array[sl->pos].be = NULL; +    sl->pos++; +} + +struct symlist_el *symlist_find(struct symlist *sl, char *name) { +    int i = 0; +    while (i < sl->pos) { +        if (!strcmp(name, sl->array[i].name)) +            return &sl->array[i]; +        i++; +    } +    return NULL; +} + +void symlist_print(struct symlist *sl) { +    int i; +    for (i = 0; i < sl->pos; i++) { +        printf("%d:%s\n", sl->array[i].id, sl->array[i].name); +        if (sl->array[i].be != NULL) { +            printf("  "); +            boolexp_print(sl->array[i].be); +            printf("\n"); +        } +    } +} + +void symlist_free(struct symlist *sl) { +    free(sl->array); +    free(sl); +} diff --git a/programs/src/kconfig/symlist.h b/programs/src/kconfig/symlist.h new file mode 100644 index 0000000..caa827a --- /dev/null +++ b/programs/src/kconfig/symlist.h @@ -0,0 +1,24 @@ +#ifndef _SYMLIST_H_ +#define _SYMLIST_H_ + +#include <stdbool.h> +#include <string.h> +#include "boolexp.h" + +struct symlist_el { +    unsigned int id; +    char *name; +    struct boolexp *be; +}; +struct symlist { +    struct symlist_el *array; +    size_t size, pos; +}; + +struct symlist *symlist_create(); +void symlist_add(struct symlist *sl, char *name); +struct symlist_el *symlist_find(struct symlist *sl, char *name); +void symlist_print(struct symlist *sl); +void symlist_free(struct symlist *sl); + +#endif /* _SYMLIST_H_ */ | 
