Browse Source

Merge/rework config system per the latest from linux-2.6.0-test2
-Erik

Eric Andersen 21 years ago
parent
commit
fcf8c55eb4

+ 113 - 113
extra/config/conf.c

@@ -35,50 +35,12 @@ static struct menu *rootEntry;
 
 static char nohelp_text[] = "Sorry, no help available for this option yet.\n";
 
-#if 0
-static void printc(int ch)
-{
-	static int sep = 0;
-
-	if (!sep) {
-		putchar('[');
-		sep = 1;
-	} else if (ch)
-		putchar('/');
-	if (!ch) {
-		putchar(']');
-		putchar(' ');
-		sep = 0;
-	} else
-		putchar(ch);
-}
-#endif
-
-static void printo(const char *o)
-{
-	static int sep = 0;
-
-	if (!sep) {
-		putchar('(');
-		sep = 1;
-	} else if (o) {
-		putchar(',');
-		putchar(' ');
-	}
-	if (!o) {
-		putchar(')');
-		putchar(' ');
-		sep = 0;
-	} else
-		printf("%s", o);
-}
-
 static void strip(char *str)
 {
 	char *p = str;
 	int l;
 
-	while ((isspace((int)*p)))
+	while ((isspace(*p)))
 		p++;
 	l = strlen(p);
 	if (p != str)
@@ -86,10 +48,20 @@ static void strip(char *str)
 	if (!l)
 		return;
 	p = str + l - 1;
-	while ((isspace((int)*p)))
+	while ((isspace(*p)))
 		*p-- = 0;
 }
 
+static void check_stdin(void)
+{
+	if (!valid_stdin && input_mode == ask_silent) {
+		printf("aborted!\n\n");
+		printf("Console input/output is redirected. ");
+		printf("Run 'make oldconfig' to update configuration.\n\n");
+		exit(1);
+	}
+}
+
 static void conf_askvalue(struct symbol *sym, const char *def)
 {
 	enum symbol_type type = sym_get_type(sym);
@@ -101,6 +73,13 @@ static void conf_askvalue(struct symbol *sym, const char *def)
 	line[0] = '\n';
 	line[1] = 0;
 
+	if (!sym_is_changable(sym)) {
+		printf("%s\n", def);
+		line[0] = '\n';
+		line[1] = 0;
+		return;
+	}
+
 	switch (input_mode) {
 	case ask_new:
 	case ask_silent:
@@ -108,12 +87,7 @@ static void conf_askvalue(struct symbol *sym, const char *def)
 			printf("%s\n", def);
 			return;
 		}
-		if (!valid_stdin && input_mode == ask_silent) {
-			printf("aborted!\n\n");
-			printf("Console input/output is redirected. ");
-			printf("Run 'make oldconfig' to update configuration.\n\n");
-			exit(1);
-		}
+		check_stdin();
 	case ask_all:
 		fflush(stdout);
 		fgets(line, 128, stdin);
@@ -294,9 +268,8 @@ help:
 static int conf_choice(struct menu *menu)
 {
 	struct symbol *sym, *def_sym;
-	struct menu *cmenu, *def_menu;
-	const char *help;
-	int type, len;
+	struct menu *child;
+	int type;
 	bool is_new;
 
 	sym = menu->sym;
@@ -314,72 +287,111 @@ static int conf_choice(struct menu *menu)
 			break;
 		}
 	} else {
-		sym->def = sym->curr;
-		if (S_TRI(sym->curr) == mod) {
+		switch (sym_get_tristate_value(sym)) {
+		case no:
+			return 1;
+		case mod:
 			printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
 			return 0;
+		case yes:
+			break;
 		}
 	}
 
 	while (1) {
-		printf("%*s%s ", indent - 1, "", menu_get_prompt(menu));
+		int cnt, def;
+
+		printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
 		def_sym = sym_get_choice_value(sym);
-		def_menu = NULL;
-		for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
-			if (!menu_is_visible(cmenu))
+		cnt = def = 0;
+		line[0] = '0';
+		line[1] = 0;
+		for (child = menu->list; child; child = child->next) {
+			if (!menu_is_visible(child))
 				continue;
-			printo(menu_get_prompt(cmenu));
-			if (cmenu->sym == def_sym)
-				def_menu = cmenu;
-		}
-		printo(NULL);
-		if (def_menu)
-			printf("[%s] ", menu_get_prompt(def_menu));
-		else {
+			if (!child->sym) {
+				printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+				continue;
+			}
+			cnt++;
+			if (child->sym == def_sym) {
+				def = cnt;
+				printf("%*c", indent, '>');
+			} else
+				printf("%*c", indent, ' ');
+			printf(" %d. %s", cnt, menu_get_prompt(child));
+			if (child->sym->name)
+				printf(" (%s)", child->sym->name);
+			if (!sym_has_value(child->sym))
+				printf(" (NEW)");
 			printf("\n");
-			return 1;
 		}
+		printf("%*schoice", indent - 1, "");
+		if (cnt == 1) {
+			printf("[1]: 1\n");
+			goto conf_childs;
+		}
+		printf("[1-%d", cnt);
+		if (sym->help)
+			printf("?");
+		printf("]: ");
 		switch (input_mode) {
 		case ask_new:
 		case ask_silent:
+			if (!is_new) {
+				cnt = def;
+				printf("%d\n", cnt);
+				break;
+			}
+			check_stdin();
 		case ask_all:
-			conf_askvalue(sym, menu_get_prompt(def_menu));
+			fflush(stdout);
+			fgets(line, 128, stdin);
 			strip(line);
+			if (line[0] == '?') {
+				printf("\n%s\n", menu->sym->help ?
+					menu->sym->help : nohelp_text);
+				continue;
+			}
+			if (!line[0])
+				cnt = def;
+			else if (isdigit(line[0]))
+				cnt = atoi(line);
+			else
+				continue;
+			break;
+		case set_random:
+			def = (random() % cnt) + 1;
+		case set_default:
+		case set_yes:
+		case set_mod:
+		case set_no:
+			cnt = def;
+			printf("%d\n", cnt);
 			break;
-		default:
-			line[0] = 0;
-			printf("\n");
 		}
-		if (line[0] == '?' && !line[1]) {
-			help = nohelp_text;
-			if (menu->sym->help)
-				help = menu->sym->help;
-			printf("\n%s\n", help);
-			continue;
+
+	conf_childs:
+		for (child = menu->list; child; child = child->next) {
+			if (!child->sym || !menu_is_visible(child))
+				continue;
+			if (!--cnt)
+				break;
 		}
-		if (line[0]) {
-			len = strlen(line);
-			line[len] = 0;
-
-			def_menu = NULL;
-			for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
-				if (!cmenu->sym || !menu_is_visible(cmenu))
-					continue;
-				if (!strncasecmp(line, menu_get_prompt(cmenu), len)) {
-					def_menu = cmenu;
-					break;
-				}
-			}
+		if (!child)
+			continue;
+		if (line[strlen(line) - 1] == '?') {
+			printf("\n%s\n", child->sym->help ?
+				child->sym->help : nohelp_text);
+			continue;
 		}
-		if (def_menu) {
-			sym_set_choice_value(sym, def_menu->sym);
-			if (def_menu->list) {
-				indent += 2;
-				conf(def_menu->list);
-				indent -= 2;
-			}
-			return 1;
+		sym_set_choice_value(sym, child->sym);
+		if (child->list) {
+			indent += 2;
+			conf(child->list);
+			indent -= 2;
 		}
+		return 1;
 	}
 }
 
@@ -420,7 +432,7 @@ static void conf(struct menu *menu)
 
 	if (sym_is_choice(sym)) {
 		conf_choice(menu);
-		if (S_TRI(sym->curr) != mod)
+		if (sym->curr.tri != mod)
 			return;
 		goto conf_childs;
 	}
@@ -454,29 +466,17 @@ static void check_conf(struct menu *menu)
 		return;
 
 	sym = menu->sym;
-	if (!sym)
-		goto conf_childs;
-
-	if (sym_is_choice(sym)) {
-		if (!sym_has_value(sym)) {
+	if (sym) {
+		if (sym_is_changable(sym) && !sym_has_value(sym)) {
 			if (!conf_cnt++)
 				printf("*\n* Restart config...\n*\n");
 			rootEntry = menu_get_parent_menu(menu);
 			conf(rootEntry);
 		}
-		if (sym_get_tristate_value(sym) != mod)
+		if (sym_is_choice(sym) && sym_get_tristate_value(sym) != mod)
 			return;
-		goto conf_childs;
 	}
 
-	if (!sym_has_value(sym)) {
-		if (!conf_cnt++)
-			printf("*\n* Restart config...\n*\n");
-		rootEntry = menu_get_parent_menu(menu);
-		conf(rootEntry);
-	}
-
-conf_childs:
 	for (child = menu->list; child; child = child->next)
 		check_conf(child);
 }
@@ -536,8 +536,8 @@ int main(int ac, char **av)
 			printf("***\n"
 				"*** You have not yet configured uClibc!\n"
 				"***\n"
-				"*** Please run some configurator (e.g. \"make oldconfig\"\n"
-				"*** or \"make menuconfig\").\n"
+				"*** Please run some configurator (e.g. \"make config\" or\n"
+				"*** \"make oldconfig\" or \"make menuconfig\").\n"
 				"***\n");
 			exit(1);
 		}

+ 159 - 96
extra/config/confdata.c

@@ -1,11 +1,9 @@
 /*
  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
  * Released under the terms of the GNU GPL v2.0.
- *
- * Allow 'n' as a symbol value.
- * 2002-11-05 Petr Baudis <pasky@ucw.cz>
  */
 
+#include <sys/stat.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -38,7 +36,7 @@ static char *conf_expand_value(const char *in)
 		strncat(res_value, in, src - in);
 		src++;
 		dst = name;
-		while (isalnum((int)*src) || *src == '_')
+		while (isalnum(*src) || *src == '_')
 			*dst++ = *src++;
 		*dst = 0;
 		sym = sym_lookup(name, 0);
@@ -53,7 +51,18 @@ static char *conf_expand_value(const char *in)
 
 char *conf_get_default_confname(void)
 {
-	return conf_expand_value(conf_defname);
+	struct stat buf;
+	static char fullname[4096+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;
 }
 
 int conf_read(const char *name)
@@ -68,12 +77,12 @@ int conf_read(const char *name)
 	int i;
 
 	if (name) {
-		in = fopen(name, "r");
+		in = zconf_fopen(name);
 	} else {
 		const char **names = conf_confnames;
 		while ((name = *names++)) {
 			name = conf_expand_value(name);
-			in = fopen(name, "r");
+			in = zconf_fopen(name);
 			if (in) {
 				printf("#\n"
 				       "# using defaults found in %s\n"
@@ -93,44 +102,43 @@ int conf_read(const char *name)
 		case S_INT:
 		case S_HEX:
 		case S_STRING:
-			if (S_VAL(sym->def))
-				free(S_VAL(sym->def));
+			if (sym->user.val)
+				free(sym->user.val);
 		default:
-			S_VAL(sym->def) = NULL;
-			S_TRI(sym->def) = no;
-			;
+			sym->user.val = NULL;
+			sym->user.tri = no;
 		}
 	}
 
 	while (fgets(line, sizeof(line), in)) {
 		lineno++;
+		sym = NULL;
 		switch (line[0]) {
-		case '\n':
-			break;
-		case ' ':
-			break;
 		case '#':
-			p = strchr(line, ' ');
-			if (!p)
+			if (line[1]!=' ')
 				continue;
-			*p++ = 0;
-			p = strchr(p, ' ');
+			p = strchr(line + 2, ' ');
 			if (!p)
 				continue;
 			*p++ = 0;
 			if (strncmp(p, "is not set", 10))
 				continue;
-			sym = sym_lookup(line+2, 0);
+			sym = sym_find(line + 2);
+			if (!sym) {
+				fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 2);
+				break;
+			}
 			switch (sym->type) {
 			case S_BOOLEAN:
 			case S_TRISTATE:
-				sym->def = symbol_no.curr;
+				sym->user.tri = no;
 				sym->flags &= ~SYMBOL_NEW;
 				break;
 			default:
 				;
 			}
 			break;
+
 		case 'A' ... 'Z':
 			p = strchr(line, '=');
 			if (!p)
@@ -145,24 +153,24 @@ int conf_read(const char *name)
 				break;
 			}
 			switch (sym->type) {
-  			case S_TRISTATE:
+			case S_TRISTATE:
 				if (p[0] == 'm') {
-					S_TRI(sym->def) = mod;
+					sym->user.tri = mod;
 					sym->flags &= ~SYMBOL_NEW;
 					break;
 				}
 			case S_BOOLEAN:
 				if (p[0] == 'y') {
-					S_TRI(sym->def) = yes;
+					sym->user.tri = yes;
 					sym->flags &= ~SYMBOL_NEW;
 					break;
 				}
 				if (p[0] == 'n') {
-					S_TRI(sym->def) = no;
+					sym->user.tri = no;
 					sym->flags &= ~SYMBOL_NEW;
 					break;
 				}
-  				break;
+				break;
 			case S_STRING:
 				if (*p++ != '"')
 					break;
@@ -173,48 +181,71 @@ int conf_read(const char *name)
 					}
 					memmove(p2, p2 + 1, strlen(p2));
 				}
+				if (!p2) {
+					fprintf(stderr, "%s:%d: invalid string found\n", name, lineno);
+					exit(1);
+				}
 			case S_INT:
 			case S_HEX:
 				if (sym_string_valid(sym, p)) {
-					S_VAL(sym->def) = strdup(p);
+					sym->user.val = strdup(p);
 					sym->flags &= ~SYMBOL_NEW;
-				} else
-					fprintf(stderr, "%s:%d:symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
+				} else {
+					fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
+					exit(1);
+				}
 				break;
 			default:
 				;
 			}
-			if (sym_is_choice_value(sym)) {
-				prop = sym_get_choice_prop(sym);
-				switch (S_TRI(sym->def)) {
-				case mod:
-					if (S_TRI(prop->def->def) == yes)
-						/* warn? */;
-					break;
-				case yes:
-					if (S_TRI(prop->def->def) != no)
-						/* warn? */;
-					S_VAL(prop->def->def) = sym;
-					break;
-				case no:
-					break;
-				}
-				S_TRI(prop->def->def) = S_TRI(sym->def);
-			}
+			break;
+		case '\n':
 			break;
 		default:
 			continue;
 		}
+		if (sym && sym_is_choice_value(sym)) {
+			struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+			switch (sym->user.tri) {
+			case no:
+				break;
+			case mod:
+				if (cs->user.tri == yes)
+					/* warn? */;
+				break;
+			case yes:
+				if (cs->user.tri != no)
+					/* warn? */;
+				cs->user.val = sym;
+				break;
+			}
+			cs->user.tri = E_OR(cs->user.tri, sym->user.tri);
+			cs->flags &= ~SYMBOL_NEW;
+		}
 	}
 	fclose(in);
 
 	for_all_symbols(i, sym) {
+		sym_calc_value(sym);
+		if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+			if (sym->visible == no)
+				sym->flags |= SYMBOL_NEW;
+			switch (sym->type) {
+			case S_STRING:
+			case S_INT:
+			case S_HEX:
+				if (!sym_string_within_range(sym, sym->user.val))
+					sym->flags |= SYMBOL_NEW;
+			default:
+				break;
+			}
+		}
 		if (!sym_is_choice(sym))
 			continue;
 		prop = sym_get_choice_prop(sym);
-		for (e = prop->dep; e; e = e->left.expr)
-			sym->flags |= e->right.sym->flags & SYMBOL_NEW;
-		sym->flags &= ~SYMBOL_NEW;
+		for (e = prop->expr; e; e = e->left.expr)
+			if (e->right.sym->visible != no)
+				sym->flags |= e->right.sym->flags & SYMBOL_NEW;
 	}
 
 	sym_change_count = 1;
@@ -227,36 +258,57 @@ int conf_write(const char *name)
 	FILE *out, *out_h;
 	struct symbol *sym;
 	struct menu *menu;
-	char oldname[128];
+	const char *basename;
+	char dirname[128], tmpname[128], newname[128];
 	int type, l;
 	const char *str;
 
-	out = fopen(".tmpconfig", "w");
+	dirname[0] = 0;
+	if (name && name[0]) {
+		char *slash = strrchr(name, '/');
+		if (slash) {
+			int size = slash - name + 1;
+			memcpy(dirname, name, size);
+			dirname[size] = 0;
+			if (slash[1])
+				basename = slash + 1;
+			else
+				basename = conf_def_filename;
+		} else
+			basename = name;
+	} else
+		basename = conf_def_filename;
+
+	sprintf(newname, "%s.tmpconfig.%d", dirname, getpid());
+	out = fopen(newname, "w");
 	if (!out)
 		return 1;
-	out_h = fopen(".tmpconfig.h", "w");
-	if (!out_h)
-		return 1;
+	out_h = NULL;
+	if (!name) {
+		out_h = fopen(".tmpconfig.h", "w");
+		if (!out_h)
+			return 1;
+	}
 	fprintf(out, "#\n"
 		     "# Automatically generated make config: don't edit\n"
 		     "#\n");
-	fprintf(out_h, "/*\n"
-		       " * Automatically generated C config: don't edit\n"
-		       " */\n"
-		       "#if !defined __FEATURES_H && !defined __need_uClibc_config_h\n"
-		       "#error Never include <bits/uClibc_config.h> directly; use <features.h> instead.\n"
-		       "#endif\n"
-		       "#define AUTOCONF_INCLUDED\n\n"
-		       "/*\n"
-		       " * Version Number\n"
-		       " */\n"
-		       "#define __UCLIBC_MAJOR__ %s\n"
-		       "#define __UCLIBC_MINOR__ %s\n"
-		       "#define __UCLIBC_SUBLEVEL__ %s\n",
-		       getenv("MAJOR_VERSION"),
-		       getenv("MINOR_VERSION"),
-		       getenv("SUBLEVEL")
-       );
+	if (out_h)
+		fprintf(out_h, "/*\n"
+			     " * Automatically generated C config: don't edit\n"
+			     " */\n"
+			     "#if !defined __FEATURES_H && !defined __need_uClibc_config_h\n"
+			     "#error Never include <bits/uClibc_config.h> directly; use <features.h> instead\n"
+			     "#endif\n"
+			     "#define AUTOCONF_INCLUDED\n\n"
+			     "/*\n"
+			     " * Version Number\n"
+			     " */\n"
+			     "#define __UCLIBC_MAJOR__ %s\n"
+			     "#define __UCLIBC_MINOR__ %s\n"
+			     "#define __UCLIBC_SUBLEVEL__ %s\n",
+			     getenv("MAJOR_VERSION"),
+			     getenv("MINOR_VERSION"),
+			     getenv("SUBLEVEL"));
 
 	if (!sym_change_count)
 		sym_clear_all_valid();
@@ -272,10 +324,11 @@ int conf_write(const char *name)
 				     "#\n"
 				     "# %s\n"
 				     "#\n", str);
-			fprintf(out_h, "\n"
-				       "/*\n"
-				       " * %s\n"
-				       " */\n", str);
+			if (out_h)
+				fprintf(out_h, "\n"
+					       "/*\n"
+					       " * %s\n"
+					       " */\n", str);
 		} else if (!(sym->flags & SYMBOL_CHOICE)) {
 			sym_calc_value(sym);
 			if (!(sym->flags & SYMBOL_WRITE))
@@ -284,7 +337,7 @@ int conf_write(const char *name)
 			type = sym->type;
 			if (type == S_TRISTATE) {
 				sym_calc_value(modules_sym);
-				if (S_TRI(modules_sym->curr) == no)
+				if (modules_sym->curr.tri == no)
 					type = S_BOOLEAN;
 			}
 			switch (type) {
@@ -293,15 +346,18 @@ int conf_write(const char *name)
 				switch (sym_get_tristate_value(sym)) {
 				case no:
 					fprintf(out, "# %s is not set\n", sym->name);
-					fprintf(out_h, "#undef __%s__\n", sym->name);
+					if (out_h)
+						fprintf(out_h, "#undef %s\n", sym->name);
 					break;
 				case mod:
 					fprintf(out, "%s=m\n", sym->name);
-					fprintf(out_h, "#define __%s__MODULE 1\n", sym->name);
+					if (out_h)
+						fprintf(out_h, "#define %s_MODULE 1\n", sym->name);
 					break;
 				case yes:
 					fprintf(out, "%s=y\n", sym->name);
-					fprintf(out_h, "#define __%s__ 1\n", sym->name);
+					if (out_h)
+						fprintf(out_h, "#define __%s__ 1\n", sym->name);
 					break;
 				}
 				break;
@@ -309,34 +365,40 @@ int conf_write(const char *name)
 				// fix me
 				str = sym_get_string_value(sym);
 				fprintf(out, "%s=\"", sym->name);
-				fprintf(out_h, "#define __%s__ \"", sym->name);
+				if (out_h)
+					fprintf(out_h, "#define __%s__ \"", sym->name);
 				do {
 					l = strcspn(str, "\"\\");
 					if (l) {
 						fwrite(str, l, 1, out);
-						fwrite(str, l, 1, out_h);
+						if (out_h)
+							fwrite(str, l, 1, out_h);
 					}
 					str += l;
 					while (*str == '\\' || *str == '"') {
 						fprintf(out, "\\%c", *str);
-						fprintf(out_h, "\\%c", *str);
+						if (out_h)
+							fprintf(out_h, "\\%c", *str);
 						str++;
 					}
 				} while (*str);
 				fputs("\"\n", out);
-				fputs("\"\n", out_h);
+				if (out_h)
+					fputs("\"\n", out_h);
 				break;
 			case S_HEX:
 				str = sym_get_string_value(sym);
 				if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
 					fprintf(out, "%s=%s\n", sym->name, str);
-					fprintf(out_h, "#define __%s__ 0x%s\n", sym->name, str);
+					if (out_h)
+						fprintf(out_h, "#define __%s__ 0x%s\n", sym->name, str);
 					break;
 				}
 			case S_INT:
 				str = sym_get_string_value(sym);
 				fprintf(out, "%s=%s\n", sym->name, str);
-				fprintf(out_h, "#define __%s__ %s\n", sym->name, str);
+				if (out_h)
+					fprintf(out_h, "#define __%s__ %s\n", sym->name, str);
 				break;
 			}
 		}
@@ -356,18 +418,19 @@ int conf_write(const char *name)
 		}
 	}
 	fclose(out);
-	fclose(out_h);
-
-	if (!name) {
+	if (out_h) {
+		fclose(out_h);
 		rename(".tmpconfig.h", "include/bits/uClibc_config.h");
-		name = conf_def_filename;
 		file_write_dep(NULL);
-	} else
-		unlink(".tmpconfig.h");
-
-	sprintf(oldname, "%s.old", name);
-	rename(name, oldname);
-	if (rename(".tmpconfig", name))
+	}
+	if (!name || basename != conf_def_filename) {
+		if (!name)
+			name = conf_def_filename;
+		sprintf(tmpname, "%s.old", name);
+		rename(name, tmpname);
+	}
+	sprintf(tmpname, "%s%s", dirname, basename);
+	if (rename(newname, tmpname))
 		return 1;
 
 	sym_change_count = 0;

+ 33 - 4
extra/config/expr.c

@@ -55,6 +55,13 @@ struct expr *expr_alloc_and(struct expr *e1, struct expr *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(struct expr *org)
 {
 	struct expr *e;
@@ -158,9 +165,22 @@ static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct e
 
 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
 {
-	if (!e1 || !e2 || e1->type != e2->type)
+	if (!e1 || !e2)
 		return;
-	__expr_eliminate_eq(e1->type, ep1, ep2);
+	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);
 }
@@ -195,6 +215,7 @@ int expr_eq(struct expr *e1, struct expr *e2)
 		trans_count = old_count;
 		return res;
 	case E_CHOICE:
+	case E_RANGE:
 	case E_NONE:
 		/* panic */;
 	}
@@ -897,6 +918,7 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
 	case E_SYMBOL:
 		return expr_alloc_comp(type, e->left.sym, sym);
 	case E_CHOICE:
+	case E_RANGE:
 	case E_NONE:
 		/* panic */;
 	}
@@ -914,7 +936,7 @@ tristate expr_calc_value(struct expr *e)
 	switch (e->type) {
 	case E_SYMBOL:
 		sym_calc_value(e->left.sym);
-		return S_TRI(e->left.sym->curr);
+		return e->left.sym->curr.tri;
 	case E_AND:
 		val1 = expr_calc_value(e->left.expr);
 		val2 = expr_calc_value(e->right.expr);
@@ -1017,11 +1039,18 @@ void expr_print(struct expr *e, void (*fn)(void *, const char *), void *data, in
 		expr_print(e->right.expr, fn, data, E_AND);
 		break;
 	case E_CHOICE:
+		fn(data, e->right.sym->name);
 		if (e->left.expr) {
-			expr_print(e->left.expr, fn, data, E_CHOICE);
 			fn(data, " ^ ");
+			expr_print(e->left.expr, fn, data, E_CHOICE);
 		}
+		break;
+	case E_RANGE:
+		fn(data, "[");
+		fn(data, e->left.sym->name);
+		fn(data, " ");
 		fn(data, e->right.sym->name);
+		fn(data, "]");
 		break;
 	default:
 	  {

+ 17 - 65
extra/config/expr.h

@@ -18,10 +18,6 @@ extern "C" {
 struct file {
 	struct file *next;
 	struct file *parent;
-#ifdef CML1
-	struct statement *stmt;
-	struct statement *last_stmt;
-#endif
 	char *name;
 	int lineno;
 	int flags;
@@ -36,7 +32,7 @@ typedef enum tristate {
 } tristate;
 
 enum expr_type {
-	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL
+	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
 };
 
 union expr_data {
@@ -45,18 +41,10 @@ union expr_data {
 };
 
 struct expr {
-#ifdef CML1
-	int token;
-#else
 	enum expr_type type;
-#endif
 	union expr_data left, right;
 };
 
-#define E_TRI(ev)	((ev).tri)
-#define E_EXPR(ev)	((ev).expr)
-#define E_CALC(ev)	(E_TRI(ev) = expr_calc_value(E_EXPR(ev)))
-
 #define E_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
 #define E_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
 #define E_NOT(dep)		(2-(dep))
@@ -66,12 +54,8 @@ struct expr_value {
 	tristate tri;
 };
 
-#define S_VAL(sv)	((sv).value)
-#define S_TRI(sv)	((sv).tri)
-#define S_EQ(sv1, sv2)	(S_VAL(sv1) == S_VAL(sv2) || !strcmp(S_VAL(sv1), S_VAL(sv2)))
-
 struct symbol_value {
-	void *value;
+	void *val;
 	tristate tri;
 };
 
@@ -83,31 +67,17 @@ struct symbol {
 	struct symbol *next;
 	char *name;
 	char *help;
-#ifdef CML1
-	int type;
-#else
 	enum symbol_type type;
-#endif
-	struct symbol_value curr, def;
+	struct symbol_value curr, user;
 	tristate visible;
 	int flags;
 	struct property *prop;
 	struct expr *dep, *dep2;
-	struct menu *menu;
+	struct expr_value rev_dep;
 };
 
 #define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
 
-#ifdef CML1
-#define SYMBOL_UNKNOWN		S_UNKNOWN
-#define SYMBOL_BOOLEAN		S_BOOLEAN
-#define SYMBOL_TRISTATE		S_TRISTATE
-#define SYMBOL_INT		S_INT
-#define SYMBOL_HEX		S_HEX
-#define SYMBOL_STRING		S_STRING
-#define SYMBOL_OTHER		S_OTHER
-#endif
-
 #define SYMBOL_YES		0x0001
 #define SYMBOL_MOD		0x0002
 #define SYMBOL_NO		0x0004
@@ -122,42 +92,38 @@ struct symbol {
 #define SYMBOL_CHANGED		0x0400
 #define SYMBOL_NEW		0x0800
 #define SYMBOL_AUTO		0x1000
+#define SYMBOL_CHECKED		0x2000
+#define SYMBOL_CHECK_DONE	0x4000
+#define SYMBOL_WARNED		0x8000
 
 #define SYMBOL_MAXLENGTH	256
 #define SYMBOL_HASHSIZE		257
 #define SYMBOL_HASHMASK		0xff
 
 enum prop_type {
-	P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_ROOTMENU, P_DEFAULT, P_CHOICE
+	P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE
 };
 
 struct property {
 	struct property *next;
 	struct symbol *sym;
-#ifdef CML1
-	int token;
-#else
 	enum prop_type type;
-#endif
 	const char *text;
-	struct symbol *def;
 	struct expr_value visible;
-	struct expr *dep;
-	struct expr *dep2;
+	struct expr *expr;
 	struct menu *menu;
 	struct file *file;
 	int lineno;
-#ifdef CML1
-	struct property *next_pos;
-#endif
 };
 
 #define for_all_properties(sym, st, tok) \
 	for (st = sym->prop; st; st = st->next) \
 		if (st->type == (tok))
-#define for_all_prompts(sym, st) for_all_properties(sym, st, P_PROMPT)
 #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;
@@ -166,12 +132,16 @@ struct menu {
 	struct symbol *sym;
 	struct property *prompt;
 	struct expr *dep;
+	unsigned int flags;
 	//char *help;
 	struct file *file;
 	int lineno;
 	void *data;
 };
 
+#define MENU_CHANGED		0x0001
+#define MENU_ROOT		0x0002
+
 #ifndef SWIG
 
 extern struct file *file_list;
@@ -181,18 +151,12 @@ struct file *lookup_file(const char *name);
 extern struct symbol symbol_yes, symbol_no, symbol_mod;
 extern struct symbol *modules_sym;
 extern int cdebug;
-extern int print_type;
 struct expr *expr_alloc_symbol(struct symbol *sym);
-#ifdef CML1
-struct expr *expr_alloc_one(int token, struct expr *ce);
-struct expr *expr_alloc_two(int token, struct expr *e1, struct expr *e2);
-struct expr *expr_alloc_comp(int token, struct symbol *s1, struct symbol *s2);
-#else
 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);
-#endif
 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(struct expr *org);
 void expr_free(struct expr *e);
 int expr_eq(struct expr *e1, struct expr *e2);
@@ -212,17 +176,6 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
 void expr_fprint(struct expr *e, FILE *out);
 void print_expr(int mask, struct expr *e, int prevtoken);
 
-#ifdef CML1
-static inline int expr_is_yes(struct expr *e)
-{
-	return !e || (e->token == WORD && e->left.sym == &symbol_yes);
-}
-
-static inline int expr_is_no(struct expr *e)
-{
-	return e && (e->token == WORD && e->left.sym == &symbol_no);
-}
-#else
 static inline int expr_is_yes(struct expr *e)
 {
 	return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
@@ -233,7 +186,6 @@ static inline int expr_is_no(struct expr *e)
 	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 }
 #endif
-#endif
 
 #ifdef __cplusplus
 }

File diff suppressed because it is too large
+ 377 - 327
extra/config/lex.zconf.c_shipped


+ 13 - 6
extra/config/lkc.h

@@ -21,12 +21,14 @@ extern "C" {
 #include "lkc_proto.h"
 #undef P
 
-void symbol_end(char *help);
+#define SRCTREE "srctree"
+
 int zconfparse(void);
 void zconfdump(FILE *out);
 
 extern int zconfdebug;
 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);
@@ -47,9 +49,11 @@ void menu_add_menu(void);
 void menu_end_menu(void);
 void menu_add_entry(struct symbol *sym);
 void menu_end_entry(void);
-struct property *create_prop(enum prop_type type);
 void menu_add_dep(struct expr *dep);
-struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep);
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
+void 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_finalize(struct menu *parent);
 void menu_set_type(int type);
 struct file *file_lookup(const char *name);
@@ -61,16 +65,20 @@ extern struct menu *current_menu;
 /* symbol.c */
 void sym_init(void);
 void sym_clear_all_valid(void);
+void sym_set_changed(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);
 
 static inline tristate sym_get_tristate_value(struct symbol *sym)
 {
-	return S_TRI(sym->curr);
+	return sym->curr.tri;
 }
 
 
 static inline struct symbol *sym_get_choice_value(struct symbol *sym)
 {
-	return (struct symbol *)S_VAL(sym->curr);
+	return (struct symbol *)sym->curr.val;
 }
 
 static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval)
@@ -95,7 +103,6 @@ static inline bool sym_is_optional(struct symbol *sym)
 
 static inline bool sym_has_value(struct symbol *sym)
 {
-	//return S_VAL(sym->def) != NULL;
 	return sym->flags & SYMBOL_NEW ? false : true;
 }
 

+ 5 - 4
extra/config/lkc_proto.h

@@ -5,7 +5,7 @@ P(conf_read,int,(const char *name));
 P(conf_write,int,(const char *name));
 
 /* menu.c */
-extern struct menu rootmenu;
+P(rootmenu,struct menu,);
 
 P(menu_is_visible,bool,(struct menu *menu));
 P(menu_get_prompt,const char *,(struct menu *menu));
@@ -14,17 +14,18 @@ P(menu_get_parent_menu,struct menu *,(struct menu *menu));
 
 /* symbol.c */
 P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
-extern int sym_change_count;
+P(sym_change_count,int,);
 
 P(sym_lookup,struct symbol *,(const char *name, int isconst));
 P(sym_find,struct symbol *,(const char *name));
-P(sym_type_name,const char *,(int type));
+P(sym_type_name,const char *,(enum symbol_type type));
 P(sym_calc_value,void,(struct symbol *sym));
-P(sym_get_type,int,(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));

+ 37 - 11
extra/config/mconf.c

@@ -28,6 +28,7 @@
 #define LKC_DIRECT_LINK
 #include "lkc.h"
 
+static char menu_backtitle[128];
 static const char menu_instructions[] =
 	"Arrow keys navigate the menu.  "
 	"<Enter> selects submenus --->.  "
@@ -120,6 +121,7 @@ static void show_readme(void);
 static void init_wsize(void)
 {
 	struct winsize ws;
+	char *env;
 
 	if (ioctl(1, TIOCGWINSZ, &ws) == -1) {
 		rows = 24;
@@ -127,6 +129,20 @@ static void init_wsize(void)
 	} else {
 		rows = ws.ws_row;
 		cols = ws.ws_col;
+		if (!rows) {
+			env = getenv("LINES");
+			if (env)
+				rows = atoi(env);
+			if (!rows)
+				rows = 24;
+		}
+		if (!cols) {
+			env = getenv("COLUMNS");
+			if (env)
+				cols = atoi(env);
+			if (!cols)
+				cols = 80;
+		}
 	}
 
 	if (rows < 19 || cols < 80) {
@@ -226,9 +242,7 @@ static void build_conf(struct menu *menu)
 						menu->data ? "-->" : "++>",
 						indent + 1, ' ', prompt);
 				} else {
-					if (menu->parent != &rootmenu)
-						cprint_name("   %*c", indent + 1, ' ');
-					cprint_name("%s  --->", prompt);
+					cprint_name("   %*c%s  --->", indent + 1, ' ', prompt);
 				}
 
 				if (single_menu_mode && menu->data)
@@ -303,7 +317,10 @@ static void build_conf(struct menu *menu)
 			switch (type) {
 			case S_BOOLEAN:
 				cprint_tag("t%p", menu);
-				cprint_name("[%c]", val == no ? ' ' : '*');
+				if (sym_is_changable(sym))
+					cprint_name("[%c]", val == no ? ' ' : '*');
+				else
+					cprint_name("---");
 				break;
 			case S_TRISTATE:
 				cprint_tag("t%p", menu);
@@ -312,7 +329,10 @@ static void build_conf(struct menu *menu)
 				case mod: ch = 'M'; break;
 				default:  ch = ' '; break;
 				}
-				cprint_name("<%c>", ch);
+				if (sym_is_changable(sym))
+					cprint_name("<%c>", ch);
+				else
+					cprint_name("---");
 				break;
 			default:
 				cprint_tag("s%p", menu);
@@ -321,12 +341,18 @@ static void build_conf(struct menu *menu)
 				if (tmp < 0)
 					tmp = 0;
 				cprint_name("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
-					sym_has_value(sym) ? "" : " (NEW)");
+					(sym_has_value(sym) || !sym_is_changable(sym)) ?
+					"" : " (NEW)");
 				goto conf_childs;
 			}
 		}
 		cprint_name("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
-			sym_has_value(sym) ? "" : " (NEW)");
+			(sym_has_value(sym) || !sym_is_changable(sym)) ?
+			"" : " (NEW)");
+		if (menu->prompt->type == P_MENU) {
+			cprint_name("  --->");
+			return;
+		}
 	}
 
 conf_childs:
@@ -390,13 +416,15 @@ static void conf(struct menu *menu)
 			switch (type) {
 			case 'm':
 				if (single_menu_mode)
-					submenu->data = (submenu->data)? NULL : (void *)1;
+					submenu->data = (void *) (long) !submenu->data;
 				else
 					conf(submenu);
 				break;
 			case 't':
 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 					conf_choice(submenu);
+				else if (submenu->prompt->type == P_MENU)
+					conf(submenu);
 				break;
 			case 's':
 				conf_string(submenu);
@@ -602,7 +630,6 @@ static void conf_cleanup(void)
 {
 	tcsetattr(1, TCSAFLUSH, &ios_org);
 	unlink(".help.tmp");
-	unlink("lxdialog.scrltmp");
 }
 
 static void winch_handler(int sig)
@@ -638,10 +665,9 @@ int main(int ac, char **av)
 	conf_parse(av[1]);
 	conf_read(NULL);
 
-	backtitle = malloc(128);
 	sym = sym_lookup("VERSION", 0);
 	sym_calc_value(sym);
-	snprintf(backtitle, 128, "uClibc v%s Configuration",
+	snprintf(menu_backtitle, 128, "uClibc v%s Configuration",
 		sym_get_string_value(sym));
 
 	mode = getenv("MENUCONFIG_MODE");

+ 141 - 53
extra/config/menu.c

@@ -54,9 +54,34 @@ void menu_end_menu(void)
 	current_menu = current_menu->parent;
 }
 
+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, dep);
+	current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep));
 }
 
 void menu_set_type(int type)
@@ -69,56 +94,43 @@ void menu_set_type(int type)
 		sym->type = type;
 		return;
 	}
-	fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n",
+	fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n",
 		current_entry->file->name, current_entry->lineno,
 		sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type));
 }
 
-struct property *create_prop(enum prop_type type)
-{
-	struct property *prop;
-
-	prop = malloc(sizeof(*prop));
-	memset(prop, 0, sizeof(*prop));
-	prop->type = type;
-	prop->file = current_file;
-	prop->lineno = zconf_lineno();
-
-	return prop;
-}
-
-struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep)
+struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep)
 {
-	struct property *prop = create_prop(token);
-	struct property **propp;
+	struct property *prop = prop_alloc(type, current_entry->sym);
 
-	prop->sym = current_entry->sym;
 	prop->menu = current_entry;
 	prop->text = prompt;
-	prop->def = def;
-	E_EXPR(prop->visible) = dep;
+	prop->expr = expr;
+	prop->visible.expr = menu_check_dep(dep);
 
-	if (prompt)
+	if (prompt) {
+		if (current_entry->prompt)
+			fprintf(stderr, "%s:%d: prompt redefined\n",
+				current_entry->file->name, current_entry->lineno);
 		current_entry->prompt = prop;
-
-	/* append property to the prop list of symbol */
-	if (prop->sym) {
-		for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
-			;
-		*propp = prop;
 	}
 
 	return prop;
 }
 
-void menu_add_prompt(int token, char *prompt, struct expr *dep)
+void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep)
 {
-	current_entry->prompt = menu_add_prop(token, prompt, NULL, dep);
+	menu_add_prop(type, prompt, NULL, dep);
 }
 
-void menu_add_default(int token, struct symbol *def, struct expr *dep)
+void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
 {
-	current_entry->prompt = menu_add_prop(token, NULL, def, 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_finalize(struct menu *parent)
@@ -126,7 +138,7 @@ void menu_finalize(struct menu *parent)
 	struct menu *menu, *last_menu;
 	struct symbol *sym;
 	struct property *prop;
-	struct expr *parentdep, *basedep, *dep, *dep2;
+	struct expr *parentdep, *basedep, *dep, *dep2, **ep;
 
 	sym = parent->sym;
 	if (parent->list) {
@@ -143,7 +155,7 @@ void menu_finalize(struct menu *parent)
 			}
 			parentdep = expr_alloc_symbol(sym);
 		} else if (parent->prompt)
-			parentdep = E_EXPR(parent->prompt->visible);
+			parentdep = parent->prompt->visible.expr;
 		else
 			parentdep = parent->dep;
 
@@ -159,23 +171,28 @@ void menu_finalize(struct menu *parent)
 			for (; prop; prop = prop->next) {
 				if (prop->menu != menu)
 					continue;
-				dep = expr_transform(E_EXPR(prop->visible));
+				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);
-				E_EXPR(prop->visible) = 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 && parent->prompt) {
-		basedep = E_EXPR(parent->prompt->visible);
+	} 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 ? E_EXPR(menu->prompt->visible) : menu->dep;
+			dep = menu->prompt ? menu->prompt->visible.expr : menu->dep;
 			if (!expr_contains_symbol(dep, sym))
 				break;
 			if (expr_depends_symbol(dep, sym))
@@ -204,14 +221,27 @@ void menu_finalize(struct menu *parent)
 	for (menu = parent->list; menu; menu = menu->next) {
 		if (sym && sym_is_choice(sym) && menu->sym) {
 			menu->sym->flags |= SYMBOL_CHOICEVAL;
+			if (!menu->prompt)
+				fprintf(stderr, "%s:%d:warning: choice value must have a prompt\n",
+					menu->file->name, menu->lineno);
+			for (prop = menu->sym->prop; prop; prop = prop->next) {
+				if (prop->type == P_PROMPT && prop->menu != menu) {
+					fprintf(stderr, "%s:%d:warning: choice values currently only support a single prompt\n",
+						prop->file->name, prop->lineno);
+					
+				}
+				if (prop->type == P_DEFAULT)
+					fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n",
+						prop->file->name, prop->lineno);
+			}
 			current_entry = menu;
 			menu_set_type(sym->type);
-			menu_add_prop(P_CHOICE, NULL, parent->sym, NULL);
-			prop = sym_get_choice_prop(parent->sym);
-			//dep = expr_alloc_one(E_CHOICE, dep);
-			//dep->right.sym = menu->sym;
-			prop->dep = expr_alloc_one(E_CHOICE, prop->dep);
-			prop->dep->right.sym = menu->sym;
+			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_CHOICE, NULL);
+			(*ep)->right.sym = menu->sym;
 		}
 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
 			for (last_menu = menu->list; ; last_menu = last_menu->next) {
@@ -224,20 +254,79 @@ void menu_finalize(struct menu *parent)
 			menu->list = NULL;
 		}
 	}
+
+	if (sym && !(sym->flags & SYMBOL_WARNED)) {
+		struct symbol *sym2;
+		if (sym->type == S_UNKNOWN)
+			fprintf(stderr, "%s:%d:warning: config symbol defined without type\n",
+				parent->file->name, parent->lineno);
+
+		if (sym_is_choice(sym) && !parent->prompt)
+			fprintf(stderr, "%s:%d:warning: choice must have a prompt\n",
+				parent->file->name, parent->lineno);
+
+		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)
+					fprintf(stderr, "%s:%d:warning: default must be a single symbol\n",
+						prop->file->name, prop->lineno);
+				break;
+			case P_SELECT:
+				sym2 = prop_get_symbol(prop);
+				if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) ||
+				    (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE))
+					fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n",
+						prop->file->name, prop->lineno);
+				break;
+			case P_RANGE:
+				if (sym->type != S_INT && sym->type != S_HEX)
+					fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n",
+						prop->file->name, prop->lineno);
+				if (!sym_string_valid(sym, prop->expr->left.sym->name) ||
+				    !sym_string_valid(sym, prop->expr->right.sym->name))
+					fprintf(stderr, "%s:%d:warning: range is invalid\n",
+						prop->file->name, prop->lineno);
+				break;
+			default:
+				;
+			}
+		}
+		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_is_visible(struct menu *menu)
 {
+	struct menu *child;
+	struct symbol *sym;
 	tristate visible;
 
 	if (!menu->prompt)
 		return false;
-	if (menu->sym) {
-		sym_calc_value(menu->sym);
-		visible = E_TRI(menu->prompt->visible);
+	sym = menu->sym;
+	if (sym) {
+		sym_calc_value(sym);
+		visible = menu->prompt->visible.tri;
 	} else
-		visible = E_CALC(menu->prompt->visible);
-	return visible != no;
+		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))
+			return true;
+	return false;
 }
 
 const char *menu_get_prompt(struct menu *menu)
@@ -258,10 +347,9 @@ struct menu *menu_get_parent_menu(struct menu *menu)
 {
 	enum prop_type type;
 
-	while (menu != &rootmenu) {
-		menu = menu->parent;
+	for (; menu != &rootmenu; menu = menu->parent) {
 		type = menu->prompt ? menu->prompt->type : 0;
-		if (type == P_MENU || type == P_ROOTMENU)
+		if (type == P_MENU)
 			break;
 	}
 	return menu;

+ 330 - 188
extra/config/symbol.c

@@ -34,24 +34,14 @@ struct symbol *modules_sym;
 
 void sym_add_default(struct symbol *sym, const char *def)
 {
-	struct property *prop = create_prop(P_DEFAULT);
-	struct property **propp;
-
-	prop->sym = sym;
-	prop->def = sym_lookup(def, 1);
+	struct property *prop = prop_alloc(P_DEFAULT, sym);
 
-	/* append property to the prop list of symbol */
-	if (prop->sym) {
-		for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next)
-			;
-		*propp = prop;
-	}
+	prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
 }
 
 void sym_init(void)
 {
 	struct symbol *sym;
-	struct utsname uts;
 	char *p;
 	static bool inited = false;
 
@@ -59,17 +49,6 @@ void sym_init(void)
 		return;
 	inited = true;
 
-	uname(&uts);
-
-#if 0
-	sym = sym_lookup("ARCH", 0);
-	sym->type = S_STRING;
-	sym->flags |= SYMBOL_AUTO;
-	p = getenv("ARCH");
-	if (p)
-		sym_add_default(sym, p);
-#endif
-
 	sym = sym_lookup("VERSION", 0);
 	sym->type = S_STRING;
 	sym->flags |= SYMBOL_AUTO;
@@ -77,37 +56,32 @@ void sym_init(void)
 	if (p)
 		sym_add_default(sym, p);
 
-#if 0
-	sym = sym_lookup("UNAME_RELEASE", 0);
-	sym->type = S_STRING;
-	sym->flags |= SYMBOL_AUTO;
-	sym_add_default(sym, uts.release);
-#endif
-
 	sym = sym_lookup("TARGET_ARCH", 0);
 	sym->type = S_STRING;
 	sym->flags |= SYMBOL_AUTO;
 	p = getenv("TARGET_ARCH");
 	if (p)
 		sym_add_default(sym, p);
+
 }
 
-int sym_get_type(struct symbol *sym)
+enum symbol_type sym_get_type(struct symbol *sym)
 {
-	int type = sym->type;
+	enum symbol_type type = sym->type;
+
 	if (type == S_TRISTATE) {
 		if (sym_is_choice_value(sym) && sym->visible == yes)
 			type = S_BOOLEAN;
 		else {
 			sym_calc_value(modules_sym);
-			if (S_TRI(modules_sym->curr) == no)
+			if (modules_sym->curr.tri == no)
 				type = S_BOOLEAN;
 		}
 	}
 	return type;
 }
 
-const char *sym_type_name(int type)
+const char *sym_type_name(enum symbol_type type)
 {
 	switch (type) {
 	case S_BOOLEAN:
@@ -122,6 +96,8 @@ const char *sym_type_name(int type)
 		return "string";
 	case S_UNKNOWN:
 		return "unknown";
+	case S_OTHER:
+		break;
 	}
 	return "???";
 }
@@ -138,41 +114,104 @@ struct property *sym_get_choice_prop(struct symbol *sym)
 struct property *sym_get_default_prop(struct symbol *sym)
 {
 	struct property *prop;
-	tristate visible;
 
 	for_all_defaults(sym, prop) {
-		visible = E_CALC(prop->visible);
-		if (visible != no)
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
+			return prop;
+	}
+	return NULL;
+}
+
+struct property *sym_get_range_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_RANGE) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri != no)
 			return prop;
 	}
 	return NULL;
 }
 
-void sym_calc_visibility(struct symbol *sym)
+static void sym_calc_visibility(struct symbol *sym)
 {
 	struct property *prop;
-	tristate visible, oldvisible;
+	tristate tri;
 
 	/* any prompt visible? */
-	oldvisible = sym->visible;
-	visible = no;
-	for_all_prompts(sym, prop)
-		visible = E_OR(visible, E_CALC(prop->visible));
-	if (oldvisible != visible) {
-		sym->visible = visible;
-		sym->flags |= SYMBOL_CHANGED;
+	tri = no;
+	for_all_prompts(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		tri = E_OR(tri, prop->visible.tri);
+	}
+	if (sym->visible != tri) {
+		sym->visible = tri;
+		sym_set_changed(sym);
+	}
+	if (sym_is_choice_value(sym))
+		return;
+	tri = no;
+	if (sym->rev_dep.expr)
+		tri = expr_calc_value(sym->rev_dep.expr);
+	if (sym->rev_dep.tri != tri) {
+		sym->rev_dep.tri = tri;
+		sym_set_changed(sym);
+	}
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+
+	/* is the user choice visible? */
+	def_sym = sym->user.val;
+	if (def_sym) {
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
 	}
+
+	/* any of the defaults visible? */
+	for_all_defaults(sym, prop) {
+		prop->visible.tri = expr_calc_value(prop->visible.expr);
+		if (prop->visible.tri == no)
+			continue;
+		def_sym = prop_get_symbol(prop);
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* just get the first visible value */
+	prop = sym_get_choice_prop(sym);
+	for (e = prop->expr; e; e = e->left.expr) {
+		def_sym = e->right.sym;
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			return def_sym;
+	}
+
+	/* no choice? reset tristate value */
+	sym->curr.tri = no;
+	return NULL;
 }
 
 void sym_calc_value(struct symbol *sym)
 {
 	struct symbol_value newval, oldval;
-	struct property *prop, *def_prop;
-	struct symbol *def_sym;
+	struct property *prop;
 	struct expr *e;
 
+	if (!sym)
+		return;
+
 	if (sym->flags & SYMBOL_VALID)
 		return;
+	sym->flags |= SYMBOL_VALID;
 
 	oldval = sym->curr;
 
@@ -187,17 +226,10 @@ void sym_calc_value(struct symbol *sym)
 		newval = symbol_no.curr;
 		break;
 	default:
-		S_VAL(newval) = sym->name;
-		S_TRI(newval) = no;
-		if (sym->flags & SYMBOL_CONST) {
-			goto out;
-		}
-		//newval = symbol_empty.curr;
-		// generate warning somewhere here later
-		//S_TRI(newval) = yes;
-		goto out;
+		sym->curr.val = sym->name;
+		sym->curr.tri = no;
+		return;
 	}
-	sym->flags |= SYMBOL_VALID;
 	if (!sym_is_choice_value(sym))
 		sym->flags &= ~SYMBOL_WRITE;
 
@@ -206,95 +238,77 @@ void sym_calc_value(struct symbol *sym)
 	/* set default if recursively called */
 	sym->curr = newval;
 
-	if (sym->visible != no) {
-		sym->flags |= SYMBOL_WRITE;
-		if (!sym_has_value(sym)) {
-			if (!sym_is_choice(sym)) {
-				prop = sym_get_default_prop(sym);
-				if (prop) {
-					sym_calc_value(prop->def);
-					newval = prop->def->curr;
-				}
-			}
-		} else
-			newval = sym->def;
-
-		S_TRI(newval) = E_AND(S_TRI(newval), sym->visible);
-		/* if the symbol is visible and not optionial,
-		 * possibly ignore old user choice. */
-		if (!sym_is_optional(sym) && S_TRI(newval) == no)
-			S_TRI(newval) = sym->visible;
+	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);
-			S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no;
-		}
-	} else {
-		prop = sym_get_default_prop(sym);
-		if (prop) {
+			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
+		} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
 			sym->flags |= SYMBOL_WRITE;
-			sym_calc_value(prop->def);
-			newval = prop->def->curr;
+			if (sym_has_value(sym))
+				newval.tri = sym->user.tri;
+			else if (!sym_is_choice(sym)) {
+				prop = sym_get_default_prop(sym);
+				if (prop)
+					newval.tri = expr_calc_value(prop->expr);
+			}
+			newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri);
+		} else if (!sym_is_choice(sym)) {
+			prop = sym_get_default_prop(sym);
+			if (prop) {
+				sym->flags |= SYMBOL_WRITE;
+				newval.tri = expr_calc_value(prop->expr);
+			}
 		}
-	}
-
-	switch (sym_get_type(sym)) {
-	case S_TRISTATE:
-		if (S_TRI(newval) != mod)
-			break;
-		sym_calc_value(modules_sym);
-		if (S_TRI(modules_sym->curr) == no)
-			S_TRI(newval) = yes;
-		break;
-	case S_BOOLEAN:
-		if (S_TRI(newval) == mod)
-			S_TRI(newval) = yes;
-	}
-
-out:
-	sym->curr = newval;
-
-	if (sym_is_choice(sym) && S_TRI(newval) == yes) {
-		def_sym = S_VAL(sym->def);
-		if (def_sym) {
-			sym_calc_visibility(def_sym);
-			if (def_sym->visible == no)
-				def_sym = NULL;
+		if (sym_get_type(sym) == S_BOOLEAN) {
+			if (newval.tri == mod)
+				newval.tri = yes;
+			if (sym->visible == mod)
+				sym->visible = yes;
+			if (sym->rev_dep.tri == mod)
+				sym->rev_dep.tri = yes;
 		}
-		if (!def_sym) {
-			for_all_defaults(sym, def_prop) {
-				if (E_CALC(def_prop->visible) == no)
-					continue;
-				sym_calc_visibility(def_prop->def);
-				if (def_prop->def->visible != no) {
-					def_sym = def_prop->def;
-					break;
-				}
+		break;
+	case S_STRING:
+	case S_HEX:
+	case S_INT:
+		if (sym->visible != no) {
+			sym->flags |= SYMBOL_WRITE;
+			if (sym_has_value(sym)) {
+				newval.val = sym->user.val;
+				break;
 			}
 		}
-
-		if (!def_sym) {
-			prop = sym_get_choice_prop(sym);
-			for (e = prop->dep; e; e = e->left.expr) {
-				sym_calc_visibility(e->right.sym);
-				if (e->right.sym->visible != no) {
-					def_sym = e->right.sym;
-					break;
-				}
+		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;
 			}
 		}
-
-		S_VAL(newval) = def_sym;
+		break;
+	default:
+		;
 	}
 
-	if (memcmp(&oldval, &newval, sizeof(newval)))
-		sym->flags |= SYMBOL_CHANGED;
 	sym->curr = newval;
+	if (sym_is_choice(sym) && newval.tri == yes)
+		sym->curr.val = sym_calc_choice(sym);
+
+	if (memcmp(&oldval, &sym->curr, sizeof(oldval)))
+		sym_set_changed(sym);
 
 	if (sym_is_choice(sym)) {
 		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
 		prop = sym_get_choice_prop(sym);
-		for (e = prop->dep; e; e = e->left.expr)
+		for (e = prop->expr; e; e = e->left.expr) {
 			e->right.sym->flags |= flags;
+			if (flags & SYMBOL_CHANGED)
+				sym_set_changed(e->right.sym);
+		}
 	}
 }
 
@@ -308,13 +322,24 @@ void sym_clear_all_valid(void)
 	sym_change_count++;
 }
 
+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->flags |= SYMBOL_CHANGED;
+		sym_set_changed(sym);
 }
 
 bool sym_tristate_within_range(struct symbol *sym, tristate val)
@@ -327,19 +352,13 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val)
 	if (type != S_BOOLEAN && type != S_TRISTATE)
 		return false;
 
-	switch (val) {
-	case no:
-		if (sym_is_choice_value(sym) && sym->visible == yes)
-			return false;
-		return sym_is_optional(sym);
-	case mod:
-		if (sym_is_choice_value(sym) && sym->visible == yes)
-			return false;
-		return type == S_TRISTATE;
-	case yes:
-		return type == S_BOOLEAN || sym->visible == yes;
-	}
-	return false;
+	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)
@@ -351,16 +370,16 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
 
 	if (sym->flags & SYMBOL_NEW) {
 		sym->flags &= ~SYMBOL_NEW;
-		sym->flags |= SYMBOL_CHANGED;
+		sym_set_changed(sym);
 	}
 	if (sym_is_choice_value(sym) && val == yes) {
-		struct property *prop = sym_get_choice_prop(sym);
+		struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
 
-		S_VAL(prop->def->def) = sym;
-		prop->def->flags &= ~SYMBOL_NEW;
+		cs->user.val = sym;
+		cs->flags &= ~SYMBOL_NEW;
 	}
 
-	S_TRI(sym->def) = val;
+	sym->user.tri = val;
 	if (oldval != val) {
 		sym_clear_all_valid();
 		if (sym == modules_sym)
@@ -404,12 +423,12 @@ bool sym_string_valid(struct symbol *sym, const char *str)
 		ch = *str++;
 		if (ch == '-')
 			ch = *str++;
-		if (!isdigit((int)ch))
+		if (!isdigit(ch))
 			return false;
 		if (ch == '0' && *str != 0)
 			return false;
 		while ((ch = *str++)) {
-			if (!isdigit((int)ch))
+			if (!isdigit(ch))
 				return false;
 		}
 		return true;
@@ -418,21 +437,58 @@ bool sym_string_valid(struct symbol *sym, const char *str)
 			str += 2;
 		ch = *str++;
 		do {
-			if (!isxdigit((int)ch))
+			if (!isxdigit(ch))
 				return false;
 		} while ((ch = *str++));
 		return true;
 	case S_BOOLEAN:
 	case S_TRISTATE:
 		switch (str[0]) {
-		case 'y':
-		case 'Y':
+		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;
+	int 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 = strtol(str, NULL, 10);
+		return val >= strtol(prop->expr->left.sym->name, NULL, 10) &&
+		       val <= strtol(prop->expr->right.sym->name, NULL, 10);
+	case S_HEX:
+		if (!sym_string_valid(sym, str))
+			return false;
+		prop = sym_get_range_prop(sym);
+		if (!prop)
+			return true;
+		val = strtol(str, NULL, 16);
+		return val >= strtol(prop->expr->left.sym->name, NULL, 16) &&
+		       val <= strtol(prop->expr->right.sym->name, NULL, 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':
+		case 'm': case 'M':
 			return sym_tristate_within_range(sym, mod);
-		case 'n':
-		case 'N':
+		case 'n': case 'N':
 			return sym_tristate_within_range(sym, no);
 		}
 		return false;
@@ -451,14 +507,11 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
 	case S_BOOLEAN:
 	case S_TRISTATE:
 		switch (newval[0]) {
-		case 'y':
-		case 'Y':
+		case 'y': case 'Y':
 			return sym_set_tristate_value(sym, yes);
-		case 'm':
-		case 'M':
+		case 'm': case 'M':
 			return sym_set_tristate_value(sym, mod);
-		case 'n':
-		case 'N':
+		case 'n': case 'N':
 			return sym_set_tristate_value(sym, no);
 		}
 		return false;
@@ -466,23 +519,23 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
 		;
 	}
 
-	if (!sym_string_valid(sym, newval))
+	if (!sym_string_within_range(sym, newval))
 		return false;
 
 	if (sym->flags & SYMBOL_NEW) {
 		sym->flags &= ~SYMBOL_NEW;
-		sym->flags |= SYMBOL_CHANGED;
+		sym_set_changed(sym);
 	}
 
-	oldval = S_VAL(sym->def);
+	oldval = sym->user.val;
 	size = strlen(newval) + 1;
 	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 		size += 2;
-		S_VAL(sym->def) = val = malloc(size);
+		sym->user.val = val = malloc(size);
 		*val++ = '0';
 		*val++ = 'x';
 	} else if (!oldval || strcmp(oldval, newval))
-		S_VAL(sym->def) = val = malloc(size);
+		sym->user.val = val = malloc(size);
 	else
 		return true;
 
@@ -513,20 +566,12 @@ const char *sym_get_string_value(struct symbol *sym)
 	default:
 		;
 	}
-	return (const char *)S_VAL(sym->curr);
+	return (const char *)sym->curr.val;
 }
 
 bool sym_is_changable(struct symbol *sym)
 {
-	if (sym->visible == no)
-		return false;
-	/* at least 'n' and 'y'/'m' is selectable */
-	if (sym_is_optional(sym))
-		return true;
-	/* no 'n', so 'y' and 'm' must be selectable */
-	if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes)
-		return true;
-	return false;
+	return sym->visible > sym->rev_dep.tri;
 }
 
 struct symbol *sym_lookup(const char *name, int isconst)
@@ -536,7 +581,6 @@ struct symbol *sym_lookup(const char *name, int isconst)
 	char *new_name;
 	int hash = 0;
 
-	//printf("lookup: %s -> ", name);
 	if (name) {
 		if (name[0] && !name[1]) {
 			switch (name[0]) {
@@ -552,10 +596,8 @@ struct symbol *sym_lookup(const char *name, int isconst)
 		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 			if (!strcmp(symbol->name, name)) {
 				if ((isconst && symbol->flags & SYMBOL_CONST) ||
-				    (!isconst && !(symbol->flags & SYMBOL_CONST))) {
-					//printf("h:%p\n", symbol);
+				    (!isconst && !(symbol->flags & SYMBOL_CONST)))
 					return symbol;
-				}
 			}
 		}
 		new_name = strdup(name);
@@ -575,7 +617,6 @@ struct symbol *sym_lookup(const char *name, int isconst)
 	symbol->next = symbol_hash[hash];
 	symbol_hash[hash] = symbol;
 
-	//printf("n:%p\n", symbol);
 	return symbol;
 }
 
@@ -608,6 +649,104 @@ struct symbol *sym_find(const char *name)
 	return symbol;
 }
 
+struct symbol *sym_check_deps(struct symbol *sym);
+
+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;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+
+	if (sym->flags & SYMBOL_CHECK_DONE)
+		return NULL;
+	if (sym->flags & SYMBOL_CHECK) {
+		printf("Warning! Found recursive dependency: %s", sym->name);
+		return sym;
+	}
+
+	sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+	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)
+			continue;
+		sym2 = sym_check_expr_deps(prop->visible.expr);
+		if (sym2)
+			goto out;
+		if (prop->type != P_DEFAULT || sym_is_choice(sym))
+			continue;
+		sym2 = sym_check_expr_deps(prop->expr);
+		if (sym2)
+			goto out;
+	}
+out:
+	if (sym2)
+		printf(" %s", sym->name);
+	sym->flags &= ~SYMBOL_CHECK;
+	return sym2;
+}
+
+struct property *prop_alloc(enum prop_type type, struct symbol *sym)
+{
+	struct property *prop;
+	struct property **propp;
+
+	prop = malloc(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_CHOICE))
+		return prop->expr->left.sym;
+	return NULL;
+}
+
 const char *prop_get_type_name(enum prop_type type)
 {
 	switch (type) {
@@ -617,13 +756,16 @@ const char *prop_get_type_name(enum prop_type type)
 		return "comment";
 	case P_MENU:
 		return "menu";
-	case P_ROOTMENU:
-		return "rootmenu";
 	case P_DEFAULT:
 		return "default";
 	case P_CHOICE:
 		return "choice";
-	default:
-		return "unknown";
+	case P_SELECT:
+		return "select";
+	case P_RANGE:
+		return "range";
+	case P_UNKNOWN:
+		break;
 	}
+	return "unknown";
 }

+ 46 - 12
extra/config/zconf.l

@@ -7,6 +7,7 @@
  * Released under the terms of the GNU GPL v2.0.
  */
 
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -14,7 +15,6 @@
 
 #define LKC_DIRECT_LINK
 #include "lkc.h"
-#include "zconf.tab.h"
 
 #define START_STRSIZE	16
 
@@ -96,6 +96,7 @@ n	[A-Za-z0-9_]
 	"endchoice"		BEGIN(PARAM); return T_ENDCHOICE;
 	"comment"		BEGIN(PARAM); return T_COMMENT;
 	"config"		BEGIN(PARAM); return T_CONFIG;
+	"menuconfig"		BEGIN(PARAM); return T_MENUCONFIG;
 	"help"			BEGIN(PARAM); return T_HELP;
 	"if"			BEGIN(PARAM); return T_IF;
 	"endif"			BEGIN(PARAM); return T_ENDIF;
@@ -105,11 +106,17 @@ n	[A-Za-z0-9_]
 	"default"		BEGIN(PARAM); return T_DEFAULT;
 	"prompt"		BEGIN(PARAM); return T_PROMPT;
 	"tristate"		BEGIN(PARAM); return T_TRISTATE;
+	"def_tristate"		BEGIN(PARAM); return T_DEF_TRISTATE;
 	"bool"			BEGIN(PARAM); return T_BOOLEAN;
 	"boolean"		BEGIN(PARAM); return T_BOOLEAN;
+	"def_bool"		BEGIN(PARAM); return T_DEF_BOOLEAN;
+	"def_boolean"		BEGIN(PARAM); return T_DEF_BOOLEAN;
 	"int"			BEGIN(PARAM); return T_INT;
 	"hex"			BEGIN(PARAM); return T_HEX;
 	"string"		BEGIN(PARAM); return T_STRING;
+	"select"		BEGIN(PARAM); return T_SELECT;
+	"enable"		BEGIN(PARAM); return T_SELECT;
+	"range"			BEGIN(PARAM); return T_RANGE;
 	{n}+	{
 		alloc_string(yytext, yyleng);
 		zconflval.string = text;
@@ -141,6 +148,8 @@ n	[A-Za-z0-9_]
 		zconflval.string = text;
 		return T_WORD;
 	}
+	#.*	/* comment */
+	\\\n	current_file->lineno++;
 	.
 	<<EOF>> {
 		BEGIN(INITIAL);
@@ -151,29 +160,30 @@ n	[A-Za-z0-9_]
 	[^'"\\\n]+/\n	{
 		append_string(yytext, yyleng);
 		zconflval.string = text;
-		return T_STRING;
+		return T_WORD_QUOTE;
 	}
 	[^'"\\\n]+	{
 		append_string(yytext, yyleng);
 	}
 	\\.?/\n	{
-		append_string(yytext+1, yyleng);
+		append_string(yytext + 1, yyleng - 1);
 		zconflval.string = text;
-		return T_STRING;
+		return T_WORD_QUOTE;
 	}
 	\\.?	{
-		append_string(yytext+1, yyleng);
+		append_string(yytext + 1, yyleng - 1);
 	}
 	\'|\"	{
 		if (str == yytext[0]) {
 			BEGIN(PARAM);
 			zconflval.string = text;
-			return T_STRING;
+			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;
 	}
@@ -204,9 +214,8 @@ n	[A-Za-z0-9_]
 			}
 			append_string("        ", ts);
 		}
-		
 	}
-	\n/[^ \t\n] {
+	[ \t]*\n/[^ \t\n] {
 		current_file->lineno++;
 		zconf_endhelp();
 		return T_HELPTEXT;
@@ -246,12 +255,37 @@ void zconf_starthelp(void)
 static void zconf_endhelp(void)
 {
 	zconflval.string = text;
-	BEGIN(INITIAL); 
+	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[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 = fopen(name, "r");
+	yyin = zconf_fopen(name);
 	if (!yyin) {
 		printf("can't find file %s\n", name);
 		exit(1);
@@ -272,7 +306,7 @@ void zconf_nextfile(const char *name)
 	memset(buf, 0, sizeof(*buf));
 
 	current_buf->state = YY_CURRENT_BUFFER;
-	yyin = fopen(name, "r");
+	yyin = zconf_fopen(name);
 	if (!yyin) {
 		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
 		exit(1);
@@ -318,7 +352,7 @@ static struct buffer *zconf_endfile(void)
 int zconf_lineno(void)
 {
 	if (current_buf)
-		return current_file->lineno;
+		return current_file->lineno - 1;
 	else
 		return 0;
 }

File diff suppressed because it is too large
+ 408 - 297
extra/config/zconf.tab.c_shipped


+ 134 - 98
extra/config/zconf.y

@@ -27,7 +27,7 @@ struct symbol *symbol_hash[257];
 
 #define YYERROR_VERBOSE
 %}
-%expect 36
+%expect 40
 
 %union
 {
@@ -46,6 +46,7 @@ struct symbol *symbol_hash[257];
 %token T_ENDCHOICE
 %token T_COMMENT
 %token T_CONFIG
+%token T_MENUCONFIG
 %token T_HELP
 %token <string> T_HELPTEXT
 %token T_IF
@@ -56,17 +57,22 @@ struct symbol *symbol_hash[257];
 %token T_PROMPT
 %token T_DEFAULT
 %token T_TRISTATE
+%token T_DEF_TRISTATE
 %token T_BOOLEAN
+%token T_DEF_BOOLEAN
+%token T_STRING
 %token T_INT
 %token T_HEX
 %token <string> T_WORD
-%token <string> T_STRING
+%token <string> T_WORD_QUOTE
 %token T_UNEQUAL
 %token T_EOF
 %token T_EOL
 %token T_CLOSE_PAREN
 %token T_OPEN_PAREN
 %token T_ON
+%token T_SELECT
+%token T_RANGE
 
 %left T_OR
 %left T_AND
@@ -103,14 +109,15 @@ common_block:
 	  if_stmt
 	| comment_stmt
 	| config_stmt
+	| menuconfig_stmt
 	| source_stmt
 	| nl_or_eof
 ;
 
 
-/* config entry */
+/* config/menuconfig entry */
 
-config_entry_start: T_CONFIG T_WORD
+config_entry_start: T_CONFIG T_WORD T_EOL
 {
 	struct symbol *sym = sym_lookup($2, 0);
 	sym->flags |= SYMBOL_OPTIONAL;
@@ -118,74 +125,118 @@ config_entry_start: T_CONFIG T_WORD
 	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2);
 };
 
-config_stmt: config_entry_start T_EOL config_option_list
+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 T_EOL
-	| config_option_list depends T_EOL
+	| config_option_list config_option
+	| config_option_list depends
 	| config_option_list help
 	| config_option_list T_EOL
-{ };
+;
 
-config_option: T_TRISTATE prompt_stmt_opt
+config_option: T_TRISTATE prompt_stmt_opt T_EOL
 {
 	menu_set_type(S_TRISTATE);
 	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
 };
 
-config_option: T_BOOLEAN prompt_stmt_opt
+config_option: T_DEF_TRISTATE expr if_expr T_EOL
+{
+	menu_add_expr(P_DEFAULT, $2, $3);
+	menu_set_type(S_TRISTATE);
+	printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_BOOLEAN prompt_stmt_opt T_EOL
 {
 	menu_set_type(S_BOOLEAN);
 	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
 };
 
-config_option: T_INT prompt_stmt_opt
+config_option: T_DEF_BOOLEAN expr if_expr T_EOL
+{
+	menu_add_expr(P_DEFAULT, $2, $3);
+	menu_set_type(S_BOOLEAN);
+	printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno());
+};
+
+config_option: T_INT prompt_stmt_opt T_EOL
 {
 	menu_set_type(S_INT);
 	printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
 };
 
-config_option: T_HEX prompt_stmt_opt
+config_option: T_HEX prompt_stmt_opt T_EOL
 {
 	menu_set_type(S_HEX);
 	printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
 };
 
-config_option: T_STRING prompt_stmt_opt
+config_option: T_STRING prompt_stmt_opt T_EOL
 {
 	menu_set_type(S_STRING);
 	printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
 };
 
-config_option: T_PROMPT prompt if_expr
+config_option: T_PROMPT prompt if_expr T_EOL
 {
-	menu_add_prop(P_PROMPT, $2, NULL, $3);
+	menu_add_prompt(P_PROMPT, $2, $3);
 	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 };
 
-config_option: T_DEFAULT symbol if_expr
+config_option: T_DEFAULT expr if_expr T_EOL
 {
-	menu_add_prop(P_DEFAULT, NULL, $2, $3);
+	menu_add_expr(P_DEFAULT, $2, $3);
 	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
 };
 
+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());
+};
+
 /* choice entry */
 
-choice: T_CHOICE
+choice: T_CHOICE T_EOL
 {
 	struct symbol *sym = sym_lookup(NULL, 0);
 	sym->flags |= SYMBOL_CHOICE;
 	menu_add_entry(sym);
-	menu_add_prop(P_CHOICE, NULL, NULL, NULL);
+	menu_add_expr(P_CHOICE, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
 };
 
-choice_entry: choice T_EOL choice_option_list
+choice_entry: choice choice_option_list
 {
 	menu_end_entry();
 	menu_add_menu();
@@ -200,7 +251,7 @@ choice_end: end
 };
 
 choice_stmt:
-	  choice_entry choice_block choice_end T_EOL
+	  choice_entry choice_block choice_end
 	| choice_entry choice_block
 {
 	printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
@@ -209,28 +260,39 @@ choice_stmt:
 
 choice_option_list:
 	  /* empty */
-	| choice_option_list choice_option T_EOL
-	| choice_option_list depends T_EOL
+	| choice_option_list choice_option
+	| choice_option_list depends
 	| choice_option_list help
 	| choice_option_list T_EOL
 ;
 
-choice_option: T_PROMPT prompt if_expr
+choice_option: T_PROMPT prompt if_expr T_EOL
 {
-	menu_add_prop(P_PROMPT, $2, NULL, $3);
+	menu_add_prompt(P_PROMPT, $2, $3);
 	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
 };
 
-choice_option: T_OPTIONAL
+choice_option: T_TRISTATE prompt_stmt_opt T_EOL
+{
+	menu_set_type(S_TRISTATE);
+	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
+};
+
+choice_option: T_BOOLEAN prompt_stmt_opt T_EOL
+{
+	menu_set_type(S_BOOLEAN);
+	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
+};
+
+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 symbol
+choice_option: T_DEFAULT T_WORD if_expr T_EOL
 {
-	menu_add_prop(P_DEFAULT, NULL, $2, NULL);
-	//current_choice->prop->def = $2;
+	menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3);
 	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
 };
 
@@ -241,11 +303,10 @@ choice_block:
 
 /* if entry */
 
-if: T_IF expr
+if: T_IF expr T_EOL
 {
 	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
 	menu_add_entry(NULL);
-	//current_entry->prompt = menu_add_prop(T_IF, NULL, NULL, $2);
 	menu_add_dep($2);
 	menu_end_entry();
 	menu_add_menu();
@@ -260,8 +321,8 @@ if_end: end
 };
 
 if_stmt:
-	  if T_EOL if_block if_end T_EOL
-	| if T_EOL if_block
+	  if if_block if_end
+	| if if_block
 {
 	printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
 	zconfnerrs++;
@@ -276,14 +337,14 @@ if_block:
 
 /* menu entry */
 
-menu: T_MENU prompt
+menu: T_MENU prompt T_EOL
 {
 	menu_add_entry(NULL);
 	menu_add_prop(P_MENU, $2, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 };
 
-menu_entry: menu T_EOL depends_list
+menu_entry: menu depends_list
 {
 	menu_end_entry();
 	menu_add_menu();
@@ -298,7 +359,7 @@ menu_end: end
 };
 
 menu_stmt:
-	  menu_entry menu_block menu_end T_EOL
+	  menu_entry menu_block menu_end
 	| menu_entry menu_block
 {
 	printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
@@ -313,27 +374,27 @@ menu_block:
 	| menu_block error T_EOL		{ zconfprint("invalid menu option"); yyerrok; }
 ;
 
-source: T_SOURCE prompt
+source: T_SOURCE prompt T_EOL
 {
 	$$ = $2;
 	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2);
 };
 
-source_stmt: source T_EOL
+source_stmt: source
 {
 	zconf_nextfile($1);
 };
 
 /* comment entry */
 
-comment: T_COMMENT prompt
+comment: T_COMMENT prompt T_EOL
 {
 	menu_add_entry(NULL);
 	menu_add_prop(P_COMMENT, $2, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
 };
 
-comment_stmt: comment T_EOL depends_list
+comment_stmt: comment depends_list
 {
 	menu_end_entry();
 };
@@ -354,21 +415,21 @@ help: help_start T_HELPTEXT
 /* depends option */
 
 depends_list:	  /* empty */
-		| depends_list depends T_EOL
+		| depends_list depends
 		| depends_list T_EOL
-{ };
+;
 
-depends: T_DEPENDS T_ON expr
+depends: T_DEPENDS T_ON expr T_EOL
 {
 	menu_add_dep($3);
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
 }
-	| T_DEPENDS expr
+	| T_DEPENDS expr T_EOL
 {
 	menu_add_dep($2);
 	printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
 }
-	| T_REQUIRES expr
+	| T_REQUIRES expr T_EOL
 {
 	menu_add_dep($2);
 	printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
@@ -378,22 +439,18 @@ depends: T_DEPENDS T_ON expr
 
 prompt_stmt_opt:
 	  /* empty */
-	| prompt
-{
-	menu_add_prop(P_PROMPT, $1, NULL, NULL);
-}
-	| prompt T_IF expr
+	| prompt if_expr
 {
-	menu_add_prop(P_PROMPT, $1, NULL, $3);
+	menu_add_prop(P_PROMPT, $1, NULL, $2);
 };
 
 prompt:	  T_WORD
-	| T_STRING
+	| T_WORD_QUOTE
 ;
 
-end:	  T_ENDMENU		{ $$ = T_ENDMENU; }
-	| T_ENDCHOICE		{ $$ = T_ENDCHOICE; }
-	| T_ENDIF		{ $$ = T_ENDIF; }
+end:	  T_ENDMENU nl_or_eof	{ $$ = T_ENDMENU; }
+	| T_ENDCHOICE nl_or_eof	{ $$ = T_ENDCHOICE; }
+	| T_ENDIF nl_or_eof	{ $$ = T_ENDIF; }
 ;
 
 nl_or_eof:
@@ -413,26 +470,34 @@ expr:	  symbol				{ $$ = expr_alloc_symbol($1); }
 ;
 
 symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); }
-	| T_STRING	{ $$ = sym_lookup($1, 1); free($1); }
+	| T_WORD_QUOTE	{ $$ = sym_lookup($1, 1); free($1); }
 ;
 
 %%
 
 void conf_parse(const char *name)
 {
+	struct symbol *sym;
+	int i;
+
 	zconf_initscan(name);
 
 	sym_init();
 	menu_init();
-	rootmenu.prompt = menu_add_prop(P_MENU, "uClibc Configuration", NULL, NULL);
+	modules_sym = sym_lookup("MODULES", 0);
+	rootmenu.prompt = menu_add_prop(P_MENU, "Linux Kernel Configuration", NULL, NULL);
 
 	//zconfdebug = 1;
 	zconfparse();
 	if (zconfnerrs)
 		exit(1);
 	menu_finalize(&rootmenu);
-
-	modules_sym = sym_lookup("MODULES", 0);
+	for_all_symbols(i, sym) {
+                if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym))
+                        printf("\n");
+		else
+			sym->flags |= SYMBOL_CHECK_DONE;
+        }
 
 	sym_change_count = 1;
 }
@@ -448,7 +513,7 @@ const char *zconf_tokenname(int token)
 	case T_ENDIF:		return "endif";
 	}
 	return "<token>";
-} 
+}
 
 static bool zconf_endtoken(int token, int starttoken, int endtoken)
 {
@@ -470,7 +535,7 @@ static void zconfprint(const char *err, ...)
 {
 	va_list ap;
 
-	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
+	fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1);
 	va_start(ap, err);
 	vfprintf(stderr, err, ap);
 	va_end(ap);
@@ -479,7 +544,7 @@ static void zconfprint(const char *err, ...)
 
 static void zconferror(const char *err)
 {
-	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err);
+	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
 }
 
 void print_quoted_string(FILE *out, const char *str)
@@ -504,8 +569,6 @@ void print_symbol(FILE *out, struct menu *menu)
 	struct symbol *sym = menu->sym;
 	struct property *prop;
 
-	//sym->flags |= SYMBOL_PRINTED;
-
 	if (sym_is_choice(sym))
 		fprintf(out, "choice\n");
 	else
@@ -530,13 +593,6 @@ void print_symbol(FILE *out, struct menu *menu)
 		fputs("  ???\n", out);
 		break;
 	}
-#if 0
-	if (!expr_is_yes(sym->dep)) {
-		fputs("  depends ", out);
-		expr_fprint(sym->dep, out);
-		fputc('\n', out);
-	}
-#endif
 	for (prop = sym->prop; prop; prop = prop->next) {
 		if (prop->menu != menu)
 			continue;
@@ -544,25 +600,18 @@ void print_symbol(FILE *out, struct menu *menu)
 		case P_PROMPT:
 			fputs("  prompt ", out);
 			print_quoted_string(out, prop->text);
-			if (prop->def) {
-				fputc(' ', out);
-				if (prop->def->flags & SYMBOL_CONST)
-					print_quoted_string(out, prop->def->name);
-				else
-					fputs(prop->def->name, out);
-			}
-			if (!expr_is_yes(E_EXPR(prop->visible))) {
+			if (!expr_is_yes(prop->visible.expr)) {
 				fputs(" if ", out);
-				expr_fprint(E_EXPR(prop->visible), out);
+				expr_fprint(prop->visible.expr, out);
 			}
 			fputc('\n', out);
 			break;
 		case P_DEFAULT:
 			fputs( "  default ", out);
-			print_quoted_string(out, prop->def->name);
-			if (!expr_is_yes(E_EXPR(prop->visible))) {
+			expr_fprint(prop->expr, out);
+			if (!expr_is_yes(prop->visible.expr)) {
 				fputs(" if ", out);
-				expr_fprint(E_EXPR(prop->visible), out);
+				expr_fprint(prop->visible.expr, out);
 			}
 			fputc('\n', out);
 			break;
@@ -585,7 +634,6 @@ void print_symbol(FILE *out, struct menu *menu)
 
 void zconfdump(FILE *out)
 {
-	//struct file *file;
 	struct property *prop;
 	struct symbol *sym;
 	struct menu *menu;
@@ -596,11 +644,6 @@ void zconfdump(FILE *out)
 			print_symbol(out, menu);
 		else if ((prop = menu->prompt)) {
 			switch (prop->type) {
-			//case T_MAINMENU:
-			//	fputs("\nmainmenu ", out);
-			//	print_quoted_string(out, prop->text);
-			//	fputs("\n", out);
-			//	break;
 			case P_COMMENT:
 				fputs("\ncomment ", out);
 				print_quoted_string(out, prop->text);
@@ -611,19 +654,12 @@ void zconfdump(FILE *out)
 				print_quoted_string(out, prop->text);
 				fputs("\n", out);
 				break;
-			//case T_SOURCE:
-			//	fputs("\nsource ", out);
-			//	print_quoted_string(out, prop->text);
-			//	fputs("\n", out);
-			//	break;
-			//case T_IF:
-			//	fputs("\nif\n", out);
 			default:
 				;
 			}
-			if (!expr_is_yes(E_EXPR(prop->visible))) {
+			if (!expr_is_yes(prop->visible.expr)) {
 				fputs("  depends ", out);
-				expr_fprint(E_EXPR(prop->visible), out);
+				expr_fprint(prop->visible.expr, out);
 				fputc('\n', out);
 			}
 			fputs("\n", out);

Some files were not shown because too many files changed in this diff