Browse Source

build: add new menuconfig code based on linux 3.9

SVN-Revision: 36361
Felix Fietkau 12 years ago
parent
commit
9d5510a500

+ 8 - 3
include/toplevel.mk

@@ -89,10 +89,15 @@ config-clean: FORCE
 
 
 defconfig: scripts/config/conf prepare-tmpinfo FORCE
 defconfig: scripts/config/conf prepare-tmpinfo FORCE
 	touch .config
 	touch .config
-	$< -D .config Config.in
+	$< --defconfig .config Config.in
+
+confdefault-y=allyes
+confdefault-m=allmod
+confdefault-n=allno
+confdefault:=$(confdefault-$(CONFDEFAULT))
 
 
 oldconfig: scripts/config/conf prepare-tmpinfo FORCE
 oldconfig: scripts/config/conf prepare-tmpinfo FORCE
-	$< -$(if $(CONFDEFAULT),$(CONFDEFAULT),o) Config.in
+	$< --$(if $(confdefault),$(confdefault),old)config Config.in
 
 
 menuconfig: scripts/config/mconf prepare-tmpinfo FORCE
 menuconfig: scripts/config/mconf prepare-tmpinfo FORCE
 	if [ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
 	if [ \! -e .config -a -e $(HOME)/.openwrt/defconfig ]; then \
@@ -147,7 +152,7 @@ prereq:: prepare-tmpinfo .config
 	@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
 	@+$(PREP_MK) $(NO_TRACE_MAKE) -r -s prereq
 	@( \
 	@( \
 		cp .config tmp/.config; \
 		cp .config tmp/.config; \
-		./scripts/config/conf -D tmp/.config -w tmp/.config Config.in > /dev/null 2>&1; \
+		./scripts/config/conf --defconfig tmp/.config -w tmp/.config Config.in > /dev/null 2>&1; \
 		if ./scripts/kconfig.pl '>' .config tmp/.config | grep -q CONFIG; then \
 		if ./scripts/kconfig.pl '>' .config tmp/.config | grep -q CONFIG; then \
 			printf "$(_R)WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!$(_N)\n" >&2; \
 			printf "$(_R)WARNING: your configuration is out of sync. Please run make menuconfig, oldconfig or defconfig!$(_N)\n" >&2; \
 		fi \
 		fi \

+ 14 - 16
scripts/config/Makefile

@@ -13,41 +13,39 @@
 # Platform specific fixes
 # Platform specific fixes
 #
 #
 # FreeBSD
 # FreeBSD
-export CFLAGS+=-DKBUILD_NO_NLS
+
+check_lxdialog = $(shell $(SHELL) $(CURDIR)/lxdialog/check-lxdialog.sh -$(1))
+export CFLAGS += -DKBUILD_NO_NLS -I. $(call check_lxdialog,ccflags)
 
 
 conf-objs	:= conf.o zconf.tab.o
 conf-objs	:= conf.o zconf.tab.o
 mconf-objs	:= mconf.o zconf.tab.o
 mconf-objs	:= mconf.o zconf.tab.o
+lxdialog-objs := \
+	lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o \
+	lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
 
 
-clean-files	:= lkc_defs.h qconf.moc .tmp_qtcheck \
-		   .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
-
-all: conf mconf lxdialog/lxdialog
+clean-files	:= zconf.tab.c lex.zconf.c zconf.hash.c
 
 
-lxdialog/lxdialog:
-	$(MAKE) -C lxdialog
+all: conf mconf
 
 
 conf: $(conf-objs)
 conf: $(conf-objs)
-mconf: $(mconf-objs) 
+mconf: $(mconf-objs) $(lxdialog-objs)
+	$(CC) -o $@ $^ $(call check_lxdialog,ldflags $(CC))
 
 
 clean:
 clean:
-	rm -f *.o $(clean-files) conf mconf
-	$(MAKE) -C lxdialog clean
+	rm -f *.o lxdialog/*.o $(clean-files) conf mconf
 
 
-zconf.tab.o: lex.zconf.c zconf.hash.c confdata.c
+zconf.tab.o: zconf.lex.c zconf.hash.c confdata.c
 
 
 kconfig_load.o: lkc_defs.h
 kconfig_load.o: lkc_defs.h
 
 
-lkc_defs.h: $(src)/lkc_proto.h
-	sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
-
 zconf.tab.c: zconf.y
 zconf.tab.c: zconf.y
-lex.zconf.c: zconf.l
+zconf.lex.c: zconf.l
 zconf.hash.c: zconf.gperf
 zconf.hash.c: zconf.gperf
 
 
 %.tab.c: %.y
 %.tab.c: %.y
 	cp $@_shipped $@ || bison -l -b $* -p $(notdir $*) $<
 	cp $@_shipped $@ || bison -l -b $* -p $(notdir $*) $<
 
 
-lex.%.c: %.l
+%.lex.c: %.l
 	cp $@_shipped $@ || flex -L -P$(notdir $*) -o$@ $<
 	cp $@_shipped $@ || flex -L -P$(notdir $*) -o$@ $<
 
 
 %.hash.c: %.gperf
 %.hash.c: %.gperf

+ 1 - 1
scripts/config/README

@@ -1,2 +1,2 @@
-These files were taken from the Linux 2.6.16.7 Kernel
+These files were taken from the Linux 3.9 Kernel
 Configuration System and modified for the OpenWrt Buildroot.
 Configuration System and modified for the OpenWrt Buildroot.

+ 297 - 224
scripts/config/conf.c

@@ -3,38 +3,55 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
+#include <locale.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
-#include <unistd.h>
 #include <time.h>
 #include <time.h>
+#include <unistd.h>
+#include <getopt.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 static void conf(struct menu *menu);
 static void conf(struct menu *menu);
 static void check_conf(struct menu *menu);
 static void check_conf(struct menu *menu);
-
-enum {
-	ask_all,
-	ask_new,
-	ask_silent,
-	set_default,
-	set_yes,
-	set_mod,
-	set_no,
-	set_random
-} input_mode = ask_all;
-char *defconfig_file;
+static void xfgets(char *str, int size, FILE *in);
+
+enum input_mode {
+	oldaskconfig,
+	silentoldconfig,
+	oldconfig,
+	allnoconfig,
+	allyesconfig,
+	allmodconfig,
+	alldefconfig,
+	randconfig,
+	defconfig,
+	savedefconfig,
+	listnewconfig,
+	olddefconfig,
+} input_mode = oldaskconfig;
 
 
 static int indent = 1;
 static int indent = 1;
+static int tty_stdio;
 static int valid_stdin = 1;
 static int valid_stdin = 1;
+static int sync_kconfig;
 static int conf_cnt;
 static int conf_cnt;
 static char line[128];
 static char line[128];
 static struct menu *rootEntry;
 static struct menu *rootEntry;
 
 
-static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
+static void print_help(struct menu *menu)
+{
+	struct gstr help = str_new();
+
+	menu_get_ext_help(menu, &help);
+
+	printf("\n%s\n", str_get(&help));
+	str_free(&help);
+}
 
 
 static void strip(char *str)
 static void strip(char *str)
 {
 {
@@ -55,7 +72,7 @@ static void strip(char *str)
 
 
 static void check_stdin(void)
 static void check_stdin(void)
 {
 {
-	if (!valid_stdin && input_mode == ask_silent) {
+	if (!valid_stdin) {
 		printf(_("aborted!\n\n"));
 		printf(_("aborted!\n\n"));
 		printf(_("Console input/output is redirected. "));
 		printf(_("Console input/output is redirected. "));
 		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
 		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
@@ -63,27 +80,12 @@ static void check_stdin(void)
 	}
 	}
 }
 }
 
 
-static char *fgets_check_stream(char *s, int size, FILE *stream)
-{
-	char *ret = fgets(s, size, stream);
-
-	if (ret == NULL && feof(stream)) {
-		printf(_("aborted!\n\n"));
-		printf(_("Console input is closed. "));
-		printf(_("Run 'make oldconfig' to update configuration.\n\n"));
-		exit(1);
-	}
-
-	return ret;
-}
-
-static void conf_askvalue(struct symbol *sym, const char *def)
+static int conf_askvalue(struct symbol *sym, const char *def)
 {
 {
 	enum symbol_type type = sym_get_type(sym);
 	enum symbol_type type = sym_get_type(sym);
-	tristate val;
 
 
 	if (!sym_has_value(sym))
 	if (!sym_has_value(sym))
-		printf("(NEW) ");
+		printf(_("(NEW) "));
 
 
 	line[0] = '\n';
 	line[0] = '\n';
 	line[1] = 0;
 	line[1] = 0;
@@ -92,33 +94,24 @@ static void conf_askvalue(struct symbol *sym, const char *def)
 		printf("%s\n", def);
 		printf("%s\n", def);
 		line[0] = '\n';
 		line[0] = '\n';
 		line[1] = 0;
 		line[1] = 0;
-		return;
+		return 0;
 	}
 	}
 
 
 	switch (input_mode) {
 	switch (input_mode) {
-	case set_no:
-	case set_mod:
-	case set_yes:
-	case set_random:
-		if (sym_has_value(sym)) {
-			printf("%s\n", def);
-			return;
-		}
-		break;
-	case ask_new:
-	case ask_silent:
+	case oldconfig:
+	case silentoldconfig:
 		if (sym_has_value(sym)) {
 		if (sym_has_value(sym)) {
 			printf("%s\n", def);
 			printf("%s\n", def);
-			return;
+			return 0;
 		}
 		}
 		check_stdin();
 		check_stdin();
-	case ask_all:
+		/* fall through */
+	case oldaskconfig:
 		fflush(stdout);
 		fflush(stdout);
-		fgets_check_stream(line, 128, stdin);
-		return;
-	case set_default:
-		printf("%s\n", def);
-		return;
+		xfgets(line, 128, stdin);
+		if (!tty_stdio)
+			printf("\n");
+		return 1;
 	default:
 	default:
 		break;
 		break;
 	}
 	}
@@ -128,84 +121,38 @@ static void conf_askvalue(struct symbol *sym, const char *def)
 	case S_HEX:
 	case S_HEX:
 	case S_STRING:
 	case S_STRING:
 		printf("%s\n", def);
 		printf("%s\n", def);
-		return;
+		return 1;
 	default:
 	default:
 		;
 		;
 	}
 	}
-	switch (input_mode) {
-	case set_yes:
-		if (sym_tristate_within_range(sym, yes)) {
-			line[0] = 'y';
-			line[1] = '\n';
-			line[2] = 0;
-			break;
-		}
-	case set_mod:
-		if (type == S_TRISTATE) {
-			if (sym_tristate_within_range(sym, mod)) {
-				line[0] = 'm';
-				line[1] = '\n';
-				line[2] = 0;
-				break;
-			}
-		} else {
-			if (sym_tristate_within_range(sym, yes)) {
-				line[0] = 'y';
-				line[1] = '\n';
-				line[2] = 0;
-				break;
-			}
-		}
-	case set_no:
-		if (sym_tristate_within_range(sym, no)) {
-			line[0] = 'n';
-			line[1] = '\n';
-			line[2] = 0;
-			break;
-		}
-	case set_random:
-		do {
-			val = (tristate)(random() % 3);
-		} while (!sym_tristate_within_range(sym, val));
-		switch (val) {
-		case no: line[0] = 'n'; break;
-		case mod: line[0] = 'm'; break;
-		case yes: line[0] = 'y'; break;
-		}
-		line[1] = '\n';
-		line[2] = 0;
-		break;
-	default:
-		break;
-	}
 	printf("%s", line);
 	printf("%s", line);
+	return 1;
 }
 }
 
 
-int conf_string(struct menu *menu)
+static int conf_string(struct menu *menu)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
-	const char *def, *help;
+	const char *def;
 
 
 	while (1) {
 	while (1) {
-		printf("%*s%s ", indent - 1, "", menu->prompt->text);
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
 		printf("(%s) ", sym->name);
 		printf("(%s) ", sym->name);
 		def = sym_get_string_value(sym);
 		def = sym_get_string_value(sym);
 		if (sym_get_string_value(sym))
 		if (sym_get_string_value(sym))
 			printf("[%s] ", def);
 			printf("[%s] ", def);
-		conf_askvalue(sym, def);
+		if (!conf_askvalue(sym, def))
+			return 0;
 		switch (line[0]) {
 		switch (line[0]) {
 		case '\n':
 		case '\n':
 			break;
 			break;
 		case '?':
 		case '?':
 			/* print help */
 			/* print help */
 			if (line[1] == '\n') {
 			if (line[1] == '\n') {
-				help = nohelp_text;
-				if (menu->sym->help)
-					help = menu->sym->help;
-				printf("\n%s\n", menu->sym->help);
+				print_help(menu);
 				def = NULL;
 				def = NULL;
 				break;
 				break;
 			}
 			}
+			/* fall through */
 		default:
 		default:
 			line[strlen(line)-1] = 0;
 			line[strlen(line)-1] = 0;
 			def = line;
 			def = line;
@@ -218,15 +165,12 @@ int conf_string(struct menu *menu)
 static int conf_sym(struct menu *menu)
 static int conf_sym(struct menu *menu)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
-	int type;
 	tristate oldval, newval;
 	tristate oldval, newval;
-	const char *help;
 
 
 	while (1) {
 	while (1) {
-		printf("%*s%s ", indent - 1, "", menu->prompt->text);
+		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
 		if (sym->name)
 		if (sym->name)
 			printf("(%s) ", sym->name);
 			printf("(%s) ", sym->name);
-		type = sym_get_type(sym);
 		putchar('[');
 		putchar('[');
 		oldval = sym_get_tristate_value(sym);
 		oldval = sym_get_tristate_value(sym);
 		switch (oldval) {
 		switch (oldval) {
@@ -246,10 +190,11 @@ static int conf_sym(struct menu *menu)
 			printf("/m");
 			printf("/m");
 		if (oldval != yes && sym_tristate_within_range(sym, yes))
 		if (oldval != yes && sym_tristate_within_range(sym, yes))
 			printf("/y");
 			printf("/y");
-		if (sym->help)
+		if (menu_has_help(menu))
 			printf("/?");
 			printf("/?");
 		printf("] ");
 		printf("] ");
-		conf_askvalue(sym, sym_get_string_value(sym));
+		if (!conf_askvalue(sym, sym_get_string_value(sym)))
+			return 0;
 		strip(line);
 		strip(line);
 
 
 		switch (line[0]) {
 		switch (line[0]) {
@@ -282,10 +227,7 @@ static int conf_sym(struct menu *menu)
 		if (sym_set_tristate_value(sym, newval))
 		if (sym_set_tristate_value(sym, newval))
 			return 0;
 			return 0;
 help:
 help:
-		help = nohelp_text;
-		if (sym->help)
-			help = sym->help;
-		printf("\n%s\n", help);
+		print_help(menu);
 	}
 	}
 }
 }
 
 
@@ -293,11 +235,9 @@ static int conf_choice(struct menu *menu)
 {
 {
 	struct symbol *sym, *def_sym;
 	struct symbol *sym, *def_sym;
 	struct menu *child;
 	struct menu *child;
-	int type;
 	bool is_new;
 	bool is_new;
 
 
 	sym = menu->sym;
 	sym = menu->sym;
-	type = sym_get_type(sym);
 	is_new = !sym_has_value(sym);
 	is_new = !sym_has_value(sym);
 	if (sym_is_changable(sym)) {
 	if (sym_is_changable(sym)) {
 		conf_sym(menu);
 		conf_sym(menu);
@@ -315,7 +255,7 @@ static int conf_choice(struct menu *menu)
 		case no:
 		case no:
 			return 1;
 			return 1;
 		case mod:
 		case mod:
-			printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+			printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
 			return 0;
 			return 0;
 		case yes:
 		case yes:
 			break;
 			break;
@@ -325,16 +265,15 @@ static int conf_choice(struct menu *menu)
 	while (1) {
 	while (1) {
 		int cnt, def;
 		int cnt, def;
 
 
-		printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu));
+		printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
 		def_sym = sym_get_choice_value(sym);
 		def_sym = sym_get_choice_value(sym);
 		cnt = def = 0;
 		cnt = def = 0;
-		line[0] = '0';
-		line[1] = 0;
+		line[0] = 0;
 		for (child = menu->list; child; child = child->next) {
 		for (child = menu->list; child; child = child->next) {
 			if (!menu_is_visible(child))
 			if (!menu_is_visible(child))
 				continue;
 				continue;
 			if (!child->sym) {
 			if (!child->sym) {
-				printf("%*c %s\n", indent, '*', menu_get_prompt(child));
+				printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
 				continue;
 				continue;
 			}
 			}
 			cnt++;
 			cnt++;
@@ -343,38 +282,38 @@ static int conf_choice(struct menu *menu)
 				printf("%*c", indent, '>');
 				printf("%*c", indent, '>');
 			} else
 			} else
 				printf("%*c", indent, ' ');
 				printf("%*c", indent, ' ');
-			printf(" %d. %s", cnt, menu_get_prompt(child));
+			printf(" %d. %s", cnt, _(menu_get_prompt(child)));
 			if (child->sym->name)
 			if (child->sym->name)
 				printf(" (%s)", child->sym->name);
 				printf(" (%s)", child->sym->name);
 			if (!sym_has_value(child->sym))
 			if (!sym_has_value(child->sym))
-				printf(" (NEW)");
+				printf(_(" (NEW)"));
 			printf("\n");
 			printf("\n");
 		}
 		}
-		printf("%*schoice", indent - 1, "");
+		printf(_("%*schoice"), indent - 1, "");
 		if (cnt == 1) {
 		if (cnt == 1) {
 			printf("[1]: 1\n");
 			printf("[1]: 1\n");
 			goto conf_childs;
 			goto conf_childs;
 		}
 		}
 		printf("[1-%d", cnt);
 		printf("[1-%d", cnt);
-		if (sym->help)
+		if (menu_has_help(menu))
 			printf("?");
 			printf("?");
 		printf("]: ");
 		printf("]: ");
 		switch (input_mode) {
 		switch (input_mode) {
-		case ask_new:
-		case ask_silent:
+		case oldconfig:
+		case silentoldconfig:
 			if (!is_new) {
 			if (!is_new) {
 				cnt = def;
 				cnt = def;
 				printf("%d\n", cnt);
 				printf("%d\n", cnt);
 				break;
 				break;
 			}
 			}
 			check_stdin();
 			check_stdin();
-		case ask_all:
+			/* fall through */
+		case oldaskconfig:
 			fflush(stdout);
 			fflush(stdout);
-			fgets_check_stream(line, 128, stdin);
+			xfgets(line, 128, stdin);
 			strip(line);
 			strip(line);
 			if (line[0] == '?') {
 			if (line[0] == '?') {
-				printf("\n%s\n", menu->sym->help ?
-					menu->sym->help : nohelp_text);
+				print_help(menu);
 				continue;
 				continue;
 			}
 			}
 			if (!line[0])
 			if (!line[0])
@@ -384,14 +323,7 @@ static int conf_choice(struct menu *menu)
 			else
 			else
 				continue;
 				continue;
 			break;
 			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);
+		default:
 			break;
 			break;
 		}
 		}
 
 
@@ -404,15 +336,14 @@ static int conf_choice(struct menu *menu)
 		}
 		}
 		if (!child)
 		if (!child)
 			continue;
 			continue;
-		if (line[strlen(line) - 1] == '?') {
-			printf("\n%s\n", child->sym->help ?
-				child->sym->help : nohelp_text);
+		if (line[0] && line[strlen(line) - 1] == '?') {
+			print_help(child);
 			continue;
 			continue;
 		}
 		}
 		sym_set_choice_value(sym, child->sym);
 		sym_set_choice_value(sym, child->sym);
-		if (child->list) {
+		for (child = child->list; child; child = child->next) {
 			indent += 2;
 			indent += 2;
-			conf(child->list);
+			conf(child);
 			indent -= 2;
 			indent -= 2;
 		}
 		}
 		return 1;
 		return 1;
@@ -435,16 +366,20 @@ static void conf(struct menu *menu)
 
 
 		switch (prop->type) {
 		switch (prop->type) {
 		case P_MENU:
 		case P_MENU:
-			if (input_mode == ask_silent && rootEntry != menu) {
+			if ((input_mode == silentoldconfig ||
+			     input_mode == listnewconfig ||
+			     input_mode == olddefconfig) &&
+			    rootEntry != menu) {
 				check_conf(menu);
 				check_conf(menu);
 				return;
 				return;
 			}
 			}
+			/* fall through */
 		case P_COMMENT:
 		case P_COMMENT:
 			prompt = menu_get_prompt(menu);
 			prompt = menu_get_prompt(menu);
 			if (prompt)
 			if (prompt)
 				printf("%*c\n%*c %s\n%*c\n",
 				printf("%*c\n%*c %s\n%*c\n",
 					indent, '*',
 					indent, '*',
-					indent, '*', prompt,
+					indent, '*', _(prompt),
 					indent, '*');
 					indent, '*');
 		default:
 		default:
 			;
 			;
@@ -493,10 +428,16 @@ static void check_conf(struct menu *menu)
 	if (sym && !sym_has_value(sym)) {
 	if (sym && !sym_has_value(sym)) {
 		if (sym_is_changable(sym) ||
 		if (sym_is_changable(sym) ||
 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
-			if (!conf_cnt++)
-				printf(_("*\n* Restart config...\n*\n"));
-			rootEntry = menu_get_parent_menu(menu);
-			conf(rootEntry);
+			if (input_mode == listnewconfig) {
+				if (sym->name && !sym_is_choice_value(sym)) {
+					printf("%s%s\n", CONFIG_, sym->name);
+				}
+			} else if (input_mode != olddefconfig) {
+				if (!conf_cnt++)
+					printf(_("*\n* Restart config...\n*\n"));
+				rootEntry = menu_get_parent_menu(menu);
+				conf(rootEntry);
+			}
 		}
 		}
 	}
 	}
 
 
@@ -504,110 +445,242 @@ static void check_conf(struct menu *menu)
 		check_conf(child);
 		check_conf(child);
 }
 }
 
 
+static struct option long_opts[] = {
+	{"oldaskconfig",    no_argument,       NULL, oldaskconfig},
+	{"oldconfig",       no_argument,       NULL, oldconfig},
+	{"silentoldconfig", no_argument,       NULL, silentoldconfig},
+	{"defconfig",       optional_argument, NULL, defconfig},
+	{"savedefconfig",   required_argument, NULL, savedefconfig},
+	{"allnoconfig",     no_argument,       NULL, allnoconfig},
+	{"allyesconfig",    no_argument,       NULL, allyesconfig},
+	{"allmodconfig",    no_argument,       NULL, allmodconfig},
+	{"alldefconfig",    no_argument,       NULL, alldefconfig},
+	{"randconfig",      no_argument,       NULL, randconfig},
+	{"listnewconfig",   no_argument,       NULL, listnewconfig},
+	{"olddefconfig",    no_argument,       NULL, olddefconfig},
+	/*
+	 * oldnoconfig is an alias of olddefconfig, because people already
+	 * are dependent on its behavior(sets new symbols to their default
+	 * value but not 'n') with the counter-intuitive name.
+	 */
+	{"oldnoconfig",     no_argument,       NULL, olddefconfig},
+	{NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+
+	printf("Usage: %s [option] <kconfig-file>\n", progname);
+	printf("[option] is _one_ of the following:\n");
+	printf("  --listnewconfig         List new options\n");
+	printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
+	printf("  --oldconfig             Update a configuration using a provided .config as base\n");
+	printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
+	printf("  --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
+	printf("  --oldnoconfig           An alias of olddefconfig\n");
+	printf("  --defconfig <file>      New config with default defined in <file>\n");
+	printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
+	printf("  --allnoconfig           New config where all options are answered with no\n");
+	printf("  --allyesconfig          New config where all options are answered with yes\n");
+	printf("  --allmodconfig          New config where all options are answered with mod\n");
+	printf("  --alldefconfig          New config with all symbols set to default\n");
+	printf("  --randconfig            New config with random answer to all options\n");
+}
+
 int main(int ac, char **av)
 int main(int ac, char **av)
 {
 {
-	int i = 1;
-	const char *name;
-	char *output = NULL;
+	const char *progname = av[0];
+	int opt;
+	const char *name, *defconfig_file = NULL /* gcc uninit */;
 	struct stat tmpstat;
 	struct stat tmpstat;
+	const char *input_file = NULL, *output_file = NULL;
 
 
-	while (ac > i && av[i][0] == '-') {
-		switch (av[i++][1]) {
-		case 'o':
-			input_mode = ask_new;
-			break;
-		case 's':
-			input_mode = ask_silent;
-			valid_stdin = isatty(0) && isatty(1) && isatty(2);
-			break;
-		case 'd':
-			input_mode = set_default;
-			break;
-		case 'D':
-			input_mode = set_default;
-			defconfig_file = av[i++];
-			if (!defconfig_file) {
-				printf(_("%s: No default config file specified\n"),
-					av[0]);
-				exit(1);
-			}
-			break;
-		case 'w':
-			output = av[i++];
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	tty_stdio = isatty(0) && isatty(1) && isatty(2);
+
+	while ((opt = getopt_long(ac, av, "r:w:", long_opts, NULL)) != -1) {
+		input_mode = (enum input_mode)opt;
+		switch (opt) {
+		case silentoldconfig:
+			sync_kconfig = 1;
 			break;
 			break;
-		case 'n':
-			input_mode = set_no;
+		case defconfig:
+		case savedefconfig:
+			defconfig_file = optarg;
 			break;
 			break;
-		case 'm':
-			input_mode = set_mod;
+		case randconfig:
+		{
+			struct timeval now;
+			unsigned int seed;
+
+			/*
+			 * Use microseconds derived seed,
+			 * compensate for systems where it may be zero
+			 */
+			gettimeofday(&now, NULL);
+
+			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+			srand(seed);
 			break;
 			break;
-		case 'y':
-			input_mode = set_yes;
+		}
+		case oldaskconfig:
+		case oldconfig:
+		case allnoconfig:
+		case allyesconfig:
+		case allmodconfig:
+		case alldefconfig:
+		case listnewconfig:
+		case olddefconfig:
 			break;
 			break;
 		case 'r':
 		case 'r':
-			input_mode = set_random;
-			srandom(time(NULL));
+			input_file = optarg;
+			break;
+		case 'w':
+			output_file = optarg;
 			break;
 			break;
-		case 'h':
 		case '?':
 		case '?':
-			printf("%s [-o|-s] config\n", av[0]);
-			exit(0);
+			conf_usage(progname);
+			exit(1);
+			break;
 		}
 		}
 	}
 	}
-  	name = av[i];
-	if (!name) {
+	if (ac == optind) {
 		printf(_("%s: Kconfig file missing\n"), av[0]);
 		printf(_("%s: Kconfig file missing\n"), av[0]);
+		conf_usage(progname);
+		exit(1);
 	}
 	}
+	name = av[optind];
 	conf_parse(name);
 	conf_parse(name);
 	//zconfdump(stdout);
 	//zconfdump(stdout);
+	if (sync_kconfig) {
+		name = conf_get_configname();
+		if (stat(name, &tmpstat)) {
+			fprintf(stderr, _("***\n"
+				"*** Configuration file \"%s\" not found!\n"
+				"***\n"
+				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+				"*** \"make menuconfig\" or \"make xconfig\").\n"
+				"***\n"), name);
+			exit(1);
+		}
+	}
+
 	switch (input_mode) {
 	switch (input_mode) {
-	case set_default:
+	case defconfig:
 		if (!defconfig_file)
 		if (!defconfig_file)
 			defconfig_file = conf_get_default_confname();
 			defconfig_file = conf_get_default_confname();
 		if (conf_read(defconfig_file)) {
 		if (conf_read(defconfig_file)) {
-			printf("***\n"
+			printf(_("***\n"
 				"*** Can't find default configuration \"%s\"!\n"
 				"*** Can't find default configuration \"%s\"!\n"
-				"***\n", defconfig_file);
+				"***\n"), defconfig_file);
 			exit(1);
 			exit(1);
 		}
 		}
 		break;
 		break;
-	case ask_silent:
-		if (stat(".config", &tmpstat)) {
-			printf(_("***\n"
-				"*** You have not yet configured your build!\n"
-				"***\n"
-				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
-				"*** \"make menuconfig\" or \"make xconfig\").\n"
-				"***\n"));
-			exit(1);
-		}
-	case ask_all:
-	case ask_new:
-	case set_no:
-	case set_mod:
-	case set_yes:
-	case set_random:
-		conf_read(NULL);
+	case savedefconfig:
+	case silentoldconfig:
+	case oldaskconfig:
+	case oldconfig:
+	case listnewconfig:
+	case olddefconfig:
+	case allnoconfig:
+	case allyesconfig:
+	case allmodconfig:
+	case alldefconfig:
+	case randconfig:
+		conf_read(input_file);
 		break;
 		break;
 	default:
 	default:
 		break;
 		break;
 	}
 	}
 
 
-	if (input_mode != ask_silent) {
+	if (sync_kconfig) {
+		if (conf_get_changed()) {
+			name = getenv("KCONFIG_NOSILENTUPDATE");
+			if (name && *name) {
+				fprintf(stderr,
+					_("\n*** The configuration requires explicit update.\n\n"));
+				return 1;
+			}
+		}
+		valid_stdin = tty_stdio;
+	}
+
+	switch (input_mode) {
+	case allnoconfig:
+		conf_set_all_new_symbols(def_no);
+		break;
+	case allyesconfig:
+		conf_set_all_new_symbols(def_yes);
+		break;
+	case allmodconfig:
+		conf_set_all_new_symbols(def_mod);
+		break;
+	case alldefconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case randconfig:
+		conf_set_all_new_symbols(def_random);
+		break;
+	case defconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case savedefconfig:
+		break;
+	case oldaskconfig:
 		rootEntry = &rootmenu;
 		rootEntry = &rootmenu;
 		conf(&rootmenu);
 		conf(&rootmenu);
-		if (input_mode == ask_all) {
-			input_mode = ask_silent;
-			valid_stdin = 1;
-		}
+		input_mode = silentoldconfig;
+		/* fall through */
+	case oldconfig:
+	case listnewconfig:
+	case olddefconfig:
+	case silentoldconfig:
+		/* Update until a loop caused no more changes */
+		do {
+			conf_cnt = 0;
+			check_conf(&rootmenu);
+		} while (conf_cnt &&
+			 (input_mode != listnewconfig &&
+			  input_mode != olddefconfig));
+		break;
 	}
 	}
-	do {
-		conf_cnt = 0;
-		check_conf(&rootmenu);
-	} while (conf_cnt);
-	if (conf_write(output)) {
-		fprintf(stderr, _("\n*** Error during writing of the build configuration.\n\n"));
-		return 1;
+
+	if (sync_kconfig) {
+		/* silentoldconfig is used during the build so we shall update autoconf.
+		 * All other commands are only used to generate a config.
+		 */
+		if ((output_file || conf_get_changed()) &&
+		    conf_write(output_file)) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			exit(1);
+		}
+		if (conf_write_autoconf()) {
+			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
+			return 1;
+		}
+	} else if (input_mode == savedefconfig) {
+		if (conf_write_defconfig(defconfig_file)) {
+			fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+			        defconfig_file);
+			return 1;
+		}
+	} else if (input_mode != listnewconfig) {
+		if (conf_write(output_file)) {
+			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+			exit(1);
+		}
 	}
 	}
 	return 0;
 	return 0;
 }
 }
+
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(char *str, int size, FILE *in)
+{
+	if (fgets(str, size, in) == NULL)
+		fprintf(stderr, "\nError in reading or end of file.\n");
+}

File diff suppressed because it is too large
+ 580 - 285
scripts/config/confdata.c


+ 60 - 23
scripts/config/expr.c

@@ -7,15 +7,13 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 #define DEBUG_EXPR	0
 #define DEBUG_EXPR	0
 
 
 struct expr *expr_alloc_symbol(struct symbol *sym)
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = E_SYMBOL;
 	e->type = E_SYMBOL;
 	e->left.sym = sym;
 	e->left.sym = sym;
 	return e;
 	return e;
@@ -23,8 +21,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym)
 
 
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = type;
 	e->type = type;
 	e->left.expr = ce;
 	e->left.expr = ce;
 	return e;
 	return e;
@@ -32,8 +29,7 @@ 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_two(enum expr_type type, struct expr *e1, struct expr *e2)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = type;
 	e->type = type;
 	e->left.expr = e1;
 	e->left.expr = e1;
 	e->right.expr = e2;
 	e->right.expr = e2;
@@ -42,8 +38,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 
 
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = type;
 	e->type = type;
 	e->left.sym = s1;
 	e->left.sym = s1;
 	e->right.sym = s2;
 	e->right.sym = s2;
@@ -64,14 +59,14 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
 	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 }
 }
 
 
-struct expr *expr_copy(struct expr *org)
+struct expr *expr_copy(const struct expr *org)
 {
 {
 	struct expr *e;
 	struct expr *e;
 
 
 	if (!org)
 	if (!org)
 		return NULL;
 		return NULL;
 
 
-	e = malloc(sizeof(*org));
+	e = xmalloc(sizeof(*org));
 	memcpy(e, org, sizeof(*org));
 	memcpy(e, org, sizeof(*org));
 	switch (org->type) {
 	switch (org->type) {
 	case E_SYMBOL:
 	case E_SYMBOL:
@@ -87,7 +82,7 @@ struct expr *expr_copy(struct expr *org)
 		break;
 		break;
 	case E_AND:
 	case E_AND:
 	case E_OR:
 	case E_OR:
-	case E_CHOICE:
+	case E_LIST:
 		e->left.expr = expr_copy(org->left.expr);
 		e->left.expr = expr_copy(org->left.expr);
 		e->right.expr = expr_copy(org->right.expr);
 		e->right.expr = expr_copy(org->right.expr);
 		break;
 		break;
@@ -217,7 +212,7 @@ int expr_eq(struct expr *e1, struct expr *e2)
 		expr_free(e2);
 		expr_free(e2);
 		trans_count = old_count;
 		trans_count = old_count;
 		return res;
 		return res;
-	case E_CHOICE:
+	case E_LIST:
 	case E_RANGE:
 	case E_RANGE:
 	case E_NONE:
 	case E_NONE:
 		/* panic */;
 		/* panic */;
@@ -648,7 +643,7 @@ struct expr *expr_transform(struct expr *e)
 	case E_EQUAL:
 	case E_EQUAL:
 	case E_UNEQUAL:
 	case E_UNEQUAL:
 	case E_SYMBOL:
 	case E_SYMBOL:
-	case E_CHOICE:
+	case E_LIST:
 		break;
 		break;
 	default:
 	default:
 		e->left.expr = expr_transform(e->left.expr);
 		e->left.expr = expr_transform(e->left.expr);
@@ -932,7 +927,7 @@ struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symb
 		break;
 		break;
 	case E_SYMBOL:
 	case E_SYMBOL:
 		return expr_alloc_comp(type, e->left.sym, sym);
 		return expr_alloc_comp(type, e->left.sym, sym);
-	case E_CHOICE:
+	case E_LIST:
 	case E_RANGE:
 	case E_RANGE:
 	case E_NONE:
 	case E_NONE:
 		/* panic */;
 		/* panic */;
@@ -955,14 +950,14 @@ tristate expr_calc_value(struct expr *e)
 	case E_AND:
 	case E_AND:
 		val1 = expr_calc_value(e->left.expr);
 		val1 = expr_calc_value(e->left.expr);
 		val2 = expr_calc_value(e->right.expr);
 		val2 = expr_calc_value(e->right.expr);
-		return E_AND(val1, val2);
+		return EXPR_AND(val1, val2);
 	case E_OR:
 	case E_OR:
 		val1 = expr_calc_value(e->left.expr);
 		val1 = expr_calc_value(e->left.expr);
 		val2 = expr_calc_value(e->right.expr);
 		val2 = expr_calc_value(e->right.expr);
-		return E_OR(val1, val2);
+		return EXPR_OR(val1, val2);
 	case E_NOT:
 	case E_NOT:
 		val1 = expr_calc_value(e->left.expr);
 		val1 = expr_calc_value(e->left.expr);
-		return E_NOT(val1);
+		return EXPR_NOT(val1);
 	case E_EQUAL:
 	case E_EQUAL:
 		sym_calc_value(e->left.sym);
 		sym_calc_value(e->left.sym);
 		sym_calc_value(e->right.sym);
 		sym_calc_value(e->right.sym);
@@ -1000,9 +995,9 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2)
 		if (t2 == E_OR)
 		if (t2 == E_OR)
 			return 1;
 			return 1;
 	case E_OR:
 	case E_OR:
-		if (t2 == E_CHOICE)
+		if (t2 == E_LIST)
 			return 1;
 			return 1;
-	case E_CHOICE:
+	case E_LIST:
 		if (t2 == 0)
 		if (t2 == 0)
 			return 1;
 			return 1;
 	default:
 	default:
@@ -1013,6 +1008,48 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2)
 #endif
 #endif
 }
 }
 
 
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+	if (e == NULL)
+		return NULL;
+
+	while (e->type != E_SYMBOL)
+		e = e->left.expr;
+
+	return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+	struct expr *ret;
+
+	switch (e1->type) {
+	case E_OR:
+		return expr_alloc_and(
+		    expr_simplify_unmet_dep(e1->left.expr, e2),
+		    expr_simplify_unmet_dep(e1->right.expr, e2));
+	case E_AND: {
+		struct expr *e;
+		e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+		e = expr_eliminate_dups(e);
+		ret = (!expr_eq(e, e1)) ? e1 : NULL;
+		expr_free(e);
+		break;
+		}
+	default:
+		ret = e1;
+		break;
+	}
+
+	return expr_get_leftmost_symbol(ret);
+}
+
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 {
 {
 	if (!e) {
 	if (!e) {
@@ -1059,11 +1096,11 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
 		fn(data, NULL, " && ");
 		fn(data, NULL, " && ");
 		expr_print(e->right.expr, fn, data, E_AND);
 		expr_print(e->right.expr, fn, data, E_AND);
 		break;
 		break;
-	case E_CHOICE:
+	case E_LIST:
 		fn(data, e->right.sym, e->right.sym->name);
 		fn(data, e->right.sym, e->right.sym->name);
 		if (e->left.expr) {
 		if (e->left.expr) {
 			fn(data, NULL, " ^ ");
 			fn(data, NULL, " ^ ");
-			expr_print(e->left.expr, fn, data, E_CHOICE);
+			expr_print(e->left.expr, fn, data, E_LIST);
 		}
 		}
 		break;
 		break;
 	case E_RANGE:
 	case E_RANGE:
@@ -1087,7 +1124,7 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
 
 
 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 {
 {
-	fwrite(str, strlen(str), 1, data);
+	xfwrite(str, strlen(str), 1, data);
 }
 }
 
 
 void expr_fprint(struct expr *e, FILE *out)
 void expr_fprint(struct expr *e, FILE *out)

+ 87 - 45
scripts/config/expr.h

@@ -10,7 +10,9 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdio.h>
+#include "list.h"
 #ifndef __cplusplus
 #ifndef __cplusplus
 #include <stdbool.h>
 #include <stdbool.h>
 #endif
 #endif
@@ -18,21 +20,16 @@ extern "C" {
 struct file {
 struct file {
 	struct file *next;
 	struct file *next;
 	struct file *parent;
 	struct file *parent;
-	char *name;
+	const char *name;
 	int lineno;
 	int lineno;
-	int flags;
 };
 };
 
 
-#define FILE_BUSY		0x0001
-#define FILE_SCANNED		0x0002
-#define FILE_PRINTED		0x0004
-
 typedef enum tristate {
 typedef enum tristate {
 	no, mod, yes
 	no, mod, yes
 } tristate;
 } tristate;
 
 
 enum expr_type {
 enum expr_type {
-	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE
+	E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
 };
 };
 
 
 union expr_data {
 union expr_data {
@@ -45,9 +42,12 @@ struct expr {
 	union expr_data left, right;
 	union expr_data left, right;
 };
 };
 
 
-#define E_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
-#define E_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
-#define E_NOT(dep)		(2-(dep))
+#define EXPR_OR(dep1, dep2)	(((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2)	(((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep)		(2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+	for (e = (l); e && (s = e->right.sym); e = e->left.expr)
 
 
 struct expr_value {
 struct expr_value {
 	struct expr *expr;
 	struct expr *expr;
@@ -63,56 +63,89 @@ 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_OTHER
 };
 };
 
 
+/* enum values are used as index to symbol.def[] */
+enum {
+	S_DEF_USER,		/* main user value */
+	S_DEF_AUTO,		/* values read from auto.conf */
+	S_DEF_DEF3,		/* Reserved for UI usage */
+	S_DEF_DEF4,		/* Reserved for UI usage */
+	S_DEF_COUNT
+};
+
 struct symbol {
 struct symbol {
 	struct symbol *next;
 	struct symbol *next;
 	char *name;
 	char *name;
-	char *help;
 	enum symbol_type type;
 	enum symbol_type type;
-	struct symbol_value curr, user;
+	struct symbol_value curr;
+	struct symbol_value def[S_DEF_COUNT];
 	tristate visible;
 	tristate visible;
 	int flags;
 	int flags;
 	struct property *prop;
 	struct property *prop;
-	struct expr *dep, *dep2;
+	struct expr_value dir_dep;
 	struct expr_value rev_dep;
 	struct expr_value rev_dep;
-	struct expr_value rev_dep_inv;
 };
 };
 
 
 #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(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
 
 
-#define SYMBOL_YES		0x0001
-#define SYMBOL_MOD		0x0002
-#define SYMBOL_NO		0x0004
-#define SYMBOL_CONST		0x0007
-#define SYMBOL_CHECK		0x0008
-#define SYMBOL_CHOICE		0x0010
-#define SYMBOL_CHOICEVAL	0x0020
-#define SYMBOL_PRINTED		0x0040
-#define SYMBOL_VALID		0x0080
-#define SYMBOL_OPTIONAL		0x0100
-#define SYMBOL_WRITE		0x0200
-#define SYMBOL_CHANGED		0x0400
-#define SYMBOL_NEW		0x0800
-#define SYMBOL_AUTO		0x1000
-#define SYMBOL_CHECKED		0x2000
-#define SYMBOL_WARNED		0x8000
+#define SYMBOL_CONST      0x0001  /* symbol is const */
+#define SYMBOL_CHECK      0x0008  /* used during dependency checking */
+#define SYMBOL_CHOICE     0x0010  /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL  0x0020  /* used as a value in a choice block */
+#define SYMBOL_VALID      0x0080  /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL   0x0100  /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE      0x0200  /* ? */
+#define SYMBOL_CHANGED    0x0400  /* ? */
+#define SYMBOL_AUTO       0x1000  /* value from environment variable */
+#define SYMBOL_CHECKED    0x2000  /* used during dependency checking */
+#define SYMBOL_WARNED     0x8000  /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF        0x10000  /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER   0x10000  /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO   0x20000  /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
 
 
 #define SYMBOL_MAXLENGTH	256
 #define SYMBOL_MAXLENGTH	256
-#define SYMBOL_HASHSIZE		257
-
+#define SYMBOL_HASHSIZE		9973
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ *         default y
+ *         prompt "foo prompt"
+ *         select BAR
+ * config BAZ
+ *         int "BAZ Value"
+ *         range 1..255
+ */
 enum prop_type {
 enum prop_type {
-	P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_DESELECT, P_SELECT, P_RANGE, P_RESET
+	P_UNKNOWN,
+	P_PROMPT,   /* prompt "foo prompt" or "BAZ Value" */
+	P_COMMENT,  /* text associated with a comment */
+	P_MENU,     /* prompt associated with a menuconfig option */
+	P_DEFAULT,  /* default y */
+	P_CHOICE,   /* choice value */
+	P_SELECT,   /* select BAR */
+	P_RANGE,    /* range 7..100 (for a symbol) */
+	P_ENV,      /* value from environment variable */
+	P_SYMBOL,   /* where a symbol is defined */
+	P_RESET,	/* reset to defaults condition */
 };
 };
 
 
 struct property {
 struct property {
-	struct property *next;
-	struct symbol *sym;
-	enum prop_type type;
-	const char *text;
+	struct property *next;     /* next property - null if last */
+	struct symbol *sym;        /* the symbol for which the property is associated */
+	enum prop_type type;       /* type of property */
+	const char *text;          /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
 	struct expr_value visible;
 	struct expr_value visible;
-	struct expr *expr;
-	struct menu *menu;
-	struct file *file;
-	int lineno;
+	struct expr *expr;         /* the optional conditional part of the property */
+	struct menu *menu;         /* the menu the property are associated with
+	                            * valid for: P_SELECT, P_RANGE, P_CHOICE,
+	                            * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+	struct file *file;         /* what file was this property defined */
+	int lineno;                /* what lineno was this property defined */
 };
 };
 
 
 #define for_all_properties(sym, st, tok) \
 #define for_all_properties(sym, st, tok) \
@@ -130,9 +163,10 @@ struct menu {
 	struct menu *list;
 	struct menu *list;
 	struct symbol *sym;
 	struct symbol *sym;
 	struct property *prompt;
 	struct property *prompt;
+	struct expr *visibility;
 	struct expr *dep;
 	struct expr *dep;
 	unsigned int flags;
 	unsigned int flags;
-	//char *help;
+	char *help;
 	struct file *file;
 	struct file *file;
 	int lineno;
 	int lineno;
 	void *data;
 	void *data;
@@ -141,7 +175,14 @@ struct menu {
 #define MENU_CHANGED		0x0001
 #define MENU_CHANGED		0x0001
 #define MENU_ROOT		0x0002
 #define MENU_ROOT		0x0002
 
 
-#ifndef SWIG
+struct jump_key {
+	struct list_head entries;
+	size_t offset;
+	struct menu *target;
+	int index;
+};
+
+#define JUMP_NB			9
 
 
 extern struct file *file_list;
 extern struct file *file_list;
 extern struct file *current_file;
 extern struct file *current_file;
@@ -149,6 +190,7 @@ struct file *lookup_file(const char *name);
 
 
 extern struct symbol symbol_yes, symbol_no, symbol_mod;
 extern struct symbol symbol_yes, symbol_no, symbol_mod;
 extern struct symbol *modules_sym;
 extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
 extern int cdebug;
 extern int cdebug;
 struct expr *expr_alloc_symbol(struct symbol *sym);
 struct expr *expr_alloc_symbol(struct symbol *sym);
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
@@ -156,7 +198,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
 struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
-struct expr *expr_copy(struct expr *org);
+struct expr *expr_copy(const struct expr *org);
 void expr_free(struct expr *e);
 void expr_free(struct expr *e);
 int expr_eq(struct expr *e1, struct expr *e2);
 int expr_eq(struct expr *e1, struct expr *e2);
 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
@@ -171,6 +213,7 @@ struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
 struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
 struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
 void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
 void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
 
 
 void expr_fprint(struct expr *e, FILE *out);
 void expr_fprint(struct expr *e, FILE *out);
 struct gstr; /* forward */
 struct gstr; /* forward */
@@ -185,7 +228,6 @@ static inline int expr_is_no(struct expr *e)
 {
 {
 	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 }
 }
-#endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 0 - 35
scripts/config/kconfig_load.c

@@ -1,35 +0,0 @@
-#include <dlfcn.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "lkc.h"
-
-#define P(name,type,arg)	type (*name ## _p) arg
-#include "lkc_proto.h"
-#undef P
-
-void kconfig_load(void)
-{
-	void *handle;
-	char *error;
-
-	handle = dlopen("./libkconfig.so", RTLD_LAZY);
-	if (!handle) {
-		handle = dlopen("./scripts/kconfig/libkconfig.so", RTLD_LAZY);
-		if (!handle) {
-			fprintf(stderr, "%s\n", dlerror());
-			exit(1);
-		}
-	}
-
-#define P(name,type,arg)			\
-{						\
-	name ## _p = dlsym(handle, #name);	\
-        if ((error = dlerror()))  {		\
-                fprintf(stderr, "%s\n", error);	\
-		exit(1);			\
-	}					\
-}
-#include "lkc_proto.h"
-#undef P
-}

+ 0 - 1
scripts/config/lex.backup

@@ -1 +0,0 @@
-No backing up.

+ 91 - 0
scripts/config/list.h

@@ -0,0 +1,91 @@
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Copied from include/linux/...
+ */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:        the pointer to the member.
+ * @type:       the type of the container struct this is embedded in.
+ * @member:     the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                      \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *_new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = _new;
+	_new->next = next;
+	_new->prev = prev;
+	prev->next = _new;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+	__list_add(_new, head->prev, head);
+}
+
+#endif

+ 66 - 20
scripts/config/lkc.h

@@ -11,35 +11,56 @@
 #ifndef KBUILD_NO_NLS
 #ifndef KBUILD_NO_NLS
 # include <libintl.h>
 # include <libintl.h>
 #else
 #else
-# define gettext(Msgid) ((const char *) (Msgid))
-# define textdomain(Domainname) ((const char *) (Domainname))
-# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
+static inline const char *gettext(const char *txt) { return txt; }
+static inline void textdomain(const char *domainname) {}
+static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
 #endif
 #endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#ifdef LKC_DIRECT_LINK
 #define P(name,type,arg)	extern type name arg
 #define P(name,type,arg)	extern type name arg
-#else
-#include "lkc_defs.h"
-#define P(name,type,arg)	extern type (*name ## _p) arg
-#endif
 #include "lkc_proto.h"
 #include "lkc_proto.h"
 #undef P
 #undef P
 
 
 #define SRCTREE "srctree"
 #define SRCTREE "srctree"
 
 
+#ifndef PACKAGE
 #define PACKAGE "linux"
 #define PACKAGE "linux"
+#endif
+
 #define LOCALEDIR "/usr/share/locale"
 #define LOCALEDIR "/usr/share/locale"
 
 
 #define _(text) gettext(text)
 #define _(text) gettext(text)
 #define N_(text) (text)
 #define N_(text) (text)
 
 
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+static inline const char *CONFIG_prefix(void)
+{
+	return getenv( "CONFIG_" ) ?: CONFIG_;
+}
+#undef CONFIG_
+#define CONFIG_ CONFIG_prefix()
 
 
 #define TF_COMMAND	0x0001
 #define TF_COMMAND	0x0001
 #define TF_PARAM	0x0002
 #define TF_PARAM	0x0002
+#define TF_OPTION	0x0004
+
+enum conf_def_mode {
+	def_default,
+	def_yes,
+	def_mod,
+	def_no,
+	def_random
+};
+
+#define T_OPT_MODULES		1
+#define T_OPT_DEFCONFIG_LIST	2
+#define T_OPT_ENV		3
 
 
 struct kconf_id {
 struct kconf_id {
 	int name;
 	int name;
@@ -48,50 +69,69 @@ struct kconf_id {
 	enum symbol_type stype;
 	enum symbol_type stype;
 };
 };
 
 
+extern int zconfdebug;
+
 int zconfparse(void);
 int zconfparse(void);
 void zconfdump(FILE *out);
 void zconfdump(FILE *out);
-
-extern int zconfdebug;
 void zconf_starthelp(void);
 void zconf_starthelp(void);
 FILE *zconf_fopen(const char *name);
 FILE *zconf_fopen(const char *name);
 void zconf_initscan(const char *name);
 void zconf_initscan(const char *name);
 void zconf_nextfile(const char *name);
 void zconf_nextfile(const char *name);
 int zconf_lineno(void);
 int zconf_lineno(void);
-char *zconf_curname(void);
+const char *zconf_curname(void);
 
 
 /* confdata.c */
 /* confdata.c */
-extern const char conf_def_filename[];
-
+const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
 char *conf_get_default_confname(void);
 char *conf_get_default_confname(void);
+void sym_set_change_count(int count);
+void sym_add_change_count(int count);
+void conf_set_all_new_symbols(enum conf_def_mode mode);
+
+struct conf_printer {
+	void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+	void (*print_comment)(FILE *, const char *, void *);
+};
 
 
-/* kconfig_load.c */
-void kconfig_load(void);
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+	assert(len != 0);
+
+	if (fwrite(str, len, count, out) != count)
+		fprintf(stderr, "Error in writing or end of file.\n");
+}
 
 
 /* menu.c */
 /* menu.c */
-void menu_init(void);
+void _menu_init(void);
+void menu_warn(struct menu *menu, const char *fmt, ...);
 struct menu *menu_add_menu(void);
 struct menu *menu_add_menu(void);
 void menu_end_menu(void);
 void menu_end_menu(void);
 void menu_add_entry(struct symbol *sym);
 void menu_add_entry(struct symbol *sym);
 void menu_end_entry(void);
 void menu_end_entry(void);
 void menu_add_dep(struct expr *dep);
 void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
 void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep);
+void menu_add_option(int token, char *arg);
 void menu_finalize(struct menu *parent);
 void menu_finalize(struct menu *parent);
 void menu_set_type(int type);
 void menu_set_type(int type);
 
 
 /* util.c */
 /* util.c */
 struct file *file_lookup(const char *name);
 struct file *file_lookup(const char *name);
 int file_write_dep(const char *name);
 int file_write_dep(const char *name);
+void *xmalloc(size_t size);
+void *xcalloc(size_t nmemb, size_t size);
 
 
 struct gstr {
 struct gstr {
 	size_t len;
 	size_t len;
 	char  *s;
 	char  *s;
 	/*
 	/*
-	 * when max_width is not zero long lines in string s (if any) get
-	 * wrapped not to exceed the max_width value
-	 */
+	* when max_width is not zero long lines in string s (if any) get
+	* wrapped not to exceed the max_width value
+	*/
 	int max_width;
 	int max_width;
 };
 };
 struct gstr str_new(void);
 struct gstr str_new(void);
@@ -102,12 +142,18 @@ void str_printf(struct gstr *gs, const char *fmt, ...);
 const char *str_get(struct gstr *gs);
 const char *str_get(struct gstr *gs);
 
 
 /* symbol.c */
 /* symbol.c */
+extern struct expr *sym_env_list;
+
 void sym_init(void);
 void sym_init(void);
 void sym_clear_all_valid(void);
 void sym_clear_all_valid(void);
+void sym_set_all_changed(void);
 void sym_set_changed(struct symbol *sym);
 void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
 struct symbol *sym_check_deps(struct symbol *sym);
 struct symbol *sym_check_deps(struct symbol *sym);
 struct property *prop_alloc(enum prop_type type, struct symbol *sym);
 struct property *prop_alloc(enum prop_type type, struct symbol *sym);
 struct symbol *prop_get_symbol(struct property *prop);
 struct symbol *prop_get_symbol(struct property *prop);
+struct property *sym_get_env_prop(struct symbol *sym);
 
 
 static inline tristate sym_get_tristate_value(struct symbol *sym)
 static inline tristate sym_get_tristate_value(struct symbol *sym)
 {
 {
@@ -142,7 +188,7 @@ static inline bool sym_is_optional(struct symbol *sym)
 
 
 static inline bool sym_has_value(struct symbol *sym)
 static inline bool sym_has_value(struct symbol *sym)
 {
 {
-	return sym->flags & SYMBOL_NEW ? false : true;
+	return sym->flags & SYMBOL_DEF_USER ? true : false;
 }
 }
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 20 - 5
scripts/config/lkc_proto.h

@@ -1,25 +1,40 @@
+#include <stdarg.h>
 
 
 /* confdata.c */
 /* confdata.c */
 P(conf_parse,void,(const char *name));
 P(conf_parse,void,(const char *name));
 P(conf_read,int,(const char *name));
 P(conf_read,int,(const char *name));
-P(conf_reset,void,(void));
-P(conf_read_simple,int,(const char *name, int load_config));
+P(conf_read_simple,int,(const char *name, int));
+P(conf_reset,void,(int));
+P(conf_write_defconfig,int,(const char *name));
 P(conf_write,int,(const char *name));
 P(conf_write,int,(const char *name));
+P(conf_write_autoconf,int,(void));
+P(conf_get_changed,bool,(void));
+P(conf_set_changed_callback, void,(void (*fn)(void)));
+P(conf_set_message_callback, void,(void (*fn)(const char *fmt, va_list ap)));
 
 
 /* menu.c */
 /* menu.c */
 P(rootmenu,struct menu,);
 P(rootmenu,struct menu,);
 
 
-P(menu_is_visible,bool,(struct menu *menu));
+P(menu_is_visible, bool, (struct menu *menu));
+P(menu_has_prompt, bool, (struct menu *menu));
 P(menu_get_prompt,const char *,(struct menu *menu));
 P(menu_get_prompt,const char *,(struct menu *menu));
 P(menu_get_root_menu,struct menu *,(struct menu *menu));
 P(menu_get_root_menu,struct menu *,(struct menu *menu));
 P(menu_get_parent_menu,struct menu *,(struct menu *menu));
 P(menu_get_parent_menu,struct menu *,(struct menu *menu));
+P(menu_has_help,bool,(struct menu *menu));
+P(menu_get_help,const char *,(struct menu *menu));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym, struct list_head
+			 *head));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr, struct list_head
+				   *head));
+P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
 
 
 /* symbol.c */
 /* symbol.c */
 P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
 P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]);
-P(sym_change_count,int,);
 
 
-P(sym_lookup,struct symbol *,(const char *name, int isconst));
+P(sym_lookup,struct symbol *,(const char *name, int flags));
 P(sym_find,struct symbol *,(const char *name));
 P(sym_find,struct symbol *,(const char *name));
+P(sym_expand_string_value,const char *,(const char *in));
+P(sym_escape_string_value, const char *,(const char *in));
 P(sym_re_search,struct symbol **,(const char *pattern));
 P(sym_re_search,struct symbol **,(const char *pattern));
 P(sym_type_name,const char *,(enum symbol_type type));
 P(sym_type_name,const char *,(enum symbol_type type));
 P(sym_calc_value,void,(struct symbol *sym));
 P(sym_calc_value,void,(struct symbol *sym));

+ 0 - 28
scripts/config/lxdialog/Makefile

@@ -1,28 +0,0 @@
-# Makefile to build lxdialog package
-#
-
-all: lxdialog
-
-# Use reursively expanded variables so we do not call gcc unless
-# we really need to do so. (Do not call gcc as part of make mrproper)
-CFLAGS := $(shell sh check-lxdialog.sh -ccflags)
-LIBS := $(shell sh check-lxdialog.sh -ldflags gcc)
-
-# workaround for OpenBSD, which does not use symlinks to libncurses.so
-OS := $(shell uname -s)
-ifeq ($(strip $(OS)),OpenBSD)
-LIBS := -lncurses
-endif
-ifeq ($(shell uname -o),Cygwin)
-LIBS := -lncurses
-endif
-always		:= $(hostprogs-y) dochecklxdialog
-
-%.o: %.c
-	$(CC) -c $(CFLAGS) -o $@ $<
-
-lxdialog: checklist.o menubox.o textbox.o yesno.o inputbox.o util.o lxdialog.o msgbox.o
-	$(CC) -o $@ $^ $(LIBS)
-
-clean:
-	rm -f *.o lxdialog

+ 21 - 26
scripts/config/lxdialog/check-lxdialog.sh

@@ -1,24 +1,14 @@
-#!/usr/bin/env bash
+#!/bin/sh
 # Check ncurses compatibility
 # Check ncurses compatibility
 
 
 # What library to link
 # What library to link
 ldflags()
 ldflags()
 {
 {
-	for ext in so dylib; do
-		for dir in "" /usr/local/lib /opt/local/lib; do
-			$cc ${dir:+-L$dir} -print-file-name=libncursesw.$ext | grep -q /
+	for ext in so a dll.a dylib ; do
+		for lib in ncursesw ncurses curses ; do
+			$cc -print-file-name=lib${lib}.${ext} | grep -q /
 			if [ $? -eq 0 ]; then
 			if [ $? -eq 0 ]; then
-				echo $dir '-lncursesw'
-				exit
-			fi
-			$cc ${dir:+-L$dir} -print-file-name=libncurses.$ext | grep -q /
-			if [ $? -eq 0 ]; then
-				echo $dir '-lncurses'
-				exit 
-			fi
-			$cc ${dir:+-L$dir} -print-file-name=libcurses.$ext | grep -q /
-			if [ $? -eq 0 ]; then
-				echo $dir '-lcurses'
+				echo "-l${lib}"
 				exit
 				exit
 			fi
 			fi
 		done
 		done
@@ -29,12 +19,13 @@ ldflags()
 # Where is ncurses.h?
 # Where is ncurses.h?
 ccflags()
 ccflags()
 {
 {
-	if [ -f /usr/include/ncurses/ncurses.h ]; then
+	if [ -f /usr/include/ncursesw/curses.h ]; then
+		echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"'
+		echo ' -DNCURSES_WIDECHAR=1'
+	elif [ -f /usr/include/ncurses/ncurses.h ]; then
 		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
 		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
 	elif [ -f /usr/include/ncurses/curses.h ]; then
 	elif [ -f /usr/include/ncurses/curses.h ]; then
 		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
 		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
-	elif [ -f /opt/local/include/ncurses/ncurses.h ]; then
-		echo '-I/opt/local/include -I/opt/local/include/ncurses -DCURSES_LOC="<ncurses/ncurses.h>"'
 	elif [ -f /usr/include/ncurses.h ]; then
 	elif [ -f /usr/include/ncurses.h ]; then
 		echo '-DCURSES_LOC="<ncurses.h>"'
 		echo '-DCURSES_LOC="<ncurses.h>"'
 	else
 	else
@@ -48,19 +39,23 @@ trap "rm -f $tmp" 0 1 2 3 15
 
 
 # Check if we can link to ncurses
 # Check if we can link to ncurses
 check() {
 check() {
-	echo "main() {}" | $cc -xc - -o $tmp 2> /dev/null
+        $cc -x c - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
 	if [ $? != 0 ]; then
 	if [ $? != 0 ]; then
-		echo " *** Unable to find the ncurses libraries."          1>&2
-		echo " *** make menuconfig require the ncurses libraries"  1>&2
-		echo " *** "                                               1>&2
-		echo " *** Install ncurses (ncurses-devel) and try again"  1>&2
-		echo " *** "                                               1>&2
-		exit 1
+	    echo " *** Unable to find the ncurses libraries or the"       1>&2
+	    echo " *** required header files."                            1>&2
+	    echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
+	    echo " *** "                                                  1>&2
+	    echo " *** Install ncurses (ncurses-devel) and try again."    1>&2
+	    echo " *** "                                                  1>&2
+	    exit 1
 	fi
 	fi
 }
 }
 
 
 usage() {
 usage() {
-	printf "Usage: $0 [-check compiler options|-header|-library]\n"
+	printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n"
 }
 }
 
 
 if [ $# -eq 0 ]; then
 if [ $# -eq 0 ]; then

+ 102 - 104
scripts/config/lxdialog/checklist.c

@@ -28,29 +28,35 @@ static int list_width, check_x, item_x;
 /*
 /*
  * Print list item
  * Print list item
  */
  */
-static void print_item(WINDOW * win, const char *item, int status, int choice,
-		       int selected)
+static void print_item(WINDOW * win, int choice, int selected)
 {
 {
 	int i;
 	int i;
+	char *list_item = malloc(list_width + 1);
+
+	strncpy(list_item, item_str(), list_width - item_x);
+	list_item[list_width - item_x] = '\0';
 
 
 	/* Clear 'residue' of last item */
 	/* Clear 'residue' of last item */
-	wattrset(win, menubox_attr);
+	wattrset(win, dlg.menubox.atr);
 	wmove(win, choice, 0);
 	wmove(win, choice, 0);
 	for (i = 0; i < list_width; i++)
 	for (i = 0; i < list_width; i++)
 		waddch(win, ' ');
 		waddch(win, ' ');
 
 
 	wmove(win, choice, check_x);
 	wmove(win, choice, check_x);
-	wattrset(win, selected ? check_selected_attr : check_attr);
-	wprintw(win, "(%c)", status ? 'X' : ' ');
-
-	wattrset(win, selected ? tag_selected_attr : tag_attr);
-	mvwaddch(win, choice, item_x, item[0]);
-	wattrset(win, selected ? item_selected_attr : item_attr);
-	waddstr(win, (char *)item + 1);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	if (!item_is_tag(':'))
+		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, list_item[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, list_item + 1);
 	if (selected) {
 	if (selected) {
 		wmove(win, choice, check_x + 1);
 		wmove(win, choice, check_x + 1);
 		wrefresh(win);
 		wrefresh(win);
 	}
 	}
+	free(list_item);
 }
 }
 
 
 /*
 /*
@@ -62,11 +68,11 @@ static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
 	wmove(win, y, x);
 	wmove(win, y, x);
 
 
 	if (scroll > 0) {
 	if (scroll > 0) {
-		wattrset(win, uarrow_attr);
+		wattrset(win, dlg.uarrow.atr);
 		waddch(win, ACS_UARROW);
 		waddch(win, ACS_UARROW);
 		waddstr(win, "(-)");
 		waddstr(win, "(-)");
 	} else {
 	} else {
-		wattrset(win, menubox_attr);
+		wattrset(win, dlg.menubox.atr);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
@@ -77,11 +83,11 @@ static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
 	wmove(win, y, x);
 	wmove(win, y, x);
 
 
 	if ((height < item_no) && (scroll + choice < item_no - 1)) {
 	if ((height < item_no) && (scroll + choice < item_no - 1)) {
-		wattrset(win, darrow_attr);
+		wattrset(win, dlg.darrow.atr);
 		waddch(win, ACS_DARROW);
 		waddch(win, ACS_DARROW);
 		waddstr(win, "(+)");
 		waddstr(win, "(+)");
 	} else {
 	} else {
-		wattrset(win, menubox_border_attr);
+		wattrset(win, dlg.menubox_border.atr);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
@@ -97,8 +103,8 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
 	int x = width / 2 - 11;
 	int x = width / 2 - 11;
 	int y = height - 2;
 	int y = height - 2;
 
 
-	print_button(dialog, "Select", y, x, selected == 0);
-	print_button(dialog, " Help ", y, x + 14, selected == 1);
+	print_button(dialog, gettext("Select"), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
 
 
 	wmove(dialog, y, x + 1 + 14 * selected);
 	wmove(dialog, y, x + 1 + 14 * selected);
 	wrefresh(dialog);
 	wrefresh(dialog);
@@ -109,32 +115,29 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
  * in the style of radiolist (only one option turned on at a time).
  * in the style of radiolist (only one option turned on at a time).
  */
  */
 int dialog_checklist(const char *title, const char *prompt, int height,
 int dialog_checklist(const char *title, const char *prompt, int height,
-		     int width, int list_height, int item_no,
-		     const char *const *items)
+		     int width, int list_height)
 {
 {
 	int i, x, y, box_x, box_y;
 	int i, x, y, box_x, box_y;
-	int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
+	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
 	WINDOW *dialog, *list;
 	WINDOW *dialog, *list;
 
 
-	/* Allocate space for storing item on/off status */
-	if ((status = malloc(sizeof(int) * item_no)) == NULL) {
-		endwin();
-		fprintf(stderr,
-			"\nCan't allocate memory in dialog_checklist().\n");
-		exit(-1);
+	/* which item to highlight */
+	item_foreach() {
+		if (item_is_tag('X'))
+			choice = item_n();
+		if (item_is_selected()) {
+			choice = item_n();
+			break;
+		}
 	}
 	}
 
 
-	/* Initializes status */
-	for (i = 0; i < item_no; i++) {
-		status[i] = !strcasecmp(items[i * 3 + 2], "on");
-		if ((!choice && status[i])
-		    || !strcasecmp(items[i * 3 + 2], "selected"))
-			choice = i + 1;
-	}
-	if (choice)
-		choice--;
+do_resize:
+	if (getmaxy(stdscr) < (height + 6))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 6))
+		return -ERRDISPLAYTOOSMALL;
 
 
-	max_choice = MIN(list_height, item_no);
+	max_choice = MIN(list_height, item_count());
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	x = (COLS - width) / 2;
@@ -145,17 +148,18 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 	dialog = newwin(height, width, y, x);
 	dialog = newwin(height, width, y, x);
 	keypad(dialog, TRUE);
 	keypad(dialog, TRUE);
 
 
-	draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
-	wattrset(dialog, border_attr);
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	for (i = 0; i < width - 2; i++)
 	for (i = 0; i < width - 2; i++)
 		waddch(dialog, ACS_HLINE);
 		waddch(dialog, ACS_HLINE);
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	waddch(dialog, ACS_RTEE);
 	waddch(dialog, ACS_RTEE);
 
 
 	print_title(dialog, title, width);
 	print_title(dialog, title, width);
 
 
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 
 
 	list_width = width - 6;
 	list_width = width - 6;
@@ -170,12 +174,13 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 
 
 	/* draw a box around the list items */
 	/* draw a box around the list items */
 	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
 	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
-	         menubox_border_attr, menubox_attr);
+	         dlg.menubox_border.atr, dlg.menubox.atr);
 
 
 	/* Find length of longest item in order to center checklist */
 	/* Find length of longest item in order to center checklist */
 	check_x = 0;
 	check_x = 0;
-	for (i = 0; i < item_no; i++)
-		check_x = MAX(check_x, +strlen(items[i * 3 + 1]) + 4);
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+	check_x = MIN(check_x, list_width);
 
 
 	check_x = (list_width - check_x) / 2;
 	check_x = (list_width - check_x) / 2;
 	item_x = check_x + 4;
 	item_x = check_x + 4;
@@ -187,26 +192,27 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 
 
 	/* Print the list */
 	/* Print the list */
 	for (i = 0; i < max_choice; i++) {
 	for (i = 0; i < max_choice; i++) {
-		print_item(list, items[(scroll + i) * 3 + 1],
-			   status[i + scroll], i, i == choice);
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
 	}
 	}
 
 
-	print_arrows(dialog, choice, item_no, scroll,
+	print_arrows(dialog, choice, item_count(), scroll,
 		     box_y, box_x + check_x + 5, list_height);
 		     box_y, box_x + check_x + 5, list_height);
 
 
 	print_buttons(dialog, height, width, 0);
 	print_buttons(dialog, height, width, 0);
 
 
-	wnoutrefresh(list);
 	wnoutrefresh(dialog);
 	wnoutrefresh(dialog);
+	wnoutrefresh(list);
 	doupdate();
 	doupdate();
 
 
-	while (key != ESC) {
+	while (key != KEY_ESC) {
 		key = wgetch(dialog);
 		key = wgetch(dialog);
 
 
-		for (i = 0; i < max_choice; i++)
-			if (toupper(key) ==
-			    toupper(items[(scroll + i) * 3 + 1][0]))
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
 				break;
 				break;
+		}
 
 
 		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
 		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
 		    key == '+' || key == '-') {
 		    key == '+' || key == '-') {
@@ -217,47 +223,48 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 					/* Scroll list down */
 					/* Scroll list down */
 					if (list_height > 1) {
 					if (list_height > 1) {
 						/* De-highlight current first item */
 						/* De-highlight current first item */
-						print_item(list, items[scroll * 3 + 1],
-							   status[scroll], 0, FALSE);
+						item_set(scroll);
+						print_item(list, 0, FALSE);
 						scrollok(list, TRUE);
 						scrollok(list, TRUE);
 						wscrl(list, -1);
 						wscrl(list, -1);
 						scrollok(list, FALSE);
 						scrollok(list, FALSE);
 					}
 					}
 					scroll--;
 					scroll--;
-					print_item(list, items[scroll * 3 + 1], status[scroll], 0, TRUE);
-					wnoutrefresh(list);
-
-					print_arrows(dialog, choice, item_no,
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
 						     scroll, box_y, box_x + check_x + 5, list_height);
 						     scroll, box_y, box_x + check_x + 5, list_height);
 
 
-					wrefresh(dialog);
+					wnoutrefresh(dialog);
+					wrefresh(list);
 
 
 					continue;	/* wait for another key press */
 					continue;	/* wait for another key press */
 				} else
 				} else
 					i = choice - 1;
 					i = choice - 1;
 			} else if (key == KEY_DOWN || key == '+') {
 			} else if (key == KEY_DOWN || key == '+') {
 				if (choice == max_choice - 1) {
 				if (choice == max_choice - 1) {
-					if (scroll + choice >= item_no - 1)
+					if (scroll + choice >= item_count() - 1)
 						continue;
 						continue;
 					/* Scroll list up */
 					/* Scroll list up */
 					if (list_height > 1) {
 					if (list_height > 1) {
 						/* De-highlight current last item before scrolling up */
 						/* De-highlight current last item before scrolling up */
-						print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
-							   status[scroll + max_choice - 1],
-							   max_choice - 1, FALSE);
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
 						scrollok(list, TRUE);
 						scrollok(list, TRUE);
 						wscrl(list, 1);
 						wscrl(list, 1);
 						scrollok(list, FALSE);
 						scrollok(list, FALSE);
 					}
 					}
 					scroll++;
 					scroll++;
-					print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
-						   status[scroll + max_choice - 1], max_choice - 1, TRUE);
-					wnoutrefresh(list);
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
 
 
-					print_arrows(dialog, choice, item_no,
+					print_arrows(dialog, choice, item_count(),
 						     scroll, box_y, box_x + check_x + 5, list_height);
 						     scroll, box_y, box_x + check_x + 5, list_height);
 
 
-					wrefresh(dialog);
+					wnoutrefresh(dialog);
+					wrefresh(list);
 
 
 					continue;	/* wait for another key press */
 					continue;	/* wait for another key press */
 				} else
 				} else
@@ -265,14 +272,14 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 			}
 			}
 			if (i != choice) {
 			if (i != choice) {
 				/* De-highlight current item */
 				/* De-highlight current item */
-				print_item(list, items[(scroll + choice) * 3 + 1],
-					   status[scroll + choice], choice, FALSE);
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
 				/* Highlight new item */
 				/* Highlight new item */
 				choice = i;
 				choice = i;
-				print_item(list, items[(scroll + choice) * 3 + 1],
-					   status[scroll + choice], choice, TRUE);
-				wnoutrefresh(list);
-				wrefresh(dialog);
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
 			}
 			}
 			continue;	/* wait for another key press */
 			continue;	/* wait for another key press */
 		}
 		}
@@ -280,10 +287,19 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 		case 'H':
 		case 'H':
 		case 'h':
 		case 'h':
 		case '?':
 		case '?':
-			fprintf(stderr, "%s", items[(scroll + choice) * 3]);
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_foreach()
+				item_set_selected(0);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			delwin(list);
 			delwin(dialog);
 			delwin(dialog);
-			free(status);
-			return 1;
+			return button;
 		case TAB:
 		case TAB:
 		case KEY_LEFT:
 		case KEY_LEFT:
 		case KEY_RIGHT:
 		case KEY_RIGHT:
@@ -293,42 +309,24 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 			print_buttons(dialog, height, width, button);
 			print_buttons(dialog, height, width, button);
 			wrefresh(dialog);
 			wrefresh(dialog);
 			break;
 			break;
-		case 'S':
-		case 's':
-		case ' ':
-		case '\n':
-			if (!button) {
-				if (!status[scroll + choice]) {
-					for (i = 0; i < item_no; i++)
-						status[i] = 0;
-					status[scroll + choice] = 1;
-					for (i = 0; i < max_choice; i++)
-						print_item(list, items[(scroll + i) * 3 + 1],
-							   status[scroll + i], i, i == choice);
-				}
-				wnoutrefresh(list);
-				wrefresh(dialog);
-
-				for (i = 0; i < item_no; i++)
-					if (status[i])
-						fprintf(stderr, "%s", items[i * 3]);
-			} else
-				fprintf(stderr, "%s", items[(scroll + choice) * 3]);
-			delwin(dialog);
-			free(status);
-			return button;
 		case 'X':
 		case 'X':
 		case 'x':
 		case 'x':
-			key = ESC;
-		case ESC:
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
 			break;
 			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 		}
 
 
 		/* Now, update everything... */
 		/* Now, update everything... */
 		doupdate();
 		doupdate();
 	}
 	}
-
+	delwin(list);
 	delwin(dialog);
 	delwin(dialog);
-	free(status);
-	return -1;		/* ESC pressed */
+	return key;		/* ESC pressed */
 }
 }

+ 0 - 154
scripts/config/lxdialog/colors.h

@@ -1,154 +0,0 @@
-/*
- *  colors.h -- color attribute definitions
- *
- *  AUTHOR: Savio Lam ([email protected])
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version 2
- *  of the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- *   Default color definitions
- *
- *   *_FG = foreground
- *   *_BG = background
- *   *_HL = highlight?
- */
-#define SCREEN_FG                    COLOR_CYAN
-#define SCREEN_BG                    COLOR_BLUE
-#define SCREEN_HL                    TRUE
-
-#define SHADOW_FG                    COLOR_BLACK
-#define SHADOW_BG                    COLOR_BLACK
-#define SHADOW_HL                    TRUE
-
-#define DIALOG_FG                    COLOR_BLACK
-#define DIALOG_BG                    COLOR_WHITE
-#define DIALOG_HL                    FALSE
-
-#define TITLE_FG                     COLOR_BLUE
-#define TITLE_BG                     COLOR_WHITE
-#define TITLE_HL                     TRUE
-
-#define BORDER_FG                    COLOR_WHITE
-#define BORDER_BG                    COLOR_WHITE
-#define BORDER_HL                    TRUE
-
-#define BUTTON_ACTIVE_FG             COLOR_WHITE
-#define BUTTON_ACTIVE_BG             COLOR_BLUE
-#define BUTTON_ACTIVE_HL             TRUE
-
-#define BUTTON_INACTIVE_FG           COLOR_BLACK
-#define BUTTON_INACTIVE_BG           COLOR_WHITE
-#define BUTTON_INACTIVE_HL           FALSE
-
-#define BUTTON_KEY_ACTIVE_FG         COLOR_WHITE
-#define BUTTON_KEY_ACTIVE_BG         COLOR_BLUE
-#define BUTTON_KEY_ACTIVE_HL         TRUE
-
-#define BUTTON_KEY_INACTIVE_FG       COLOR_RED
-#define BUTTON_KEY_INACTIVE_BG       COLOR_WHITE
-#define BUTTON_KEY_INACTIVE_HL       FALSE
-
-#define BUTTON_LABEL_ACTIVE_FG       COLOR_YELLOW
-#define BUTTON_LABEL_ACTIVE_BG       COLOR_BLUE
-#define BUTTON_LABEL_ACTIVE_HL       TRUE
-
-#define BUTTON_LABEL_INACTIVE_FG     COLOR_BLACK
-#define BUTTON_LABEL_INACTIVE_BG     COLOR_WHITE
-#define BUTTON_LABEL_INACTIVE_HL     TRUE
-
-#define INPUTBOX_FG                  COLOR_BLACK
-#define INPUTBOX_BG                  COLOR_WHITE
-#define INPUTBOX_HL                  FALSE
-
-#define INPUTBOX_BORDER_FG           COLOR_BLACK
-#define INPUTBOX_BORDER_BG           COLOR_WHITE
-#define INPUTBOX_BORDER_HL           FALSE
-
-#define SEARCHBOX_FG                 COLOR_BLACK
-#define SEARCHBOX_BG                 COLOR_WHITE
-#define SEARCHBOX_HL                 FALSE
-
-#define SEARCHBOX_TITLE_FG           COLOR_BLUE
-#define SEARCHBOX_TITLE_BG           COLOR_WHITE
-#define SEARCHBOX_TITLE_HL           TRUE
-
-#define SEARCHBOX_BORDER_FG          COLOR_WHITE
-#define SEARCHBOX_BORDER_BG          COLOR_WHITE
-#define SEARCHBOX_BORDER_HL          TRUE
-
-#define POSITION_INDICATOR_FG        COLOR_BLUE
-#define POSITION_INDICATOR_BG        COLOR_WHITE
-#define POSITION_INDICATOR_HL        TRUE
-
-#define MENUBOX_FG                   COLOR_BLACK
-#define MENUBOX_BG                   COLOR_WHITE
-#define MENUBOX_HL                   FALSE
-
-#define MENUBOX_BORDER_FG            COLOR_WHITE
-#define MENUBOX_BORDER_BG            COLOR_WHITE
-#define MENUBOX_BORDER_HL            TRUE
-
-#define ITEM_FG                      COLOR_BLACK
-#define ITEM_BG                      COLOR_WHITE
-#define ITEM_HL                      FALSE
-
-#define ITEM_SELECTED_FG             COLOR_WHITE
-#define ITEM_SELECTED_BG             COLOR_BLUE
-#define ITEM_SELECTED_HL             TRUE
-
-#define TAG_FG                       COLOR_BLUE
-#define TAG_BG                       COLOR_WHITE
-#define TAG_HL                       TRUE
-
-#define TAG_SELECTED_FG              COLOR_YELLOW
-#define TAG_SELECTED_BG              COLOR_BLUE
-#define TAG_SELECTED_HL              TRUE
-
-#define TAG_KEY_FG                   COLOR_BLUE
-#define TAG_KEY_BG                   COLOR_WHITE
-#define TAG_KEY_HL                   TRUE
-
-#define TAG_KEY_SELECTED_FG          COLOR_YELLOW
-#define TAG_KEY_SELECTED_BG          COLOR_BLUE
-#define TAG_KEY_SELECTED_HL          TRUE
-
-#define CHECK_FG                     COLOR_BLACK
-#define CHECK_BG                     COLOR_WHITE
-#define CHECK_HL                     FALSE
-
-#define CHECK_SELECTED_FG            COLOR_WHITE
-#define CHECK_SELECTED_BG            COLOR_BLUE
-#define CHECK_SELECTED_HL            TRUE
-
-#define UARROW_FG                    COLOR_GREEN
-#define UARROW_BG                    COLOR_WHITE
-#define UARROW_HL                    TRUE
-
-#define DARROW_FG                    COLOR_GREEN
-#define DARROW_BG                    COLOR_WHITE
-#define DARROW_HL                    TRUE
-
-/* End of default color definitions */
-
-#define C_ATTR(x,y)                  ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
-#define COLOR_NAME_LEN               10
-#define COLOR_COUNT                  8
-
-/*
- * Global variables
- */
-
-extern int color_table[][3];

+ 111 - 52
scripts/config/lxdialog/dialog.h

@@ -24,6 +24,13 @@
 #include <ctype.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
+#include <stdbool.h>
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
 
 
 #ifdef __sun__
 #ifdef __sun__
 #define CURS_MACROS
 #define CURS_MACROS
@@ -48,7 +55,7 @@
 
 
 #define TR(params) _tracef params
 #define TR(params) _tracef params
 
 
-#define ESC 27
+#define KEY_ESC 27
 #define TAB 9
 #define TAB 9
 #define MAX_LEN 2048
 #define MAX_LEN 2048
 #define BUF_SIZE (10*1024)
 #define BUF_SIZE (10*1024)
@@ -86,63 +93,112 @@
 #define ACS_DARROW 'v'
 #define ACS_DARROW 'v'
 #endif
 #endif
 
 
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
 /*
 /*
- * Attribute names
+ *   Color definitions
  */
  */
-#define screen_attr                   attributes[0]
-#define shadow_attr                   attributes[1]
-#define dialog_attr                   attributes[2]
-#define title_attr                    attributes[3]
-#define border_attr                   attributes[4]
-#define button_active_attr            attributes[5]
-#define button_inactive_attr          attributes[6]
-#define button_key_active_attr        attributes[7]
-#define button_key_inactive_attr      attributes[8]
-#define button_label_active_attr      attributes[9]
-#define button_label_inactive_attr    attributes[10]
-#define inputbox_attr                 attributes[11]
-#define inputbox_border_attr          attributes[12]
-#define searchbox_attr                attributes[13]
-#define searchbox_title_attr          attributes[14]
-#define searchbox_border_attr         attributes[15]
-#define position_indicator_attr       attributes[16]
-#define menubox_attr                  attributes[17]
-#define menubox_border_attr           attributes[18]
-#define item_attr                     attributes[19]
-#define item_selected_attr            attributes[20]
-#define tag_attr                      attributes[21]
-#define tag_selected_attr             attributes[22]
-#define tag_key_attr                  attributes[23]
-#define tag_key_selected_attr         attributes[24]
-#define check_attr                    attributes[25]
-#define check_selected_attr           attributes[26]
-#define uarrow_attr                   attributes[27]
-#define darrow_attr                   attributes[28]
-
-/* number of attributes */
-#define ATTRIBUTE_COUNT               29
+struct dialog_color {
+	chtype atr;	/* Color attribute */
+	int fg;		/* foreground */
+	int bg;		/* background */
+	int hl;		/* highlight this item */
+};
+
+struct dialog_info {
+	const char *backtitle;
+	struct dialog_color screen;
+	struct dialog_color shadow;
+	struct dialog_color dialog;
+	struct dialog_color title;
+	struct dialog_color border;
+	struct dialog_color button_active;
+	struct dialog_color button_inactive;
+	struct dialog_color button_key_active;
+	struct dialog_color button_key_inactive;
+	struct dialog_color button_label_active;
+	struct dialog_color button_label_inactive;
+	struct dialog_color inputbox;
+	struct dialog_color inputbox_border;
+	struct dialog_color searchbox;
+	struct dialog_color searchbox_title;
+	struct dialog_color searchbox_border;
+	struct dialog_color position_indicator;
+	struct dialog_color menubox;
+	struct dialog_color menubox_border;
+	struct dialog_color item;
+	struct dialog_color item_selected;
+	struct dialog_color tag;
+	struct dialog_color tag_selected;
+	struct dialog_color tag_key;
+	struct dialog_color tag_key_selected;
+	struct dialog_color check;
+	struct dialog_color check_selected;
+	struct dialog_color uarrow;
+	struct dialog_color darrow;
+};
 
 
 /*
 /*
  * Global variables
  * Global variables
  */
  */
-extern bool use_colors;
-extern bool use_shadow;
-
-extern chtype attributes[];
-
-extern const char *backtitle;
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+extern int saved_x, saved_y;		/* Needed in signal handler in mconf.c */
 
 
 /*
 /*
  * Function prototypes
  * Function prototypes
  */
  */
-extern void create_rc(const char *filename);
-extern int parse_rc(void);
 
 
-void init_dialog(void);
-void end_dialog(void);
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+	char str[MAXITEMSTR];	/* promtp displayed */
+	char tag;
+	void *data;	/* pointer to menu item - used by menubox+checklist */
+	int selected;	/* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+	struct dialog_item node;
+	struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+	for (item_cur = item_head ? item_head: item_cur; \
+	     item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void end_dialog(int x, int y);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
 void dialog_clear(void);
 void dialog_clear(void);
-void color_setup(void);
 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
 void print_button(WINDOW * win, const char *label, int y, int x, int selected);
 void print_button(WINDOW * win, const char *label, int y, int x, int selected);
 void print_title(WINDOW *dialog, const char *title, int width);
 void print_title(WINDOW *dialog, const char *title, int width);
@@ -154,14 +210,17 @@ int first_alpha(const char *string, const char *exempt);
 int dialog_yesno(const char *title, const char *prompt, int height, int width);
 int dialog_yesno(const char *title, const char *prompt, int height, int width);
 int dialog_msgbox(const char *title, const char *prompt, int height,
 int dialog_msgbox(const char *title, const char *prompt, int height,
 		  int width, int pause);
 		  int width, int pause);
-int dialog_textbox(const char *title, const char *file, int height, int width);
-int dialog_menu(const char *title, const char *prompt, int height, int width,
-		int menu_height, const char *choice, int item_no,
-		const char *const *items);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+			       *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data);
+int dialog_menu(const char *title, const char *prompt,
+		const void *selected, int *s_scroll);
 int dialog_checklist(const char *title, const char *prompt, int height,
 int dialog_checklist(const char *title, const char *prompt, int height,
-		     int width, int list_height, int item_no,
-		     const char *const *items);
-extern char dialog_input_result[];
+		     int width, int list_height);
 int dialog_inputbox(const char *title, const char *prompt, int height,
 int dialog_inputbox(const char *title, const char *prompt, int height,
 		    int width, const char *init);
 		    int width, const char *init);
 
 

+ 127 - 50
scripts/config/lxdialog/inputbox.c

@@ -31,8 +31,8 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
 	int x = width / 2 - 11;
 	int x = width / 2 - 11;
 	int y = height - 2;
 	int y = height - 2;
 
 
-	print_button(dialog, "  Ok  ", y, x, selected == 0);
-	print_button(dialog, " Help ", y, x + 14, selected == 1);
+	print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
 
 
 	wmove(dialog, y, x + 1 + 14 * selected);
 	wmove(dialog, y, x + 1 + 14 * selected);
 	wrefresh(dialog);
 	wrefresh(dialog);
@@ -45,10 +45,22 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
                     const char *init)
                     const char *init)
 {
 {
 	int i, x, y, box_y, box_x, box_width;
 	int i, x, y, box_y, box_x, box_width;
-	int input_x = 0, scroll = 0, key = 0, button = -1;
+	int input_x = 0, key = 0, button = -1;
+	int show_x, len, pos;
 	char *instr = dialog_input_result;
 	char *instr = dialog_input_result;
 	WINDOW *dialog;
 	WINDOW *dialog;
 
 
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (getmaxy(stdscr) <= (height - 2))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) <= (width - 2))
+		return -ERRDISPLAYTOOSMALL;
+
 	/* center dialog box on screen */
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	x = (COLS - width) / 2;
 	y = (LINES - height) / 2;
 	y = (LINES - height) / 2;
@@ -58,17 +70,18 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 	dialog = newwin(height, width, y, x);
 	dialog = newwin(height, width, y, x);
 	keypad(dialog, TRUE);
 	keypad(dialog, TRUE);
 
 
-	draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
-	wattrset(dialog, border_attr);
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	for (i = 0; i < width - 2; i++)
 	for (i = 0; i < width - 2; i++)
 		waddch(dialog, ACS_HLINE);
 		waddch(dialog, ACS_HLINE);
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	waddch(dialog, ACS_RTEE);
 	waddch(dialog, ACS_RTEE);
 
 
 	print_title(dialog, title, width);
 	print_title(dialog, title, width);
 
 
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 
 
 	/* Draw the input field box */
 	/* Draw the input field box */
@@ -76,27 +89,26 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 	getyx(dialog, y, x);
 	getyx(dialog, y, x);
 	box_y = y + 2;
 	box_y = y + 2;
 	box_x = (width - box_width) / 2;
 	box_x = (width - box_width) / 2;
-	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, border_attr, dialog_attr);
+	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+		 dlg.dialog.atr, dlg.border.atr);
 
 
 	print_buttons(dialog, height, width, 0);
 	print_buttons(dialog, height, width, 0);
 
 
 	/* Set up the initial value */
 	/* Set up the initial value */
 	wmove(dialog, box_y, box_x);
 	wmove(dialog, box_y, box_x);
-	wattrset(dialog, inputbox_attr);
-
-	if (!init)
-		instr[0] = '\0';
-	else
-		strcpy(instr, init);
+	wattrset(dialog, dlg.inputbox.atr);
 
 
-	input_x = strlen(instr);
+	len = strlen(instr);
+	pos = len;
 
 
-	if (input_x >= box_width) {
-		scroll = input_x - box_width + 1;
+	if (len >= box_width) {
+		show_x = len - box_width + 1;
 		input_x = box_width - 1;
 		input_x = box_width - 1;
 		for (i = 0; i < box_width - 1; i++)
 		for (i = 0; i < box_width - 1; i++)
-			waddch(dialog, instr[scroll + i]);
+			waddch(dialog, instr[show_x + i]);
 	} else {
 	} else {
+		show_x = 0;
+		input_x = len;
 		waddstr(dialog, instr);
 		waddstr(dialog, instr);
 	}
 	}
 
 
@@ -104,7 +116,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 
 
 	wrefresh(dialog);
 	wrefresh(dialog);
 
 
-	while (key != ESC) {
+	while (key != KEY_ESC) {
 		key = wgetch(dialog);
 		key = wgetch(dialog);
 
 
 		if (button == -1) {	/* Input box selected */
 		if (button == -1) {	/* Input box selected */
@@ -113,45 +125,104 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 			case KEY_UP:
 			case KEY_UP:
 			case KEY_DOWN:
 			case KEY_DOWN:
 				break;
 				break;
-			case KEY_LEFT:
-				continue;
-			case KEY_RIGHT:
-				continue;
 			case KEY_BACKSPACE:
 			case KEY_BACKSPACE:
 			case 127:
 			case 127:
-				if (input_x || scroll) {
-					wattrset(dialog, inputbox_attr);
-					if (!input_x) {
-						scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
-						wmove(dialog, box_y, box_x);
-						for (i = 0; i < box_width; i++)
-							waddch(dialog,
-							       instr[scroll + input_x + i] ?
-							       instr[scroll + input_x + i] : ' ');
-						input_x = strlen(instr) - scroll;
+				if (pos) {
+					wattrset(dialog, dlg.inputbox.atr);
+					if (input_x == 0) {
+						show_x--;
 					} else
 					} else
 						input_x--;
 						input_x--;
-					instr[scroll + input_x] = '\0';
-					mvwaddch(dialog, box_y, input_x + box_x, ' ');
+
+					if (pos < len) {
+						for (i = pos - 1; i < len; i++) {
+							instr[i] = instr[i+1];
+						}
+					}
+
+					pos--;
+					len--;
+					instr[len] = '\0';
+					wmove(dialog, box_y, box_x);
+					for (i = 0; i < box_width; i++) {
+						if (!instr[show_x + i]) {
+							waddch(dialog, ' ');
+							break;
+						}
+						waddch(dialog, instr[show_x + i]);
+					}
 					wmove(dialog, box_y, input_x + box_x);
 					wmove(dialog, box_y, input_x + box_x);
 					wrefresh(dialog);
 					wrefresh(dialog);
 				}
 				}
 				continue;
 				continue;
+			case KEY_LEFT:
+				if (pos > 0) {
+					if (input_x > 0) {
+						wmove(dialog, box_y, --input_x + box_x);
+					} else if (input_x == 0) {
+						show_x--;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, box_x);
+					}
+					pos--;
+				}
+				continue;
+			case KEY_RIGHT:
+				if (pos < len) {
+					if (input_x < box_width - 1) {
+						wmove(dialog, box_y, ++input_x + box_x);
+					} else if (input_x == box_width - 1) {
+						show_x++;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
+					}
+					pos++;
+				}
+				continue;
 			default:
 			default:
 				if (key < 0x100 && isprint(key)) {
 				if (key < 0x100 && isprint(key)) {
-					if (scroll + input_x < MAX_LEN) {
-						wattrset(dialog, inputbox_attr);
-						instr[scroll + input_x] = key;
-						instr[scroll + input_x + 1] = '\0';
+					if (len < MAX_LEN) {
+						wattrset(dialog, dlg.inputbox.atr);
+						if (pos < len) {
+							for (i = len; i > pos; i--)
+								instr[i] = instr[i-1];
+							instr[pos] = key;
+						} else {
+							instr[len] = key;
+						}
+						pos++;
+						len++;
+						instr[len] = '\0';
+
 						if (input_x == box_width - 1) {
 						if (input_x == box_width - 1) {
-							scroll++;
-							wmove(dialog, box_y, box_x);
-							for (i = 0; i < box_width - 1; i++)
-								waddch(dialog, instr [scroll + i]);
+							show_x++;
 						} else {
 						} else {
-							wmove(dialog, box_y, input_x++ + box_x);
-							waddch(dialog, key);
+							input_x++;
 						}
 						}
+
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
 						wrefresh(dialog);
 						wrefresh(dialog);
 					} else
 					} else
 						flash();	/* Alarm user about overflow */
 						flash();	/* Alarm user about overflow */
@@ -172,7 +243,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 		case KEY_LEFT:
 		case KEY_LEFT:
 			switch (button) {
 			switch (button) {
 			case -1:
 			case -1:
-				button = 1;	/* Indicates "Cancel" button is selected */
+				button = 1;	/* Indicates "Help" button is selected */
 				print_buttons(dialog, height, width, 1);
 				print_buttons(dialog, height, width, 1);
 				break;
 				break;
 			case 0:
 			case 0:
@@ -196,7 +267,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 				print_buttons(dialog, height, width, 0);
 				print_buttons(dialog, height, width, 0);
 				break;
 				break;
 			case 0:
 			case 0:
-				button = 1;	/* Indicates "Cancel" button is selected */
+				button = 1;	/* Indicates "Help" button is selected */
 				print_buttons(dialog, height, width, 1);
 				print_buttons(dialog, height, width, 1);
 				break;
 				break;
 			case 1:
 			case 1:
@@ -213,12 +284,18 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 			return (button == -1 ? 0 : button);
 			return (button == -1 ? 0 : button);
 		case 'X':
 		case 'X':
 		case 'x':
 		case 'x':
-			key = ESC;
-		case ESC:
+			key = KEY_ESC;
 			break;
 			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 		}
 	}
 	}
 
 
 	delwin(dialog);
 	delwin(dialog);
-	return -1;		/* ESC pressed */
+	return KEY_ESC;		/* ESC pressed */
 }
 }

+ 0 - 204
scripts/config/lxdialog/lxdialog.c

@@ -1,204 +0,0 @@
-/*
- *  dialog - Display simple dialog boxes from shell scripts
- *
- *  ORIGINAL AUTHOR: Savio Lam ([email protected])
- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap ([email protected])
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version 2
- *  of the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "dialog.h"
-
-static void Usage(const char *name);
-
-typedef int (jumperFn) (const char *title, int argc, const char *const *argv);
-
-struct Mode {
-	char *name;
-	int argmin, argmax, argmod;
-	jumperFn *jumper;
-};
-
-jumperFn j_menu, j_radiolist, j_yesno, j_textbox, j_inputbox;
-jumperFn j_msgbox, j_infobox;
-
-static struct Mode modes[] = {
-	{"--menu", 9, 0, 3, j_menu},
-	{"--radiolist", 9, 0, 3, j_radiolist},
-	{"--yesno", 5, 5, 1, j_yesno},
-	{"--textbox", 5, 5, 1, j_textbox},
-	{"--inputbox", 5, 6, 1, j_inputbox},
-	{"--msgbox", 5, 5, 1, j_msgbox},
-	{"--infobox", 5, 5, 1, j_infobox},
-	{NULL, 0, 0, 0, NULL}
-};
-
-static struct Mode *modePtr;
-
-#ifdef LOCALE
-#include <locale.h>
-#endif
-
-int main(int argc, const char *const *argv)
-{
-	int offset = 0, opt_clear = 0, end_common_opts = 0, retval;
-	const char *title = NULL;
-
-#ifdef LOCALE
-	(void)setlocale(LC_ALL, "");
-#endif
-
-#ifdef TRACE
-	trace(TRACE_CALLS | TRACE_UPDATE);
-#endif
-	if (argc < 2) {
-		Usage(argv[0]);
-		exit(-1);
-	}
-
-	while (offset < argc - 1 && !end_common_opts) {	/* Common options */
-		if (!strcmp(argv[offset + 1], "--title")) {
-			if (argc - offset < 3 || title != NULL) {
-				Usage(argv[0]);
-				exit(-1);
-			} else {
-				title = argv[offset + 2];
-				offset += 2;
-			}
-		} else if (!strcmp(argv[offset + 1], "--backtitle")) {
-			if (backtitle != NULL) {
-				Usage(argv[0]);
-				exit(-1);
-			} else {
-				backtitle = argv[offset + 2];
-				offset += 2;
-			}
-		} else if (!strcmp(argv[offset + 1], "--clear")) {
-			if (opt_clear) {	/* Hey, "--clear" can't appear twice! */
-				Usage(argv[0]);
-				exit(-1);
-			} else if (argc == 2) {	/* we only want to clear the screen */
-				init_dialog();
-				refresh();	/* init_dialog() will clear the screen for us */
-				end_dialog();
-				return 0;
-			} else {
-				opt_clear = 1;
-				offset++;
-			}
-		} else		/* no more common options */
-			end_common_opts = 1;
-	}
-
-	if (argc - 1 == offset) {	/* no more options */
-		Usage(argv[0]);
-		exit(-1);
-	}
-	/* use a table to look for the requested mode, to avoid code duplication */
-
-	for (modePtr = modes; modePtr->name; modePtr++)	/* look for the mode */
-		if (!strcmp(argv[offset + 1], modePtr->name))
-			break;
-
-	if (!modePtr->name)
-		Usage(argv[0]);
-	if (argc - offset < modePtr->argmin)
-		Usage(argv[0]);
-	if (modePtr->argmax && argc - offset > modePtr->argmax)
-		Usage(argv[0]);
-
-	init_dialog();
-	retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset);
-
-	if (opt_clear) {	/* clear screen before exit */
-		attr_clear(stdscr, LINES, COLS, screen_attr);
-		refresh();
-	}
-	end_dialog();
-
-	exit(retval);
-}
-
-/*
- * Print program usage
- */
-static void Usage(const char *name)
-{
-	fprintf(stderr, "\
-\ndialog, by Savio Lam ([email protected]).\
-\n  patched by Stuart Herbert ([email protected])\
-\n  modified/gutted for use as a Linux kernel config tool by \
-\n  William Roadcap ([email protected])\
-\n\
-\n* Display dialog boxes from shell scripts *\
-\n\
-\nUsage: %s --clear\
-\n       %s [--title <title>] [--backtitle <backtitle>] --clear <Box options>\
-\n\
-\nBox options:\
-\n\
-\n  --menu      <text> <height> <width> <menu height> <tag1> <item1>...\
-\n  --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
-\n  --textbox   <file> <height> <width>\
-\n  --inputbox  <text> <height> <width> [<init>]\
-\n  --yesno     <text> <height> <width>\
-\n", name, name);
-	exit(-1);
-}
-
-/*
- * These are the program jumpers
- */
-
-int j_menu(const char *t, int ac, const char *const *av)
-{
-	return dialog_menu(t, av[2], atoi(av[3]), atoi(av[4]),
-			   atoi(av[5]), av[6], (ac - 6) / 2, av + 7);
-}
-
-int j_radiolist(const char *t, int ac, const char *const *av)
-{
-	return dialog_checklist(t, av[2], atoi(av[3]), atoi(av[4]),
-				atoi(av[5]), (ac - 6) / 3, av + 6);
-}
-
-int j_textbox(const char *t, int ac, const char *const *av)
-{
-	return dialog_textbox(t, av[2], atoi(av[3]), atoi(av[4]));
-}
-
-int j_yesno(const char *t, int ac, const char *const *av)
-{
-	return dialog_yesno(t, av[2], atoi(av[3]), atoi(av[4]));
-}
-
-int j_inputbox(const char *t, int ac, const char *const *av)
-{
-	int ret = dialog_inputbox(t, av[2], atoi(av[3]), atoi(av[4]),
-				  ac == 6 ? av[5] : (char *)NULL);
-	if (ret == 0)
-		fprintf(stderr, "%s", dialog_input_result);
-	return ret;
-}
-
-int j_msgbox(const char *t, int ac, const char *const *av)
-{
-	return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 1);
-}
-
-int j_infobox(const char *t, int ac, const char *const *av)
-{
-	return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 0);
-}

+ 113 - 102
scripts/config/lxdialog/menubox.c

@@ -26,7 +26,7 @@
  *
  *
  *    *)  A bugfix for the Page-Down problem
  *    *)  A bugfix for the Page-Down problem
  *
  *
- *    *)  Formerly when I used Page Down and Page Up, the cursor would be set 
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set
  *        to the first position in the menu box.  Now lxdialog is a bit
  *        to the first position in the menu box.  Now lxdialog is a bit
  *        smarter and works more like other menu systems (just have a look at
  *        smarter and works more like other menu systems (just have a look at
  *        it).
  *        it).
@@ -58,25 +58,24 @@
 
 
 #include "dialog.h"
 #include "dialog.h"
 
 
-#define ITEM_IDENT 1   /* Indent of menu entries. Fixed for all menus */
-static int menu_width;
+static int menu_width, item_x;
 
 
 /*
 /*
  * Print menu item
  * Print menu item
  */
  */
-static void do_print_item(WINDOW * win, const char *item, int choice,
+static void do_print_item(WINDOW * win, const char *item, int line_y,
                           int selected, int hotkey)
                           int selected, int hotkey)
 {
 {
 	int j;
 	int j;
 	char *menu_item = malloc(menu_width + 1);
 	char *menu_item = malloc(menu_width + 1);
 
 
-	strncpy(menu_item, item, menu_width - ITEM_IDENT);
-	menu_item[menu_width] = 0;
+	strncpy(menu_item, item, menu_width - item_x);
+	menu_item[menu_width - item_x] = '\0';
 	j = first_alpha(menu_item, "YyNnMmHh");
 	j = first_alpha(menu_item, "YyNnMmHh");
 
 
 	/* Clear 'residue' of last item */
 	/* Clear 'residue' of last item */
-	wattrset(win, menubox_attr);
-	wmove(win, choice, 0);
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, line_y, 0);
 #if OLD_NCURSES
 #if OLD_NCURSES
 	{
 	{
 		int i;
 		int i;
@@ -86,23 +85,24 @@ static void do_print_item(WINDOW * win, const char *item, int choice,
 #else
 #else
 	wclrtoeol(win);
 	wclrtoeol(win);
 #endif
 #endif
-	wattrset(win, selected ? item_selected_attr : item_attr);
-	mvwaddstr(win, choice, ITEM_IDENT, menu_item);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	mvwaddstr(win, line_y, item_x, menu_item);
 	if (hotkey) {
 	if (hotkey) {
-		wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
-		mvwaddch(win, choice, ITEM_IDENT + j, menu_item[j]);
+		wattrset(win, selected ? dlg.tag_key_selected.atr
+			 : dlg.tag_key.atr);
+		mvwaddch(win, line_y, item_x + j, menu_item[j]);
 	}
 	}
 	if (selected) {
 	if (selected) {
-		wmove(win, choice, ITEM_IDENT + 1);
+		wmove(win, line_y, item_x + 1);
 	}
 	}
 	free(menu_item);
 	free(menu_item);
 	wrefresh(win);
 	wrefresh(win);
 }
 }
 
 
-#define print_item(index, choice, selected) \
-do {\
-	int hotkey = (items[(index) * 2][0] != ':'); \
-	do_print_item(menu, items[(index) * 2 + 1], choice, selected, hotkey); \
+#define print_item(index, choice, selected)				\
+do {									\
+	item_set(index);						\
+	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
 } while (0)
 } while (0)
 
 
 /*
 /*
@@ -118,11 +118,11 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
 	wmove(win, y, x);
 	wmove(win, y, x);
 
 
 	if (scroll > 0) {
 	if (scroll > 0) {
-		wattrset(win, uarrow_attr);
+		wattrset(win, dlg.uarrow.atr);
 		waddch(win, ACS_UARROW);
 		waddch(win, ACS_UARROW);
 		waddstr(win, "(-)");
 		waddstr(win, "(-)");
 	} else {
 	} else {
-		wattrset(win, menubox_attr);
+		wattrset(win, dlg.menubox.atr);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
@@ -134,11 +134,11 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
 	wrefresh(win);
 	wrefresh(win);
 
 
 	if ((height < item_no) && (scroll + height < item_no)) {
 	if ((height < item_no) && (scroll + height < item_no)) {
-		wattrset(win, darrow_attr);
+		wattrset(win, dlg.darrow.atr);
 		waddch(win, ACS_DARROW);
 		waddch(win, ACS_DARROW);
 		waddstr(win, "(+)");
 		waddstr(win, "(+)");
 	} else {
 	} else {
-		wattrset(win, menubox_border_attr);
+		wattrset(win, dlg.menubox_border.atr);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
 		waddch(win, ACS_HLINE);
@@ -154,12 +154,14 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
  */
  */
 static void print_buttons(WINDOW * win, int height, int width, int selected)
 static void print_buttons(WINDOW * win, int height, int width, int selected)
 {
 {
-	int x = width / 2 - 16;
+	int x = width / 2 - 28;
 	int y = height - 2;
 	int y = height - 2;
 
 
-	print_button(win, "Select", y, x, selected == 0);
-	print_button(win, " Exit ", y, x + 12, selected == 1);
-	print_button(win, " Help ", y, x + 24, selected == 2);
+	print_button(win, gettext("Select"), y, x, selected == 0);
+	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
+	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+	print_button(win, gettext(" Save "), y, x + 36, selected == 3);
+	print_button(win, gettext(" Load "), y, x + 48, selected == 4);
 
 
 	wmove(win, y, x + 1 + 12 * selected);
 	wmove(win, y, x + 1 + 12 * selected);
 	wrefresh(win);
 	wrefresh(win);
@@ -179,17 +181,26 @@ static void do_scroll(WINDOW *win, int *scroll, int n)
 /*
 /*
  * Display a menu for choosing among a number of options
  * Display a menu for choosing among a number of options
  */
  */
-int dialog_menu(const char *title, const char *prompt, int height, int width,
-                int menu_height, const char *current, int item_no,
-                const char *const *items)
+int dialog_menu(const char *title, const char *prompt,
+                const void *selected, int *s_scroll)
 {
 {
 	int i, j, x, y, box_x, box_y;
 	int i, j, x, y, box_x, box_y;
+	int height, width, menu_height;
 	int key = 0, button = 0, scroll = 0, choice = 0;
 	int key = 0, button = 0, scroll = 0, choice = 0;
 	int first_item =  0, max_choice;
 	int first_item =  0, max_choice;
 	WINDOW *dialog, *menu;
 	WINDOW *dialog, *menu;
-	FILE *f;
 
 
-	max_choice = MIN(menu_height, item_no);
+do_resize:
+	height = getmaxy(stdscr);
+	width = getmaxx(stdscr);
+	if (height < 15 || width < 65)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 10;
+
+	max_choice = MIN(menu_height, item_count());
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	x = (COLS - width) / 2;
@@ -200,18 +211,19 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 	dialog = newwin(height, width, y, x);
 	dialog = newwin(height, width, y, x);
 	keypad(dialog, TRUE);
 	keypad(dialog, TRUE);
 
 
-	draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
-	wattrset(dialog, border_attr);
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	for (i = 0; i < width - 2; i++)
 	for (i = 0; i < width - 2; i++)
 		waddch(dialog, ACS_HLINE);
 		waddch(dialog, ACS_HLINE);
-	wattrset(dialog, dialog_attr);
-	wbkgdset(dialog, dialog_attr & A_COLOR);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
 	waddch(dialog, ACS_RTEE);
 	waddch(dialog, ACS_RTEE);
 
 
 	print_title(dialog, title, width);
 	print_title(dialog, title, width);
 
 
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 
 
 	menu_width = width - 6;
 	menu_width = width - 6;
@@ -225,31 +237,29 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 
 
 	/* draw a box around the menu items */
 	/* draw a box around the menu items */
 	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
 	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
-		 menubox_border_attr, menubox_attr);
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	if (menu_width >= 80)
+		item_x = (menu_width - 70) / 2;
+	else
+		item_x = 4;
 
 
 	/* Set choice to default item */
 	/* Set choice to default item */
-	for (i = 0; i < item_no; i++)
-		if (strcmp(current, items[i * 2]) == 0)
-			choice = i;
-
-	/* get the scroll info from the temp file */
-	if ((f = fopen("lxdialog.scrltmp", "r")) != NULL) {
-		if ((fscanf(f, "%d\n", &scroll) == 1) && (scroll <= choice) &&
-		    (scroll + max_choice > choice) && (scroll >= 0) &&
-		    (scroll + max_choice <= item_no)) {
-			first_item = scroll;
-			choice = choice - scroll;
-			fclose(f);
-		} else {
-			scroll = 0;
-			remove("lxdialog.scrltmp");
-			fclose(f);
-			f = NULL;
-		}
+	item_foreach()
+		if (selected && (selected == item_data()))
+			choice = item_n();
+	/* get the saved scroll info */
+	scroll = *s_scroll;
+	if ((scroll <= choice) && (scroll + max_choice > choice) &&
+	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
+		first_item = scroll;
+		choice = choice - scroll;
+	} else {
+		scroll = 0;
 	}
 	}
-	if ((choice >= max_choice) || (f == NULL && choice >= max_choice / 2)) {
-		if (choice >= item_no - max_choice / 2)
-			scroll = first_item = item_no - max_choice;
+	if ((choice >= max_choice)) {
+		if (choice >= item_count() - max_choice / 2)
+			scroll = first_item = item_count() - max_choice;
 		else
 		else
 			scroll = first_item = choice - max_choice / 2;
 			scroll = first_item = choice - max_choice / 2;
 		choice = choice - scroll;
 		choice = choice - scroll;
@@ -262,14 +272,14 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 
 
 	wnoutrefresh(menu);
 	wnoutrefresh(menu);
 
 
-	print_arrows(dialog, item_no, scroll,
-		     box_y, box_x + ITEM_IDENT + 1, menu_height);
+	print_arrows(dialog, item_count(), scroll,
+		     box_y, box_x + item_x + 1, menu_height);
 
 
 	print_buttons(dialog, height, width, 0);
 	print_buttons(dialog, height, width, 0);
-	wmove(menu, choice, ITEM_IDENT + 1);
+	wmove(menu, choice, item_x + 1);
 	wrefresh(menu);
 	wrefresh(menu);
 
 
-	while (key != ESC) {
+	while (key != KEY_ESC) {
 		key = wgetch(menu);
 		key = wgetch(menu);
 
 
 		if (key < 256 && isalpha(key))
 		if (key < 256 && isalpha(key))
@@ -279,14 +289,16 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 			i = max_choice;
 			i = max_choice;
 		else {
 		else {
 			for (i = choice + 1; i < max_choice; i++) {
 			for (i = choice + 1; i < max_choice; i++) {
-				j = first_alpha(items[(scroll + i) * 2 + 1], "YyNnMmHh");
-				if (key == tolower(items[(scroll + i) * 2 + 1][j]))
+				item_set(scroll + i);
+				j = first_alpha(item_str(), "YyNnMmHh");
+				if (key == tolower(item_str()[j]))
 					break;
 					break;
 			}
 			}
 			if (i == max_choice)
 			if (i == max_choice)
 				for (i = 0; i < max_choice; i++) {
 				for (i = 0; i < max_choice; i++) {
-					j = first_alpha(items [(scroll + i) * 2 + 1], "YyNnMmHh");
-					if (key == tolower(items[(scroll + i) * 2 + 1][j]))
+					item_set(scroll + i);
+					j = first_alpha(item_str(), "YyNnMmHh");
+					if (key == tolower(item_str()[j]))
 						break;
 						break;
 				}
 				}
 		}
 		}
@@ -311,7 +323,7 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 				print_item(scroll+choice, choice, FALSE);
 				print_item(scroll+choice, choice, FALSE);
 
 
 				if ((choice > max_choice - 3) &&
 				if ((choice > max_choice - 3) &&
-				    (scroll + max_choice < item_no)) {
+				    (scroll + max_choice < item_count())) {
 					/* Scroll menu up */
 					/* Scroll menu up */
 					do_scroll(menu, &scroll, 1);
 					do_scroll(menu, &scroll, 1);
 
 
@@ -334,7 +346,7 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 
 
 			} else if (key == KEY_NPAGE) {
 			} else if (key == KEY_NPAGE) {
 				for (i = 0; (i < max_choice); i++) {
 				for (i = 0; (i < max_choice); i++) {
-					if (scroll + max_choice < item_no) {
+					if (scroll + max_choice < item_count()) {
 						do_scroll(menu, &scroll, 1);
 						do_scroll(menu, &scroll, 1);
 						print_item(scroll+max_choice-1,
 						print_item(scroll+max_choice-1,
 							   max_choice - 1, FALSE);
 							   max_choice - 1, FALSE);
@@ -348,8 +360,8 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 
 
 			print_item(scroll + choice, choice, TRUE);
 			print_item(scroll + choice, choice, TRUE);
 
 
-			print_arrows(dialog, item_no, scroll,
-				     box_y, box_x + ITEM_IDENT + 1, menu_height);
+			print_arrows(dialog, item_count(), scroll,
+				     box_y, box_x + item_x + 1, menu_height);
 
 
 			wnoutrefresh(dialog);
 			wnoutrefresh(dialog);
 			wrefresh(menu);
 			wrefresh(menu);
@@ -362,7 +374,7 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 		case TAB:
 		case TAB:
 		case KEY_RIGHT:
 		case KEY_RIGHT:
 			button = ((key == KEY_LEFT ? --button : ++button) < 0)
 			button = ((key == KEY_LEFT ? --button : ++button) < 0)
-			    ? 2 : (button > 2 ? 0 : button);
+			    ? 4 : (button > 4 ? 0 : button);
 
 
 			print_buttons(dialog, height, width, button);
 			print_buttons(dialog, height, width, button);
 			wrefresh(menu);
 			wrefresh(menu);
@@ -373,53 +385,52 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
 		case 'n':
 		case 'n':
 		case 'm':
 		case 'm':
 		case '/':
 		case '/':
+		case 'h':
+		case '?':
+		case 'z':
+		case '\n':
 			/* save scroll info */
 			/* save scroll info */
-			if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) {
-				fprintf(f, "%d\n", scroll);
-				fclose(f);
-			}
+			*s_scroll = scroll;
+			delwin(menu);
 			delwin(dialog);
 			delwin(dialog);
-			fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
+			item_set(scroll + choice);
+			item_set_selected(1);
 			switch (key) {
 			switch (key) {
+			case 'h':
+			case '?':
+				return 2;
 			case 's':
 			case 's':
-				return 3;
 			case 'y':
 			case 'y':
-				return 3;
+				return 5;
 			case 'n':
 			case 'n':
-				return 4;
+				return 6;
 			case 'm':
 			case 'm':
-				return 5;
+				return 7;
 			case ' ':
 			case ' ':
-				return 6;
+				return 8;
 			case '/':
 			case '/':
-				return 7;
+				return 9;
+			case 'z':
+				return 10;
+			case '\n':
+				return button;
 			}
 			}
 			return 0;
 			return 0;
-		case 'h':
-		case '?':
-			button = 2;
-		case '\n':
-			delwin(dialog);
-			if (button == 2)
-				fprintf(stderr, "%s \"%s\"\n",
-					items[(scroll + choice) * 2],
-					items[(scroll + choice) * 2 + 1] +
-					first_alpha(items [(scroll + choice) * 2 + 1], ""));
-			else
-				fprintf(stderr, "%s\n",
-					items[(scroll + choice) * 2]);
-
-			remove("lxdialog.scrltmp");
-			return button;
 		case 'e':
 		case 'e':
 		case 'x':
 		case 'x':
-			key = ESC;
-		case ESC:
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(menu);
 			break;
 			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
 		}
 		}
 	}
 	}
-
+	delwin(menu);
 	delwin(dialog);
 	delwin(dialog);
-	remove("lxdialog.scrltmp");
-	return -1;		/* ESC pressed */
+	return key;		/* ESC pressed */
 }
 }

+ 0 - 71
scripts/config/lxdialog/msgbox.c

@@ -1,71 +0,0 @@
-/*
- *  msgbox.c -- implements the message box and info box
- *
- *  ORIGINAL AUTHOR: Savio Lam ([email protected])
- *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap ([email protected])
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version 2
- *  of the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "dialog.h"
-
-/*
- * Display a message box. Program will pause and display an "OK" button
- * if the parameter 'pause' is non-zero.
- */
-int dialog_msgbox(const char *title, const char *prompt, int height, int width,
-                  int pause)
-{
-	int i, x, y, key = 0;
-	WINDOW *dialog;
-
-	/* center dialog box on screen */
-	x = (COLS - width) / 2;
-	y = (LINES - height) / 2;
-
-	draw_shadow(stdscr, y, x, height, width);
-
-	dialog = newwin(height, width, y, x);
-	keypad(dialog, TRUE);
-
-	draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
-
-	print_title(dialog, title, width);
-
-	wattrset(dialog, dialog_attr);
-	print_autowrap(dialog, prompt, width - 2, 1, 2);
-
-	if (pause) {
-		wattrset(dialog, border_attr);
-		mvwaddch(dialog, height - 3, 0, ACS_LTEE);
-		for (i = 0; i < width - 2; i++)
-			waddch(dialog, ACS_HLINE);
-		wattrset(dialog, dialog_attr);
-		waddch(dialog, ACS_RTEE);
-
-		print_button(dialog, "  Ok  ", height - 2, width / 2 - 4, TRUE);
-
-		wrefresh(dialog);
-		while (key != ESC && key != '\n' && key != ' ' &&
-		       key != 'O' && key != 'o' && key != 'X' && key != 'x')
-			key = wgetch(dialog);
-	} else {
-		key = '\n';
-		wrefresh(dialog);
-	}
-
-	delwin(dialog);
-	return key == ESC ? -1 : 0;
-}

+ 191 - 316
scripts/config/lxdialog/textbox.c

@@ -22,59 +22,80 @@
 #include "dialog.h"
 #include "dialog.h"
 
 
 static void back_lines(int n);
 static void back_lines(int n);
-static void print_page(WINDOW * win, int height, int width);
-static void print_line(WINDOW * win, int row, int width);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
 static char *get_line(void);
 static char *get_line(void);
-static void print_position(WINDOW * win, int height, int width);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static char *buf;
+static char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+			     int cur_y, int cur_x, update_text_fn update_text,
+			     void *data)
+{
+	print_page(box, boxh, boxw, update_text, data);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
 
 
-static int hscroll, fd, file_size, bytes_read;
-static int begin_reached = 1, end_reached, page_length;
-static char *buf, *page;
 
 
 /*
 /*
  * Display text from a file in a dialog box.
  * Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
  */
  */
-int dialog_textbox(const char *title, const char *file, int height, int width)
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data)
 {
 {
-	int i, x, y, cur_x, cur_y, fpos, key = 0;
-	int passed_end;
-	char search_term[MAX_LEN + 1];
-	WINDOW *dialog, *text;
-
-	search_term[0] = '\0';	/* no search term entered yet */
-
-	/* Open input file for reading */
-	if ((fd = open(file, O_RDONLY)) == -1) {
-		endwin();
-		fprintf(stderr, "\nCan't open input file in dialog_textbox().\n");
-		exit(-1);
-	}
-	/* Get file size. Actually, 'file_size' is the real file size - 1,
-	   since it's only the last byte offset from the beginning */
-	if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
-		endwin();
-		fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
-		exit(-1);
-	}
-	/* Restore file pointer to beginning of file after getting file size */
-	if (lseek(fd, 0, SEEK_SET) == -1) {
-		endwin();
-		fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
-		exit(-1);
-	}
-	/* Allocate space for read buffer */
-	if ((buf = malloc(BUF_SIZE + 1)) == NULL) {
-		endwin();
-		fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
-		exit(-1);
-	}
-	if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
-		endwin();
-		fprintf(stderr, "\nError reading file in dialog_textbox().\n");
-		exit(-1);
+	int i, x, y, cur_x, cur_y, key = 0;
+	int height, width, boxh, boxw;
+	WINDOW *dialog, *box;
+	bool done = false;
+
+	begin_reached = 1;
+	end_reached = 0;
+	page_length = 0;
+	hscroll = 0;
+	buf = tbuf;
+	page = buf;	/* page is pointer to start of page to be displayed */
+
+	if (_vscroll && *_vscroll) {
+		begin_reached = 0;
+
+		for (i = 0; i < *_vscroll; i++)
+			get_line();
 	}
 	}
-	buf[bytes_read] = '\0';	/* mark end of valid data */
-	page = buf;		/* page is pointer to start of page to be displayed */
+	if (_hscroll)
+		hscroll = *_hscroll;
+
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < 8 || width < 8)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	x = (COLS - width) / 2;
@@ -85,182 +106,108 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
 	dialog = newwin(height, width, y, x);
 	dialog = newwin(height, width, y, x);
 	keypad(dialog, TRUE);
 	keypad(dialog, TRUE);
 
 
-	/* Create window for text region, used for scrolling text */
-	text = subwin(dialog, height - 4, width - 2, y + 1, x + 1);
-	wattrset(text, dialog_attr);
-	wbkgdset(text, dialog_attr & A_COLOR);
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
 
 
-	keypad(text, TRUE);
+	keypad(box, TRUE);
 
 
 	/* register the new window, along with its borders */
 	/* register the new window, along with its borders */
-	draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
 
 
-	wattrset(dialog, border_attr);
+	wattrset(dialog, dlg.border.atr);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	for (i = 0; i < width - 2; i++)
 	for (i = 0; i < width - 2; i++)
 		waddch(dialog, ACS_HLINE);
 		waddch(dialog, ACS_HLINE);
-	wattrset(dialog, dialog_attr);
-	wbkgdset(dialog, dialog_attr & A_COLOR);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
 	waddch(dialog, ACS_RTEE);
 	waddch(dialog, ACS_RTEE);
 
 
 	print_title(dialog, title, width);
 	print_title(dialog, title, width);
 
 
-	print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
+	print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
 	wnoutrefresh(dialog);
 	wnoutrefresh(dialog);
 	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
 	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
 
 
 	/* Print first page of text */
 	/* Print first page of text */
-	attr_clear(text, height - 4, width - 2, dialog_attr);
-	print_page(text, height - 4, width - 2);
-	print_position(dialog, height, width);
-	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-	wrefresh(dialog);
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+			 data);
 
 
-	while ((key != ESC) && (key != '\n')) {
+	while (!done) {
 		key = wgetch(dialog);
 		key = wgetch(dialog);
 		switch (key) {
 		switch (key) {
 		case 'E':	/* Exit */
 		case 'E':	/* Exit */
 		case 'e':
 		case 'e':
 		case 'X':
 		case 'X':
 		case 'x':
 		case 'x':
-			delwin(dialog);
-			free(buf);
-			close(fd);
-			return 0;
+		case 'q':
+		case '\n':
+			done = true;
+			break;
 		case 'g':	/* First page */
 		case 'g':	/* First page */
 		case KEY_HOME:
 		case KEY_HOME:
 			if (!begin_reached) {
 			if (!begin_reached) {
 				begin_reached = 1;
 				begin_reached = 1;
-				/* First page not in buffer? */
-				if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
-					endwin();
-					fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
-					exit(-1);
-				}
-				if (fpos > bytes_read) {	/* Yes, we have to read it in */
-					if (lseek(fd, 0, SEEK_SET) == -1) {
-						endwin();
-						fprintf(stderr, "\nError moving file pointer in "
-							        "dialog_textbox().\n");
-						exit(-1);
-					}
-					if ((bytes_read =
-					     read(fd, buf, BUF_SIZE)) == -1) {
-						endwin();
-						fprintf(stderr, "\nError reading file in dialog_textbox().\n");
-						exit(-1);
-					}
-					buf[bytes_read] = '\0';
-				}
 				page = buf;
 				page = buf;
-				print_page(text, height - 4, width - 2);
-				print_position(dialog, height, width);
-				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-				wrefresh(dialog);
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x, update_text,
+						 data);
 			}
 			}
 			break;
 			break;
 		case 'G':	/* Last page */
 		case 'G':	/* Last page */
 		case KEY_END:
 		case KEY_END:
 
 
 			end_reached = 1;
 			end_reached = 1;
-			/* Last page not in buffer? */
-			if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
-				endwin();
-				fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
-				exit(-1);
-			}
-			if (fpos < file_size) {	/* Yes, we have to read it in */
-				if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
-					endwin();
-					fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
-					exit(-1);
-				}
-				if ((bytes_read =
-				     read(fd, buf, BUF_SIZE)) == -1) {
-					endwin();
-					fprintf(stderr, "\nError reading file in dialog_textbox().\n");
-					exit(-1);
-				}
-				buf[bytes_read] = '\0';
-			}
-			page = buf + bytes_read;
-			back_lines(height - 4);
-			print_page(text, height - 4, width - 2);
-			print_position(dialog, height, width);
-			wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-			wrefresh(dialog);
+			/* point to last char in buf */
+			page = buf + strlen(buf);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'K':	/* Previous line */
 		case 'K':	/* Previous line */
 		case 'k':
 		case 'k':
 		case KEY_UP:
 		case KEY_UP:
-			if (!begin_reached) {
-				back_lines(page_length + 1);
-
-				/* We don't call print_page() here but use scrolling to ensure
-				   faster screen update. However, 'end_reached' and
-				   'page_length' should still be updated, and 'page' should
-				   point to start of next page. This is done by calling
-				   get_line() in the following 'for' loop. */
-				scrollok(text, TRUE);
-				wscrl(text, -1);	/* Scroll text region down one line */
-				scrollok(text, FALSE);
-				page_length = 0;
-				passed_end = 0;
-				for (i = 0; i < height - 4; i++) {
-					if (!i) {
-						/* print first line of page */
-						print_line(text, 0, width - 2);
-						wnoutrefresh(text);
-					} else
-						/* Called to update 'end_reached' and 'page' */
-						get_line();
-					if (!passed_end)
-						page_length++;
-					if (end_reached && !passed_end)
-						passed_end = 1;
-				}
+			if (begin_reached)
+				break;
 
 
-				print_position(dialog, height, width);
-				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-				wrefresh(dialog);
-			}
+			back_lines(page_length + 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'B':	/* Previous page */
 		case 'B':	/* Previous page */
 		case 'b':
 		case 'b':
+		case 'u':
 		case KEY_PPAGE:
 		case KEY_PPAGE:
 			if (begin_reached)
 			if (begin_reached)
 				break;
 				break;
-			back_lines(page_length + height - 4);
-			print_page(text, height - 4, width - 2);
-			print_position(dialog, height, width);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'J':	/* Next line */
 		case 'J':	/* Next line */
 		case 'j':
 		case 'j':
 		case KEY_DOWN:
 		case KEY_DOWN:
-			if (!end_reached) {
-				begin_reached = 0;
-				scrollok(text, TRUE);
-				scroll(text);	/* Scroll text region up one line */
-				scrollok(text, FALSE);
-				print_line(text, height - 5, width - 2);
-				wnoutrefresh(text);
-				print_position(dialog, height, width);
-				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-				wrefresh(dialog);
-			}
+			if (end_reached)
+				break;
+
+			back_lines(page_length - 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case KEY_NPAGE:	/* Next page */
 		case KEY_NPAGE:	/* Next page */
 		case ' ':
 		case ' ':
+		case 'd':
 			if (end_reached)
 			if (end_reached)
 				break;
 				break;
 
 
 			begin_reached = 0;
 			begin_reached = 0;
-			print_page(text, height - 4, width - 2);
-			print_position(dialog, height, width);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case '0':	/* Beginning of line */
 		case '0':	/* Beginning of line */
 		case 'H':	/* Scroll left */
 		case 'H':	/* Scroll left */
@@ -275,9 +222,8 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
 				hscroll--;
 				hscroll--;
 			/* Reprint current page to scroll horizontally */
 			/* Reprint current page to scroll horizontally */
 			back_lines(page_length);
 			back_lines(page_length);
-			print_page(text, height - 4, width - 2);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'L':	/* Scroll right */
 		case 'L':	/* Scroll right */
 		case 'l':
 		case 'l':
@@ -287,140 +233,97 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
 			hscroll++;
 			hscroll++;
 			/* Reprint current page to scroll horizontally */
 			/* Reprint current page to scroll horizontally */
 			back_lines(page_length);
 			back_lines(page_length);
-			print_page(text, height - 4, width - 2);
-			wmove(dialog, cur_y, cur_x);
-			wrefresh(dialog);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
-		case ESC:
+		case KEY_ESC:
+			if (on_key_esc(dialog) == KEY_ESC)
+				done = true;
 			break;
 			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		default:
+			for (i = 0; keys[i]; i++) {
+				if (key == keys[i]) {
+					done = true;
+					break;
+				}
+			}
 		}
 		}
 	}
 	}
-
+	delwin(box);
 	delwin(dialog);
 	delwin(dialog);
-	free(buf);
-	close(fd);
-	return -1;		/* ESC pressed */
+	if (_vscroll) {
+		const char *s;
+
+		s = buf;
+		*_vscroll = 0;
+		back_lines(page_length);
+		while (s < page && (s = strchr(s, '\n'))) {
+			(*_vscroll)++;
+			s++;
+		}
+	}
+	if (_hscroll)
+		*_hscroll = hscroll;
+	return key;
 }
 }
 
 
 /*
 /*
- * Go back 'n' lines in text file. Called by dialog_textbox().
+ * Go back 'n' lines in text. Called by dialog_textbox().
  * 'page' will be updated to point to the desired line in 'buf'.
  * 'page' will be updated to point to the desired line in 'buf'.
  */
  */
 static void back_lines(int n)
 static void back_lines(int n)
 {
 {
-	int i, fpos;
+	int i;
 
 
 	begin_reached = 0;
 	begin_reached = 0;
-	/* We have to distinguish between end_reached and !end_reached
-	   since at end of file, the line is not ended by a '\n'.
-	   The code inside 'if' basically does a '--page' to move one
-	   character backward so as to skip '\n' of the previous line */
-	if (!end_reached) {
-		/* Either beginning of buffer or beginning of file reached? */
-		if (page == buf) {
-			if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
-				endwin();
-				fprintf(stderr, "\nError moving file pointer in "
-					        "back_lines().\n");
-				exit(-1);
-			}
-			if (fpos > bytes_read) {	/* Not beginning of file yet */
-				/* We've reached beginning of buffer, but not beginning of
-				   file yet, so read previous part of file into buffer.
-				   Note that we only move backward for BUF_SIZE/2 bytes,
-				   but not BUF_SIZE bytes to avoid re-reading again in
-				   print_page() later */
-				/* Really possible to move backward BUF_SIZE/2 bytes? */
-				if (fpos < BUF_SIZE / 2 + bytes_read) {
-					/* No, move less then */
-					if (lseek(fd, 0, SEEK_SET) == -1) {
-						endwin();
-						fprintf(stderr, "\nError moving file pointer in "
-						                "back_lines().\n");
-						exit(-1);
-					}
-					page = buf + fpos - bytes_read;
-				} else {	/* Move backward BUF_SIZE/2 bytes */
-					if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
-						endwin();
-						fprintf(stderr, "\nError moving file pointer "
-						                "in back_lines().\n");
-						exit(-1);
-					}
-					page = buf + BUF_SIZE / 2;
-				}
-				if ((bytes_read =
-				     read(fd, buf, BUF_SIZE)) == -1) {
-					endwin();
-					fprintf(stderr, "\nError reading file in back_lines().\n");
-					exit(-1);
-				}
-				buf[bytes_read] = '\0';
-			} else {	/* Beginning of file reached */
-				begin_reached = 1;
-				return;
+	/* Go back 'n' lines */
+	for (i = 0; i < n; i++) {
+		if (*page == '\0') {
+			if (end_reached) {
+				end_reached = 0;
+				continue;
 			}
 			}
 		}
 		}
-		if (*(--page) != '\n') {	/* '--page' here */
-			/* Something's wrong... */
-			endwin();
-			fprintf(stderr, "\nInternal error in back_lines().\n");
-			exit(-1);
+		if (page == buf) {
+			begin_reached = 1;
+			return;
 		}
 		}
-	}
-	/* Go back 'n' lines */
-	for (i = 0; i < n; i++)
+		page--;
 		do {
 		do {
 			if (page == buf) {
 			if (page == buf) {
-				if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
-					endwin();
-					fprintf(stderr, "\nError moving file pointer in back_lines().\n");
-					exit(-1);
-				}
-				if (fpos > bytes_read) {
-					/* Really possible to move backward BUF_SIZE/2 bytes? */
-					if (fpos < BUF_SIZE / 2 + bytes_read) {
-						/* No, move less then */
-						if (lseek(fd, 0, SEEK_SET) == -1) {
-							endwin();
-							fprintf(stderr, "\nError moving file pointer "
-							                "in back_lines().\n");
-							exit(-1);
-						}
-						page = buf + fpos - bytes_read;
-					} else {	/* Move backward BUF_SIZE/2 bytes */
-						if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
-							endwin();
-							fprintf(stderr, "\nError moving file pointer"
-							                " in back_lines().\n");
-							exit(-1);
-						}
-						page = buf + BUF_SIZE / 2;
-					}
-					if ((bytes_read =
-					     read(fd, buf, BUF_SIZE)) == -1) {
-						endwin();
-						fprintf(stderr, "\nError reading file in "
-						                "back_lines().\n");
-						exit(-1);
-					}
-					buf[bytes_read] = '\0';
-				} else {	/* Beginning of file reached */
-					begin_reached = 1;
-					return;
-				}
+				begin_reached = 1;
+				return;
 			}
 			}
-		} while (*(--page) != '\n');
-	page++;
+			page--;
+		} while (*page != '\n');
+		page++;
+	}
 }
 }
 
 
 /*
 /*
- * Print a new page of text. Called by dialog_textbox().
+ * Print a new page of text.
  */
  */
-static void print_page(WINDOW * win, int height, int width)
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data)
 {
 {
 	int i, passed_end = 0;
 	int i, passed_end = 0;
 
 
+	if (update_text) {
+		char *end;
+
+		for (i = 0; i < height; i++)
+			get_line();
+		end = page;
+		back_lines(height);
+		update_text(buf, page - buf, end - buf, data);
+	}
+
 	page_length = 0;
 	page_length = 0;
 	for (i = 0; i < height; i++) {
 	for (i = 0; i < height; i++) {
 		print_line(win, i, width);
 		print_line(win, i, width);
@@ -433,11 +336,10 @@ static void print_page(WINDOW * win, int height, int width)
 }
 }
 
 
 /*
 /*
- * Print a new line of text. Called by dialog_textbox() and print_page().
+ * Print a new line of text.
  */
  */
 static void print_line(WINDOW * win, int row, int width)
 static void print_line(WINDOW * win, int row, int width)
 {
 {
-	int y, x;
 	char *line;
 	char *line;
 
 
 	line = get_line();
 	line = get_line();
@@ -446,10 +348,10 @@ static void print_line(WINDOW * win, int row, int width)
 	waddch(win, ' ');
 	waddch(win, ' ');
 	waddnstr(win, line, MIN(strlen(line), width - 2));
 	waddnstr(win, line, MIN(strlen(line), width - 2));
 
 
-	getyx(win, y, x);
 	/* Clear 'residue' of previous line */
 	/* Clear 'residue' of previous line */
 #if OLD_NCURSES
 #if OLD_NCURSES
 	{
 	{
+		int x = getcurx(win);
 		int i;
 		int i;
 		for (i = 0; i < width - x; i++)
 		for (i = 0; i < width - x; i++)
 			waddch(win, ' ');
 			waddch(win, ' ');
@@ -466,35 +368,14 @@ static void print_line(WINDOW * win, int row, int width)
  */
  */
 static char *get_line(void)
 static char *get_line(void)
 {
 {
-	int i = 0, fpos;
+	int i = 0;
 	static char line[MAX_LEN + 1];
 	static char line[MAX_LEN + 1];
 
 
 	end_reached = 0;
 	end_reached = 0;
 	while (*page != '\n') {
 	while (*page != '\n') {
 		if (*page == '\0') {
 		if (*page == '\0') {
-			/* Either end of file or end of buffer reached */
-			if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
-				endwin();
-				fprintf(stderr, "\nError moving file pointer in "
-				                "get_line().\n");
-				exit(-1);
-			}
-			if (fpos < file_size) {	/* Not end of file yet */
-				/* We've reached end of buffer, but not end of file yet,
-				   so read next part of file into buffer */
-				if ((bytes_read =
-				     read(fd, buf, BUF_SIZE)) == -1) {
-					endwin();
-					fprintf(stderr, "\nError reading file in get_line().\n");
-					exit(-1);
-				}
-				buf[bytes_read] = '\0';
-				page = buf;
-			} else {
-				if (!end_reached)
-					end_reached = 1;
-				break;
-			}
+			end_reached = 1;
+			break;
 		} else if (i < MAX_LEN)
 		} else if (i < MAX_LEN)
 			line[i++] = *(page++);
 			line[i++] = *(page++);
 		else {
 		else {
@@ -507,7 +388,7 @@ static char *get_line(void)
 	if (i <= MAX_LEN)
 	if (i <= MAX_LEN)
 		line[i] = '\0';
 		line[i] = '\0';
 	if (!end_reached)
 	if (!end_reached)
-		page++;		/* move pass '\n' */
+		page++;		/* move past '\n' */
 
 
 	return line;
 	return line;
 }
 }
@@ -515,19 +396,13 @@ static char *get_line(void)
 /*
 /*
  * Print current position
  * Print current position
  */
  */
-static void print_position(WINDOW * win, int height, int width)
+static void print_position(WINDOW * win)
 {
 {
-	int fpos, percent;
+	int percent;
 
 
-	if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
-		endwin();
-		fprintf(stderr, "\nError moving file pointer in print_position().\n");
-		exit(-1);
-	}
-	wattrset(win, position_indicator_attr);
-	wbkgdset(win, position_indicator_attr & A_COLOR);
-	percent = !file_size ?
-	    100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
-	wmove(win, height - 3, width - 9);
+	wattrset(win, dlg.position_indicator.atr);
+	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+	percent = (page - buf) * 100 / strlen(buf);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
 	wprintw(win, "(%3d%%)", percent);
 	wprintw(win, "(%3d%%)", percent);
 }
 }

+ 413 - 111
scripts/config/lxdialog/util.c

@@ -19,87 +19,222 @@
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
+#include <stdarg.h>
+
 #include "dialog.h"
 #include "dialog.h"
 
 
-/* use colors by default? */
-bool use_colors = 1;
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+	dlg.screen.atr = A_NORMAL;
+	dlg.shadow.atr = A_NORMAL;
+	dlg.dialog.atr = A_NORMAL;
+	dlg.title.atr = A_BOLD;
+	dlg.border.atr = A_NORMAL;
+	dlg.button_active.atr = A_REVERSE;
+	dlg.button_inactive.atr = A_DIM;
+	dlg.button_key_active.atr = A_REVERSE;
+	dlg.button_key_inactive.atr = A_BOLD;
+	dlg.button_label_active.atr = A_REVERSE;
+	dlg.button_label_inactive.atr = A_NORMAL;
+	dlg.inputbox.atr = A_NORMAL;
+	dlg.inputbox_border.atr = A_NORMAL;
+	dlg.searchbox.atr = A_NORMAL;
+	dlg.searchbox_title.atr = A_BOLD;
+	dlg.searchbox_border.atr = A_NORMAL;
+	dlg.position_indicator.atr = A_BOLD;
+	dlg.menubox.atr = A_NORMAL;
+	dlg.menubox_border.atr = A_NORMAL;
+	dlg.item.atr = A_NORMAL;
+	dlg.item_selected.atr = A_REVERSE;
+	dlg.tag.atr = A_BOLD;
+	dlg.tag_selected.atr = A_REVERSE;
+	dlg.tag_key.atr = A_BOLD;
+	dlg.tag_key_selected.atr = A_REVERSE;
+	dlg.check.atr = A_BOLD;
+	dlg.check_selected.atr = A_REVERSE;
+	dlg.uarrow.atr = A_BOLD;
+	dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+	dlg.dialog.fg = (f);       \
+	dlg.dialog.bg = (b);       \
+	dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
 
 
-const char *backtitle = NULL;
+	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+	set_classic_theme();
+	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
 
 
 /*
 /*
- * Attribute values, default is for mono display
+ * Select color theme
  */
  */
-chtype attributes[] = {
-	A_NORMAL,		/* screen_attr */
-	A_NORMAL,		/* shadow_attr */
-	A_NORMAL,		/* dialog_attr */
-	A_BOLD,			/* title_attr */
-	A_NORMAL,		/* border_attr */
-	A_REVERSE,		/* button_active_attr */
-	A_DIM,			/* button_inactive_attr */
-	A_REVERSE,		/* button_key_active_attr */
-	A_BOLD,			/* button_key_inactive_attr */
-	A_REVERSE,		/* button_label_active_attr */
-	A_NORMAL,		/* button_label_inactive_attr */
-	A_NORMAL,		/* inputbox_attr */
-	A_NORMAL,		/* inputbox_border_attr */
-	A_NORMAL,		/* searchbox_attr */
-	A_BOLD,			/* searchbox_title_attr */
-	A_NORMAL,		/* searchbox_border_attr */
-	A_BOLD,			/* position_indicator_attr */
-	A_NORMAL,		/* menubox_attr */
-	A_NORMAL,		/* menubox_border_attr */
-	A_NORMAL,		/* item_attr */
-	A_REVERSE,		/* item_selected_attr */
-	A_BOLD,			/* tag_attr */
-	A_REVERSE,		/* tag_selected_attr */
-	A_BOLD,			/* tag_key_attr */
-	A_REVERSE,		/* tag_key_selected_attr */
-	A_BOLD,			/* check_attr */
-	A_REVERSE,		/* check_selected_attr */
-	A_BOLD,			/* uarrow_attr */
-	A_BOLD			/* darrow_attr */
-};
-
-#include "colors.h"
+static int set_theme(const char *theme)
+{
+	int use_color = 1;
+	if (!theme)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "classic") == 0)
+		set_classic_theme();
+	else if (strcmp(theme, "bluetitle") == 0)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "blackbg") == 0)
+		set_blackbg_theme();
+	else if (strcmp(theme, "mono") == 0)
+		use_color = 0;
+
+	return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+	static int pair = 0;
+
+	pair++;
+	init_pair(pair, color->fg, color->bg);
+	if (color->hl)
+		color->atr = A_BOLD | COLOR_PAIR(pair);
+	else
+		color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+	init_one_color(&dlg.screen);
+	init_one_color(&dlg.shadow);
+	init_one_color(&dlg.dialog);
+	init_one_color(&dlg.title);
+	init_one_color(&dlg.border);
+	init_one_color(&dlg.button_active);
+	init_one_color(&dlg.button_inactive);
+	init_one_color(&dlg.button_key_active);
+	init_one_color(&dlg.button_key_inactive);
+	init_one_color(&dlg.button_label_active);
+	init_one_color(&dlg.button_label_inactive);
+	init_one_color(&dlg.inputbox);
+	init_one_color(&dlg.inputbox_border);
+	init_one_color(&dlg.searchbox);
+	init_one_color(&dlg.searchbox_title);
+	init_one_color(&dlg.searchbox_border);
+	init_one_color(&dlg.position_indicator);
+	init_one_color(&dlg.menubox);
+	init_one_color(&dlg.menubox_border);
+	init_one_color(&dlg.item);
+	init_one_color(&dlg.item_selected);
+	init_one_color(&dlg.tag);
+	init_one_color(&dlg.tag_selected);
+	init_one_color(&dlg.tag_key);
+	init_one_color(&dlg.tag_key_selected);
+	init_one_color(&dlg.check);
+	init_one_color(&dlg.check_selected);
+	init_one_color(&dlg.uarrow);
+	init_one_color(&dlg.darrow);
+}
 
 
 /*
 /*
- * Table of color values
+ * Setup for color display
  */
  */
-int color_table[][3] = {
-	{SCREEN_FG, SCREEN_BG, SCREEN_HL},
-	{SHADOW_FG, SHADOW_BG, SHADOW_HL},
-	{DIALOG_FG, DIALOG_BG, DIALOG_HL},
-	{TITLE_FG, TITLE_BG, TITLE_HL},
-	{BORDER_FG, BORDER_BG, BORDER_HL},
-	{BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
-	{BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
-	{BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
-	{BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG,
-	 BUTTON_KEY_INACTIVE_HL},
-	{BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG,
-	 BUTTON_LABEL_ACTIVE_HL},
-	{BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
-	 BUTTON_LABEL_INACTIVE_HL},
-	{INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
-	{INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
-	{SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
-	{SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
-	{SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
-	{POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
-	{MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
-	{MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
-	{ITEM_FG, ITEM_BG, ITEM_HL},
-	{ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
-	{TAG_FG, TAG_BG, TAG_HL},
-	{TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
-	{TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
-	{TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
-	{CHECK_FG, CHECK_BG, CHECK_HL},
-	{CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
-	{UARROW_FG, UARROW_BG, UARROW_HL},
-	{DARROW_FG, DARROW_BG, DARROW_HL},
-};				/* color_table */
+static void color_setup(const char *theme)
+{
+	int use_color;
+
+	use_color = set_theme(theme);
+	if (use_color && has_colors()) {
+		start_color();
+		init_dialog_colors();
+	} else
+		set_mono_theme();
+}
 
 
 /*
 /*
  * Set window to attribute 'attr'
  * Set window to attribute 'attr'
@@ -119,13 +254,13 @@ void attr_clear(WINDOW * win, int height, int width, chtype attr)
 
 
 void dialog_clear(void)
 void dialog_clear(void)
 {
 {
-	attr_clear(stdscr, LINES, COLS, screen_attr);
+	attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
 	/* Display background title if it exists ... - SLH */
 	/* Display background title if it exists ... - SLH */
-	if (backtitle != NULL) {
+	if (dlg.backtitle != NULL) {
 		int i;
 		int i;
 
 
-		wattrset(stdscr, screen_attr);
-		mvwaddstr(stdscr, 0, 1, (char *)backtitle);
+		wattrset(stdscr, dlg.screen.atr);
+		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
 		wmove(stdscr, 1, 1);
 		wmove(stdscr, 1, 1);
 		for (i = 1; i < COLS - 1; i++)
 		for (i = 1; i < COLS - 1; i++)
 			waddch(stdscr, ACS_HLINE);
 			waddch(stdscr, ACS_HLINE);
@@ -136,44 +271,45 @@ void dialog_clear(void)
 /*
 /*
  * Do some initialization for dialog
  * Do some initialization for dialog
  */
  */
-void init_dialog(void)
+int init_dialog(const char *backtitle)
 {
 {
+	int height, width;
+
 	initscr();		/* Init curses */
 	initscr();		/* Init curses */
+
+	/* Get current cursor position for signal handler in mconf.c */
+	getyx(stdscr, saved_y, saved_x);
+
+	getmaxyx(stdscr, height, width);
+	if (height < 19 || width < 80) {
+		endwin();
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	dlg.backtitle = backtitle;
+	color_setup(getenv("MENUCONFIG_COLOR"));
+
 	keypad(stdscr, TRUE);
 	keypad(stdscr, TRUE);
 	cbreak();
 	cbreak();
 	noecho();
 	noecho();
-
-	if (use_colors)		/* Set up colors */
-		color_setup();
-
 	dialog_clear();
 	dialog_clear();
+
+	return 0;
 }
 }
 
 
-/*
- * Setup for color display
- */
-void color_setup(void)
+void set_dialog_backtitle(const char *backtitle)
 {
 {
-	int i;
-
-	if (has_colors()) {	/* Terminal supports color? */
-		start_color();
-
-		/* Initialize color pairs */
-		for (i = 0; i < ATTRIBUTE_COUNT; i++)
-			init_pair(i + 1, color_table[i][0], color_table[i][1]);
-
-		/* Setup color attributes */
-		for (i = 0; i < ATTRIBUTE_COUNT; i++)
-			attributes[i] = C_ATTR(color_table[i][2], i + 1);
-	}
+	dlg.backtitle = backtitle;
 }
 }
 
 
 /*
 /*
  * End using dialog functions.
  * End using dialog functions.
  */
  */
-void end_dialog(void)
+void end_dialog(int x, int y)
 {
 {
+	/* move cursor back to original position */
+	move(y, x);
+	refresh();
 	endwin();
 	endwin();
 }
 }
 
 
@@ -184,7 +320,7 @@ void print_title(WINDOW *dialog, const char *title, int width)
 {
 {
 	if (title) {
 	if (title) {
 		int tlen = MIN(width - 2, strlen(title));
 		int tlen = MIN(width - 2, strlen(title));
-		wattrset(dialog, title_attr);
+		wattrset(dialog, dlg.title.atr);
 		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
 		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
 		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
 		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
 		waddch(dialog, ' ');
 		waddch(dialog, ' ');
@@ -224,7 +360,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 		newl = 1;
 		newl = 1;
 		word = tempstr;
 		word = tempstr;
 		while (word && *word) {
 		while (word && *word) {
-			sp = index(word, ' ');
+			sp = strchr(word, ' ');
 			if (sp)
 			if (sp)
 				*sp++ = 0;
 				*sp++ = 0;
 
 
@@ -236,7 +372,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 			if (wlen > room ||
 			if (wlen > room ||
 			    (newl && wlen < 4 && sp
 			    (newl && wlen < 4 && sp
 			     && wlen + 1 + strlen(sp) > room
 			     && wlen + 1 + strlen(sp) > room
-			     && (!(sp2 = index(sp, ' '))
+			     && (!(sp2 = strchr(sp, ' '))
 				 || wlen + 1 + (sp2 - sp) > room))) {
 				 || wlen + 1 + (sp2 - sp) > room))) {
 				cur_y++;
 				cur_y++;
 				cur_x = x;
 				cur_x = x;
@@ -264,21 +400,23 @@ void print_button(WINDOW * win, const char *label, int y, int x, int selected)
 	int i, temp;
 	int i, temp;
 
 
 	wmove(win, y, x);
 	wmove(win, y, x);
-	wattrset(win, selected ? button_active_attr : button_inactive_attr);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
 	waddstr(win, "<");
 	waddstr(win, "<");
 	temp = strspn(label, " ");
 	temp = strspn(label, " ");
 	label += temp;
 	label += temp;
-	wattrset(win, selected ? button_label_active_attr
-		 : button_label_inactive_attr);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
 	for (i = 0; i < temp; i++)
 	for (i = 0; i < temp; i++)
 		waddch(win, ' ');
 		waddch(win, ' ');
-	wattrset(win, selected ? button_key_active_attr
-		 : button_key_inactive_attr);
+	wattrset(win, selected ? dlg.button_key_active.atr
+		 : dlg.button_key_inactive.atr);
 	waddch(win, label[0]);
 	waddch(win, label[0]);
-	wattrset(win, selected ? button_label_active_attr
-		 : button_label_inactive_attr);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
 	waddstr(win, (char *)label + 1);
 	waddstr(win, (char *)label + 1);
-	wattrset(win, selected ? button_active_attr : button_inactive_attr);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
 	waddstr(win, ">");
 	waddstr(win, ">");
 	wmove(win, y, x + temp + 1);
 	wmove(win, y, x + temp + 1);
 }
 }
@@ -326,7 +464,7 @@ void draw_shadow(WINDOW * win, int y, int x, int height, int width)
 	int i;
 	int i;
 
 
 	if (has_colors()) {	/* Whether terminal supports color? */
 	if (has_colors()) {	/* Whether terminal supports color? */
-		wattrset(win, shadow_attr);
+		wattrset(win, dlg.shadow.atr);
 		wmove(win, y + height, x + 2);
 		wmove(win, y + height, x + 2);
 		for (i = 0; i < width; i++)
 		for (i = 0; i < width; i++)
 			waddch(win, winch(win) & A_CHARTEXT);
 			waddch(win, winch(win) & A_CHARTEXT);
@@ -360,3 +498,167 @@ int first_alpha(const char *string, const char *exempt)
 
 
 	return 0;
 	return 0;
 }
 }
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+	int key;
+	int key2;
+	int key3;
+
+	nodelay(win, TRUE);
+	keypad(win, FALSE);
+	key = wgetch(win);
+	key2 = wgetch(win);
+	do {
+		key3 = wgetch(win);
+	} while (key3 != ERR);
+	nodelay(win, FALSE);
+	keypad(win, TRUE);
+	if (key == KEY_ESC && key2 == ERR)
+		return KEY_ESC;
+	else if (key != ERR && key != KEY_ESC && key2 == ERR)
+		ungetch(key);
+
+	return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+	struct dialog_list *p, *next;
+
+	for (p = item_head; p; p = next) {
+		next = p->next;
+		free(p);
+	}
+	item_head = NULL;
+	item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+	va_list ap;
+	struct dialog_list *p = malloc(sizeof(*p));
+
+	if (item_head)
+		item_cur->next = p;
+	else
+		item_head = p;
+	item_cur = p;
+	memset(p, 0, sizeof(*p));
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+	va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+        size_t avail;
+
+	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+		  avail, fmt, ap);
+	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+	va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+	item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+	item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+	item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+	item_foreach()
+		if (item_is_selected())
+			return 1;
+	return 0;
+}
+
+void *item_data(void)
+{
+	return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+	return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next)
+		n++;
+	return n;
+}
+
+void item_set(int n)
+{
+	int i = 0;
+	item_foreach()
+		if (i++ == n)
+			return;
+}
+
+int item_n(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next) {
+		if (p == item_cur)
+			return n;
+		n++;
+	}
+	return 0;
+}
+
+const char *item_str(void)
+{
+	return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+	return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+	return (item_cur->node.tag == tag);
+}

+ 21 - 9
scripts/config/lxdialog/yesno.c

@@ -29,8 +29,8 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
 	int x = width / 2 - 10;
 	int x = width / 2 - 10;
 	int y = height - 2;
 	int y = height - 2;
 
 
-	print_button(dialog, " Yes ", y, x, selected == 0);
-	print_button(dialog, "  No  ", y, x + 13, selected == 1);
+	print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+	print_button(dialog, gettext("  No  "), y, x + 13, selected == 1);
 
 
 	wmove(dialog, y, x + 1 + 13 * selected);
 	wmove(dialog, y, x + 1 + 13 * selected);
 	wrefresh(dialog);
 	wrefresh(dialog);
@@ -44,6 +44,12 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
 	int i, x, y, key = 0, button = 0;
 	int i, x, y, key = 0, button = 0;
 	WINDOW *dialog;
 	WINDOW *dialog;
 
 
+do_resize:
+	if (getmaxy(stdscr) < (height + 4))
+		return -ERRDISPLAYTOOSMALL;
+	if (getmaxx(stdscr) < (width + 4))
+		return -ERRDISPLAYTOOSMALL;
+
 	/* center dialog box on screen */
 	/* center dialog box on screen */
 	x = (COLS - width) / 2;
 	x = (COLS - width) / 2;
 	y = (LINES - height) / 2;
 	y = (LINES - height) / 2;
@@ -53,22 +59,23 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
 	dialog = newwin(height, width, y, x);
 	dialog = newwin(height, width, y, x);
 	keypad(dialog, TRUE);
 	keypad(dialog, TRUE);
 
 
-	draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
-	wattrset(dialog, border_attr);
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
 	for (i = 0; i < width - 2; i++)
 	for (i = 0; i < width - 2; i++)
 		waddch(dialog, ACS_HLINE);
 		waddch(dialog, ACS_HLINE);
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	waddch(dialog, ACS_RTEE);
 	waddch(dialog, ACS_RTEE);
 
 
 	print_title(dialog, title, width);
 	print_title(dialog, title, width);
 
 
-	wattrset(dialog, dialog_attr);
+	wattrset(dialog, dlg.dialog.atr);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 	print_autowrap(dialog, prompt, width - 2, 1, 3);
 
 
 	print_buttons(dialog, height, width, 0);
 	print_buttons(dialog, height, width, 0);
 
 
-	while (key != ESC) {
+	while (key != KEY_ESC) {
 		key = wgetch(dialog);
 		key = wgetch(dialog);
 		switch (key) {
 		switch (key) {
 		case 'Y':
 		case 'Y':
@@ -92,11 +99,16 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
 		case '\n':
 		case '\n':
 			delwin(dialog);
 			delwin(dialog);
 			return button;
 			return button;
-		case ESC:
+		case KEY_ESC:
+			key = on_key_esc(dialog);
 			break;
 			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
 		}
 		}
 	}
 	}
 
 
 	delwin(dialog);
 	delwin(dialog);
-	return -1;		/* ESC pressed */
+	return key;		/* ESC pressed */
 }
 }

File diff suppressed because it is too large
+ 273 - 443
scripts/config/mconf.c


+ 319 - 67
scripts/config/menu.c

@@ -3,19 +3,22 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
+#include <ctype.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
+static const char nohelp_text[] = "There is no help available for this option.";
+
 struct menu rootmenu;
 struct menu rootmenu;
 static struct menu **last_entry_ptr;
 static struct menu **last_entry_ptr;
 
 
 struct file *file_list;
 struct file *file_list;
 struct file *current_file;
 struct file *current_file;
 
 
-static void menu_warn(struct menu *menu, const char *fmt, ...)
+void menu_warn(struct menu *menu, const char *fmt, ...)
 {
 {
 	va_list ap;
 	va_list ap;
 	va_start(ap, fmt);
 	va_start(ap, fmt);
@@ -35,7 +38,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...)
 	va_end(ap);
 	va_end(ap);
 }
 }
 
 
-void menu_init(void)
+void _menu_init(void)
 {
 {
 	current_entry = current_menu = &rootmenu;
 	current_entry = current_menu = &rootmenu;
 	last_entry_ptr = &rootmenu.list;
 	last_entry_ptr = &rootmenu.list;
@@ -45,7 +48,7 @@ void menu_add_entry(struct symbol *sym)
 {
 {
 	struct menu *menu;
 	struct menu *menu;
 
 
-	menu = malloc(sizeof(*menu));
+	menu = xmalloc(sizeof(*menu));
 	memset(menu, 0, sizeof(*menu));
 	memset(menu, 0, sizeof(*menu));
 	menu->sym = sym;
 	menu->sym = sym;
 	menu->parent = current_menu;
 	menu->parent = current_menu;
@@ -55,6 +58,8 @@ void menu_add_entry(struct symbol *sym)
 	*last_entry_ptr = menu;
 	*last_entry_ptr = menu;
 	last_entry_ptr = &menu->next;
 	last_entry_ptr = &menu->next;
 	current_entry = menu;
 	current_entry = menu;
+	if (sym)
+		menu_add_symbol(P_SYMBOL, sym, NULL);
 }
 }
 
 
 void menu_end_entry(void)
 void menu_end_entry(void)
@@ -74,9 +79,34 @@ void menu_end_menu(void)
 	current_menu = current_menu->parent;
 	current_menu = current_menu->parent;
 }
 }
 
 
+static struct expr *menu_check_dep(struct expr *e)
+{
+	if (!e)
+		return e;
+
+	switch (e->type) {
+	case E_NOT:
+		e->left.expr = menu_check_dep(e->left.expr);
+		break;
+	case E_OR:
+	case E_AND:
+		e->left.expr = menu_check_dep(e->left.expr);
+		e->right.expr = menu_check_dep(e->right.expr);
+		break;
+	case E_SYMBOL:
+		/* change 'm' into 'm' && MODULES */
+		if (e->left.sym == &symbol_mod)
+			return expr_alloc_and(e, expr_alloc_symbol(modules_sym));
+		break;
+	default:
+		break;
+	}
+	return e;
+}
+
 void menu_add_dep(struct expr *dep)
 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)
 void menu_set_type(int type)
@@ -89,7 +119,7 @@ void menu_set_type(int type)
 		sym->type = type;
 		sym->type = type;
 		return;
 		return;
 	}
 	}
-	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'\n",
+	menu_warn(current_entry, "type of '%s' redefined from '%s' to '%s'",
 	    sym->name ? sym->name : "<choice>",
 	    sym->name ? sym->name : "<choice>",
 	    sym_type_name(sym->type), sym_type_name(type));
 	    sym_type_name(sym->type), sym_type_name(type));
 }
 }
@@ -99,15 +129,34 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
 	struct property *prop = prop_alloc(type, current_entry->sym);
 	struct property *prop = prop_alloc(type, current_entry->sym);
 
 
 	prop->menu = current_entry;
 	prop->menu = current_entry;
-	prop->text = prompt;
 	prop->expr = expr;
 	prop->expr = expr;
-	prop->visible.expr = dep;
+	prop->visible.expr = menu_check_dep(dep);
 
 
 	if (prompt) {
 	if (prompt) {
-		if (current_entry->prompt)
-			menu_warn(current_entry, "prompt redefined\n");
+		if (isspace(*prompt)) {
+			prop_warn(prop, "leading whitespace ignored");
+			while (isspace(*prompt))
+				prompt++;
+		}
+		if (current_entry->prompt && current_entry != &rootmenu)
+			prop_warn(prop, "prompt redefined");
+
+		/* Apply all upper menus' visibilities to actual prompts. */
+		if(type == P_PROMPT) {
+			struct menu *menu = current_entry;
+
+			while ((menu = menu->parent) != NULL) {
+				if (!menu->visibility)
+					continue;
+				prop->visible.expr
+					= expr_alloc_and(prop->visible.expr,
+							 menu->visibility);
+			}
+		}
+
 		current_entry->prompt = prop;
 		current_entry->prompt = prop;
 	}
 	}
+	prop->text = prompt;
 
 
 	return prop;
 	return prop;
 }
 }
@@ -117,6 +166,12 @@ struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr
 	return menu_add_prop(type, prompt, NULL, dep);
 	return menu_add_prop(type, prompt, NULL, dep);
 }
 }
 
 
+void menu_add_visibility(struct expr *expr)
+{
+	current_entry->visibility = expr_alloc_and(current_entry->visibility,
+	    expr);
+}
+
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
 {
 {
 	menu_add_prop(type, NULL, expr, dep);
 	menu_add_prop(type, NULL, expr, dep);
@@ -127,13 +182,34 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
 	menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
 }
 }
 
 
-static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+void menu_add_option(int token, char *arg)
+{
+	struct property *prop;
+
+	switch (token) {
+	case T_OPT_MODULES:
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(current_entry->sym);
+		break;
+	case T_OPT_DEFCONFIG_LIST:
+		if (!sym_defconfig_list)
+			sym_defconfig_list = current_entry->sym;
+		else if (sym_defconfig_list != current_entry->sym)
+			zconf_error("trying to redefine defconfig symbol");
+		break;
+	case T_OPT_ENV:
+		prop_add_env(arg);
+		break;
+	}
+}
+
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
 {
 {
 	return sym2->type == S_INT || sym2->type == S_HEX ||
 	return sym2->type == S_INT || sym2->type == S_HEX ||
 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
 }
 }
 
 
-void sym_check_prop(struct symbol *sym)
+static void sym_check_prop(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
 	struct symbol *sym2;
 	struct symbol *sym2;
@@ -143,8 +219,17 @@ void sym_check_prop(struct symbol *sym)
 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
 			    prop->expr->type != E_SYMBOL)
 			    prop->expr->type != E_SYMBOL)
 				prop_warn(prop,
 				prop_warn(prop,
-				    "default for config symbol '%'"
+				    "default for config symbol '%s'"
 				    " must be a single symbol", sym->name);
 				    " must be a single symbol", sym->name);
+			if (prop->expr->type != E_SYMBOL)
+				break;
+			sym2 = prop_get_symbol(prop);
+			if (sym->type == S_HEX || sym->type == S_INT) {
+				if (!menu_validate_number(sym, sym2))
+					prop_warn(prop,
+					    "'%s': number is invalid",
+					    sym->name);
+			}
 			break;
 			break;
 		case P_SELECT:
 		case P_SELECT:
 			sym2 = prop_get_symbol(prop);
 			sym2 = prop_get_symbol(prop);
@@ -152,40 +237,20 @@ void sym_check_prop(struct symbol *sym)
 				prop_warn(prop,
 				prop_warn(prop,
 				    "config symbol '%s' uses select, but is "
 				    "config symbol '%s' uses select, but is "
 				    "not boolean or tristate", sym->name);
 				    "not boolean or tristate", sym->name);
-			else if (sym2->type == S_UNKNOWN)
-				prop_warn(prop,
-				    "'select' used by config symbol '%s' "
-				    "refer to undefined symbol '%s'",
-				    sym->name, sym2->name);
-			else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
+			else if (sym2->type != S_UNKNOWN &&
+			         sym2->type != S_BOOLEAN &&
+			         sym2->type != S_TRISTATE)
 				prop_warn(prop,
 				prop_warn(prop,
 				    "'%s' has wrong type. 'select' only "
 				    "'%s' has wrong type. 'select' only "
 				    "accept arguments of boolean and "
 				    "accept arguments of boolean and "
 				    "tristate type", sym2->name);
 				    "tristate type", sym2->name);
 			break;
 			break;
-		case P_DESELECT:
-			sym2 = prop_get_symbol(prop);
-			if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
-				prop_warn(prop,
-				    "config symbol '%s' uses deselect, but is "
-				    "not boolean or tristate", sym->name);
-			else if (sym2->type == S_UNKNOWN)
-				prop_warn(prop,
-				    "'deselect' used by config symbol '%s' "
-				    "refer to undefined symbol '%s'",
-				    sym->name, sym2->name);
-			else if (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)
-				prop_warn(prop,
-				    "'%s' has wrong type. 'deselect' only "
-				    "accept arguments of boolean and "
-				    "tristate type", sym2->name);
-			break;
 		case P_RANGE:
 		case P_RANGE:
 			if (sym->type != S_INT && sym->type != S_HEX)
 			if (sym->type != S_INT && sym->type != S_HEX)
 				prop_warn(prop, "range is only allowed "
 				prop_warn(prop, "range is only allowed "
 				                "for int or hex symbols");
 				                "for int or hex symbols");
-			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
-			    !menu_range_valid_sym(sym, prop->expr->right.sym))
+			if (!menu_validate_number(sym, prop->expr->left.sym) ||
+			    !menu_validate_number(sym, prop->expr->right.sym))
 				prop_warn(prop, "range is invalid");
 				prop_warn(prop, "range is invalid");
 			break;
 			break;
 		default:
 		default:
@@ -204,15 +269,21 @@ void menu_finalize(struct menu *parent)
 	sym = parent->sym;
 	sym = parent->sym;
 	if (parent->list) {
 	if (parent->list) {
 		if (sym && sym_is_choice(sym)) {
 		if (sym && sym_is_choice(sym)) {
-			/* find the first choice value and find out choice type */
+			if (sym->type == S_UNKNOWN) {
+				/* find the first choice value to find out choice type */
+				current_entry = parent;
+				for (menu = parent->list; menu; menu = menu->next) {
+					if (menu->sym && menu->sym->type != S_UNKNOWN) {
+						menu_set_type(menu->sym->type);
+						break;
+					}
+				}
+			}
+			/* set the type of the remaining choice values */
 			for (menu = parent->list; menu; menu = menu->next) {
 			for (menu = parent->list; menu; menu = menu->next) {
-				if (menu->sym) {
-					current_entry = parent;
-					menu_set_type(menu->sym->type);
-					current_entry = menu;
+				current_entry = menu;
+				if (menu->sym && menu->sym->type == S_UNKNOWN)
 					menu_set_type(sym->type);
 					menu_set_type(sym->type);
-					break;
-				}
 			}
 			}
 			parentdep = expr_alloc_symbol(sym);
 			parentdep = expr_alloc_symbol(sym);
 		} else if (parent->prompt)
 		} else if (parent->prompt)
@@ -229,12 +300,11 @@ void menu_finalize(struct menu *parent)
 				prop = menu->sym->prop;
 				prop = menu->sym->prop;
 			else
 			else
 				prop = menu->prompt;
 				prop = menu->prompt;
-
 			for (; prop; prop = prop->next) {
 			for (; prop; prop = prop->next) {
 				if (prop->menu != menu)
 				if (prop->menu != menu)
 					continue;
 					continue;
 				dep = expr_transform(prop->visible.expr);
 				dep = expr_transform(prop->visible.expr);
-				dep = expr_alloc_and(expr_copy(menu->dep), dep);
+				dep = expr_alloc_and(expr_copy(basedep), dep);
 				dep = expr_eliminate_dups(dep);
 				dep = expr_eliminate_dups(dep);
 				if (menu->sym && menu->sym->type != S_TRISTATE)
 				if (menu->sym && menu->sym->type != S_TRISTATE)
 					dep = expr_trans_bool(dep);
 					dep = expr_trans_bool(dep);
@@ -244,11 +314,6 @@ void menu_finalize(struct menu *parent)
 					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
 					es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr,
 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
 							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
 				}
 				}
-				if (prop->type == P_DESELECT) {
-					struct symbol *es = prop_get_symbol(prop);
-					es->rev_dep_inv.expr = expr_alloc_or(es->rev_dep_inv.expr,
-							expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
-				}
 			}
 			}
 		}
 		}
 		for (menu = parent->list; menu; menu = menu->next)
 		for (menu = parent->list; menu; menu = menu->next)
@@ -284,26 +349,47 @@ void menu_finalize(struct menu *parent)
 			parent->next = last_menu->next;
 			parent->next = last_menu->next;
 			last_menu->next = NULL;
 			last_menu->next = NULL;
 		}
 		}
+
+		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
 	}
 	}
 	for (menu = parent->list; menu; menu = menu->next) {
 	for (menu = parent->list; menu; menu = menu->next) {
-		if (sym && sym_is_choice(sym) && menu->sym) {
+		if (sym && sym_is_choice(sym) &&
+		    menu->sym && !sym_is_choice_value(menu->sym)) {
+			current_entry = menu;
 			menu->sym->flags |= SYMBOL_CHOICEVAL;
 			menu->sym->flags |= SYMBOL_CHOICEVAL;
 			if (!menu->prompt)
 			if (!menu->prompt)
 				menu_warn(menu, "choice value must have a prompt");
 				menu_warn(menu, "choice value must have a prompt");
 			for (prop = menu->sym->prop; prop; prop = prop->next) {
 			for (prop = menu->sym->prop; prop; prop = prop->next) {
-				if (prop->type == P_PROMPT && prop->menu != menu) {
-					prop_warn(prop, "choice values "
-					    "currently only support a "
-					    "single prompt");
+				if (prop->type == P_DEFAULT)
+					prop_warn(prop, "defaults for choice "
+						  "values not supported");
+				if (prop->menu == menu)
+					continue;
+				if (prop->type == P_PROMPT &&
+				    prop->menu->parent->sym != sym)
+					prop_warn(prop, "choice value used outside its choice group");
+			}
+			/* Non-tristate choice values of tristate choices must
+			 * depend on the choice being set to Y. The choice
+			 * values' dependencies were propagated to their
+			 * properties above, so the change here must be re-
+			 * propagated.
+			 */
+			if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) {
+				basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes);
+				menu->dep = expr_alloc_and(basedep, menu->dep);
+				for (prop = menu->sym->prop; prop; prop = prop->next) {
+					if (prop->menu != menu)
+						continue;
+					prop->visible.expr = expr_alloc_and(expr_copy(basedep),
+									    prop->visible.expr);
 				}
 				}
 			}
 			}
-			current_entry = menu;
-			menu_set_type(sym->type);
 			menu_add_symbol(P_CHOICE, sym, NULL);
 			menu_add_symbol(P_CHOICE, sym, NULL);
 			prop = sym_get_choice_prop(sym);
 			prop = sym_get_choice_prop(sym);
 			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
 			for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
 				;
 				;
-			*ep = expr_alloc_one(E_CHOICE, NULL);
+			*ep = expr_alloc_one(E_LIST, NULL);
 			(*ep)->right.sym = menu->sym;
 			(*ep)->right.sym = menu->sym;
 		}
 		}
 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
 		if (menu->list && (!menu->prompt || !menu->prompt->text)) {
@@ -320,11 +406,10 @@ void menu_finalize(struct menu *parent)
 
 
 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
 	if (sym && !(sym->flags & SYMBOL_WARNED)) {
 		if (sym->type == S_UNKNOWN)
 		if (sym->type == S_UNKNOWN)
-			menu_warn(parent, "config symbol defined "
-			    "without type\n");
+			menu_warn(parent, "config symbol defined without type");
 
 
 		if (sym_is_choice(sym) && !parent->prompt)
 		if (sym_is_choice(sym) && !parent->prompt)
-			menu_warn(parent, "choice must have a prompt\n");
+			menu_warn(parent, "choice must have a prompt");
 
 
 		/* Check properties connected to this symbol */
 		/* Check properties connected to this symbol */
 		sym_check_prop(sym);
 		sym_check_prop(sym);
@@ -338,6 +423,13 @@ void menu_finalize(struct menu *parent)
 	}
 	}
 }
 }
 
 
+bool menu_has_prompt(struct menu *menu)
+{
+	if (!menu->prompt)
+		return false;
+	return true;
+}
+
 bool menu_is_visible(struct menu *menu)
 bool menu_is_visible(struct menu *menu)
 {
 {
 	struct menu *child;
 	struct menu *child;
@@ -346,6 +438,12 @@ bool menu_is_visible(struct menu *menu)
 
 
 	if (!menu->prompt)
 	if (!menu->prompt)
 		return false;
 		return false;
+
+	if (menu->visibility) {
+		if (expr_calc_value(menu->visibility) == no)
+			return no;
+	}
+
 	sym = menu->sym;
 	sym = menu->sym;
 	if (sym) {
 	if (sym) {
 		sym_calc_value(sym);
 		sym_calc_value(sym);
@@ -355,21 +453,27 @@ bool menu_is_visible(struct menu *menu)
 
 
 	if (visible != no)
 	if (visible != no)
 		return true;
 		return true;
+
 	if (!sym || sym_get_tristate_value(menu->sym) == no)
 	if (!sym || sym_get_tristate_value(menu->sym) == no)
 		return false;
 		return false;
 
 
-	for (child = menu->list; child; child = child->next)
-		if (menu_is_visible(child))
+	for (child = menu->list; child; child = child->next) {
+		if (menu_is_visible(child)) {
+			if (sym)
+				sym->flags |= SYMBOL_DEF_USER;
 			return true;
 			return true;
+		}
+	}
+
 	return false;
 	return false;
 }
 }
 
 
 const char *menu_get_prompt(struct menu *menu)
 const char *menu_get_prompt(struct menu *menu)
 {
 {
 	if (menu->prompt)
 	if (menu->prompt)
-		return _(menu->prompt->text);
+		return menu->prompt->text;
 	else if (menu->sym)
 	else if (menu->sym)
-		return _(menu->sym->name);
+		return menu->sym->name;
 	return NULL;
 	return NULL;
 }
 }
 
 
@@ -390,3 +494,151 @@ struct menu *menu_get_parent_menu(struct menu *menu)
 	return menu;
 	return menu;
 }
 }
 
 
+bool menu_has_help(struct menu *menu)
+{
+	return menu->help != NULL;
+}
+
+const char *menu_get_help(struct menu *menu)
+{
+	if (menu->help)
+		return menu->help;
+	else
+		return "";
+}
+
+static void get_prompt_str(struct gstr *r, struct property *prop,
+			   struct list_head *head)
+{
+	int i, j;
+	struct menu *submenu[8], *menu, *location = NULL;
+	struct jump_key *jump;
+
+	str_printf(r, _("Prompt: %s\n"), _(prop->text));
+	str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+		prop->menu->lineno);
+	if (!expr_is_yes(prop->visible.expr)) {
+		str_append(r, _("  Depends on: "));
+		expr_gstr_print(prop->visible.expr, r);
+		str_append(r, "\n");
+	}
+	menu = prop->menu->parent;
+	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+		bool accessible = menu_is_visible(menu);
+
+		submenu[i++] = menu;
+		if (location == NULL && accessible)
+			location = menu;
+	}
+	if (head && location) {
+		jump = xmalloc(sizeof(struct jump_key));
+
+		if (menu_is_visible(prop->menu)) {
+			/*
+			 * There is not enough room to put the hint at the
+			 * beginning of the "Prompt" line. Put the hint on the
+			 * last "Location" line even when it would belong on
+			 * the former.
+			 */
+			jump->target = prop->menu;
+		} else
+			jump->target = location;
+
+		if (list_empty(head))
+			jump->index = 0;
+		else
+			jump->index = list_entry(head->prev, struct jump_key,
+						 entries)->index + 1;
+
+		list_add_tail(&jump->entries, head);
+	}
+
+	if (i > 0) {
+		str_printf(r, _("  Location:\n"));
+		for (j = 4; --i >= 0; j += 2) {
+			menu = submenu[i];
+			if (head && location && menu == location)
+				jump->offset = r->len - 1;
+			str_printf(r, "%*c-> %s", j, ' ',
+				   _(menu_get_prompt(menu)));
+			if (menu->sym) {
+				str_printf(r, " (%s [=%s])", menu->sym->name ?
+					menu->sym->name : _("<choice>"),
+					sym_get_string_value(menu->sym));
+			}
+			str_append(r, "\n");
+		}
+	}
+}
+
+/*
+ * head is optional and may be NULL
+ */
+void get_symbol_str(struct gstr *r, struct symbol *sym,
+		    struct list_head *head)
+{
+	bool hit;
+	struct property *prop;
+
+	if (sym && sym->name) {
+		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+			   sym_get_string_value(sym));
+		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
+		if (sym->type == S_INT || sym->type == S_HEX) {
+			prop = sym_get_range_prop(sym);
+			if (prop) {
+				str_printf(r, "Range : ");
+				expr_gstr_print(prop->expr, r);
+				str_append(r, "\n");
+			}
+		}
+	}
+	for_all_prompts(sym, prop)
+		get_prompt_str(r, prop, head);
+	hit = false;
+	for_all_properties(sym, prop, P_SELECT) {
+		if (!hit) {
+			str_append(r, "  Selects: ");
+			hit = true;
+		} else
+			str_printf(r, " && ");
+		expr_gstr_print(prop->expr, r);
+	}
+	if (hit)
+		str_append(r, "\n");
+	if (sym->rev_dep.expr) {
+		str_append(r, _("  Selected by: "));
+		expr_gstr_print(sym->rev_dep.expr, r);
+		str_append(r, "\n");
+	}
+	str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
+{
+	struct symbol *sym;
+	struct gstr res = str_new();
+	int i;
+
+	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+		get_symbol_str(&res, sym, head);
+	if (!i)
+		str_append(&res, _("No matches found.\n"));
+	return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+	struct symbol *sym = menu->sym;
+	const char *help_text = nohelp_text;
+
+	if (menu_has_help(menu)) {
+		if (sym->name)
+			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+		help_text = menu_get_help(menu);
+	}
+	str_printf(help, "%s\n", _(help_text));
+	if (sym)
+		get_symbol_str(help, sym, NULL);
+}

+ 553 - 142
scripts/config/symbol.c

@@ -9,43 +9,43 @@
 #include <regex.h>
 #include <regex.h>
 #include <sys/utsname.h>
 #include <sys/utsname.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 struct symbol symbol_yes = {
 struct symbol symbol_yes = {
 	.name = "y",
 	.name = "y",
 	.curr = { "y", yes },
 	.curr = { "y", yes },
-	.flags = SYMBOL_YES|SYMBOL_VALID,
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
 }, symbol_mod = {
 }, symbol_mod = {
 	.name = "m",
 	.name = "m",
 	.curr = { "m", mod },
 	.curr = { "m", mod },
-	.flags = SYMBOL_MOD|SYMBOL_VALID,
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
 }, symbol_no = {
 }, symbol_no = {
 	.name = "n",
 	.name = "n",
 	.curr = { "n", no },
 	.curr = { "n", no },
-	.flags = SYMBOL_NO|SYMBOL_VALID,
+	.flags = SYMBOL_CONST|SYMBOL_VALID,
 }, symbol_empty = {
 }, symbol_empty = {
 	.name = "",
 	.name = "",
 	.curr = { "", no },
 	.curr = { "", no },
 	.flags = SYMBOL_VALID,
 	.flags = SYMBOL_VALID,
 };
 };
 
 
-int sym_change_count;
+struct symbol *sym_defconfig_list;
 struct symbol *modules_sym;
 struct symbol *modules_sym;
 tristate modules_val;
 tristate modules_val;
 
 
-void sym_add_default(struct symbol *sym, const char *def)
+struct expr *sym_env_list;
+
+static void sym_add_default(struct symbol *sym, const char *def)
 {
 {
 	struct property *prop = prop_alloc(P_DEFAULT, sym);
 	struct property *prop = prop_alloc(P_DEFAULT, sym);
 
 
-	prop->expr = expr_alloc_symbol(sym_lookup(def, 1));
+	prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST));
 }
 }
 
 
 void sym_init(void)
 void sym_init(void)
 {
 {
 	struct symbol *sym;
 	struct symbol *sym;
 	struct utsname uts;
 	struct utsname uts;
-	char *p;
 	static bool inited = false;
 	static bool inited = false;
 
 
 	if (inited)
 	if (inited)
@@ -54,19 +54,6 @@ void sym_init(void)
 
 
 	uname(&uts);
 	uname(&uts);
 
 
-	sym = sym_lookup("ARCH", 0);
-	sym->type = S_STRING;
-	p = getenv("ARCH");
-	if (p)
-		sym_add_default(sym, p);
-
-	sym = sym_lookup("OPENWRTVERSION", 0);
-	sym->type = S_STRING;
-	sym->flags |= SYMBOL_AUTO;
-	p = getenv("OPENWRTVERSION");
-	if (p)
-		sym_add_default(sym, p);
-
 	sym = sym_lookup("UNAME_RELEASE", 0);
 	sym = sym_lookup("UNAME_RELEASE", 0);
 	sym->type = S_STRING;
 	sym->type = S_STRING;
 	sym->flags |= SYMBOL_AUTO;
 	sym->flags |= SYMBOL_AUTO;
@@ -80,11 +67,8 @@ enum symbol_type sym_get_type(struct symbol *sym)
 	if (type == S_TRISTATE) {
 	if (type == S_TRISTATE) {
 		if (sym_is_choice_value(sym) && sym->visible == yes)
 		if (sym_is_choice_value(sym) && sym->visible == yes)
 			type = S_BOOLEAN;
 			type = S_BOOLEAN;
-/* tristate always enabled */
-#if 0
 		else if (modules_val == no)
 		else if (modules_val == no)
 			type = S_BOOLEAN;
 			type = S_BOOLEAN;
-#endif
 	}
 	}
 	return type;
 	return type;
 }
 }
@@ -119,6 +103,15 @@ struct property *sym_get_choice_prop(struct symbol *sym)
 	return NULL;
 	return NULL;
 }
 }
 
 
+struct property *sym_get_env_prop(struct symbol *sym)
+{
+	struct property *prop;
+
+	for_all_properties(sym, prop, P_ENV)
+		return prop;
+	return NULL;
+}
+
 struct property *sym_get_default_prop(struct symbol *sym)
 struct property *sym_get_default_prop(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
@@ -131,7 +124,7 @@ struct property *sym_get_default_prop(struct symbol *sym)
 	return NULL;
 	return NULL;
 }
 }
 
 
-struct property *sym_get_range_prop(struct symbol *sym)
+static struct property *sym_get_range_prop(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
 
 
@@ -196,26 +189,31 @@ static void sym_calc_visibility(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
 	tristate tri;
 	tristate tri;
-	int deselected = 0;
 
 
 	/* any prompt visible? */
 	/* any prompt visible? */
 	tri = no;
 	tri = no;
 	for_all_prompts(sym, prop) {
 	for_all_prompts(sym, prop) {
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
-		tri = E_OR(tri, prop->visible.tri);
+		tri = EXPR_OR(tri, prop->visible.tri);
 	}
 	}
-	if (tri == mod && (sym->type != S_TRISTATE))
+	if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
 		tri = yes;
 		tri = yes;
-	if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) {
-		tri = no;
-		deselected = 1;
-	}
 	if (sym->visible != tri) {
 	if (sym->visible != tri) {
 		sym->visible = tri;
 		sym->visible = tri;
 		sym_set_changed(sym);
 		sym_set_changed(sym);
 	}
 	}
-	if (sym_is_choice_value(sym) || deselected)
+	if (sym_is_choice_value(sym))
 		return;
 		return;
+	/* defaulting to "yes" if no explicit "depends on" are given */
+	tri = yes;
+	if (sym->dir_dep.expr)
+		tri = expr_calc_value(sym->dir_dep.expr);
+	if (tri == mod)
+		tri = yes;
+	if (sym->dir_dep.tri != tri) {
+		sym->dir_dep.tri = tri;
+		sym_set_changed(sym);
+	}
 	tri = no;
 	tri = no;
 	if (sym->rev_dep.expr)
 	if (sym->rev_dep.expr)
 		tri = expr_calc_value(sym->rev_dep.expr);
 		tri = expr_calc_value(sym->rev_dep.expr);
@@ -227,63 +225,68 @@ static void sym_calc_visibility(struct symbol *sym)
 	}
 	}
 }
 }
 
 
-static struct symbol *sym_calc_choice(struct symbol *sym)
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
 {
 {
 	struct symbol *def_sym;
 	struct symbol *def_sym;
 	struct property *prop;
 	struct property *prop;
 	struct expr *e;
 	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? */
 	/* any of the defaults visible? */
 	for_all_defaults(sym, prop) {
 	for_all_defaults(sym, prop) {
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
 		if (prop->visible.tri == no)
 		if (prop->visible.tri == no)
 			continue;
 			continue;
 		def_sym = prop_get_symbol(prop);
 		def_sym = prop_get_symbol(prop);
-		sym_calc_visibility(def_sym);
 		if (def_sym->visible != no)
 		if (def_sym->visible != no)
 			return def_sym;
 			return def_sym;
 	}
 	}
 
 
 	/* just get the first visible value */
 	/* just get the first visible value */
 	prop = sym_get_choice_prop(sym);
 	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);
+	expr_list_for_each_sym(prop->expr, e, def_sym)
 		if (def_sym->visible != no)
 		if (def_sym->visible != no)
 			return def_sym;
 			return def_sym;
-	}
 
 
-	/* no choice? reset tristate value */
-	sym->curr.tri = no;
+	/* failed to locate any defaults */
 	return NULL;
 	return NULL;
 }
 }
 
 
-void sym_set_changed(struct symbol *sym)
+static struct symbol *sym_calc_choice(struct symbol *sym)
 {
 {
+	struct symbol *def_sym;
 	struct property *prop;
 	struct property *prop;
+	struct expr *e;
+	int flags;
 
 
-	sym->flags |= SYMBOL_CHANGED;
-	for (prop = sym->prop; prop; prop = prop->next) {
-		if (prop->menu)
-			prop->menu->flags |= MENU_CHANGED;
+	/* first calculate all choice values' visibilities */
+	flags = sym->flags;
+	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym) {
+		sym_calc_visibility(def_sym);
+		if (def_sym->visible != no)
+			flags &= def_sym->flags;
 	}
 	}
-}
 
 
-void sym_set_all_changed(void)
-{
-	struct symbol *sym;
-	int i;
+	sym->flags &= flags | ~SYMBOL_DEF_USER;
 
 
-	for_all_symbols(i, sym)
-		sym_set_changed(sym);
+	/* is the user choice visible? */
+	def_sym = sym->def[S_DEF_USER].val;
+	if (def_sym && def_sym->visible != no)
+		return def_sym;
+
+	def_sym = sym_choice_default(sym);
+
+	if (def_sym == NULL)
+		/* no choice? reset tristate value */
+		sym->curr.tri = no;
+
+	return def_sym;
 }
 }
 
 
 void sym_calc_value(struct symbol *sym)
 void sym_calc_value(struct symbol *sym)
@@ -330,24 +333,42 @@ void sym_calc_value(struct symbol *sym)
 		if (sym_is_choice_value(sym) && sym->visible == yes) {
 		if (sym_is_choice_value(sym) && sym->visible == yes) {
 			prop = sym_get_choice_prop(sym);
 			prop = sym_get_choice_prop(sym);
 			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
 			newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no;
-		} else if (sym->rev_dep_inv.expr && (expr_calc_value(sym->rev_dep_inv.expr) == yes)) {
-			newval.tri = no;
-		} else if (E_OR(sym->visible, sym->rev_dep.tri) != no) {
-			sym->flags |= SYMBOL_WRITE;
-			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);
+		} else {
+			if (sym->visible != no) {
+				/* if the symbol is visible use the user value
+				 * if available, otherwise try the default value
+				 */
+				sym->flags |= SYMBOL_WRITE;
+				if (sym_has_value(sym)) {
+					newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri,
+							      sym->visible);
+					goto calc_newval;
+				}
 			}
 			}
-			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) {
+			if (sym->rev_dep.tri != no)
 				sym->flags |= SYMBOL_WRITE;
 				sym->flags |= SYMBOL_WRITE;
-				newval.tri = expr_calc_value(prop->expr);
+			if (!sym_is_choice(sym)) {
+				prop = sym_get_default_prop(sym);
+				if (prop) {
+					sym->flags |= SYMBOL_WRITE;
+					newval.tri = EXPR_AND(expr_calc_value(prop->expr),
+							      prop->visible.tri);
+				}
+			}
+		calc_newval:
+			if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+				struct expr *e;
+				e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+				    sym->dir_dep.expr);
+				fprintf(stderr, "warning: (");
+				expr_fprint(e, stderr);
+				fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+					sym->name);
+				expr_fprint(sym->dir_dep.expr, stderr);
+				fprintf(stderr, ")\n");
+				expr_free(e);
 			}
 			}
+			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
 		}
 		}
 		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
 		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
 			newval.tri = yes;
 			newval.tri = yes;
@@ -358,7 +379,7 @@ void sym_calc_value(struct symbol *sym)
 		if (sym->visible != no) {
 		if (sym->visible != no) {
 			sym->flags |= SYMBOL_WRITE;
 			sym->flags |= SYMBOL_WRITE;
 			if (sym_has_value(sym)) {
 			if (sym_has_value(sym)) {
-				newval.val = sym->user.val;
+				newval.val = sym->def[S_DEF_USER].val;
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -382,7 +403,6 @@ void sym_calc_value(struct symbol *sym)
 	sym_validate_range(sym);
 	sym_validate_range(sym);
 
 
 	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
 	if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
-		sym->flags &= ~SYMBOL_VALID;
 		sym_set_changed(sym);
 		sym_set_changed(sym);
 		if (modules_sym == sym) {
 		if (modules_sym == sym) {
 			sym_set_all_changed();
 			sym_set_all_changed();
@@ -391,12 +411,15 @@ void sym_calc_value(struct symbol *sym)
 	}
 	}
 
 
 	if (sym_is_choice(sym)) {
 	if (sym_is_choice(sym)) {
-		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
+		struct symbol *choice_sym;
+
 		prop = sym_get_choice_prop(sym);
 		prop = sym_get_choice_prop(sym);
-		for (e = prop->expr; e; e = e->left.expr) {
-			e->right.sym->flags |= flags;
-			if (flags & SYMBOL_CHANGED)
-				sym_set_changed(e->right.sym);
+		expr_list_for_each_sym(prop->expr, e, choice_sym) {
+			if ((sym->flags & SYMBOL_WRITE) &&
+			    choice_sym->visible != no)
+				choice_sym->flags |= SYMBOL_WRITE;
+			if (sym->flags & SYMBOL_CHANGED)
+				sym_set_changed(choice_sym);
 		}
 		}
 	}
 	}
 
 
@@ -411,11 +434,31 @@ void sym_clear_all_valid(void)
 
 
 	for_all_symbols(i, sym)
 	for_all_symbols(i, sym)
 		sym->flags &= ~SYMBOL_VALID;
 		sym->flags &= ~SYMBOL_VALID;
-	sym_change_count++;
+	sym_add_change_count(1);
 	if (modules_sym)
 	if (modules_sym)
 		sym_calc_value(modules_sym);
 		sym_calc_value(modules_sym);
 }
 }
 
 
+void sym_set_changed(struct symbol *sym)
+{
+	struct property *prop;
+
+	sym->flags |= SYMBOL_CHANGED;
+	for (prop = sym->prop; prop; prop = prop->next) {
+		if (prop->menu)
+			prop->menu->flags |= MENU_CHANGED;
+	}
+}
+
+void sym_set_all_changed(void)
+{
+	struct symbol *sym;
+	int i;
+
+	for_all_symbols(i, sym)
+		sym_set_changed(sym);
+}
+
 bool sym_tristate_within_range(struct symbol *sym, tristate val)
 bool sym_tristate_within_range(struct symbol *sym, tristate val)
 {
 {
 	int type = sym_get_type(sym);
 	int type = sym_get_type(sym);
@@ -442,8 +485,8 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
 	if (oldval != val && !sym_tristate_within_range(sym, val))
 	if (oldval != val && !sym_tristate_within_range(sym, val))
 		return false;
 		return false;
 
 
-	if (sym->flags & SYMBOL_NEW) {
-		sym->flags &= ~SYMBOL_NEW;
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
 		sym_set_changed(sym);
 		sym_set_changed(sym);
 	}
 	}
 	/*
 	/*
@@ -455,19 +498,18 @@ bool sym_set_tristate_value(struct symbol *sym, tristate val)
 		struct property *prop;
 		struct property *prop;
 		struct expr *e;
 		struct expr *e;
 
 
-		cs->user.val = sym;
-		cs->flags &= ~SYMBOL_NEW;
+		cs->def[S_DEF_USER].val = sym;
+		cs->flags |= SYMBOL_DEF_USER;
 		prop = sym_get_choice_prop(cs);
 		prop = sym_get_choice_prop(cs);
 		for (e = prop->expr; e; e = e->left.expr) {
 		for (e = prop->expr; e; e = e->left.expr) {
 			if (e->right.sym->visible != no)
 			if (e->right.sym->visible != no)
-				e->right.sym->flags &= ~SYMBOL_NEW;
+				e->right.sym->flags |= SYMBOL_DEF_USER;
 		}
 		}
 	}
 	}
 
 
-	sym->user.tri = val;
-	if (oldval != val) {
+	sym->def[S_DEF_USER].tri = val;
+	if (oldval != val)
 		sym_clear_all_valid();
 		sym_clear_all_valid();
-	}
 
 
 	return true;
 	return true;
 }
 }
@@ -605,20 +647,20 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
 	if (!sym_string_within_range(sym, newval))
 	if (!sym_string_within_range(sym, newval))
 		return false;
 		return false;
 
 
-	if (sym->flags & SYMBOL_NEW) {
-		sym->flags &= ~SYMBOL_NEW;
+	if (!(sym->flags & SYMBOL_DEF_USER)) {
+		sym->flags |= SYMBOL_DEF_USER;
 		sym_set_changed(sym);
 		sym_set_changed(sym);
 	}
 	}
 
 
-	oldval = sym->user.val;
+	oldval = sym->def[S_DEF_USER].val;
 	size = strlen(newval) + 1;
 	size = strlen(newval) + 1;
 	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 		size += 2;
 		size += 2;
-		sym->user.val = val = malloc(size);
+		sym->def[S_DEF_USER].val = val = xmalloc(size);
 		*val++ = '0';
 		*val++ = '0';
 		*val++ = 'x';
 		*val++ = 'x';
 	} else if (!oldval || strcmp(oldval, newval))
 	} else if (!oldval || strcmp(oldval, newval))
-		sym->user.val = val = malloc(size);
+		sym->def[S_DEF_USER].val = val = xmalloc(size);
 	else
 	else
 		return true;
 		return true;
 
 
@@ -629,6 +671,80 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
 	return true;
 	return true;
 }
 }
 
 
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *ds;
+	const char *str;
+	tristate val;
+
+	sym_calc_visibility(sym);
+	sym_calc_value(modules_sym);
+	val = symbol_no.curr.tri;
+	str = symbol_empty.curr.val;
+
+	/* If symbol has a default value look it up */
+	prop = sym_get_default_prop(sym);
+	if (prop != NULL) {
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			/* The visibility may limit the value from yes => mod */
+			val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+			break;
+		default:
+			/*
+			 * The following fails to handle the situation
+			 * where a default value is further limited by
+			 * the valid range.
+			 */
+			ds = prop_get_symbol(prop);
+			if (ds != NULL) {
+				sym_calc_value(ds);
+				str = (const char *)ds->curr.val;
+			}
+		}
+	}
+
+	/* Handle select statements */
+	val = EXPR_OR(val, sym->rev_dep.tri);
+
+	/* transpose mod to yes if modules are not enabled */
+	if (val == mod)
+		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+			val = yes;
+
+	/* transpose mod to yes if type is bool */
+	if (sym->type == S_BOOLEAN && val == mod)
+		val = yes;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (val) {
+		case no: return "n";
+		case mod: return "m";
+		case yes: return "y";
+		}
+	case S_INT:
+	case S_HEX:
+		return str;
+	case S_STRING:
+		return str;
+	case S_OTHER:
+	case S_UNKNOWN:
+		break;
+	}
+	return "";
+}
+
 const char *sym_get_string_value(struct symbol *sym)
 const char *sym_get_string_value(struct symbol *sym)
 {
 {
 	tristate val;
 	tristate val;
@@ -641,7 +757,8 @@ const char *sym_get_string_value(struct symbol *sym)
 		case no:
 		case no:
 			return "n";
 			return "n";
 		case mod:
 		case mod:
-			return "m";
+			sym_calc_value(modules_sym);
+			return (modules_sym->curr.tri == no) ? "n" : "m";
 		case yes:
 		case yes:
 			return "y";
 			return "y";
 		}
 		}
@@ -657,12 +774,20 @@ bool sym_is_changable(struct symbol *sym)
 	return sym->visible > sym->rev_dep.tri;
 	return sym->visible > sym->rev_dep.tri;
 }
 }
 
 
-struct symbol *sym_lookup(const char *name, int isconst)
+static unsigned strhash(const char *s)
+{
+	/* fnv32 hash */
+	unsigned hash = 2166136261U;
+	for (; *s; s++)
+		hash = (hash ^ *s) * 0x01000193;
+	return hash;
+}
+
+struct symbol *sym_lookup(const char *name, int flags)
 {
 {
 	struct symbol *symbol;
 	struct symbol *symbol;
-	const char *ptr;
 	char *new_name;
 	char *new_name;
-	int hash = 0;
+	int hash;
 
 
 	if (name) {
 	if (name) {
 		if (name[0] && !name[1]) {
 		if (name[0] && !name[1]) {
@@ -672,30 +797,26 @@ struct symbol *sym_lookup(const char *name, int isconst)
 			case 'n': return &symbol_no;
 			case 'n': return &symbol_no;
 			}
 			}
 		}
 		}
-		for (ptr = name; *ptr; ptr++)
-			hash += *ptr;
-		hash &= 0xff;
+		hash = strhash(name) % SYMBOL_HASHSIZE;
 
 
 		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 		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)))
-					return symbol;
-			}
+			if (symbol->name &&
+			    !strcmp(symbol->name, name) &&
+			    (flags ? symbol->flags & flags
+				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
+				return symbol;
 		}
 		}
 		new_name = strdup(name);
 		new_name = strdup(name);
 	} else {
 	} else {
 		new_name = NULL;
 		new_name = NULL;
-		hash = 256;
+		hash = 0;
 	}
 	}
 
 
-	symbol = malloc(sizeof(*symbol));
+	symbol = xmalloc(sizeof(*symbol));
 	memset(symbol, 0, sizeof(*symbol));
 	memset(symbol, 0, sizeof(*symbol));
 	symbol->name = new_name;
 	symbol->name = new_name;
 	symbol->type = S_UNKNOWN;
 	symbol->type = S_UNKNOWN;
-	symbol->flags = SYMBOL_NEW;
-	if (isconst)
-		symbol->flags |= SYMBOL_CONST;
+	symbol->flags |= flags;
 
 
 	symbol->next = symbol_hash[hash];
 	symbol->next = symbol_hash[hash];
 	symbol_hash[hash] = symbol;
 	symbol_hash[hash] = symbol;
@@ -706,7 +827,6 @@ struct symbol *sym_lookup(const char *name, int isconst)
 struct symbol *sym_find(const char *name)
 struct symbol *sym_find(const char *name)
 {
 {
 	struct symbol *symbol = NULL;
 	struct symbol *symbol = NULL;
-	const char *ptr;
 	int hash = 0;
 	int hash = 0;
 
 
 	if (!name)
 	if (!name)
@@ -719,12 +839,11 @@ struct symbol *sym_find(const char *name)
 		case 'n': return &symbol_no;
 		case 'n': return &symbol_no;
 		}
 		}
 	}
 	}
-	for (ptr = name; *ptr; ptr++)
-		hash += *ptr;
-	hash &= 0xff;
+	hash = strhash(name) % SYMBOL_HASHSIZE;
 
 
 	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
-		if (!strcmp(symbol->name, name) &&
+		if (symbol->name &&
+		    !strcmp(symbol->name, name) &&
 		    !(symbol->flags & SYMBOL_CONST))
 		    !(symbol->flags & SYMBOL_CONST))
 				break;
 				break;
 	}
 	}
@@ -732,6 +851,98 @@ struct symbol *sym_find(const char *name)
 	return symbol;
 	return symbol;
 }
 }
 
 
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+	const char *src;
+	char *res;
+	size_t reslen;
+
+	reslen = strlen(in) + 1;
+	res = xmalloc(reslen);
+	res[0] = '\0';
+
+	while ((src = strchr(in, '$'))) {
+		char *p, name[SYMBOL_MAXLENGTH];
+		const char *symval = "";
+		struct symbol *sym;
+		size_t newlen;
+
+		strncat(res, in, src - in);
+		src++;
+
+		p = name;
+		while (isalnum(*src) || *src == '_')
+			*p++ = *src++;
+		*p = '\0';
+
+		sym = sym_find(name);
+		if (sym != NULL) {
+			sym_calc_value(sym);
+			symval = sym_get_string_value(sym);
+		}
+
+		newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+		if (newlen > reslen) {
+			reslen = newlen;
+			res = realloc(res, reslen);
+		}
+
+		strcat(res, symval);
+		in = src;
+	}
+	strcat(res, in);
+
+	return res;
+}
+
+const char *sym_escape_string_value(const char *in)
+{
+	const char *p;
+	size_t reslen;
+	char *res;
+	size_t l;
+
+	reslen = strlen(in) + strlen("\"\"") + 1;
+
+	p = in;
+	for (;;) {
+		l = strcspn(p, "\"\\");
+		p += l;
+
+		if (p[0] == '\0')
+			break;
+
+		reslen++;
+		p++;
+	}
+
+	res = xmalloc(reslen);
+	res[0] = '\0';
+
+	strcat(res, "\"");
+
+	p = in;
+	for (;;) {
+		l = strcspn(p, "\"\\");
+		strncat(res, p, l);
+		p += l;
+
+		if (p[0] == '\0')
+			break;
+
+		strcat(res, "\\");
+		strncat(res, p++, 1);
+	}
+
+	strcat(res, "\"");
+	return res;
+}
+
 struct symbol **sym_re_search(const char *pattern)
 struct symbol **sym_re_search(const char *pattern)
 {
 {
 	struct symbol *sym, **sym_arr = NULL;
 	struct symbol *sym, **sym_arr = NULL;
@@ -769,8 +980,112 @@ struct symbol **sym_re_search(const char *pattern)
 	return sym_arr;
 	return sym_arr;
 }
 }
 
 
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note inser() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+	struct dep_stack *prev, *next;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+	memset(stack, 0, sizeof(*stack));
+	if (check_top)
+		check_top->next = stack;
+	stack->prev = check_top;
+	stack->sym = sym;
+	check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+	check_top = check_top->prev;
+	if (check_top)
+		check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+	struct dep_stack *stack;
+	struct symbol *sym, *next_sym;
+	struct menu *menu = NULL;
+	struct property *prop;
+	struct dep_stack cv_stack;
+
+	if (sym_is_choice_value(last_sym)) {
+		dep_stack_insert(&cv_stack, last_sym);
+		last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+	}
 
 
-struct symbol *sym_check_deps(struct symbol *sym);
+	for (stack = check_top; stack != NULL; stack = stack->prev)
+		if (stack->sym == last_sym)
+			break;
+	if (!stack) {
+		fprintf(stderr, "unexpected recursive dependency error\n");
+		return;
+	}
+
+	for (; stack; stack = stack->next) {
+		sym = stack->sym;
+		next_sym = stack->next ? stack->next->sym : last_sym;
+		prop = stack->prop;
+		if (prop == NULL)
+			prop = stack->sym->prop;
+
+		/* for choice values find the menu entry (used below) */
+		if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+			for (prop = sym->prop; prop; prop = prop->next) {
+				menu = prop->menu;
+				if (prop->menu)
+					break;
+			}
+		}
+		if (stack->sym == last_sym)
+			fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+				prop->file->name, prop->lineno);
+		if (stack->expr) {
+			fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				prop_get_type_name(prop->type),
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (stack->prop) {
+			fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice(sym)) {
+			fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice_value(sym)) {
+			fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else {
+			fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		}
+	}
+
+	if (check_top == &cv_stack)
+		dep_stack_remove();
+}
 
 
 static struct symbol *sym_check_expr_deps(struct expr *e)
 static struct symbol *sym_check_expr_deps(struct expr *e)
 {
 {
@@ -802,44 +1117,109 @@ static struct symbol *sym_check_expr_deps(struct expr *e)
 	return NULL;
 	return NULL;
 }
 }
 
 
-struct symbol *sym_check_deps(struct symbol *sym)
+/* return NULL when dependencies are OK */
+static struct symbol *sym_check_sym_deps(struct symbol *sym)
 {
 {
 	struct symbol *sym2;
 	struct symbol *sym2;
 	struct property *prop;
 	struct property *prop;
+	struct dep_stack stack;
 
 
-	if (sym->flags & SYMBOL_CHECK) {
-		printf("Warning! Found recursive dependency: %s", sym->name);
-		return sym;
-	}
-	if (sym->flags & SYMBOL_CHECKED)
-		return NULL;
+	dep_stack_insert(&stack, sym);
 
 
-	sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
 	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 	if (sym2)
 	if (sym2)
 		goto out;
 		goto out;
 
 
 	for (prop = sym->prop; prop; prop = prop->next) {
 	for (prop = sym->prop; prop; prop = prop->next) {
-		if (prop->type == P_CHOICE || prop->type == P_SELECT || prop->type == P_DESELECT)
+		if (prop->type == P_CHOICE || prop->type == P_SELECT)
 			continue;
 			continue;
+		stack.prop = prop;
 		sym2 = sym_check_expr_deps(prop->visible.expr);
 		sym2 = sym_check_expr_deps(prop->visible.expr);
 		if (sym2)
 		if (sym2)
-			goto out;
+			break;
 		if (prop->type != P_DEFAULT || sym_is_choice(sym))
 		if (prop->type != P_DEFAULT || sym_is_choice(sym))
 			continue;
 			continue;
+		stack.expr = prop->expr;
 		sym2 = sym_check_expr_deps(prop->expr);
 		sym2 = sym_check_expr_deps(prop->expr);
 		if (sym2)
 		if (sym2)
-			goto out;
+			break;
+		stack.expr = NULL;
 	}
 	}
+
 out:
 out:
-	if (sym2) {
-		printf(" %s", sym->name);
-		if (sym2 == sym) {
-			printf("\n");
-			sym2 = NULL;
-		}
+	dep_stack_remove();
+
+	return sym2;
+}
+
+static struct symbol *sym_check_choice_deps(struct symbol *choice)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	struct expr *e;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, choice);
+
+	prop = sym_get_choice_prop(choice);
+	expr_list_for_each_sym(prop->expr, e, sym)
+		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+
+	choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+	sym2 = sym_check_sym_deps(choice);
+	choice->flags &= ~SYMBOL_CHECK;
+	if (sym2)
+		goto out;
+
+	expr_list_for_each_sym(prop->expr, e, sym) {
+		sym2 = sym_check_sym_deps(sym);
+		if (sym2)
+			break;
+	}
+out:
+	expr_list_for_each_sym(prop->expr, e, sym)
+		sym->flags &= ~SYMBOL_CHECK;
+
+	if (sym2 && sym_is_choice_value(sym2) &&
+	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
+		sym2 = choice;
+
+	dep_stack_remove();
+
+	return sym2;
+}
+
+struct symbol *sym_check_deps(struct symbol *sym)
+{
+	struct symbol *sym2;
+	struct property *prop;
+
+	if (sym->flags & SYMBOL_CHECK) {
+		sym_check_print_recursive(sym);
+		return sym;
 	}
 	}
-	sym->flags &= ~SYMBOL_CHECK;
+	if (sym->flags & SYMBOL_CHECKED)
+		return NULL;
+
+	if (sym_is_choice_value(sym)) {
+		struct dep_stack stack;
+
+		/* for choice groups start the check with main choice symbol */
+		dep_stack_insert(&stack, sym);
+		prop = sym_get_choice_prop(sym);
+		sym2 = sym_check_deps(prop_get_symbol(prop));
+		dep_stack_remove();
+	} else if (sym_is_choice(sym)) {
+		sym2 = sym_check_choice_deps(sym);
+	} else {
+		sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
+		sym2 = sym_check_sym_deps(sym);
+		sym->flags &= ~SYMBOL_CHECK;
+	}
+
+	if (sym2 && sym2 == sym)
+		sym2 = NULL;
+
 	return sym2;
 	return sym2;
 }
 }
 
 
@@ -848,7 +1228,7 @@ struct property *prop_alloc(enum prop_type type, struct symbol *sym)
 	struct property *prop;
 	struct property *prop;
 	struct property **propp;
 	struct property **propp;
 
 
-	prop = malloc(sizeof(*prop));
+	prop = xmalloc(sizeof(*prop));
 	memset(prop, 0, sizeof(*prop));
 	memset(prop, 0, sizeof(*prop));
 	prop->type = type;
 	prop->type = type;
 	prop->sym = sym;
 	prop->sym = sym;
@@ -868,7 +1248,7 @@ struct property *prop_alloc(enum prop_type type, struct symbol *sym)
 struct symbol *prop_get_symbol(struct property *prop)
 struct symbol *prop_get_symbol(struct property *prop)
 {
 {
 	if (prop->expr && (prop->expr->type == E_SYMBOL ||
 	if (prop->expr && (prop->expr->type == E_SYMBOL ||
-			   prop->expr->type == E_CHOICE))
+			   prop->expr->type == E_LIST))
 		return prop->expr->left.sym;
 		return prop->expr->left.sym;
 	return NULL;
 	return NULL;
 }
 }
@@ -878,6 +1258,8 @@ const char *prop_get_type_name(enum prop_type type)
 	switch (type) {
 	switch (type) {
 	case P_PROMPT:
 	case P_PROMPT:
 		return "prompt";
 		return "prompt";
+	case P_ENV:
+		return "env";
 	case P_COMMENT:
 	case P_COMMENT:
 		return "comment";
 		return "comment";
 	case P_MENU:
 	case P_MENU:
@@ -888,12 +1270,41 @@ const char *prop_get_type_name(enum prop_type type)
 		return "choice";
 		return "choice";
 	case P_SELECT:
 	case P_SELECT:
 		return "select";
 		return "select";
-	case P_DESELECT:
-		return "deselect";
 	case P_RANGE:
 	case P_RANGE:
 		return "range";
 		return "range";
+	case P_SYMBOL:
+		return "symbol";
 	case P_UNKNOWN:
 	case P_UNKNOWN:
 		break;
 		break;
 	}
 	}
 	return "unknown";
 	return "unknown";
 }
 }
+
+static void prop_add_env(const char *env)
+{
+	struct symbol *sym, *sym2;
+	struct property *prop;
+	char *p;
+
+	sym = current_entry->sym;
+	sym->flags |= SYMBOL_AUTO;
+	for_all_properties(sym, prop, P_ENV) {
+		sym2 = prop_get_symbol(prop);
+		if (strcmp(sym2->name, env))
+			menu_warn(current_entry, "redefining environment symbol from %s",
+				  sym2->name);
+		return;
+	}
+
+	prop = prop_alloc(P_ENV, sym);
+	prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST));
+
+	sym_env_list = expr_alloc_one(E_LIST, sym_env_list);
+	sym_env_list->right.sym = sym;
+
+	p = getenv(env);
+	if (p)
+		sym_add_default(sym, p);
+	else
+		menu_warn(current_entry, "environment variable %s undefined", env);
+}

+ 86 - 11
scripts/config/util.c

@@ -5,6 +5,8 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
+#include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include "lkc.h"
 #include "lkc.h"
 
 
@@ -12,26 +14,76 @@
 struct file *file_lookup(const char *name)
 struct file *file_lookup(const char *name)
 {
 {
 	struct file *file;
 	struct file *file;
+	const char *file_name = sym_expand_string_value(name);
 
 
 	for (file = file_list; file; file = file->next) {
 	for (file = file_list; file; file = file->next) {
-		if (!strcmp(name, file->name))
+		if (!strcmp(name, file->name)) {
+			free((void *)file_name);
 			return file;
 			return file;
+		}
 	}
 	}
 
 
-	file = malloc(sizeof(*file));
+	file = xmalloc(sizeof(*file));
 	memset(file, 0, sizeof(*file));
 	memset(file, 0, sizeof(*file));
-	file->name = strdup(name);
+	file->name = file_name;
 	file->next = file_list;
 	file->next = file_list;
 	file_list = file;
 	file_list = file;
 	return file;
 	return file;
 }
 }
 
 
-/* Allocate initial growable sting */
+/* write a dependency file as used by kbuild to track dependencies */
+int file_write_dep(const char *name)
+{
+	struct symbol *sym, *env_sym;
+	struct expr *e;
+	struct file *file;
+	FILE *out;
+
+	if (!name)
+		name = ".kconfig.d";
+	out = fopen("..config.tmp", "w");
+	if (!out)
+		return 1;
+	fprintf(out, "deps_config := \\\n");
+	for (file = file_list; file; file = file->next) {
+		if (file->next)
+			fprintf(out, "\t%s \\\n", file->name);
+		else
+			fprintf(out, "\t%s\n", file->name);
+	}
+	fprintf(out, "\n%s: \\\n"
+		     "\t$(deps_config)\n\n", conf_get_autoconfig_name());
+
+	expr_list_for_each_sym(sym_env_list, e, sym) {
+		struct property *prop;
+		const char *value;
+
+		prop = sym_get_env_prop(sym);
+		env_sym = prop_get_symbol(prop);
+		if (!env_sym)
+			continue;
+		value = getenv(env_sym->name);
+		if (!value)
+			value = "";
+		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
+		fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
+		fprintf(out, "endif\n");
+	}
+
+	fprintf(out, "\n$(deps_config): ;\n");
+	fclose(out);
+	rename("..config.tmp", name);
+	return 0;
+}
+
+
+/* Allocate initial growable string */
 struct gstr str_new(void)
 struct gstr str_new(void)
 {
 {
 	struct gstr gs;
 	struct gstr gs;
-	gs.s = malloc(sizeof(char) * 64);
-	gs.len = 16;
+	gs.s = xmalloc(sizeof(char) * 64);
+	gs.len = 64;
+	gs.max_width = 0;
 	strcpy(gs.s, "\0");
 	strcpy(gs.s, "\0");
 	return gs;
 	return gs;
 }
 }
@@ -42,6 +94,7 @@ struct gstr str_assign(const char *s)
 	struct gstr gs;
 	struct gstr gs;
 	gs.s = strdup(s);
 	gs.s = strdup(s);
 	gs.len = strlen(s) + 1;
 	gs.len = strlen(s) + 1;
+	gs.max_width = 0;
 	return gs;
 	return gs;
 }
 }
 
 
@@ -57,12 +110,15 @@ void str_free(struct gstr *gs)
 /* Append to growable string */
 /* Append to growable string */
 void str_append(struct gstr *gs, const char *s)
 void str_append(struct gstr *gs, const char *s)
 {
 {
-	size_t l = strlen(gs->s) + strlen(s) + 1;
-	if (l > gs->len) {
-		gs->s   = realloc(gs->s, l);
-		gs->len = l;
+	size_t l;
+	if (s) {
+		l = strlen(gs->s) + strlen(s) + 1;
+		if (l > gs->len) {
+			gs->s   = realloc(gs->s, l);
+			gs->len = l;
+		}
+		strcat(gs->s, s);
 	}
 	}
-	strcat(gs->s, s);
 }
 }
 
 
 /* Append printf formatted string to growable string */
 /* Append printf formatted string to growable string */
@@ -82,3 +138,22 @@ const char *str_get(struct gstr *gs)
 	return gs->s;
 	return gs->s;
 }
 }
 
 
+void *xmalloc(size_t size)
+{
+	void *p = malloc(size);
+	if (p)
+		return p;
+	fprintf(stderr, "Out of memory.\n");
+	exit(1);
+}
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+	void *p = calloc(nmemb, size);
+	if (p)
+		return p;
+	fprintf(stderr, "Out of memory.\n");
+	exit(1);
+}
+
+

+ 7 - 5
scripts/config/zconf.gperf

@@ -9,6 +9,7 @@
 
 
 struct kconf_id;
 struct kconf_id;
 
 
+
 %%
 %%
 mainmenu,	T_MAINMENU,	TF_COMMAND
 mainmenu,	T_MAINMENU,	TF_COMMAND
 menu,		T_MENU,		TF_COMMAND
 menu,		T_MENU,		TF_COMMAND
@@ -23,9 +24,7 @@ help,		T_HELP,		TF_COMMAND
 if,		T_IF,		TF_COMMAND|TF_PARAM
 if,		T_IF,		TF_COMMAND|TF_PARAM
 endif,		T_ENDIF,	TF_COMMAND
 endif,		T_ENDIF,	TF_COMMAND
 depends,	T_DEPENDS,	TF_COMMAND
 depends,	T_DEPENDS,	TF_COMMAND
-requires,	T_REQUIRES,	TF_COMMAND
 optional,	T_OPTIONAL,	TF_COMMAND
 optional,	T_OPTIONAL,	TF_COMMAND
-reset,		T_RESET,	TF_COMMAND
 default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN
 default,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN
 prompt,		T_PROMPT,	TF_COMMAND
 prompt,		T_PROMPT,	TF_COMMAND
 tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE
 tristate,	T_TYPE,		TF_COMMAND, S_TRISTATE
@@ -33,13 +32,16 @@ def_tristate,	T_DEFAULT,	TF_COMMAND, S_TRISTATE
 bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN
 bool,		T_TYPE,		TF_COMMAND, S_BOOLEAN
 boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN
 boolean,	T_TYPE,		TF_COMMAND, S_BOOLEAN
 def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
 def_bool,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
-def_boolean,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN
 int,		T_TYPE,		TF_COMMAND, S_INT
 int,		T_TYPE,		TF_COMMAND, S_INT
 hex,		T_TYPE,		TF_COMMAND, S_HEX
 hex,		T_TYPE,		TF_COMMAND, S_HEX
 string,		T_TYPE,		TF_COMMAND, S_STRING
 string,		T_TYPE,		TF_COMMAND, S_STRING
-deselect,	T_DESELECT,	TF_COMMAND
 select,		T_SELECT,	TF_COMMAND
 select,		T_SELECT,	TF_COMMAND
-enable,		T_SELECT,	TF_COMMAND
 range,		T_RANGE,	TF_COMMAND
 range,		T_RANGE,	TF_COMMAND
+visible,	T_VISIBLE,	TF_COMMAND
+option,		T_OPTION,	TF_COMMAND
 on,		T_ON,		TF_PARAM
 on,		T_ON,		TF_PARAM
+modules,	T_OPT_MODULES,	TF_OPTION
+defconfig_list,	T_OPT_DEFCONFIG_LIST,TF_OPTION
+env,		T_OPT_ENV,	TF_OPTION
+reset,		T_RESET,	TF_COMMAND
 %%
 %%

+ 124 - 116
scripts/config/zconf.hash.c_shipped

@@ -1,4 +1,4 @@
-/* ANSI-C code produced by gperf version 3.0.1 */
+/* ANSI-C code produced by gperf version 3.0.4 */
 /* Command-line: gperf  */
 /* Command-line: gperf  */
 /* Computed positions: -k'1,3' */
 /* Computed positions: -k'1,3' */
 
 
@@ -30,46 +30,44 @@
 #endif
 #endif
 
 
 struct kconf_id;
 struct kconf_id;
-/* maximum key range = 40, duplicates = 0 */
+/* maximum key range = 47, duplicates = 0 */
 
 
-#ifdef __GNUC__
-__inline
-#else
-#ifdef __cplusplus
+#if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) || defined(__GNUC_STDC_INLINE__)
 inline
 inline
-#endif
+#elif defined(__GNUC__)
+__inline
 #endif
 #endif
 static unsigned int
 static unsigned int
 kconf_id_hash (register const char *str, register unsigned int len)
 kconf_id_hash (register const char *str, register unsigned int len)
 {
 {
   static unsigned char asso_values[] =
   static unsigned char asso_values[] =
     {
     {
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 35,  0, 20,
-       5,  0,  5, 42,  0, 25, 42, 42,  5,  5,
-      10,  0, 25, 15,  0,  0,  0, 10, 42, 42,
-       0, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
-      42, 42, 42, 42, 42, 42
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 40,  5,
+       0,  0,  5, 49,  5, 20, 49, 49,  5, 20,
+       5,  0, 35, 49,  0, 15,  0, 10, 15, 49,
+      25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
+      49, 49, 49, 49, 49, 49
     };
     };
   register int hval = len;
   register int hval = len;
 
 
@@ -89,129 +87,139 @@ kconf_id_hash (register const char *str, register unsigned int len)
 struct kconf_id_strings_t
 struct kconf_id_strings_t
   {
   {
     char kconf_id_strings_str2[sizeof("on")];
     char kconf_id_strings_str2[sizeof("on")];
-    char kconf_id_strings_str3[sizeof("hex")];
-    char kconf_id_strings_str4[sizeof("bool")];
-    char kconf_id_strings_str5[sizeof("reset")];
-    char kconf_id_strings_str6[sizeof("string")];
-    char kconf_id_strings_str7[sizeof("boolean")];
+    char kconf_id_strings_str5[sizeof("endif")];
+    char kconf_id_strings_str6[sizeof("option")];
+    char kconf_id_strings_str7[sizeof("endmenu")];
     char kconf_id_strings_str8[sizeof("optional")];
     char kconf_id_strings_str8[sizeof("optional")];
-    char kconf_id_strings_str9[sizeof("help")];
-    char kconf_id_strings_str10[sizeof("endif")];
-    char kconf_id_strings_str11[sizeof("select")];
-    char kconf_id_strings_str12[sizeof("endmenu")];
-    char kconf_id_strings_str13[sizeof("deselect")];
-    char kconf_id_strings_str14[sizeof("endchoice")];
-    char kconf_id_strings_str15[sizeof("range")];
-    char kconf_id_strings_str16[sizeof("source")];
-    char kconf_id_strings_str17[sizeof("default")];
-    char kconf_id_strings_str18[sizeof("def_bool")];
-    char kconf_id_strings_str19[sizeof("menu")];
-    char kconf_id_strings_str21[sizeof("def_boolean")];
-    char kconf_id_strings_str22[sizeof("def_tristate")];
-    char kconf_id_strings_str23[sizeof("requires")];
-    char kconf_id_strings_str25[sizeof("menuconfig")];
-    char kconf_id_strings_str26[sizeof("choice")];
-    char kconf_id_strings_str27[sizeof("if")];
-    char kconf_id_strings_str28[sizeof("int")];
-    char kconf_id_strings_str31[sizeof("prompt")];
+    char kconf_id_strings_str9[sizeof("endchoice")];
+    char kconf_id_strings_str10[sizeof("range")];
+    char kconf_id_strings_str11[sizeof("choice")];
+    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str13[sizeof("def_bool")];
+    char kconf_id_strings_str14[sizeof("help")];
+    char kconf_id_strings_str16[sizeof("config")];
+    char kconf_id_strings_str17[sizeof("def_tristate")];
+    char kconf_id_strings_str18[sizeof("env")];
+    char kconf_id_strings_str19[sizeof("defconfig_list")];
+    char kconf_id_strings_str20[sizeof("reset")];
+    char kconf_id_strings_str21[sizeof("string")];
+    char kconf_id_strings_str22[sizeof("if")];
+    char kconf_id_strings_str23[sizeof("int")];
+    char kconf_id_strings_str26[sizeof("select")];
+    char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("tristate")];
+    char kconf_id_strings_str29[sizeof("menu")];
+    char kconf_id_strings_str31[sizeof("source")];
     char kconf_id_strings_str32[sizeof("comment")];
     char kconf_id_strings_str32[sizeof("comment")];
-    char kconf_id_strings_str33[sizeof("tristate")];
-    char kconf_id_strings_str36[sizeof("config")];
-    char kconf_id_strings_str37[sizeof("depends")];
-    char kconf_id_strings_str38[sizeof("mainmenu")];
-    char kconf_id_strings_str41[sizeof("enable")];
+    char kconf_id_strings_str33[sizeof("hex")];
+    char kconf_id_strings_str35[sizeof("menuconfig")];
+    char kconf_id_strings_str37[sizeof("visible")];
+    char kconf_id_strings_str41[sizeof("prompt")];
+    char kconf_id_strings_str42[sizeof("depends")];
+    char kconf_id_strings_str44[sizeof("bool")];
+    char kconf_id_strings_str47[sizeof("boolean")];
+    char kconf_id_strings_str48[sizeof("mainmenu")];
   };
   };
 static struct kconf_id_strings_t kconf_id_strings_contents =
 static struct kconf_id_strings_t kconf_id_strings_contents =
   {
   {
     "on",
     "on",
-    "hex",
-    "bool",
-    "reset",
-    "string",
-    "boolean",
-    "optional",
-    "help",
     "endif",
     "endif",
-    "select",
+    "option",
     "endmenu",
     "endmenu",
-    "deselect",
+    "optional",
     "endchoice",
     "endchoice",
     "range",
     "range",
-    "source",
+    "choice",
     "default",
     "default",
     "def_bool",
     "def_bool",
-    "menu",
-    "def_boolean",
+    "help",
+    "config",
     "def_tristate",
     "def_tristate",
-    "requires",
-    "menuconfig",
-    "choice",
+    "env",
+    "defconfig_list",
+    "reset",
+    "string",
     "if",
     "if",
     "int",
     "int",
-    "prompt",
-    "comment",
+    "select",
+    "modules",
     "tristate",
     "tristate",
-    "config",
+    "menu",
+    "source",
+    "comment",
+    "hex",
+    "menuconfig",
+    "visible",
+    "prompt",
     "depends",
     "depends",
-    "mainmenu",
-    "enable"
+    "bool",
+    "boolean",
+    "mainmenu"
   };
   };
 #define kconf_id_strings ((const char *) &kconf_id_strings_contents)
 #define kconf_id_strings ((const char *) &kconf_id_strings_contents)
 #ifdef __GNUC__
 #ifdef __GNUC__
 __inline
 __inline
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
+__attribute__ ((__gnu_inline__))
+#endif
 #endif
 #endif
 struct kconf_id *
 struct kconf_id *
 kconf_id_lookup (register const char *str, register unsigned int len)
 kconf_id_lookup (register const char *str, register unsigned int len)
 {
 {
   enum
   enum
     {
     {
-      TOTAL_KEYWORDS = 32,
+      TOTAL_KEYWORDS = 33,
       MIN_WORD_LENGTH = 2,
       MIN_WORD_LENGTH = 2,
-      MAX_WORD_LENGTH = 12,
+      MAX_WORD_LENGTH = 14,
       MIN_HASH_VALUE = 2,
       MIN_HASH_VALUE = 2,
-      MAX_HASH_VALUE = 41
+      MAX_HASH_VALUE = 48
     };
     };
 
 
   static struct kconf_id wordlist[] =
   static struct kconf_id wordlist[] =
     {
     {
       {-1}, {-1},
       {-1}, {-1},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_TYPE,		TF_COMMAND, S_HEX},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str4,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_RESET,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_TYPE,		TF_COMMAND, S_STRING},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_OPTION,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_ENDMENU,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_OPTIONAL,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_OPTIONAL,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,		T_HELP,		TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_ENDIF,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_SELECT,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_ENDMENU,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DESELECT,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,	T_ENDCHOICE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15,		T_RANGE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_SOURCE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,		T_MENU,		TF_COMMAND},
-      {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,	T_REQUIRES,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_CHOICE,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,		T_HELP,		TF_COMMAND},
       {-1},
       {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25,	T_MENUCONFIG,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_CHOICE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,		T_IF,		TF_COMMAND|TF_PARAM},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,		T_TYPE,		TF_COMMAND, S_INT},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_CONFIG,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,		T_OPT_ENV,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str20,		T_RESET,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_TYPE,		TF_COMMAND, S_STRING},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,		T_IF,		TF_COMMAND|TF_PARAM},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,		T_TYPE,		TF_COMMAND, S_INT},
       {-1}, {-1},
       {-1}, {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_SELECT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SOURCE,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,	T_TYPE,		TF_COMMAND, S_TRISTATE},
-      {-1}, {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_CONFIG,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_DEPENDS,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str38,	T_MAINMENU,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,		T_TYPE,		TF_COMMAND, S_HEX},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_VISIBLE,	TF_COMMAND},
+      {-1}, {-1}, {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_PROMPT,	TF_COMMAND},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_DEPENDS,	TF_COMMAND},
+      {-1},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str44,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
       {-1}, {-1},
       {-1}, {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_SELECT,	TF_COMMAND}
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,	T_MAINMENU,	TF_COMMAND}
     };
     };
 
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)

+ 83 - 58
scripts/config/zconf.l

@@ -1,5 +1,6 @@
-%option backup nostdinit noyywrap never-interactive full ecs
-%option 8bit backup nodefault perf-report perf-report
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault perf-report perf-report
+%option noinput
 %x COMMAND HELP STRING PARAM
 %x COMMAND HELP STRING PARAM
 %{
 %{
 /*
 /*
@@ -14,7 +15,6 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <glob.h>
 #include <glob.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 #define START_STRSIZE	16
 #define START_STRSIZE	16
@@ -39,15 +39,15 @@ static int last_ts, first_ts;
 static void zconf_endhelp(void);
 static void zconf_endhelp(void);
 static void zconf_endfile(void);
 static void zconf_endfile(void);
 
 
-void new_string(void)
+static void new_string(void)
 {
 {
-	text = malloc(START_STRSIZE);
+	text = xmalloc(START_STRSIZE);
 	text_asize = START_STRSIZE;
 	text_asize = START_STRSIZE;
 	text_size = 0;
 	text_size = 0;
 	*text = 0;
 	*text = 0;
 }
 }
 
 
-void append_string(const char *str, int size)
+static void append_string(const char *str, int size)
 {
 {
 	int new_size = text_size + size + 1;
 	int new_size = text_size + size + 1;
 	if (new_size > text_asize) {
 	if (new_size > text_asize) {
@@ -61,9 +61,9 @@ void append_string(const char *str, int size)
 	text[text_size] = 0;
 	text[text_size] = 0;
 }
 }
 
 
-void alloc_string(const char *str, int size)
+static void alloc_string(const char *str, int size)
 {
 {
-	text = malloc(size + 1);
+	text = xmalloc(size + 1);
 	memcpy(text, str, size);
 	memcpy(text, str, size);
 	text[size] = 0;
 	text[size] = 0;
 }
 }
@@ -96,7 +96,7 @@ n	[A-Za-z0-9_]
 
 
 <COMMAND>{
 <COMMAND>{
 	{n}+	{
 	{n}+	{
-		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
 		BEGIN(PARAM);
 		BEGIN(PARAM);
 		current_pos.file = current_file;
 		current_pos.file = current_file;
 		current_pos.lineno = current_file->lineno;
 		current_pos.lineno = current_file->lineno;
@@ -132,7 +132,7 @@ n	[A-Za-z0-9_]
 	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	---	/* ignore */
 	---	/* ignore */
 	({n}|[-/.])+	{
 	({n}|[-/.])+	{
-		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
 		if (id && id->flags & TF_PARAM) {
 		if (id && id->flags & TF_PARAM) {
 			zconflval.id = id;
 			zconflval.id = id;
 			return id->token;
 			return id->token;
@@ -218,6 +218,11 @@ n	[A-Za-z0-9_]
 		append_string("\n", 1);
 		append_string("\n", 1);
 	}
 	}
 	[^ \t\n].* {
 	[^ \t\n].* {
+		while (yyleng) {
+			if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t'))
+				break;
+			yyleng--;
+		}
 		append_string(yytext, yyleng);
 		append_string(yytext, yyleng);
 		if (!first_ts)
 		if (!first_ts)
 			first_ts = last_ts;
 			first_ts = last_ts;
@@ -266,7 +271,7 @@ FILE *zconf_fopen(const char *name)
 	FILE *f;
 	FILE *f;
 
 
 	f = fopen(name, "r");
 	f = fopen(name, "r");
-	if (!f && name[0] != '/') {
+	if (!f && name != NULL && name[0] != '/') {
 		env = getenv(SRCTREE);
 		env = getenv(SRCTREE);
 		if (env) {
 		if (env) {
 			sprintf(fullname, "%s/%s", env, name);
 			sprintf(fullname, "%s/%s", env, name);
@@ -284,73 +289,93 @@ void zconf_initscan(const char *name)
 		exit(1);
 		exit(1);
 	}
 	}
 
 
-	current_buf = malloc(sizeof(*current_buf));
+	current_buf = xmalloc(sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 
 
 	current_file = file_lookup(name);
 	current_file = file_lookup(name);
 	current_file->lineno = 1;
 	current_file->lineno = 1;
-	current_file->flags = FILE_BUSY;
 }
 }
 
 
-void zconf_nextfile(const char *name)
+static void __zconf_nextfile(const char *name)
 {
 {
-	size_t i;
-	int retval;
-	glob_t files;
-	char *filename;
-	struct file *file;
-	struct buffer *buf;
+	struct file *iter;
+	struct file *file = file_lookup(name);
+	struct buffer *buf = xmalloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
 
 
-	retval = glob(name, GLOB_ERR | GLOB_MARK, NULL, &files);
-	if (retval == GLOB_NOMATCH)
-		return;
-
-	if (retval == GLOB_NOSPACE || retval == GLOB_ABORTED) {
-		printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
-			retval == GLOB_NOSPACE ? "failed to allocate memory" :
-				retval == GLOB_ABORTED ? "read error" : "no match",
-			name);
+	current_buf->state = YY_CURRENT_BUFFER;
+	yyin = zconf_fopen(file->name);
+	if (!yyin) {
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
 		exit(1);
 		exit(1);
 	}
 	}
-
-	for (i = files.gl_pathc-1; i != (size_t)-1; --i) {
-		filename = files.gl_pathv[i];
-
-		file = file_lookup(filename);
-		buf = malloc(sizeof(*buf));
-		memset(buf, 0, sizeof(*buf));
-		current_buf->state = YY_CURRENT_BUFFER;
-		zconfin = zconf_fopen(filename);
-		if (!zconfin) {
-			printf("%s:%d: can't open file \"%s\"\n",
-				zconf_curname(), zconf_lineno(), filename);
+	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	for (iter = current_file->parent; iter; iter = iter->parent ) {
+		if (!strcmp(current_file->name,iter->name) ) {
+			printf("%s:%d: recursive inclusion detected. "
+			       "Inclusion path:\n  current file : '%s'\n",
+			       zconf_curname(), zconf_lineno(),
+			       zconf_curname());
+			iter = current_file->parent;
+			while (iter && \
+			       strcmp(iter->name,current_file->name)) {
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno-1);
+				iter = iter->parent;
+			}
+			if (iter)
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno+1);
 			exit(1);
 			exit(1);
 		}
 		}
-		zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
-		buf->parent = current_buf;
-		current_buf = buf;
+	}
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
 
 
-		if (file->flags & FILE_BUSY) {
-			printf("recursive scan (%s)?\n", filename);
-			exit(1);
-		}
-		if (file->flags & FILE_SCANNED) {
-			printf("file %s already scanned?\n", filename);
-			exit(1);
+void zconf_nextfile(const char *name)
+{
+	glob_t gl;
+	int err;
+	int i;
+
+	err = glob(name, GLOB_ERR | GLOB_MARK, NULL, &gl);
+	if (err) {
+		const char *reason = "unknown error";
+
+		switch (err) {
+		case GLOB_NOSPACE:
+			reason = "out of memory";
+			break;
+		case GLOB_ABORTED:
+			reason = "read error";
+			break;
+		case GLOB_NOMATCH:
+			reason = "No files found";
+			break;
+		default:
+			break;
 		}
 		}
-		file->flags |= FILE_BUSY;
-		file->lineno = 1;
-		file->parent = current_file;
-		current_file = file;
+
+		printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
+			reason, name);
+
+		exit(1);
 	}
 	}
+
+	for (i = 0; i < gl.gl_pathc; i++)
+		__zconf_nextfile(gl.gl_pathv[i]);
 }
 }
 
 
 static void zconf_endfile(void)
 static void zconf_endfile(void)
 {
 {
 	struct buffer *parent;
 	struct buffer *parent;
 
 
-	current_file->flags |= FILE_SCANNED;
-	current_file->flags &= ~FILE_BUSY;
 	current_file = current_file->parent;
 	current_file = current_file->parent;
 
 
 	parent = current_buf->parent;
 	parent = current_buf->parent;
@@ -368,7 +393,7 @@ int zconf_lineno(void)
 	return current_pos.lineno;
 	return current_pos.lineno;
 }
 }
 
 
-char *zconf_curname(void)
+const char *zconf_curname(void)
 {
 {
 	return current_pos.file ? current_pos.file->name : "<none>";
 	return current_pos.file ? current_pos.file->name : "<none>";
 }
 }

+ 231 - 116
scripts/config/lex.zconf.c_shipped → scripts/config/zconf.lex.c_shipped

@@ -1,14 +1,33 @@
 
 
-#line 3 "lex.zconf.c"
+#line 3 "zconf.lex.c"
 
 
 #define  YY_INT_ALIGNED short int
 #define  YY_INT_ALIGNED short int
 
 
 /* A lexical scanner generated by flex */
 /* A lexical scanner generated by flex */
 
 
+#define yy_create_buffer zconf_create_buffer
+#define yy_delete_buffer zconf_delete_buffer
+#define yy_flex_debug zconf_flex_debug
+#define yy_init_buffer zconf_init_buffer
+#define yy_flush_buffer zconf_flush_buffer
+#define yy_load_buffer_state zconf_load_buffer_state
+#define yy_switch_to_buffer zconf_switch_to_buffer
+#define yyin zconfin
+#define yyleng zconfleng
+#define yylex zconflex
+#define yylineno zconflineno
+#define yyout zconfout
+#define yyrestart zconfrestart
+#define yytext zconftext
+#define yywrap zconfwrap
+#define yyalloc zconfalloc
+#define yyrealloc zconfrealloc
+#define yyfree zconffree
+
 #define FLEX_SCANNER
 #define FLEX_SCANNER
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MAJOR_VERSION 2
 #define YY_FLEX_MINOR_VERSION 5
 #define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 31
+#define YY_FLEX_SUBMINOR_VERSION 37
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #if YY_FLEX_SUBMINOR_VERSION > 0
 #define FLEX_BETA
 #define FLEX_BETA
 #endif
 #endif
@@ -30,7 +49,15 @@
 
 
 /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
 /* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
 
 
-#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types. 
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
 #include <inttypes.h>
 #include <inttypes.h>
 typedef int8_t flex_int8_t;
 typedef int8_t flex_int8_t;
 typedef uint8_t flex_uint8_t;
 typedef uint8_t flex_uint8_t;
@@ -45,7 +72,6 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
 typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
 
 
 /* Limits of integral types. */
 /* Limits of integral types. */
 #ifndef INT8_MIN
 #ifndef INT8_MIN
@@ -76,6 +102,8 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #define UINT32_MAX             (4294967295U)
 #endif
 #endif
 
 
+#endif /* ! C99 */
+
 #endif /* ! FLEXINT_H */
 #endif /* ! FLEXINT_H */
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -85,11 +113,12 @@ typedef unsigned int flex_uint32_t;
 
 
 #else	/* ! __cplusplus */
 #else	/* ! __cplusplus */
 
 
-#if __STDC__
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
 
 
 #define YY_USE_CONST
 #define YY_USE_CONST
 
 
-#endif	/* __STDC__ */
+#endif	/* defined (__STDC__) */
 #endif	/* ! __cplusplus */
 #endif	/* ! __cplusplus */
 
 
 #ifdef YY_USE_CONST
 #ifdef YY_USE_CONST
@@ -134,12 +163,21 @@ typedef unsigned int flex_uint32_t;
 #define YY_BUF_SIZE 16384
 #define YY_BUF_SIZE 16384
 #endif
 #endif
 
 
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
 #define YY_TYPEDEF_YY_BUFFER_STATE
 #define YY_TYPEDEF_YY_BUFFER_STATE
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
 typedef struct yy_buffer_state *YY_BUFFER_STATE;
 #endif
 #endif
 
 
-extern int zconfleng;
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t zconfleng;
 
 
 extern FILE *zconfin, *zconfout;
 extern FILE *zconfin, *zconfout;
 
 
@@ -165,16 +203,6 @@ extern FILE *zconfin, *zconfout;
 
 
 #define unput(c) yyunput( c, (yytext_ptr)  )
 #define unput(c) yyunput( c, (yytext_ptr)  )
 
 
-/* The following is because we cannot portably get our hands on size_t
- * (without autoconf's help, which isn't available because we want
- * flex-generated scanners to compile on their own).
- */
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef unsigned int yy_size_t;
-#endif
-
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #ifndef YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 #define YY_STRUCT_YY_BUFFER_STATE
 struct yy_buffer_state
 struct yy_buffer_state
@@ -192,7 +220,7 @@ struct yy_buffer_state
 	/* Number of characters read into yy_ch_buf, not including EOB
 	/* Number of characters read into yy_ch_buf, not including EOB
 	 * characters.
 	 * characters.
 	 */
 	 */
-	int yy_n_chars;
+	yy_size_t yy_n_chars;
 
 
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	/* Whether we "own" the buffer - i.e., we know we created it,
 	 * and can realloc() it to grow it, and should free() it to
 	 * and can realloc() it to grow it, and should free() it to
@@ -262,12 +290,12 @@ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
 
 
 /* yy_hold_char holds the character lost when zconftext is formed. */
 /* yy_hold_char holds the character lost when zconftext is formed. */
 static char yy_hold_char;
 static char yy_hold_char;
-static int yy_n_chars;		/* number of characters read into yy_ch_buf */
-int zconfleng;
+static yy_size_t yy_n_chars;		/* number of characters read into yy_ch_buf */
+yy_size_t zconfleng;
 
 
 /* Points to current character in buffer. */
 /* Points to current character in buffer. */
 static char *yy_c_buf_p = (char *) 0;
 static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 1;		/* whether we need to initialize */
+static int yy_init = 0;		/* whether we need to initialize */
 static int yy_start = 0;	/* start state number */
 static int yy_start = 0;	/* start state number */
 
 
 /* Flag which is used to allow zconfwrap()'s to do buffer switches
 /* Flag which is used to allow zconfwrap()'s to do buffer switches
@@ -291,7 +319,7 @@ static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file  );
 
 
 YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
 YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size  );
 YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
 YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str  );
-YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len  );
+YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,yy_size_t len  );
 
 
 void *zconfalloc (yy_size_t  );
 void *zconfalloc (yy_size_t  );
 void *zconfrealloc (void *,yy_size_t  );
 void *zconfrealloc (void *,yy_size_t  );
@@ -323,7 +351,7 @@ void zconffree (void *  );
 
 
 /* Begin user sect3 */
 /* Begin user sect3 */
 
 
-#define zconfwrap(n) 1
+#define zconfwrap() 1
 #define YY_SKIP_YYWRAP
 #define YY_SKIP_YYWRAP
 
 
 typedef unsigned char YY_CHAR;
 typedef unsigned char YY_CHAR;
@@ -736,6 +764,7 @@ int zconf_flex_debug = 0;
 #define YY_MORE_ADJ 0
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
 #define YY_RESTORE_YY_MORE_OFFSET
 char *zconftext;
 char *zconftext;
+#define YY_NO_INPUT 1
 
 
 /*
 /*
  * Copyright (C) 2002 Roman Zippel <[email protected]>
  * Copyright (C) 2002 Roman Zippel <[email protected]>
@@ -749,7 +778,6 @@ char *zconftext;
 #include <unistd.h>
 #include <unistd.h>
 #include <glob.h>
 #include <glob.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 #define START_STRSIZE	16
 #define START_STRSIZE	16
@@ -774,15 +802,15 @@ static int last_ts, first_ts;
 static void zconf_endhelp(void);
 static void zconf_endhelp(void);
 static void zconf_endfile(void);
 static void zconf_endfile(void);
 
 
-void new_string(void)
+static void new_string(void)
 {
 {
-	text = malloc(START_STRSIZE);
+	text = xmalloc(START_STRSIZE);
 	text_asize = START_STRSIZE;
 	text_asize = START_STRSIZE;
 	text_size = 0;
 	text_size = 0;
 	*text = 0;
 	*text = 0;
 }
 }
 
 
-void append_string(const char *str, int size)
+static void append_string(const char *str, int size)
 {
 {
 	int new_size = text_size + size + 1;
 	int new_size = text_size + size + 1;
 	if (new_size > text_asize) {
 	if (new_size > text_asize) {
@@ -796,9 +824,9 @@ void append_string(const char *str, int size)
 	text[text_size] = 0;
 	text[text_size] = 0;
 }
 }
 
 
-void alloc_string(const char *str, int size)
+static void alloc_string(const char *str, int size)
 {
 {
-	text = malloc(size + 1);
+	text = xmalloc(size + 1);
 	memcpy(text, str, size);
 	memcpy(text, str, size);
 	text[size] = 0;
 	text[size] = 0;
 }
 }
@@ -821,6 +849,37 @@ void alloc_string(const char *str, int size)
 #define YY_EXTRA_TYPE void *
 #define YY_EXTRA_TYPE void *
 #endif
 #endif
 
 
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+   These are made visible to non-reentrant scanners for convenience. */
+
+int zconflex_destroy (void );
+
+int zconfget_debug (void );
+
+void zconfset_debug (int debug_flag  );
+
+YY_EXTRA_TYPE zconfget_extra (void );
+
+void zconfset_extra (YY_EXTRA_TYPE user_defined  );
+
+FILE *zconfget_in (void );
+
+void zconfset_in  (FILE * in_str  );
+
+FILE *zconfget_out (void );
+
+void zconfset_out  (FILE * out_str  );
+
+yy_size_t zconfget_leng (void );
+
+char *zconfget_text (void );
+
+int zconfget_lineno (void );
+
+void zconfset_lineno (int line_number  );
+
 /* Macros after this point can all be overridden by user definitions in
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
  * section 1.
  */
  */
@@ -863,7 +922,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  * we now use fwrite().
  */
  */
-#define ECHO (void) fwrite( zconftext, zconfleng, 1, zconfout )
+#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
 #endif
 #endif
 
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -943,9 +1002,9 @@ YY_DECL
 	int str = 0;
 	int str = 0;
 	int ts, i;
 	int ts, i;
 
 
-	if ( (yy_init) )
+	if ( !(yy_init) )
 		{
 		{
-		(yy_init) = 0;
+		(yy_init) = 1;
 
 
 #ifdef YY_USER_INIT
 #ifdef YY_USER_INIT
 		YY_USER_INIT;
 		YY_USER_INIT;
@@ -1028,7 +1087,7 @@ YY_RULE_SETUP
 case 6:
 case 6:
 YY_RULE_SETUP
 YY_RULE_SETUP
 {
 {
-		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
 		BEGIN(PARAM);
 		BEGIN(PARAM);
 		current_pos.file = current_file;
 		current_pos.file = current_file;
 		current_pos.lineno = current_file->lineno;
 		current_pos.lineno = current_file->lineno;
@@ -1103,7 +1162,7 @@ YY_RULE_SETUP
 case 19:
 case 19:
 YY_RULE_SETUP
 YY_RULE_SETUP
 {
 {
-		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
 		if (id && id->flags & TF_PARAM) {
 		if (id && id->flags & TF_PARAM) {
 			zconflval.id = id;
 			zconflval.id = id;
 			return id->token;
 			return id->token;
@@ -1243,6 +1302,11 @@ YY_RULE_SETUP
 case 32:
 case 32:
 YY_RULE_SETUP
 YY_RULE_SETUP
 {
 {
+		while (zconfleng) {
+			if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
+				break;
+			zconfleng--;
+		}
 		append_string(zconftext, zconfleng);
 		append_string(zconftext, zconfleng);
 		if (!first_ts)
 		if (!first_ts)
 			first_ts = last_ts;
 			first_ts = last_ts;
@@ -1453,21 +1517,21 @@ static int yy_get_next_buffer (void)
 
 
 	else
 	else
 		{
 		{
-			size_t num_to_read =
+			yy_size_t num_to_read =
 			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 			YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
 
 
 		while ( num_to_read <= 0 )
 		while ( num_to_read <= 0 )
 			{ /* Not enough room in the buffer - grow it. */
 			{ /* Not enough room in the buffer - grow it. */
 
 
 			/* just a shorter name for the current buffer */
 			/* just a shorter name for the current buffer */
-			YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
+			YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
 
 
 			int yy_c_buf_p_offset =
 			int yy_c_buf_p_offset =
 				(int) ((yy_c_buf_p) - b->yy_ch_buf);
 				(int) ((yy_c_buf_p) - b->yy_ch_buf);
 
 
 			if ( b->yy_is_our_buffer )
 			if ( b->yy_is_our_buffer )
 				{
 				{
-				int new_size = b->yy_buf_size * 2;
+				yy_size_t new_size = b->yy_buf_size * 2;
 
 
 				if ( new_size <= 0 )
 				if ( new_size <= 0 )
 					b->yy_buf_size += b->yy_buf_size / 8;
 					b->yy_buf_size += b->yy_buf_size / 8;
@@ -1522,6 +1586,14 @@ static int yy_get_next_buffer (void)
 	else
 	else
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 		ret_val = EOB_ACT_CONTINUE_SCAN;
 
 
+	if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+		/* Extend the array by 50%, plus the number we really need. */
+		yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+		YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
+		if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+			YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+	}
+
 	(yy_n_chars) += number_to_move;
 	(yy_n_chars) += number_to_move;
 	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
 	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
 	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
 	YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
@@ -1560,7 +1632,7 @@ static int yy_get_next_buffer (void)
 	yy_current_state = yy_nxt[yy_current_state][1];
 	yy_current_state = yy_nxt[yy_current_state][1];
 	yy_is_jam = (yy_current_state <= 0);
 	yy_is_jam = (yy_current_state <= 0);
 
 
-	return yy_is_jam ? 0 : yy_current_state;
+		return yy_is_jam ? 0 : yy_current_state;
 }
 }
 
 
     static void yyunput (int c, register char * yy_bp )
     static void yyunput (int c, register char * yy_bp )
@@ -1575,7 +1647,7 @@ static int yy_get_next_buffer (void)
 	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
 	if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
 		{ /* need to shift things up to make room */
 		{ /* need to shift things up to make room */
 		/* +2 for EOB chars. */
 		/* +2 for EOB chars. */
-		register int number_to_move = (yy_n_chars) + 2;
+		register yy_size_t number_to_move = (yy_n_chars) + 2;
 		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
 		register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
 					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
 					YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
 		register char *source =
 		register char *source =
@@ -1624,7 +1696,7 @@ static int yy_get_next_buffer (void)
 
 
 		else
 		else
 			{ /* need more input */
 			{ /* need more input */
-			int offset = (yy_c_buf_p) - (yytext_ptr);
+			yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
 			++(yy_c_buf_p);
 			++(yy_c_buf_p);
 
 
 			switch ( yy_get_next_buffer(  ) )
 			switch ( yy_get_next_buffer(  ) )
@@ -1896,7 +1968,7 @@ void zconfpop_buffer_state (void)
  */
  */
 static void zconfensure_buffer_stack (void)
 static void zconfensure_buffer_stack (void)
 {
 {
-	int num_to_alloc;
+	yy_size_t num_to_alloc;
     
     
 	if (!(yy_buffer_stack)) {
 	if (!(yy_buffer_stack)) {
 
 
@@ -1908,7 +1980,9 @@ static void zconfensure_buffer_stack (void)
 		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
 		(yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								(num_to_alloc * sizeof(struct yy_buffer_state*)
 								);
 								);
-		
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
+								  
 		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
 		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
 				
 				
 		(yy_buffer_stack_max) = num_to_alloc;
 		(yy_buffer_stack_max) = num_to_alloc;
@@ -1926,6 +2000,8 @@ static void zconfensure_buffer_stack (void)
 								((yy_buffer_stack),
 								((yy_buffer_stack),
 								num_to_alloc * sizeof(struct yy_buffer_state*)
 								num_to_alloc * sizeof(struct yy_buffer_state*)
 								);
 								);
+		if ( ! (yy_buffer_stack) )
+			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
 
 
 		/* zero only the new slots.*/
 		/* zero only the new slots.*/
 		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
 		memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -1970,26 +2046,26 @@ YY_BUFFER_STATE zconf_scan_buffer  (char * base, yy_size_t  size )
 
 
 /** Setup the input buffer state to scan a string. The next call to zconflex() will
 /** Setup the input buffer state to scan a string. The next call to zconflex() will
  * scan from a @e copy of @a str.
  * scan from a @e copy of @a str.
- * @param str a NUL-terminated string to scan
+ * @param yystr a NUL-terminated string to scan
  * 
  * 
  * @return the newly allocated buffer state object.
  * @return the newly allocated buffer state object.
  * @note If you want to scan bytes that may contain NUL values, then use
  * @note If you want to scan bytes that may contain NUL values, then use
  *       zconf_scan_bytes() instead.
  *       zconf_scan_bytes() instead.
  */
  */
-YY_BUFFER_STATE zconf_scan_string (yyconst char * yy_str )
+YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
 {
 {
     
     
-	return zconf_scan_bytes(yy_str,strlen(yy_str) );
+	return zconf_scan_bytes(yystr,strlen(yystr) );
 }
 }
 
 
 /** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
 /** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
  * scan from a @e copy of @a bytes.
  * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
  * 
  * 
  * @return the newly allocated buffer state object.
  * @return the newly allocated buffer state object.
  */
  */
-YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * bytes, int  len )
+YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * yybytes, yy_size_t  _yybytes_len )
 {
 {
 	YY_BUFFER_STATE b;
 	YY_BUFFER_STATE b;
 	char *buf;
 	char *buf;
@@ -1997,15 +2073,15 @@ YY_BUFFER_STATE zconf_scan_bytes  (yyconst char * bytes, int  len )
 	int i;
 	int i;
     
     
 	/* Get memory for full buffer, including space for trailing EOB's. */
 	/* Get memory for full buffer, including space for trailing EOB's. */
-	n = len + 2;
+	n = _yybytes_len + 2;
 	buf = (char *) zconfalloc(n  );
 	buf = (char *) zconfalloc(n  );
 	if ( ! buf )
 	if ( ! buf )
 		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
 		YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
 
 
-	for ( i = 0; i < len; ++i )
-		buf[i] = bytes[i];
+	for ( i = 0; i < _yybytes_len; ++i )
+		buf[i] = yybytes[i];
 
 
-	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+	buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
 
 
 	b = zconf_scan_buffer(buf,n );
 	b = zconf_scan_buffer(buf,n );
 	if ( ! b )
 	if ( ! b )
@@ -2076,7 +2152,7 @@ FILE *zconfget_out  (void)
 /** Get the length of the current token.
 /** Get the length of the current token.
  * 
  * 
  */
  */
-int zconfget_leng  (void)
+yy_size_t zconfget_leng  (void)
 {
 {
         return zconfleng;
         return zconfleng;
 }
 }
@@ -2126,6 +2202,34 @@ void zconfset_debug (int  bdebug )
         zconf_flex_debug = bdebug ;
         zconf_flex_debug = bdebug ;
 }
 }
 
 
+static int yy_init_globals (void)
+{
+        /* Initialization is the same as for the non-reentrant scanner.
+     * This function is called from zconflex_destroy(), so don't allocate here.
+     */
+
+    (yy_buffer_stack) = 0;
+    (yy_buffer_stack_top) = 0;
+    (yy_buffer_stack_max) = 0;
+    (yy_c_buf_p) = (char *) 0;
+    (yy_init) = 0;
+    (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+    zconfin = stdin;
+    zconfout = stdout;
+#else
+    zconfin = (FILE *) 0;
+    zconfout = (FILE *) 0;
+#endif
+
+    /* For future reference: Set errno on error, since we are called by
+     * zconflex_init()
+     */
+    return 0;
+}
+
 /* zconflex_destroy is for both reentrant and non-reentrant scanners. */
 /* zconflex_destroy is for both reentrant and non-reentrant scanners. */
 int zconflex_destroy  (void)
 int zconflex_destroy  (void)
 {
 {
@@ -2141,6 +2245,10 @@ int zconflex_destroy  (void)
 	zconffree((yy_buffer_stack) );
 	zconffree((yy_buffer_stack) );
 	(yy_buffer_stack) = NULL;
 	(yy_buffer_stack) = NULL;
 
 
+    /* Reset the globals. This is important in a non-reentrant scanner so the next time
+     * zconflex() is called, initialization will occur. */
+    yy_init_globals( );
+
     return 0;
     return 0;
 }
 }
 
 
@@ -2152,7 +2260,7 @@ int zconflex_destroy  (void)
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 {
 {
 	register int i;
 	register int i;
-    	for ( i = 0; i < n; ++i )
+	for ( i = 0; i < n; ++i )
 		s1[i] = s2[i];
 		s1[i] = s2[i];
 }
 }
 #endif
 #endif
@@ -2161,7 +2269,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
 static int yy_flex_strlen (yyconst char * s )
 static int yy_flex_strlen (yyconst char * s )
 {
 {
 	register int n;
 	register int n;
-    	for ( n = 0; s[n]; ++n )
+	for ( n = 0; s[n]; ++n )
 		;
 		;
 
 
 	return n;
 	return n;
@@ -2192,19 +2300,6 @@ void zconffree (void * ptr )
 
 
 #define YYTABLES_NAME "yytables"
 #define YYTABLES_NAME "yytables"
 
 
-#undef YY_NEW_FILE
-#undef YY_FLUSH_BUFFER
-#undef yy_set_bol
-#undef yy_new_buffer
-#undef yy_set_interactive
-#undef yytext_ptr
-#undef YY_DO_BEFORE_ACTION
-
-#ifdef YY_DECL_IS_OURS
-#undef YY_DECL_IS_OURS
-#undef YY_DECL
-#endif
-
 void zconf_starthelp(void)
 void zconf_starthelp(void)
 {
 {
 	new_string();
 	new_string();
@@ -2232,7 +2327,7 @@ FILE *zconf_fopen(const char *name)
 	FILE *f;
 	FILE *f;
 
 
 	f = fopen(name, "r");
 	f = fopen(name, "r");
-	if (!f && name[0] != '/') {
+	if (!f && name != NULL && name[0] != '/') {
 		env = getenv(SRCTREE);
 		env = getenv(SRCTREE);
 		if (env) {
 		if (env) {
 			sprintf(fullname, "%s/%s", env, name);
 			sprintf(fullname, "%s/%s", env, name);
@@ -2250,73 +2345,93 @@ void zconf_initscan(const char *name)
 		exit(1);
 		exit(1);
 	}
 	}
 
 
-	current_buf = malloc(sizeof(*current_buf));
+	current_buf = xmalloc(sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 
 
 	current_file = file_lookup(name);
 	current_file = file_lookup(name);
 	current_file->lineno = 1;
 	current_file->lineno = 1;
-	current_file->flags = FILE_BUSY;
 }
 }
 
 
-void zconf_nextfile(const char *name)
+static void __zconf_nextfile(const char *name)
 {
 {
-	size_t i;
-	int retval;
-	glob_t files;
-	char *filename;
-	struct file *file;
-	struct buffer *buf;
-
-	retval = glob(name, GLOB_ERR | GLOB_MARK, NULL, &files);
-	if (retval == GLOB_NOMATCH)
-		return;
+	struct file *iter;
+	struct file *file = file_lookup(name);
+	struct buffer *buf = xmalloc(sizeof(*buf));
+	memset(buf, 0, sizeof(*buf));
 
 
-	if (retval == GLOB_NOSPACE || retval == GLOB_ABORTED) {
-		printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
-			retval == GLOB_NOSPACE ? "failed to allocate memory" :
-				retval == GLOB_ABORTED ? "read error" : "no match",
-			name);
+	current_buf->state = YY_CURRENT_BUFFER;
+	zconfin = zconf_fopen(file->name);
+	if (!zconfin) {
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
 		exit(1);
 		exit(1);
 	}
 	}
-
-	for (i = files.gl_pathc-1; i != (size_t)-1; --i) {
-		filename = files.gl_pathv[i];
-
-		file = file_lookup(filename);
-		buf = malloc(sizeof(*buf));
-		memset(buf, 0, sizeof(*buf));
-		current_buf->state = YY_CURRENT_BUFFER;
-		zconfin = zconf_fopen(filename);
-		if (!zconfin) {
-			printf("%s:%d: can't open file \"%s\"\n",
-				zconf_curname(), zconf_lineno(), filename);
+	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
+	buf->parent = current_buf;
+	current_buf = buf;
+
+	for (iter = current_file->parent; iter; iter = iter->parent ) {
+		if (!strcmp(current_file->name,iter->name) ) {
+			printf("%s:%d: recursive inclusion detected. "
+			       "Inclusion path:\n  current file : '%s'\n",
+			       zconf_curname(), zconf_lineno(),
+			       zconf_curname());
+			iter = current_file->parent;
+			while (iter && \
+			       strcmp(iter->name,current_file->name)) {
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno-1);
+				iter = iter->parent;
+			}
+			if (iter)
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno+1);
 			exit(1);
 			exit(1);
 		}
 		}
-		zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
-		buf->parent = current_buf;
-		current_buf = buf;
+	}
+	file->lineno = 1;
+	file->parent = current_file;
+	current_file = file;
+}
 
 
-		if (file->flags & FILE_BUSY) {
-			printf("recursive scan (%s)?\n", filename);
-			exit(1);
-		}
-		if (file->flags & FILE_SCANNED) {
-			printf("file %s already scanned?\n", filename);
-			exit(1);
+void zconf_nextfile(const char *name)
+{
+	glob_t gl;
+	int err;
+	int i;
+
+	err = glob(name, GLOB_ERR | GLOB_MARK, NULL, &gl);
+	if (err) {
+		const char *reason = "unknown error";
+
+		switch (err) {
+		case GLOB_NOSPACE:
+			reason = "out of memory";
+			break;
+		case GLOB_ABORTED:
+			reason = "read error";
+			break;
+		case GLOB_NOMATCH:
+			reason = "No files found";
+			break;
+		default:
+			break;
 		}
 		}
-		file->flags |= FILE_BUSY;
-		file->lineno = 1;
-		file->parent = current_file;
-		current_file = file;
+
+		printf("%s:%d: glob failed: %s \"%s\"\n", zconf_curname(), zconf_lineno(),
+			reason, name);
+
+		exit(1);
 	}
 	}
+
+	for (i = 0; i < gl.gl_pathc; i++)
+		__zconf_nextfile(gl.gl_pathv[i]);
 }
 }
 
 
 static void zconf_endfile(void)
 static void zconf_endfile(void)
 {
 {
 	struct buffer *parent;
 	struct buffer *parent;
 
 
-	current_file->flags |= FILE_SCANNED;
-	current_file->flags &= ~FILE_BUSY;
 	current_file = current_file->parent;
 	current_file = current_file->parent;
 
 
 	parent = current_buf->parent;
 	parent = current_buf->parent;
@@ -2334,7 +2449,7 @@ int zconf_lineno(void)
 	return current_pos.lineno;
 	return current_pos.lineno;
 }
 }
 
 
-char *zconf_curname(void)
+const char *zconf_curname(void)
 {
 {
 	return current_pos.file ? current_pos.file->name : "<none>";
 	return current_pos.file ? current_pos.file->name : "<none>";
 }
 }

File diff suppressed because it is too large
+ 462 - 335
scripts/config/zconf.tab.c_shipped


+ 113 - 59
scripts/config/zconf.y

@@ -11,11 +11,8 @@
 #include <string.h>
 #include <string.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
-#include "zconf.hash.c"
-
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
 
 #define PRINTD		0x0001
 #define PRINTD		0x0001
@@ -27,18 +24,14 @@ extern int zconflex(void);
 static void zconfprint(const char *err, ...);
 static void zconfprint(const char *err, ...);
 static void zconf_error(const char *err, ...);
 static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
 static void zconferror(const char *err);
-static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
 
 
-struct symbol *symbol_hash[257];
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
 
 
 static struct menu *current_menu, *current_entry;
 static struct menu *current_menu, *current_entry;
 
 
-#define YYDEBUG 0
-#if YYDEBUG
-#define YYERROR_VERBOSE
-#endif
 %}
 %}
-%expect 26
+%expect 30
 
 
 %union
 %union
 {
 {
@@ -47,7 +40,7 @@ static struct menu *current_menu, *current_entry;
 	struct symbol *symbol;
 	struct symbol *symbol;
 	struct expr *expr;
 	struct expr *expr;
 	struct menu *menu;
 	struct menu *menu;
-	struct kconf_id *id;
+	const struct kconf_id *id;
 }
 }
 
 
 %token <id>T_MAINMENU
 %token <id>T_MAINMENU
@@ -64,14 +57,14 @@ static struct menu *current_menu, *current_entry;
 %token <id>T_IF
 %token <id>T_IF
 %token <id>T_ENDIF
 %token <id>T_ENDIF
 %token <id>T_DEPENDS
 %token <id>T_DEPENDS
-%token <id>T_REQUIRES
 %token <id>T_OPTIONAL
 %token <id>T_OPTIONAL
 %token <id>T_PROMPT
 %token <id>T_PROMPT
 %token <id>T_TYPE
 %token <id>T_TYPE
 %token <id>T_DEFAULT
 %token <id>T_DEFAULT
-%token <id>T_DESELECT
 %token <id>T_SELECT
 %token <id>T_SELECT
 %token <id>T_RANGE
 %token <id>T_RANGE
+%token <id>T_VISIBLE
+%token <id>T_OPTION
 %token <id>T_ON
 %token <id>T_ON
 %token <id>T_RESET
 %token <id>T_RESET
 %token <string> T_WORD
 %token <string> T_WORD
@@ -93,6 +86,7 @@ static struct menu *current_menu, *current_entry;
 %type <id> end
 %type <id> end
 %type <id> option_name
 %type <id> option_name
 %type <menu> if_entry menu_entry choice_entry
 %type <menu> if_entry menu_entry choice_entry
+%type <string> symbol_option_arg word_opt
 
 
 %destructor {
 %destructor {
 	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
 	fprintf(stderr, "%s:%d: missing end statement for this entry\n",
@@ -101,15 +95,21 @@ static struct menu *current_menu, *current_entry;
 		menu_end_menu();
 		menu_end_menu();
 } if_entry menu_entry choice_entry
 } if_entry menu_entry choice_entry
 
 
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+%}
+
 %%
 %%
-input: stmt_list;
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
 
 
 stmt_list:
 stmt_list:
 	  /* empty */
 	  /* empty */
 	| stmt_list common_stmt
 	| stmt_list common_stmt
 	| stmt_list choice_stmt
 	| stmt_list choice_stmt
 	| stmt_list menu_stmt
 	| stmt_list menu_stmt
-	| stmt_list T_MAINMENU prompt nl
 	| stmt_list end			{ zconf_error("unexpected end statement"); }
 	| stmt_list end			{ zconf_error("unexpected end statement"); }
 	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
 	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
 	| stmt_list option_name error T_EOL
 	| stmt_list option_name error T_EOL
@@ -120,7 +120,7 @@ stmt_list:
 ;
 ;
 
 
 option_name:
 option_name:
-	T_DEPENDS | T_PROMPT | T_TYPE | T_DESELECT | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_RESET
+	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE | T_RESET
 ;
 ;
 
 
 common_stmt:
 common_stmt:
@@ -175,6 +175,7 @@ menuconfig_stmt: menuconfig_entry_start config_option_list
 config_option_list:
 config_option_list:
 	  /* empty */
 	  /* empty */
 	| config_option_list config_option
 	| config_option_list config_option
+	| config_option_list symbol_option
 	| config_option_list depends
 	| config_option_list depends
 	| config_option_list help
 	| config_option_list help
 	| config_option_list option_error
 	| config_option_list option_error
@@ -205,12 +206,6 @@ config_option: T_DEFAULT expr if_expr T_EOL
 		$1->stype);
 		$1->stype);
 };
 };
 
 
-config_option: T_DESELECT T_WORD if_expr T_EOL
-{
-	menu_add_symbol(P_DESELECT, sym_lookup($2, 0), $3);
-	printd(DEBUG_PARSE, "%s:%d:deselect\n", zconf_curname(), zconf_lineno());
-};
-
 config_option: T_SELECT T_WORD if_expr T_EOL
 config_option: T_SELECT T_WORD if_expr T_EOL
 {
 {
 	menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
 	menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3);
@@ -223,12 +218,32 @@ config_option: T_RANGE symbol symbol if_expr T_EOL
 	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
 	printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
 };
 };
 
 
+symbol_option: T_OPTION symbol_option_list T_EOL
+;
+
+symbol_option_list:
+	  /* empty */
+	| symbol_option_list T_WORD symbol_option_arg
+{
+	const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+	if (id && id->flags & TF_OPTION)
+		menu_add_option(id->token, $3);
+	else
+		zconfprint("warning: ignoring unknown option %s", $2);
+	free($2);
+};
+
+symbol_option_arg:
+	  /* empty */		{ $$ = NULL; }
+	| T_EQUAL prompt	{ $$ = $2; }
+;
+
 /* choice entry */
 /* choice entry */
 
 
-choice: T_CHOICE T_EOL
+choice: T_CHOICE word_opt T_EOL
 {
 {
-	struct symbol *sym = sym_lookup(NULL, 0);
-	sym->flags |= SYMBOL_CHOICE;
+	struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
+	sym->flags |= SYMBOL_AUTO;
 	menu_add_entry(sym);
 	menu_add_entry(sym);
 	menu_add_expr(P_CHOICE, NULL, NULL);
 	menu_add_expr(P_CHOICE, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
 	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
@@ -330,6 +345,13 @@ if_block:
 	| if_block choice_stmt
 	| if_block choice_stmt
 ;
 ;
 
 
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+	menu_add_prompt(P_MENU, $2, NULL);
+};
+
 /* menu entry */
 /* menu entry */
 
 
 menu: T_MENU prompt T_EOL
 menu: T_MENU prompt T_EOL
@@ -339,7 +361,7 @@ menu: T_MENU prompt T_EOL
 	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 };
 };
 
 
-menu_entry: menu depends_list
+menu_entry: menu visibility_list depends_list
 {
 {
 	$$ = menu_add_menu();
 	$$ = menu_add_menu();
 };
 };
@@ -392,7 +414,7 @@ help_start: T_HELP T_EOL
 
 
 help: help_start T_HELPTEXT
 help: help_start T_HELPTEXT
 {
 {
-	current_entry->sym->help = $2;
+	current_entry->help = $2;
 };
 };
 
 
 /* depends option */
 /* depends option */
@@ -408,16 +430,19 @@ depends: T_DEPENDS T_ON expr T_EOL
 {
 {
 	menu_add_dep($3);
 	menu_add_dep($3);
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
-}
-	| T_DEPENDS expr T_EOL
-{
-	menu_add_dep($2);
-	printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
-}
-	| T_REQUIRES expr T_EOL
+};
+
+/* visibility option */
+
+visibility_list:
+	  /* empty */
+	| visibility_list visible
+	| visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
 {
 {
-	menu_add_dep($2);
-	printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
+	menu_add_visibility($2);
 };
 };
 
 
 /* prompt statement */
 /* prompt statement */
@@ -457,9 +482,12 @@ expr:	  symbol				{ $$ = expr_alloc_symbol($1); }
 ;
 ;
 
 
 symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); }
 symbol:	  T_WORD	{ $$ = sym_lookup($1, 0); free($1); }
-	| T_WORD_QUOTE	{ $$ = sym_lookup($1, 1); free($1); }
+	| T_WORD_QUOTE	{ $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
 ;
 ;
 
 
+word_opt: /* empty */			{ $$ = NULL; }
+	| T_WORD
+
 %%
 %%
 
 
 void conf_parse(const char *name)
 void conf_parse(const char *name)
@@ -470,9 +498,11 @@ void conf_parse(const char *name)
 	zconf_initscan(name);
 	zconf_initscan(name);
 
 
 	sym_init();
 	sym_init();
-	menu_init();
-	modules_sym = sym_lookup("MODULES", 0);
-	rootmenu.prompt = menu_add_prompt(P_MENU, "OpenWrt Configuration", NULL);
+	_menu_init();
+	modules_sym = sym_lookup(NULL, 0);
+	modules_sym->type = S_BOOLEAN;
+	modules_sym->flags |= SYMBOL_AUTO;
+	rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
 
 #if YYDEBUG
 #if YYDEBUG
 	if (getenv("ZCONF_DEBUG"))
 	if (getenv("ZCONF_DEBUG"))
@@ -481,15 +511,27 @@ void conf_parse(const char *name)
 	zconfparse();
 	zconfparse();
 	if (zconfnerrs)
 	if (zconfnerrs)
 		exit(1);
 		exit(1);
+	if (!modules_sym->prop) {
+		struct property *prop;
+
+		prop = prop_alloc(P_DEFAULT, modules_sym);
+		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
+	}
+
+	rootmenu.prompt->text = _(rootmenu.prompt->text);
+	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
 	menu_finalize(&rootmenu);
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
 	for_all_symbols(i, sym) {
-		sym_check_deps(sym);
+		if (sym_check_deps(sym))
+			zconfnerrs++;
         }
         }
-
-	sym_change_count = 1;
+	if (zconfnerrs)
+		exit(1);
+	sym_set_change_count(1);
 }
 }
 
 
-const char *zconf_tokenname(int token)
+static const char *zconf_tokenname(int token)
 {
 {
 	switch (token) {
 	switch (token) {
 	case T_MENU:		return "menu";
 	case T_MENU:		return "menu";
@@ -499,11 +541,12 @@ const char *zconf_tokenname(int token)
 	case T_IF:		return "if";
 	case T_IF:		return "if";
 	case T_ENDIF:		return "endif";
 	case T_ENDIF:		return "endif";
 	case T_DEPENDS:		return "depends";
 	case T_DEPENDS:		return "depends";
+	case T_VISIBLE:		return "visible";
 	}
 	}
 	return "<token>";
 	return "<token>";
 }
 }
 
 
-static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
 {
 {
 	if (id->token != endtoken) {
 	if (id->token != endtoken) {
 		zconf_error("unexpected '%s' within %s block",
 		zconf_error("unexpected '%s' within %s block",
@@ -548,12 +591,10 @@ static void zconf_error(const char *err, ...)
 
 
 static void zconferror(const char *err)
 static void zconferror(const char *err)
 {
 {
-#if YYDEBUG
 	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
 	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
-#endif
 }
 }
 
 
-void print_quoted_string(FILE *out, const char *str)
+static void print_quoted_string(FILE *out, const char *str)
 {
 {
 	const char *p;
 	const char *p;
 	int len;
 	int len;
@@ -570,15 +611,15 @@ void print_quoted_string(FILE *out, const char *str)
 	putc('"', out);
 	putc('"', out);
 }
 }
 
 
-void print_symbol(FILE *out, struct menu *menu)
+static void print_symbol(FILE *out, struct menu *menu)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
 	struct property *prop;
 	struct property *prop;
 
 
 	if (sym_is_choice(sym))
 	if (sym_is_choice(sym))
-		fprintf(out, "choice\n");
+		fprintf(out, "\nchoice\n");
 	else
 	else
-		fprintf(out, "config %s\n", sym->name);
+		fprintf(out, "\nconfig %s\n", sym->name);
 	switch (sym->type) {
 	switch (sym->type) {
 	case S_BOOLEAN:
 	case S_BOOLEAN:
 		fputs("  boolean\n", out);
 		fputs("  boolean\n", out);
@@ -624,18 +665,32 @@ void print_symbol(FILE *out, struct menu *menu)
 		case P_CHOICE:
 		case P_CHOICE:
 			fputs("  #choice value\n", out);
 			fputs("  #choice value\n", out);
 			break;
 			break;
+		case P_SELECT:
+			fputs( "  select ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_RANGE:
+			fputs( "  range ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_MENU:
+			fputs( "  menu ", out);
+			print_quoted_string(out, prop->text);
+			fputc('\n', out);
+			break;
 		default:
 		default:
 			fprintf(out, "  unknown prop %d!\n", prop->type);
 			fprintf(out, "  unknown prop %d!\n", prop->type);
 			break;
 			break;
 		}
 		}
 	}
 	}
-	if (sym->help) {
-		int len = strlen(sym->help);
-		while (sym->help[--len] == '\n')
-			sym->help[len] = 0;
-		fprintf(out, "  help\n%s\n", sym->help);
+	if (menu->help) {
+		int len = strlen(menu->help);
+		while (menu->help[--len] == '\n')
+			menu->help[len] = 0;
+		fprintf(out, "  help\n%s\n", menu->help);
 	}
 	}
-	fputc('\n', out);
 }
 }
 
 
 void zconfdump(FILE *out)
 void zconfdump(FILE *out)
@@ -668,7 +723,6 @@ void zconfdump(FILE *out)
 				expr_fprint(prop->visible.expr, out);
 				expr_fprint(prop->visible.expr, out);
 				fputc('\n', out);
 				fputc('\n', out);
 			}
 			}
-			fputs("\n", out);
 		}
 		}
 
 
 		if (menu->list)
 		if (menu->list)
@@ -686,7 +740,7 @@ void zconfdump(FILE *out)
 	}
 	}
 }
 }
 
 
-#include "lex.zconf.c"
+#include "zconf.lex.c"
 #include "util.c"
 #include "util.c"
 #include "confdata.c"
 #include "confdata.c"
 #include "expr.c"
 #include "expr.c"

+ 2 - 2
scripts/diffconfig.sh

@@ -3,9 +3,9 @@ grep \^CONFIG_TARGET_ .config | head -n3 > tmp/.diffconfig.head
 grep '^CONFIG_ALL=y' .config >> tmp/.diffconfig.head
 grep '^CONFIG_ALL=y' .config >> tmp/.diffconfig.head
 grep '^CONFIG_DEVEL=y' .config >> tmp/.diffconfig.head
 grep '^CONFIG_DEVEL=y' .config >> tmp/.diffconfig.head
 grep '^CONFIG_TOOLCHAINOPTS=y' .config >> tmp/.diffconfig.head
 grep '^CONFIG_TOOLCHAINOPTS=y' .config >> tmp/.diffconfig.head
-./scripts/config/conf -D tmp/.diffconfig.head -w tmp/.diffconfig.stage1 Config.in >/dev/null
+./scripts/config/conf --defconfig=tmp/.diffconfig.head -w tmp/.diffconfig.stage1 Config.in >/dev/null
 ./scripts/kconfig.pl '>+' tmp/.diffconfig.stage1 .config >> tmp/.diffconfig.head
 ./scripts/kconfig.pl '>+' tmp/.diffconfig.stage1 .config >> tmp/.diffconfig.head
-./scripts/config/conf -D tmp/.diffconfig.head -w tmp/.diffconfig.stage2 Config.in >/dev/null
+./scripts/config/conf --defconfig=tmp/.diffconfig.head -w tmp/.diffconfig.stage2 Config.in >/dev/null
 ./scripts/kconfig.pl '>' tmp/.diffconfig.stage2 .config >> tmp/.diffconfig.head
 ./scripts/kconfig.pl '>' tmp/.diffconfig.stage2 .config >> tmp/.diffconfig.head
 cat tmp/.diffconfig.head
 cat tmp/.diffconfig.head
 rm -f tmp/.diffconfig tmp/.diffconfig.head
 rm -f tmp/.diffconfig tmp/.diffconfig.head

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