[Buildroot] [PATCH 1/2] Add a configuration subtree and an execution command to kconfig:

Konrad Eisele konrad at gaisler.com
Thu Nov 17 14:18:08 UTC 2011


New kconfig command "subsource":
subsource "<kconfig>" "<cwd>" "<.config>" "<title>"  <internal_prefix> <.config_prefix>
Allocates <kconfig> as a configuration subtree using <.config> as the configuration
file to save and load from. <cwd> is the directory path to switch to for "source" to
work, "<title>" is the Menu tile of the subtree, <internal_prefix> is a internal prefix,
and <.config_prefix> is the prefix to append/remove when saving/loading <.config>.

New kconfig config-type "execute":
Type "execute" is similar to "string". However instead of editing, the string is executed
using call to "system(<string>)" i.e.:
config EXECUTE_BUILD
	execute "title"
	default "make CFLAGS=\"\" build"
	help
	  Execute "make build"

An utility function
char *resolve_vars(const char *n, struct conf_level *l)
has been added in util.c that takes a string and replaces $(...) parts
with a symbol value i.e.:

config TARGET
	string "Specify target"
	default "all"
                help

config EXECUTE_BUILD
	execute "title"
	default "make CFLAGS=\"\" $(TARGET)"
	help
	  Execute "make"
---
 Makefile                    |    2 +-
 support/kconfig/conf.c      |    8 ++-
 support/kconfig/confdata.c  |  103 ++++++++++++++++++++++++++++++++-----------
 support/kconfig/expr.h      |   15 ++++++-
 support/kconfig/flatten.pl  |   27 +++++++++++
 support/kconfig/gconf.c     |    2 +
 support/kconfig/lkc.h       |    1 +
 support/kconfig/lkc_proto.h |    5 ++
 support/kconfig/mconf.c     |    1 +
 support/kconfig/menu.c      |    5 +-
 support/kconfig/qconf.cc    |   24 ++++++++++
 support/kconfig/qconf.h     |    1 +
 support/kconfig/symbol.c    |   54 ++++++++++++++++++++---
 support/kconfig/util.c      |   45 +++++++++++++++++++
 support/kconfig/zconf.l     |   50 ++++++++++++++++++++-
 support/kconfig/zconf.y     |   26 ++++++++++-
 16 files changed, 326 insertions(+), 43 deletions(-)
 create mode 100644 support/kconfig/flatten.pl

diff --git a/Makefile b/Makefile
index df2f859..50c5cf0 100644
--- a/Makefile
+++ b/Makefile
@@ -523,7 +523,7 @@ COMMON_CONFIG_ENV = \
 
 xconfig: $(BUILD_DIR)/buildroot-config/qconf outputmakefile
 	@mkdir -p $(BUILD_DIR)/buildroot-config
-	@$(COMMON_CONFIG_ENV) $< $(CONFIG_CONFIG_IN)
+	@$(COMMON_CONFIG_ENV) $< -s $(CONFIG_CONFIG_IN)
 
 gconfig: $(BUILD_DIR)/buildroot-config/gconf outputmakefile
 	@mkdir -p $(BUILD_DIR)/buildroot-config
diff --git a/support/kconfig/conf.c b/support/kconfig/conf.c
index 652e079..0dbe229 100644
--- a/support/kconfig/conf.c
+++ b/support/kconfig/conf.c
@@ -117,6 +117,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
 	switch (type) {
 	case S_INT:
 	case S_HEX:
+	case S_EXECUTE:
 	case S_STRING:
 		printf("%s\n", def);
 		return 1;
@@ -394,6 +395,7 @@ static void conf(struct menu *menu)
 	switch (sym->type) {
 	case S_INT:
 	case S_HEX:
+	case S_EXECUTE:
 	case S_STRING:
 		conf_string(menu);
 		break;
@@ -542,7 +544,7 @@ int main(int ac, char **av)
 	case randconfig:
 		name = getenv("KCONFIG_ALLCONFIG");
 		if (name && !stat(name, &tmpstat)) {
-			conf_read_simple(name, S_DEF_USER);
+			conf_read_simple_level(name, S_DEF_USER, 0);
 			break;
 		}
 		switch (input_mode) {
@@ -554,9 +556,9 @@ int main(int ac, char **av)
 		default: break;
 		}
 		if (!stat(name, &tmpstat))
-			conf_read_simple(name, S_DEF_USER);
+			conf_read_simple_level(name, S_DEF_USER, 0);
 		else if (!stat("all.config", &tmpstat))
-			conf_read_simple("all.config", S_DEF_USER);
+			conf_read_simple_level("all.config", S_DEF_USER, 0);
 		break;
 	default:
 		break;
diff --git a/support/kconfig/confdata.c b/support/kconfig/confdata.c
index c9f13ee..def8ec4 100644
--- a/support/kconfig/confdata.c
+++ b/support/kconfig/confdata.c
@@ -178,11 +178,11 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
 	return 0;
 }
 
-int conf_read_simple(const char *name, int def)
+int conf_read_simple_level(const char *name, int def, struct conf_level *l)
 {
 	FILE *in = NULL;
 	char line[1024];
-	char *p, *p2;
+	char *p, *p2, *lp;
 	struct symbol *sym;
 	int i, def_flags;
 
@@ -219,13 +219,14 @@ int conf_read_simple(const char *name, int def)
 		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) {
+	for_all_symbols_level(i, sym, l) {
 		sym->flags |= SYMBOL_CHANGED;
 		sym->flags &= ~(def_flags|SYMBOL_VALID);
 		if (sym_is_choice(sym))
@@ -233,6 +234,7 @@ load:
 		switch (sym->type) {
 		case S_INT:
 		case S_HEX:
+		case S_EXECUTE:
 		case S_STRING:
 			if (sym->def[def].val)
 				free(sym->def[def].val);
@@ -246,7 +248,7 @@ load:
 		conf_lineno++;
 		sym = NULL;
 		if (line[0] == '#') {
-			if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+			if (memcmp(line + 2, l ? l->conf_prefix : CONFIG_, strlen(l ? l->conf_prefix : CONFIG_)))
 				continue;
 			p = strchr(line + 2, ' ');
 			if (!p)
@@ -254,14 +256,20 @@ load:
 			*p++ = 0;
 			if (strncmp(p, "is not set", 10))
 				continue;
+			lp = line + 2;
+			if (l
+			    && l->conf_prefix
+			    && strstr(lp, l->conf_prefix) == lp) {
+				lp += strlen(l->conf_prefix);
+			}
 			if (def == S_DEF_USER) {
-				sym = sym_find(line + 2);
+				sym = sym_find_level(lp, l);
 				if (!sym) {
 					sym_add_change_count(1);
 					goto setsym;
 				}
 			} else {
-				sym = sym_lookup(line + 2, 0);
+				sym = sym_lookup_level(lp, 0, l);
 				if (sym->type == S_UNKNOWN)
 					sym->type = S_BOOLEAN;
 			}
@@ -288,14 +296,20 @@ load:
 				if (*p2 == '\r')
 					*p2 = 0;
 			}
+			lp = line;
+			if (l
+			    && l->conf_prefix
+			    && strstr(lp, l->conf_prefix) == lp) {
+				lp += strlen(l->conf_prefix);
+			}
 			if (def == S_DEF_USER) {
-				sym = sym_find(line);
+				sym = sym_find_level(lp, l);
 				if (!sym) {
 					sym_add_change_count(1);
 					goto setsym;
 				}
 			} else {
-				sym = sym_lookup(line, 0);
+				sym = sym_lookup_level(line, 0, l);
 				if (sym->type == S_UNKNOWN)
 					sym->type = S_OTHER;
 			}
@@ -337,7 +351,7 @@ setsym:
 	return 0;
 }
 
-int conf_read(const char *name)
+int conf_read_level(const char *name, struct conf_level *l)
 {
 	struct symbol *sym, *choice_sym;
 	struct property *prop;
@@ -346,10 +360,10 @@ int conf_read(const char *name)
 
 	sym_set_change_count(0);
 
-	if (conf_read_simple(name, S_DEF_USER))
+	if (conf_read_simple_level(name, S_DEF_USER, l))
 		return 1;
 
-	for_all_symbols(i, sym) {
+	for_all_symbols_level(i, sym, l) {
 		sym_calc_value(sym);
 		if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
 			goto sym_ok;
@@ -386,7 +400,7 @@ int conf_read(const char *name)
 		sym->flags &= flags | ~SYMBOL_DEF_USER;
 	}
 
-	for_all_symbols(i, sym) {
+	for_all_symbols_level(i, sym, l) {
 		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
@@ -396,6 +410,7 @@ int conf_read(const char *name)
 			if (sym->visible == no && !conf_unsaved)
 				sym->flags &= ~SYMBOL_DEF_USER;
 			switch (sym->type) {
+			case S_EXECUTE:
 			case S_STRING:
 			case S_INT:
 			case S_HEX:
@@ -416,15 +431,32 @@ int conf_read(const char *name)
 	return 0;
 }
 
+int conf_read(const char *name) {
+	int r = conf_read_level(name, 0);
+	if (!r && !name) {
+		struct conf_level *l = conf_levels;
+		while (l) {
+			char *n = resolve_vars(l->conf, l->parent);
+			if (n) {
+				if (r = conf_read_level(n, l))
+					break;
+				free(n);
+			}
+			l = l->n;
+		}
+	} 
+	return r;
+}
+
 /* Write a S_STRING */
-static void conf_write_string(bool headerfile, const char *name,
+static void conf_write_string(bool headerfile, const char *prefix, const char *name,
                               const char *str, FILE *out)
 {
 	int l;
 	if (headerfile)
-		fprintf(out, "#define %s \"", name);
+		fprintf(out, "#define %s%s \"", prefix, name);
 	else
-		fprintf(out, "%s=\"", name);
+		fprintf(out, "%s%s=\"", prefix, name);
 
 	while (1) {
 		l = strcspn(str, "\"\\");
@@ -439,6 +471,8 @@ static void conf_write_string(bool headerfile, const char *name,
 	fputs("\"\n", out);
 }
 
+#define CONFPREFIX(sym) ((sym && sym->level && sym->level->conf_prefix) ? sym->level->conf_prefix : "")
+
 static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
 {
 	const char *str;
@@ -449,24 +483,24 @@ static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
 		switch (sym_get_tristate_value(sym)) {
 		case no:
 			if (write_no)
-				fprintf(out, "# %s is not set\n",
-				    sym->name);
+				fprintf(out, "# %s%s is not set\n",
+					CONFPREFIX(sym), sym->name);
 			break;
 		case mod:
-			fprintf(out, "%s=m\n", sym->name);
+			fprintf(out, "%s%s=m\n", CONFPREFIX(sym), sym->name);
 			break;
 		case yes:
-			fprintf(out, "%s=y\n", sym->name);
+			fprintf(out, "%s%s=y\n", CONFPREFIX(sym), sym->name);
 			break;
 		}
 		break;
 	case S_STRING:
-		conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+		conf_write_string(false, CONFPREFIX(sym), sym->name, sym_get_string_value(sym), out);
 		break;
 	case S_HEX:
 	case S_INT:
 		str = sym_get_string_value(sym);
-		fprintf(out, "%s=%s\n", sym->name, str);
+		fprintf(out, "%s%s=%s\n", CONFPREFIX(sym), sym->name, str);
 		break;
 	case S_OTHER:
 	case S_UNKNOWN:
@@ -551,7 +585,7 @@ next_menu:
 	return 0;
 }
 
-int conf_write(const char *name)
+int conf_write_level(const char *name, struct conf_level *l)
 {
 	FILE *out;
 	struct symbol *sym;
@@ -621,7 +655,7 @@ int conf_write(const char *name)
 	while (menu) {
 		sym = menu->sym;
 		if (!sym) {
-			if (!menu_is_visible(menu))
+			if (!menu_is_visible(menu) || menu->level != l)
 				goto next;
 			str = menu_get_prompt(menu);
 			fprintf(out, "\n"
@@ -634,7 +668,8 @@ int conf_write(const char *name)
 				goto next;
 			sym->flags &= ~SYMBOL_WRITE;
 			/* Write config symbol to file */
-			conf_write_symbol(sym, out, true);
+			if (sym->level == l)
+				conf_write_symbol(sym, out, true);
 		}
 
 next:
@@ -668,6 +703,22 @@ next:
 	return 0;
 }
 
+int conf_write(const char *name) {
+	int r = conf_write_level(name, 0);
+	if (!r && !name) {
+		struct conf_level *l = conf_levels;
+		while (l) {
+			char *n = resolve_vars(l->conf, l->parent);
+			if (r = conf_write_level(n, l))
+				break;
+			l = l->n;
+			if (n)
+				free(n);
+		}
+	} 
+	return r;
+}
+
 static int conf_split_config(void)
 {
 	const char *name;
@@ -679,7 +730,7 @@ static int conf_split_config(void)
 	int res, i, fd;
 
 	name = conf_get_autoconfig_name();
-	conf_read_simple(name, S_DEF_AUTO);
+	conf_read_simple_level(name, S_DEF_AUTO, 0);
 
 	opwd = malloc(256);
 	_name = strdup(name);
@@ -889,7 +940,7 @@ int conf_write_autoconf(void)
 			}
 			break;
 		case S_STRING:
-			conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
+			conf_write_string(true, CONFPREFIX(sym), sym->name, sym_get_string_value(sym), out_h);
 			break;
 		case S_HEX:
 			str = sym_get_string_value(sym);
diff --git a/support/kconfig/expr.h b/support/kconfig/expr.h
index 3d238db..286bb5e 100644
--- a/support/kconfig/expr.h
+++ b/support/kconfig/expr.h
@@ -15,6 +15,16 @@ extern "C" {
 #include <stdbool.h>
 #endif
 
+struct conf_level {
+        struct conf_level *n, *parent;
+        char *sym_prefix;
+	char *conf, *conf_prefix, *cwd;
+	struct symbol *modules_sym;
+};
+extern struct conf_level *conf_levels;
+extern struct conf_level *current_conf_level;
+extern int dosubsource;
+
 struct file {
 	struct file *next;
 	struct file *parent;
@@ -62,7 +72,7 @@ struct symbol_value {
 };
 
 enum symbol_type {
-	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+	S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_EXECUTE, S_OTHER
 };
 
 /* enum values are used as index to symbol.def[] */
@@ -77,6 +87,7 @@ enum {
 struct symbol {
 	struct symbol *next;
 	char *name;
+	struct conf_level *level;
 	enum symbol_type type;
 	struct symbol_value curr;
 	struct symbol_value def[S_DEF_COUNT];
@@ -88,6 +99,7 @@ struct symbol {
 };
 
 #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 for_all_symbols_level(i, sym, l) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->level == l && sym->type != S_OTHER)
 
 #define SYMBOL_CONST      0x0001  /* symbol is const */
 #define SYMBOL_CHECK      0x0008  /* used during dependency checking */
@@ -171,6 +183,7 @@ struct menu {
 	struct file *file;
 	int lineno;
 	void *data;
+	struct conf_level *level;
 };
 
 #define MENU_CHANGED		0x0001
diff --git a/support/kconfig/flatten.pl b/support/kconfig/flatten.pl
new file mode 100644
index 0000000..1ae82e5
--- /dev/null
+++ b/support/kconfig/flatten.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+
+flatten($ARGV[0]);
+
+sub readfile {
+    my ($in) = @_;
+    usage(\*STDOUT) if (length($in) == 0) ;
+    open IN, "$in" or die "Reading \"$in\":".$!;
+    local $/ = undef;
+    $m = <IN>;
+    close IN;
+    return $m;
+}
+
+sub flatten {
+    my ($f) = @_;
+    foreach my $l (split("\n",readfile($f))) {
+	if ($l =~ /^\s*source/) {
+	    print ("# -> $l\n");
+	    my $nf = substr($l,length($&));
+	    $nf =~ s/"//g;
+	    flatten($nf);
+	} else {
+	    print ("$l\n");
+	}
+    }
+}
diff --git a/support/kconfig/gconf.c b/support/kconfig/gconf.c
index f9daf98..409977b 100644
--- a/support/kconfig/gconf.c
+++ b/support/kconfig/gconf.c
@@ -869,6 +869,7 @@ static void change_sym_value(struct menu *menu, gint col)
 	case S_INT:
 	case S_HEX:
 	case S_STRING:
+	case S_EXECUTE:
 	default:
 		break;
 	}
@@ -1205,6 +1206,7 @@ static gchar **fill_row(struct menu *menu)
 		break;
 	case S_INT:
 	case S_HEX:
+	case S_EXECUTE:
 	case S_STRING:
 		def = sym_get_string_value(sym);
 		row[COL_VALUE] = g_strdup(def);
diff --git a/support/kconfig/lkc.h b/support/kconfig/lkc.h
index e899066..f22dc87 100644
--- a/support/kconfig/lkc.h
+++ b/support/kconfig/lkc.h
@@ -78,6 +78,7 @@ void zconf_starthelp(void);
 FILE *zconf_fopen(const char *name);
 void zconf_initscan(const char *name);
 void zconf_nextfile(const char *name);
+void zconf_nextconf(const char *name, char *subdir, char *subconf, char *title, char *subprefix, char *confprefix);	
 int zconf_lineno(void);
 const char *zconf_curname(void);
 
diff --git a/support/kconfig/lkc_proto.h b/support/kconfig/lkc_proto.h
index 17342fe..334fdfc 100644
--- a/support/kconfig/lkc_proto.h
+++ b/support/kconfig/lkc_proto.h
@@ -29,7 +29,9 @@ P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
 P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
 
 P(sym_lookup,struct symbol *,(const char *name, int flags));
+P(sym_lookup_level,struct symbol *,(const char *name, int flags,struct conf_level *l));
 P(sym_find,struct symbol *,(const char *name));
+P(sym_find_level,struct symbol *,(const char *name,struct conf_level *l));
 P(sym_expand_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));
@@ -51,3 +53,6 @@ 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));
+
+/* util.c */
+P(resolve_vars,char*,(const char *n, struct conf_level *l));
diff --git a/support/kconfig/mconf.c b/support/kconfig/mconf.c
index 3ed8a25..5bd3c10 100644
--- a/support/kconfig/mconf.c
+++ b/support/kconfig/mconf.c
@@ -714,6 +714,7 @@ static void conf_string(struct menu *menu)
 		case S_HEX:
 			heading = _(inputbox_instructions_hex);
 			break;
+		case S_EXECUTE:
 		case S_STRING:
 			heading = _(inputbox_instructions_string);
 			break;
diff --git a/support/kconfig/menu.c b/support/kconfig/menu.c
index d49f8b8..1629613 100644
--- a/support/kconfig/menu.c
+++ b/support/kconfig/menu.c
@@ -54,7 +54,8 @@ void menu_add_entry(struct symbol *sym)
 	menu->parent = current_menu;
 	menu->file = current_file;
 	menu->lineno = zconf_lineno();
-
+	menu->level = current_conf_level;
+	
 	*last_entry_ptr = menu;
 	last_entry_ptr = &menu->next;
 	current_entry = menu;
@@ -216,7 +217,7 @@ static void sym_check_prop(struct symbol *sym)
 	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) &&
+			if ((sym->type == S_STRING || sym->type == S_EXECUTE || sym->type == S_INT || sym->type == S_HEX) &&
 			    prop->expr->type != E_SYMBOL)
 				prop_warn(prop,
 				    "default for config symbol '%s'"
diff --git a/support/kconfig/qconf.cc b/support/kconfig/qconf.cc
index 06dd2e3..2a74a24 100644
--- a/support/kconfig/qconf.cc
+++ b/support/kconfig/qconf.cc
@@ -296,6 +296,24 @@ ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
 	connect(this, SIGNAL(lostFocus()), SLOT(hide()));
 }
 
+void ConfigLineEdit::execute(ConfigItem* i)
+{
+	struct symbol *sym;
+	item = i;
+	sym = item->menu->sym;
+	if (sym
+	    && sym_get_string_value(sym)
+	    && sym_get_type(sym) == S_EXECUTE) {
+		const char *cmd = sym_get_string_value(sym);
+		char *rcmd = resolve_vars(cmd, sym->level);
+		conf_write(NULL);
+		if (rcmd) {
+			system(rcmd);
+			free(rcmd);
+		}
+	} 
+}
+
 void ConfigLineEdit::show(ConfigItem* i)
 {
 	item = i;
@@ -537,6 +555,9 @@ void ConfigList::changeValue(ConfigItem* item)
 		if (oldexpr != newexpr)
 			parent()->updateList(item);
 		break;
+	case S_EXECUTE:
+		parent()->lineEdit->execute(item);
+		break;
 	case S_INT:
 	case S_HEX:
 	case S_STRING:
@@ -1754,6 +1775,9 @@ int main(int ac, char** av)
 	configApp = new QApplication(ac, av);
 	if (ac > 1 && av[1][0] == '-') {
 		switch (av[1][1]) {
+		case 's':
+			dosubsource = 1;
+			break;
 		case 'h':
 		case '?':
 			usage();
diff --git a/support/kconfig/qconf.h b/support/kconfig/qconf.h
index 91677d9..1537671 100644
--- a/support/kconfig/qconf.h
+++ b/support/kconfig/qconf.h
@@ -209,6 +209,7 @@ public:
 		return (ConfigView*)Parent::parent();
 	}
 	void show(ConfigItem *i);
+	void execute(ConfigItem *i);
 	void keyPressEvent(QKeyEvent *e);
 
 public:
diff --git a/support/kconfig/symbol.c b/support/kconfig/symbol.c
index a796c95..9574e6e 100644
--- a/support/kconfig/symbol.c
+++ b/support/kconfig/symbol.c
@@ -33,6 +33,13 @@ struct symbol symbol_yes = {
 struct symbol *sym_defconfig_list;
 struct symbol *modules_sym;
 tristate modules_val;
+struct symbol *modules_sym_level(struct symbol *sym) {
+	if (sym->level) {
+		return sym->level->modules_sym;
+	} else {
+		return modules_sym;
+	}
+}
 
 struct expr *sym_env_list;
 
@@ -85,6 +92,8 @@ const char *sym_type_name(enum symbol_type type)
 		return "integer";
 	case S_HEX:
 		return "hex";
+	case S_EXECUTE:
+		return "execute";
 	case S_STRING:
 		return "string";
 	case S_UNKNOWN:
@@ -301,6 +310,7 @@ void sym_calc_value(struct symbol *sym)
 	switch (sym->type) {
 	case S_INT:
 	case S_HEX:
+	case S_EXECUTE:
 	case S_STRING:
 		newval = symbol_empty.curr;
 		break;
@@ -367,6 +377,7 @@ void sym_calc_value(struct symbol *sym)
 		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
 			newval.tri = yes;
 		break;
+	case S_EXECUTE:
 	case S_STRING:
 	case S_HEX:
 	case S_INT:
@@ -398,9 +409,9 @@ void sym_calc_value(struct symbol *sym)
 
 	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
 		sym_set_changed(sym);
-		if (modules_sym == sym) {
+		if (modules_sym_level(sym) == sym) {
 			sym_set_all_changed();
-			modules_val = modules_sym->curr.tri;
+			modules_val = modules_sym_level(sym)->curr.tri;
 		}
 	}
 
@@ -424,6 +435,7 @@ void sym_calc_value(struct symbol *sym)
 void sym_clear_all_valid(void)
 {
 	struct symbol *sym;
+	struct conf_level *l;
 	int i;
 
 	for_all_symbols(i, sym)
@@ -431,6 +443,12 @@ void sym_clear_all_valid(void)
 	sym_add_change_count(1);
 	if (modules_sym)
 		sym_calc_value(modules_sym);
+	l = conf_levels;
+	while (l) {
+		if (l->modules_sym)
+			sym_calc_value(l->modules_sym);
+		l = l->n;
+	}
 }
 
 void sym_set_changed(struct symbol *sym)
@@ -536,6 +554,7 @@ bool sym_string_valid(struct symbol *sym, const char *str)
 	signed char ch;
 
 	switch (sym->type) {
+	case S_EXECUTE:
 	case S_STRING:
 		return true;
 	case S_INT:
@@ -580,6 +599,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
 	int val;
 
 	switch (sym->type) {
+	case S_EXECUTE:
 	case S_STRING:
 		return sym_string_valid(sym, str);
 	case S_INT:
@@ -680,7 +700,7 @@ const char *sym_get_string_default(struct symbol *sym)
 	tristate val;
 
 	sym_calc_visibility(sym);
-	sym_calc_value(modules_sym);
+	sym_calc_value(modules_sym_level(sym));
 	val = symbol_no.curr.tri;
 	str = symbol_empty.curr.val;
 
@@ -712,7 +732,7 @@ const char *sym_get_string_default(struct symbol *sym)
 
 	/* transpose mod to yes if modules are not enabled */
 	if (val == mod)
-		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+		if (!sym_is_choice_value(sym) && modules_sym_level(sym)->curr.tri == no)
 			val = yes;
 
 	/* transpose mod to yes if type is bool */
@@ -730,6 +750,7 @@ const char *sym_get_string_default(struct symbol *sym)
 	case S_INT:
 	case S_HEX:
 		return str;
+	case S_EXECUTE:
 	case S_STRING:
 		return str;
 	case S_OTHER:
@@ -793,7 +814,7 @@ struct symbol *sym_lookup(const char *name, int flags)
 		hash = strhash(name) % SYMBOL_HASHSIZE;
 
 		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
-			if (symbol->name &&
+			if (symbol->name && symbol->level == current_conf_level &&
 			    !strcmp(symbol->name, name) &&
 			    (flags ? symbol->flags & flags
 				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
@@ -810,13 +831,23 @@ struct symbol *sym_lookup(const char *name, int flags)
 	symbol->name = new_name;
 	symbol->type = S_UNKNOWN;
 	symbol->flags |= flags;
-
+	symbol->level = current_conf_level;
+	
 	symbol->next = symbol_hash[hash];
 	symbol_hash[hash] = symbol;
 
 	return symbol;
 }
 
+struct symbol *sym_lookup_level(const char *name, int flags, struct conf_level *l)
+{
+	struct conf_level *ol = current_conf_level; struct symbol *sym;
+	current_conf_level = l;
+	sym = sym_lookup(name, flags);
+	current_conf_level = ol;
+	return sym;
+}
+
 struct symbol *sym_find(const char *name)
 {
 	struct symbol *symbol = NULL;
@@ -836,6 +867,7 @@ struct symbol *sym_find(const char *name)
 
 	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 		if (symbol->name &&
+		    symbol->level == current_conf_level &&
 		    !strcmp(symbol->name, name) &&
 		    !(symbol->flags & SYMBOL_CONST))
 				break;
@@ -893,6 +925,16 @@ const char *sym_expand_string_value(const char *in)
 	return res;
 }
 
+struct symbol *sym_find_level(const char *name, struct conf_level *l)
+{
+	struct conf_level *ol = current_conf_level; struct symbol *sym;
+	current_conf_level = l;
+	sym = sym_find(name);
+	current_conf_level = ol;
+	return sym;
+}
+
+
 struct symbol **sym_re_search(const char *pattern)
 {
 	struct symbol *sym, **sym_arr = NULL;
diff --git a/support/kconfig/util.c b/support/kconfig/util.c
index 8a5efaa..e0dc21d 100644
--- a/support/kconfig/util.c
+++ b/support/kconfig/util.c
@@ -263,3 +263,48 @@ const char *str_get(struct gstr *gs)
 	return gs->s;
 }
 
+#define APPEND_STR(r,a,l) if (l) {int rl=r?strlen(r):0; r = realloc(r,rl+l+1); memcpy(r+rl,a,l);r[rl+l] = 0;}
+
+char *resolve_vars(const char *n, struct conf_level *l) {
+	char *r = 0, *var = 0; const char *val = 0; int nl = strlen(n); int i,j;
+	struct symbol *sym;
+	struct conf_level *o = current_conf_level;
+	current_conf_level = l;
+	
+	for (i = 0, j = 0; i < nl; i++) {
+		if (n[i] == '$' && n[i+1] == '(') {
+			APPEND_STR(r,&n[j],i-j);
+			for (i+=2, j = i; i < nl; i++) {
+				if (n[i] == ')') {
+					break;
+				}
+			}
+			if (i < nl && i > j) {
+				var = malloc(i-j+1);
+				memcpy(var, &n[j], i-j);
+				var[i-j] = 0;
+				if ((sym = sym_lookup(var, 0))) {
+					if (sym_get_type(sym) == S_STRING) {
+						sym_calc_value(sym);
+						val  = sym_get_string_value(sym);
+						if (val) {
+							APPEND_STR(r,val,strlen(val));
+						}
+						
+					}
+				}
+				free(var);
+				j=i+1;
+			}
+		}
+	}
+	APPEND_STR(r,&n[j],i-j);
+	current_conf_level = o;
+	return r;
+error_out:
+	if (r)
+		free(r);
+	if (var)
+		free(var);
+	return 0;
+}
diff --git a/support/kconfig/zconf.l b/support/kconfig/zconf.l
index 3dbaec1..0f9d201 100644
--- a/support/kconfig/zconf.l
+++ b/support/kconfig/zconf.l
@@ -30,6 +30,7 @@ static int text_size, text_asize;
 struct buffer {
         struct buffer *parent;
         YY_BUFFER_STATE state;
+        struct conf_level *level;
 };
 
 struct buffer *current_buf;
@@ -312,6 +313,7 @@ void zconf_nextfile(const char *name)
 	}
 	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
 	buf->parent = current_buf;
+	buf->level = current_conf_level;
 	current_buf = buf;
 
 	if (file->flags & FILE_BUSY) {
@@ -331,6 +333,35 @@ void zconf_nextfile(const char *name)
 	current_file = file;
 }
 
+void zconf_nextconf(const char *name, char *subdir, char *subconf, char *title, char *subprefix, char *confprefix)
+{
+	struct conf_level **lp, *l;
+	l = malloc(sizeof(struct conf_level));
+	memset(l,0,sizeof(*l));
+	l->conf = subconf;
+	l->sym_prefix = subprefix;
+	l->conf_prefix = confprefix;
+	l->parent = current_conf_level;
+	for (lp = &conf_levels; *lp; lp = &(*lp)->n) ;
+	*lp = l;
+	current_conf_level = l;
+        
+	zconf_nextfile(name);
+
+	/* allocate per conf module-sym */
+	l->modules_sym = sym_lookup(NULL, 0);
+	l->modules_sym->type = S_BOOLEAN;
+	l->modules_sym->flags |= SYMBOL_AUTO;
+	l->cwd = getcwd(0,0);
+	chdir(subdir);
+
+	/* open new menue */
+	menu_add_entry(NULL);
+	menu_add_prompt(P_MENU, title, NULL);
+	menu_add_menu();
+
+}
+
 static void zconf_endfile(void)
 {
 	struct buffer *parent;
@@ -340,10 +371,27 @@ static void zconf_endfile(void)
 	current_file = current_file->parent;
 
 	parent = current_buf->parent;
+
 	if (parent) {
-		fclose(yyin);
+                fclose(yyin);
 		yy_delete_buffer(YY_CURRENT_BUFFER);
 		yy_switch_to_buffer(parent->state);
+
+		if (current_buf->level && (parent->level != current_buf->level)) {
+			/* close menue */
+			menu_end_menu();
+			/* restore cwd */
+			chdir(current_buf->level->cwd);
+
+			if (current_conf_level && !current_conf_level->modules_sym->prop) {
+				struct property *prop;
+				prop = prop_alloc(P_DEFAULT, current_conf_level->modules_sym);
+				prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+			}
+
+			/* switch to previous conf */
+			current_conf_level = parent->level;
+		}
 	}
 	free(current_buf);
 	current_buf = parent;
diff --git a/support/kconfig/zconf.y b/support/kconfig/zconf.y
index 0717a32..de7c498 100644
--- a/support/kconfig/zconf.y
+++ b/support/kconfig/zconf.y
@@ -20,7 +20,8 @@
 #define DEBUG_PARSE	0x0002
 
 int cdebug = PRINTD;
-
+int dosubsource = 0;
+ 
 extern int zconflex(void);
 static void zconfprint(const char *err, ...);
 static void zconf_error(const char *err, ...);
@@ -30,6 +31,8 @@ static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
 struct symbol *symbol_hash[SYMBOL_HASHSIZE];
 
 static struct menu *current_menu, *current_entry;
+struct conf_level *current_conf_level = 0;
+struct conf_level *conf_levels = 0;
 
 #define YYDEBUG 0
 #if YYDEBUG
@@ -52,6 +55,7 @@ static struct menu *current_menu, *current_entry;
 %token <id>T_MENU
 %token <id>T_ENDMENU
 %token <id>T_SOURCE
+%token <id>T_SUBSOURCE
 %token <id>T_CHOICE
 %token <id>T_ENDCHOICE
 %token <id>T_COMMENT
@@ -107,7 +111,7 @@ static struct menu *current_menu, *current_entry;
 %%
 input: nl start | start;
 
-start: mainmenu_stmt stmt_list | stmt_list;
+start: stmt_list;
 
 stmt_list:
 	  /* empty */
@@ -130,10 +134,12 @@ option_name:
 common_stmt:
 	  T_EOL
 	| if_stmt
+	| mainmenu_stmt 
 	| comment_stmt
 	| config_stmt
 	| menuconfig_stmt
 	| source_stmt
+	| subsource_stmt
 ;
 
 option_error:
@@ -389,6 +395,15 @@ source_stmt: T_SOURCE prompt T_EOL
 	zconf_nextfile($2);
 };
 
+/* subsource $2:"sub-kconfig" $3:"sub-chdir" $4:"sub-.config" $5:"Title" $6:"subdomainprefix" $7:"confprefix" */
+subsource_stmt: T_SUBSOURCE prompt prompt prompt prompt T_WORD word_opt T_EOL
+{
+	if (dosubsource) {
+		printd(DEBUG_PARSE, "%s:%d:subsource %s\n", zconf_curname(), zconf_lineno(), $2);
+		zconf_nextconf($2, $3, $4, $5, $6, $7);
+	}
+}
+
 /* comment entry */
 
 comment: T_COMMENT prompt T_EOL
@@ -522,8 +537,10 @@ void conf_parse(const char *name)
 
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
-		if (sym_check_deps(sym))
+		if (sym_check_deps(sym)) {
+			fprintf(stderr, "Cannot check dependencies for %s\n", sym->name ? sym->name : "<null>");
 			zconfnerrs++;
+		}
         }
 	if (zconfnerrs)
 		exit(1);
@@ -631,6 +648,9 @@ static void print_symbol(FILE *out, struct menu *menu)
 	case S_STRING:
 		fputs("  string\n", out);
 		break;
+	case S_EXECUTE:
+		fputs("  execute\n", out);
+		break;
 	case S_INT:
 		fputs("  integer\n", out);
 		break;
-- 
1.6.4.1




More information about the buildroot mailing list