-rw-r--r-- | scripts/kconfig/Makefile | 110 | ||||
-rw-r--r-- | scripts/kconfig/Makefile.kernel | 44 | ||||
-rw-r--r-- | scripts/kconfig/conf.c | 7 | ||||
-rw-r--r-- | scripts/kconfig/confdata.c | 74 | ||||
-rw-r--r-- | scripts/kconfig/expr.h | 5 | ||||
-rw-r--r-- | scripts/kconfig/kconfig.i | 5 | ||||
-rw-r--r-- | scripts/kconfig/lkc.h | 5 | ||||
-rw-r--r-- | scripts/kconfig/mconf.c | 101 | ||||
-rw-r--r-- | scripts/kconfig/menu.c | 2 | ||||
-rw-r--r-- | scripts/kconfig/qconf.cc | 274 | ||||
-rw-r--r-- | scripts/kconfig/qconf.h | 59 | ||||
-rw-r--r-- | scripts/kconfig/symbol.c | 35 | ||||
-rw-r--r-- | scripts/kconfig/zconf.l | 72 | ||||
-rw-r--r-- | scripts/kconfig/zconf.y | 6 |
14 files changed, 542 insertions, 257 deletions
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 7e257be..5a0d7e5 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -1,207 +1,181 @@ -VERSION=1.2 +VERSION=1.3 CC=gcc CXX=g++ -CFLAGS=-O2 -Wall -g -fPIC +CFLAGS=-O0 -Wall -g -fPIC CXXFLAGS=$(CFLAGS) -I$(HOSTQTDIR)/include LDFLAGS= LXXFLAGS=$(LDFLAGS) -L$(HOSTQTDIR)/lib -Wl,-rpath,$(HOSTQTDIR)/lib LEX=flex +LFLAGS=-L YACC=bison -YFLAGS=-d -t #-v +YFLAGS=-l +#YFLAGS=-d -t -v -l ifndef HOSTQTDIR -ifeq ($(shell if [ -e /usr/share/qt ]; then echo foundit; fi),foundit) HOSTQTDIR=/usr/share/qt -else -ifeq ($(shell if [ -e /usr/lib/qt ]; then echo foundit; fi),foundit) -HOSTQTDIR=/usr/lib/qt -endif -endif -endif - -ifndef QTLIB -ifeq ($(shell if [ -e $(HOSTQTDIR)/lib/libqt-mt.so ]; then echo foundit; fi),foundit) -QTLIB=-lqt-mt -else -ifneq ($(shell if [ -e $(HOSTQTDIR)/lib/libqt.so ]; then echo foundit; fi),foundit) -$(warning Unable to locate libqt.so!) endif -QTLIB=-lqt -endif -endif - MOC=$(wildcard $(HOSTQTDIR)/bin/moc) parse_SRC=zconf.y conf_SRC=conf.c $(parse_SRC) mconf_SRC=mconf.c $(parse_SRC) qconf_SRC=qconf.cc -lkcc_SRC=cml1.y cml1.l help.l cml1.h expr1.c HDR=expr.h lkc.h lkc_proto.h qconf.h -OTHER=README lkc_spec lkc_overview Makefile.kernel convert-all prepare-all.diff fixup-all.diff \ +OTHER=README lkc-language.txt Makefile.kernel \ kconfig.i extconf.rb example -INST=zconf.y zconf.l confdata.c expr.c symbol.c menu.c conf.c mconf.c qconf.cc kconfig_load.c images.c $(parse_SRC) $(HDR) -INSTGEN=lex.zconf.c zconf.tab.c zconf.tab.h +INST=zconf.y zconf.l confdata.c expr.c symbol.c menu.c \ + conf.c mconf.c qconf.cc kconfig_load.c images.c $(HDR) +INSTGEN=lex.zconf.c zconf.tab.c #DEBUG=1 ifdef DEBUG CFLAGS+=-DLKC_DIRECT_LINK qconf_SRC+=$(parse_SRC) else qconf_SRC+=kconfig_load.c endif -SRC=$(conf_SRC) $(mconf_SRC) $(qconf_SRC) $(lkcc_SRC) +SRC=$(conf_SRC) $(mconf_SRC) $(qconf_SRC) CSRC=$(filter %.c, $(SRC)) YSRC=$(filter %.y, $(SRC)) LSRC=$(filter %.l, $(SRC)) parse_OBJ=$(filter %.o, \ $(patsubst %.c,%.o, \ $(patsubst %.y,%.tab.o, \ $(patsubst %.l,lex.%.o, \ $(parse_SRC))))) conf_OBJ=$(filter %.o, \ $(patsubst %.c,%.o, \ $(patsubst %.y,%.tab.o, \ $(patsubst %.l,lex.%.o, \ $(conf_SRC))))) mconf_OBJ=$(filter %.o, \ $(patsubst %.c,%.o, \ $(patsubst %.y,%.tab.o, \ $(patsubst %.l,lex.%.o, \ $(mconf_SRC))))) qconf_OBJ=$(filter %.o, \ $(patsubst %.c,%.o, \ $(patsubst %.cc,%.o, \ $(patsubst %.y,%.tab.o, \ $(patsubst %.l,lex.%.o, \ $(qconf_SRC)))))) -lkcc_OBJ=$(filter %.o, \ - $(patsubst %.c,%.o, \ - $(patsubst %.y,%.tab.o, \ - $(patsubst %.l,lex.%.o, \ - $(lkcc_SRC))))) -OBJ=$(conf_OBJ) $(mconf_OBJ) $(qconf_OBJ) $(lkcc_OBJ) +OBJ=$(conf_OBJ) $(mconf_OBJ) $(qconf_OBJ) ifeq ($(MOC),) -all: lkcc conf mconf +all: conf mconf else -all: lkcc conf mconf qconf libkconfig.so +all: conf mconf qconf libkconfig.so endif -lex.help.c: help.l -lex.help.o: lex.help.c cml1.h expr.h -lex.cml1.c: cml1.l -lex.cml1.o: lex.cml1.c cml1.tab.h cml1.h expr.h -cml1.tab.c: cml1.y -cml1.tab.h: cml1.y -cml1.tab.o: cml1.tab.c cml1.h expr.h -expr1.o: expr1.c expr.h - lkc_deps := lkc.h lkc_proto.h lkc_defs.h expr.h zconf.tab.c: zconf.y zconf.tab.h: zconf.y lex.zconf.c: zconf.l zconf.tab.o: zconf.tab.c lex.zconf.c confdata.c expr.c symbol.c menu.c $(lkc_deps) #lex.zconf.o: lex.zconf.c zconf.tab.h $(lkc_deps) #confdata.o: confdata.c $(lkc_deps) #expr.o: expr.c $(lkc_deps) #symbol.o: symbol.c $(lkc_deps) #menu.o: menu.c $(lkc_deps) kconfig_load.o: kconfig_load.c $(lkc_deps) conf.o: conf.c $(lkc_deps) mconf.o: mconf.c $(lkc_deps) qconf.moc: qconf.h qconf.o: qconf.cc qconf.moc images.c $(lkc_deps) mconf: $(mconf_OBJ) $(CC) $(LDFLAGS) $^ -o $@ conf: $(conf_OBJ) $(CC) $(LDFLAGS) $^ -o $@ ifeq ($(MOC),) qconf: @echo Unable to find the QT installation. Please make sure that the @echo QT development package is correctly installed and the HOSTQTDIR @echo environment variable is set to the correct location. @false else -qconf: $(qconf_OBJ) libkconfig.so - $(CXX) $(LXXFLAGS) $^ $(QTLIB) -o $@ +qconf: $(qconf_OBJ) + $(CXX) $(LXXFLAGS) $^ -lqt -o $@ endif -lkcc: $(lkcc_OBJ) - $(CC) $(LDFLAGS) $^ -o $@ - libkconfig.so: $(parse_OBJ) $(CC) -shared $^ -o $@ lkc_defs.h: lkc_proto.h sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/' clean: - rm -f $(OBJ) lkcc conf qconf mconf *.moc lex.* *.tab.? *.output + rm -f $(OBJ) conf qconf mconf *.moc lex.* *.tab.? *.output + rm -rf .ruby .python tgz: mkdir tmp mkdir tmp/lkc-$(VERSION) cp -ra Makefile $(sort $(SRC) $(HDR) $(OTHER) $(INST)) tmp/lkc-$(VERSION) - tar -cpvz -C tmp -f lkc-$(VERSION).tar.gz lkc-$(VERSION) + tar -cpvz -C tmp --exclude CVS -f lkc-$(VERSION).tar.gz lkc-$(VERSION) rm -rf tmp %.tab.c %.tab.h: %.y $(YACC) $(YFLAGS) -b $* -p $* $< lex.%.c: %.l $(LEX) $(LFLAGS) -P$* $< %.moc: %.h $(HOSTQTDIR)/bin/moc -i $< -o $@ %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ %.o: %.cc $(CXX) $(CXXFLAGS) -c $< -o $@ ifdef KERNELSRC -install: lkcc $(INSTGEN) - set -x; mkdir $(KERNELSRC)/scripts/kconfig; \ - cp $(sort $(INST)) $(KERNELSRC)/scripts/kconfig; \ +install: $(INSTGEN) + set -x; cp $(sort $(INST)) $(KERNELSRC)/scripts/kconfig; \ for f in $(INSTGEN); do cp $$f $(KERNELSRC)/scripts/kconfig/$${f}_shipped; done; \ - cp Makefile.kernel $(KERNELSRC)/scripts/kconfig/Makefile; \ - LKCSRC=$$PWD; export LKCSRC; \ - cd $(KERNELSRC); \ - patch -p0 -N < $$LKCSRC/prepare-all.diff; \ - sh $$LKCSRC/convert-all; \ - patch -p0 -N < $$LKCSRC/fixup-all.diff - -# cp Makefile $(KERNELSRC)/scripts/kconfig/Makefile; \ - -uninstall: - patch -p0 -N -R -d $(KERNELSRC) < prepare-all.diff; \ - cd $(KERNELSRC); \ - find -name "Kconfig*" | xargs rm; \ - rm -rf scripts/kconfig log.* + cp Makefile.kernel $(KERNELSRC)/scripts/kconfig/Makefile + +diff: $(INSTGEN) + for f in $(sort $(INST)); do diff -u $(KERNELSRC)/scripts/kconfig/$$f $$f; done; \ + for f in $(INSTGEN); do diff -u $(KERNELSRC)/scripts/kconfig/$${f}_shipped $$f; done; \ + diff -u $(KERNELSRC)/scripts/kconfig/Makefile Makefile.kernel else install: @echo "Please use KERNELSRC=<path/to/linux-kernel> to install" endif ruby: .ruby libkconfig.so .ruby/kconfig.so .ruby: mkdir .ruby .ruby/kconfig_wrap.c: kconfig.i kconfig_load.c expr.h lkc_proto.h swig -ruby -o $@ $< .ruby/Makefile: extconf.rb cd .ruby; ruby ../extconf.rb .ruby/kconfig.so: .ruby/kconfig_wrap.c .ruby/Makefile make -C .ruby -.PHONY: all tgz clean ruby + +PYTHON_INCLUDE=$(shell python -c "import sys; print '-I'+sys.prefix+'/include/python'+sys.version[:3]") + +python: .python .python/kconfig.py .python/_kconfig.so + +.python: + mkdir .python + +.python/kconfig_wrap.c .python/kconfig.py: kconfig.i kconfig_load.c expr.h lkc_proto.h + swig -python -o .python/kconfig_wrap.c kconfig.i + +.python/_kconfig.so: .python/kconfig_wrap.c + cd .python; $(CC) $(CFLAGS) -shared kconfig_wrap.c -o _kconfig.so -I.. $(PYTHON_INCLUDE) + + +.PHONY: all tgz clean ruby python diff --git a/scripts/kconfig/Makefile.kernel b/scripts/kconfig/Makefile.kernel index beb4dcf..22724a7 100644 --- a/scripts/kconfig/Makefile.kernel +++ b/scripts/kconfig/Makefile.kernel @@ -1,85 +1,95 @@ ################# # # Shared Makefile for the various lkc executables: # conf: Used for defconfig, oldconfig and related targets # mconf: Used for the mconfig target. # Utilizes the lxdialog package # qconf: Used for the xconfig target # Based on QT which needs to be installed to compile it # # object files used by all lkc flavours libkconfig-objs := zconf.tab.o host-progs := conf mconf qconf conf-objs := conf.o libkconfig.so mconf-objs := mconf.o libkconfig.so qconf-objs := kconfig_load.o qconf-cxxobjs := qconf.o clean-files := libkconfig.so lkc_defs.h qconf.moc .tmp_qtcheck \ zconf.tab.c zconf.tab.h lex.zconf.c include $(TOPDIR)/Rules.make -# QT needs some extra effort... -ifndef QTDIR -QTDIR := /usr/share/qt -endif - -# Executable to generate the .moc file -MOC=$(wildcard $(QTDIR)/bin/moc) - # generated files seem to need this to find local include files HOSTCFLAGS_lex.zconf.o := -I$(src) HOSTCFLAGS_zconf.tab.o := -I$(src) -HOSTLOADLIBES_qconf := -L$(QTDIR)/lib -Wl,-rpath,$(QTDIR)/lib -lqt -ldl -HOSTCXXFLAGS_qconf.o := -I$(QTDIR)/include +HOSTLOADLIBES_qconf = -L$(QTDIR)/lib -Wl,-rpath,$(QTDIR)/lib -l$(QTLIB) -ldl +HOSTCXXFLAGS_qconf.o = -I$(QTDIR)/include $(obj)/conf.o $(obj)/mconf.o $(obj)/qconf.o: $(obj)/zconf.tab.h $(obj)/qconf.o: $(obj)/.tmp_qtcheck +ifeq ($(MAKECMDGOALS),$(obj)/qconf) +MOC = $(QTDIR)/bin/moc +-include $(obj)/.tmp_qtcheck + +# QT needs some extra effort... $(obj)/.tmp_qtcheck: -ifeq ($(MOC),) - @echo Unable to find the QT installation. Please make sure that the - @echo QT development package is correctly installed and the QTDIR - @echo environment variable is set to the correct location. - @false -else - @touch $@ + @set -e; for d in $$QTDIR /usr/share/qt /usr/lib/qt3; do \ + if [ -f $$d/include/qconfig.h ]; then DIR=$$d; break; fi; \ + done; \ + if [ -z "$$DIR" ]; then \ + echo "*"; \ + echo "* Unable to find the QT installation. Please make sure that the"; \ + echo "* QT development package is correctly installed and the QTDIR"; \ + echo "* environment variable is set to the correct location."; \ + echo "*"; \ + false; \ + fi; \ + LIB=qt; \ + if [ -f $$DIR/lib/libqt-mt.so ]; then LIB=qt-mt; fi; \ + echo "QTDIR=$$DIR" > $@; echo "QTLIB=$$LIB" >> $@; \ + if [ ! -x $$DIR/bin/moc -a -x /usr/bin/moc ]; then \ + echo "*"; \ + echo "* Unable to find $$DIR/bin/moc, using /usr/bin/moc instead."; \ + echo "*"; \ + echo "MOC=/usr/bin/moc" >> $@; \ + fi endif $(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/kconfig_load.o: $(obj)/lkc_defs.h $(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h $(obj)/%.moc: $(src)/%.h $(MOC) -i $< -o $@ $(obj)/lkc_defs.h: $(src)/lkc_proto.h sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/' ### # The following requires flex/bison # By default we use the _shipped versions, uncomment the following line if # you are modifying the flex/bison src. # LKC_GENPARSER := 1 ifdef LKC_GENPARSER $(obj)/zconf.tab.c: $(obj)/zconf.y $(obj)/zconf.tab.h: $(obj)/zconf.tab.c %.tab.c: %.y bison -t -d -v -b $* -p $(notdir $*) $< lex.%.c: %.l flex -P$(notdir $*) -o$@ $< endif diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 74c94c2..1602d5f 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -54,128 +54,129 @@ static void printc(int ch) } #endif static void printo(const char *o) { static int sep = 0; if (!sep) { putchar('('); sep = 1; } else if (o) { putchar(','); putchar(' '); } if (!o) { putchar(')'); putchar(' '); sep = 0; } else printf("%s", o); } static void strip(char *str) { char *p = str; int l; while ((isspace(*p))) p++; l = strlen(p); if (p != str) memmove(str, p, l + 1); if (!l) return; p = str + l - 1; while ((isspace(*p))) *p-- = 0; } static void conf_askvalue(struct symbol *sym, const char *def) { enum symbol_type type = sym_get_type(sym); tristate val; if (!sym_has_value(sym)) printf("(NEW) "); line[0] = '\n'; line[1] = 0; switch (input_mode) { case ask_new: case ask_silent: if (sym_has_value(sym)) { printf("%s\n", def); return; } if (!valid_stdin && input_mode == ask_silent) { printf("aborted!\n\n"); printf("Console input/output is redirected. "); printf("Run 'make oldconfig' to update configuration.\n\n"); exit(1); } case ask_all: + fflush(stdout); fgets(line, 128, stdin); return; case set_default: printf("%s\n", def); return; default: break; } switch (type) { case S_INT: case S_HEX: case S_STRING: printf("%s\n", def); return; 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; } @@ -281,151 +282,153 @@ static int conf_sym(struct menu *menu) continue; } if (sym_set_tristate_value(sym, newval)) return 0; help: help = nohelp_text; if (sym->help) help = sym->help; printf("\n%s\n", help); } } static int conf_choice(struct menu *menu) { struct symbol *sym, *def_sym; struct menu *cmenu, *def_menu; const char *help; int type, len; bool is_new; sym = menu->sym; type = sym_get_type(sym); is_new = !sym_has_value(sym); if (sym_is_changable(sym)) { conf_sym(menu); sym_calc_value(sym); switch (sym_get_tristate_value(sym)) { case no: return 1; case mod: return 0; case yes: break; } } else { sym->def = sym->curr; if (S_TRI(sym->curr) == mod) { printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); return 0; } } while (1) { printf("%*s%s ", indent - 1, "", menu_get_prompt(menu)); def_sym = sym_get_choice_value(sym); def_menu = NULL; for (cmenu = menu->list; cmenu; cmenu = cmenu->next) { if (!menu_is_visible(cmenu)) continue; printo(menu_get_prompt(cmenu)); if (cmenu->sym == def_sym) def_menu = cmenu; } printo(NULL); if (def_menu) printf("[%s] ", menu_get_prompt(def_menu)); else { printf("\n"); return 1; } switch (input_mode) { case ask_new: case ask_silent: case ask_all: + if (is_new) + sym->flags |= SYMBOL_NEW; conf_askvalue(sym, menu_get_prompt(def_menu)); strip(line); break; default: line[0] = 0; printf("\n"); } if (line[0] == '?' && !line[1]) { help = nohelp_text; if (menu->sym->help) help = menu->sym->help; printf("\n%s\n", help); continue; } if (line[0]) { - len = strlen(line) - 1; + len = strlen(line); line[len] = 0; def_menu = NULL; for (cmenu = menu->list; cmenu; cmenu = cmenu->next) { if (!cmenu->sym || !menu_is_visible(cmenu)) continue; - if (!strncmp(line, menu_get_prompt(cmenu), len)) { + if (!strncasecmp(line, menu_get_prompt(cmenu), len)) { def_menu = cmenu; break; } } } if (def_menu) { sym_set_choice_value(sym, def_menu->sym); if (def_menu->list) { indent += 2; conf(def_menu->list); indent -= 2; } return 1; } } } static void conf(struct menu *menu) { struct symbol *sym; struct property *prop; struct menu *child; if (!menu_is_visible(menu)) return; sym = menu->sym; prop = menu->prompt; if (prop) { const char *prompt; switch (prop->type) { case P_MENU: if (input_mode == ask_silent && rootEntry != menu) { check_conf(menu); return; } case P_COMMENT: prompt = menu_get_prompt(menu); if (prompt) printf("%*c\n%*c %s\n%*c\n", indent, '*', indent, '*', prompt, indent, '*'); default: ; } } if (!sym) goto conf_childs; if (sym_is_choice(sym)) { conf_choice(menu); if (S_TRI(sym->curr) != mod) return; goto conf_childs; } switch (sym->type) { case S_INT: case S_HEX: case S_STRING: conf_string(menu); diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 0f5fd97..9bf7af9 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -1,240 +1,259 @@ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ +#include <sys/stat.h> #include <ctype.h> -#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define LKC_DIRECT_LINK #include "lkc.h" const char conf_def_filename[] = ".config"; -char conf_filename[PATH_MAX+1]; const char conf_defname[] = "arch/$ARCH/defconfig"; const char *conf_confnames[] = { ".config", "/lib/modules/$UNAME_RELEASE/.config", "/etc/kernel-config", "/boot/config-$UNAME_RELEASE", conf_defname, NULL, }; static char *conf_expand_value(const char *in) { struct symbol *sym; const char *src; static char res_value[SYMBOL_MAXLENGTH]; char *dst, name[SYMBOL_MAXLENGTH]; res_value[0] = 0; dst = name; while ((src = strchr(in, '$'))) { strncat(res_value, in, src - in); src++; dst = name; while (isalnum(*src) || *src == '_') *dst++ = *src++; *dst = 0; sym = sym_lookup(name, 0); sym_calc_value(sym); strcat(res_value, sym_get_string_value(sym)); in = src; } strcat(res_value, in); return res_value; } char *conf_get_default_confname(void) { - return conf_expand_value(conf_defname); + struct stat buf; + static char fullname[PATH_MAX+1]; + char *env, *name; + + name = conf_expand_value(conf_defname); + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + if (!stat(fullname, &buf)) + return fullname; + } + return name; } int conf_read(const char *name) { FILE *in = NULL; - char line[128]; + char line[1024]; char *p, *p2; int lineno = 0; struct symbol *sym; struct property *prop; struct expr *e; int i; if (name) { - in = fopen(name, "r"); - if (in) - strcpy(conf_filename, name); + in = zconf_fopen(name); } else { const char **names = conf_confnames; while ((name = *names++)) { name = conf_expand_value(name); - in = fopen(name, "r"); + in = zconf_fopen(name); if (in) { printf("#\n" "# using defaults found in %s\n" "#\n", name); break; } } } if (!in) return 1; for_all_symbols(i, sym) { - sym->flags |= SYMBOL_NEW; + sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED; + sym->flags &= ~SYMBOL_VALID; switch (sym->type) { case S_INT: case S_HEX: case S_STRING: - if (S_VAL(sym->def)) { + if (S_VAL(sym->def)) free(S_VAL(sym->def)); - S_VAL(sym->def) = NULL; - } default: - ; + S_VAL(sym->def) = NULL; + S_TRI(sym->def) = no; } } - while (fgets(line, 128, in)) { + while (fgets(line, sizeof(line), in)) { lineno++; switch (line[0]) { case '#': if (memcmp(line + 2, "CONFIG_", 7)) continue; p = strchr(line + 9, ' '); if (!p) continue; *p++ = 0; if (strncmp(p, "is not set", 10)) continue; - //printf("%s -> n\n", line + 9); sym = sym_lookup(line + 9, 0); switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: sym->def = symbol_no.curr; sym->flags &= ~SYMBOL_NEW; break; default: ; } break; case 'C': if (memcmp(line, "CONFIG_", 7)) continue; p = strchr(line + 7, '='); if (!p) continue; *p++ = 0; p2 = strchr(p, '\n'); if (p2) *p2 = 0; - //printf("%s -> %s\n", line + 7, p); sym = sym_find(line + 7); if (!sym) { fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 7); break; } switch (sym->type) { - case S_BOOLEAN: - sym->def = symbol_yes.curr; - sym->flags &= ~SYMBOL_NEW; - break; case S_TRISTATE: - if (p[0] == 'm') - sym->def = symbol_mod.curr; - else - sym->def = symbol_yes.curr; - sym->flags &= ~SYMBOL_NEW; + if (p[0] == 'm') { + S_TRI(sym->def) = mod; + sym->flags &= ~SYMBOL_NEW; + break; + } + case S_BOOLEAN: + if (p[0] == 'y') { + S_TRI(sym->def) = yes; + sym->flags &= ~SYMBOL_NEW; + break; + } + if (p[0] == 'n') { + S_TRI(sym->def) = no; + sym->flags &= ~SYMBOL_NEW; + break; + } break; case S_STRING: if (*p++ != '"') break; for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { if (*p2 == '"') { *p2 = 0; break; } memmove(p2, p2 + 1, strlen(p2)); } + if (!p2) { + fprintf(stderr, "%s:%d: invalid string found\n", name, lineno); + exit(1); + } case S_INT: case S_HEX: if (sym_string_valid(sym, p)) { S_VAL(sym->def) = strdup(p); sym->flags &= ~SYMBOL_NEW; - } else - fprintf(stderr, "%s:%d:symbol value '%s' invalid for %s\n", name, lineno, p, sym->name); + } else { + fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name); + exit(1); + } break; default: ; } if (sym_is_choice_value(sym)) { prop = sym_get_choice_prop(sym); switch (S_TRI(sym->def)) { case mod: if (S_TRI(prop->def->def) == yes) /* warn? */; break; case yes: if (S_TRI(prop->def->def) != no) /* warn? */; S_VAL(prop->def->def) = sym; break; case no: break; } S_TRI(prop->def->def) = S_TRI(sym->def); } break; case '\n': break; default: continue; } } fclose(in); for_all_symbols(i, sym) { if (!sym_is_choice(sym)) continue; prop = sym_get_choice_prop(sym); sym->flags &= ~SYMBOL_NEW; for (e = prop->dep; e; e = e->left.expr) sym->flags |= e->right.sym->flags & SYMBOL_NEW; } sym_change_count = 1; return 0; } int conf_write(const char *name) { FILE *out, *out_h; struct symbol *sym; struct menu *menu; char oldname[128]; int type, l; const char *str; out = fopen(".tmpconfig", "w"); if (!out) return 1; out_h = fopen(".tmpconfig.h", "w"); if (!out_h) return 1; fprintf(out, "#\n" "# Automatically generated make config: don't edit\n" "#\n"); fprintf(out_h, "/*\n" " * Automatically generated C config: don't edit\n" @@ -291,70 +310,69 @@ int conf_write(const char *name) case S_STRING: // fix me str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=\"", sym->name); fprintf(out_h, "#define CONFIG_%s \"", sym->name); do { l = strcspn(str, "\"\\"); if (l) { fwrite(str, l, 1, out); fwrite(str, l, 1, out_h); } str += l; while (*str == '\\' || *str == '"') { fprintf(out, "\\%c", *str); fprintf(out_h, "\\%c", *str); str++; } } while (*str); fputs("\"\n", out); fputs("\"\n", out_h); break; case S_HEX: str = sym_get_string_value(sym); if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { fprintf(out, "CONFIG_%s=%s\n", sym->name, str); fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); break; } case S_INT: str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=%s\n", sym->name, str); fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); break; } } next: if (menu->list) { menu = menu->list; continue; } if (menu->next) menu = menu->next; else while ((menu = menu->parent)) { if (menu->next) { menu = menu->next; break; } } } fclose(out); fclose(out_h); if (!name) { rename(".tmpconfig.h", "include/linux/autoconf.h"); name = conf_def_filename; file_write_dep(NULL); } else unlink(".tmpconfig.h"); sprintf(oldname, "%s.old", name); rename(name, oldname); if (rename(".tmpconfig", name)) return 1; - strcpy(conf_filename, name); sym_change_count = 0; return 0; } diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index fd9c32a..896a296 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -105,134 +105,137 @@ struct symbol { #define SYMBOL_INT S_INT #define SYMBOL_HEX S_HEX #define SYMBOL_STRING S_STRING #define SYMBOL_OTHER S_OTHER #endif #define SYMBOL_YES 0x0001 #define SYMBOL_MOD 0x0002 #define SYMBOL_NO 0x0004 #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_MAXLENGTH 256 #define SYMBOL_HASHSIZE 257 #define SYMBOL_HASHMASK 0xff enum prop_type { P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_ROOTMENU, P_DEFAULT, P_CHOICE }; struct property { struct property *next; struct symbol *sym; #ifdef CML1 int token; #else enum prop_type type; #endif const char *text; struct symbol *def; struct expr_value visible; struct expr *dep; struct expr *dep2; struct menu *menu; struct file *file; int lineno; #ifdef CML1 struct property *next_pos; #endif }; #define for_all_properties(sym, st, tok) \ for (st = sym->prop; st; st = st->next) \ if (st->type == (tok)) #define for_all_prompts(sym, st) for_all_properties(sym, st, P_PROMPT) #define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) #define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) struct menu { struct menu *next; struct menu *parent; struct menu *list; struct symbol *sym; struct property *prompt; struct expr *dep; + unsigned int flags; //char *help; struct file *file; int lineno; - //void *data; + void *data; }; +#define MENU_CHANGED 0x0001 + #ifndef SWIG extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; extern int cdebug; extern int print_type; struct expr *expr_alloc_symbol(struct symbol *sym); #ifdef CML1 struct expr *expr_alloc_one(int token, struct expr *ce); struct expr *expr_alloc_two(int token, struct expr *e1, struct expr *e2); struct expr *expr_alloc_comp(int token, struct symbol *s1, struct symbol *s2); #else struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); #endif struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); struct expr *expr_copy(struct expr *org); void expr_free(struct expr *e); int expr_eq(struct expr *e1, struct expr *e2); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); tristate expr_calc_value(struct expr *e); struct expr *expr_eliminate_yn(struct expr *e); struct expr *expr_trans_bool(struct expr *e); struct expr *expr_eliminate_dups(struct expr *e); struct expr *expr_transform(struct expr *e); int expr_contains_symbol(struct expr *dep, struct symbol *sym); bool expr_depends_symbol(struct expr *dep, struct symbol *sym); struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2); struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2); void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2); struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); void expr_fprint(struct expr *e, FILE *out); void print_expr(int mask, struct expr *e, int prevtoken); #ifdef CML1 static inline int expr_is_yes(struct expr *e) { return !e || (e->token == WORD && e->left.sym == &symbol_yes); } static inline int expr_is_no(struct expr *e) { return e && (e->token == WORD && e->left.sym == &symbol_no); } #else static inline int expr_is_yes(struct expr *e) { return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); } static inline int expr_is_no(struct expr *e) { return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); } #endif #endif #ifdef __cplusplus diff --git a/scripts/kconfig/kconfig.i b/scripts/kconfig/kconfig.i index 699cb13..77405fc 100644 --- a/scripts/kconfig/kconfig.i +++ b/scripts/kconfig/kconfig.i @@ -1,97 +1,102 @@ %module kconfig %{ #include "kconfig_load.c" %} %init %{ kconfig_load(); %} %nodefault; #ifdef SWIGRUBY %typemap (out) char * { if ($1 == NULL) $result = Qnil; else $result = rb_str_new2($1); } %typemap (in) char * { if ($input == Qnil) $1 = NULL; else $1 = STR2CSTR($input); } %{ static void expr_to_s_help(void *data, const char *str) { rb_str_cat((VALUE)data, str, strlen(str)); } %} #endif +#ifdef SWIGPYTHON +%rename (Property) property; +%rename (default) def; +#endif + %immutable; %include "expr.h" #define P(name,type,arg) extern type name arg %include "lkc_proto.h" %mutable; #ifdef SWIGRUBY %predicate menu::isVisible; %predicate symbol::isChangable; %predicate symbol::isChoice; %predicate symbol::isChoiceValue; #endif %extend menu { bool isVisible(void) { return menu_is_visible(self); } #ifdef SWIGRUBY void each(void) { struct menu *child; for (child = self->list; child; child = child->next) rb_yield(SWIG_NewPointerObj(child, SWIGTYPE_p_menu, 0)); } static void each_menu(void) { struct menu *child; for (child = rootmenu.list; child; child = child->next) rb_yield(SWIG_NewPointerObj(child, SWIGTYPE_p_menu, 0)); } #endif } %extend symbol { void calc_value(void) { sym_calc_value(self); } tristate set_tristate(tristate val) { return sym_set_tristate_value(self, val); } bool set_string(char *val) { return sym_set_string_value(self, val); } const char *get_string(void) { return sym_get_string_value(self); } bool isChangable(void) { return sym_is_changable(self); } bool isChoice(void) { return sym_is_choice(self); } bool isChoiceValue(void) { return sym_is_choice_value(self); } static struct symbol *lookup(const char *name) { return sym_lookup(name, 0); } static struct symbol *find(const char *name) { return sym_find(name); } static const char *type_name(enum symbol_type type) { return sym_type_name(type); } #ifdef SWIGRUBY void each(void) { diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 688945b..cdd04a9 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -1,106 +1,109 @@ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ #ifndef LKC_H #define LKC_H #include "expr.h" #ifdef __cplusplus extern "C" { #endif #ifdef LKC_DIRECT_LINK #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" #undef P -void symbol_end(char *help); +#define SRCTREE "srctree" + int zconfparse(void); void zconfdump(FILE *out); extern int zconfdebug; void zconf_starthelp(void); +FILE *zconf_fopen(const char *name); void zconf_initscan(const char *name); void zconf_nextfile(const char *name); int zconf_lineno(void); char *zconf_curname(void); /* confdata.c */ extern const char conf_def_filename[]; extern char conf_filename[]; char *conf_get_default_confname(void); /* kconfig_load.c */ void kconfig_load(void); /* menu.c */ void menu_init(void); void menu_add_menu(void); void menu_end_menu(void); void menu_add_entry(struct symbol *sym); void menu_end_entry(void); struct property *create_prop(enum prop_type type); void menu_add_dep(struct expr *dep); struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep); void menu_finalize(struct menu *parent); void menu_set_type(int type); struct file *file_lookup(const char *name); int file_write_dep(const char *name); extern struct menu *current_entry; extern struct menu *current_menu; /* symbol.c */ void sym_init(void); void sym_clear_all_valid(void); +void sym_set_changed(struct symbol *sym); static inline tristate sym_get_tristate_value(struct symbol *sym) { return S_TRI(sym->curr); } static inline struct symbol *sym_get_choice_value(struct symbol *sym) { return (struct symbol *)S_VAL(sym->curr); } static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) { return sym_set_tristate_value(chval, yes); } static inline bool sym_is_choice(struct symbol *sym) { return sym->flags & SYMBOL_CHOICE ? true : false; } static inline bool sym_is_choice_value(struct symbol *sym) { return sym->flags & SYMBOL_CHOICEVAL ? true : false; } static inline bool sym_is_optional(struct symbol *sym) { return sym->flags & SYMBOL_OPTIONAL ? true : false; } static inline bool sym_has_value(struct symbol *sym) { //return S_VAL(sym->def) != NULL; return sym->flags & SYMBOL_NEW ? false : true; } #ifdef __cplusplus } #endif #endif /* LKC_H */ diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index dec8603..eba5ff7 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -1,176 +1,199 @@ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. + * + * Introduced single menu mode (show all sub-menus in one large tree). + * 2002-11-06 Petr Baudis <pasky@ucw.cz> */ #include <sys/ioctl.h> #include <sys/wait.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> +#include <limits.h> #include <signal.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> +#include <termios.h> #include <unistd.h> #define LKC_DIRECT_LINK #include "lkc.h" static char menu_backtitle[128]; static const char menu_instructions[] = "Arrow keys navigate the menu. " "<Enter> selects submenus --->. " "Highlighted letters are hotkeys. " "Pressing <Y> includes, <N> excludes, <M> modularizes features. " "Press <Esc><Esc> to exit, <?> for Help. " "Legend: [*] built-in [ ] excluded <M> module < > module capable", radiolist_instructions[] = "Use the arrow keys to navigate this window or " "press the hotkey of the item you wish to select " "followed by the <SPACE BAR>. " "Press <?> for additional information about this option.", inputbox_instructions_int[] = "Please enter a decimal value. " "Fractions will not be accepted. " "Use the <TAB> key to move from the input field to the buttons below it.", inputbox_instructions_hex[] = "Please enter a hexadecimal value. " "Use the <TAB> key to move from the input field to the buttons below it.", inputbox_instructions_string[] = "Please enter a string value. " "Use the <TAB> key to move from the input field to the buttons below it.", setmod_text[] = "This feature depends on another which has been configured as a module.\n" "As a result, this feature will be built as a module.", nohelp_text[] = - "There is no help available for this option.\n", + "There is no help available for this kernel option.\n", load_config_text[] = "Enter the name of the configuration file you wish to load. " "Accept the name shown to restore the configuration you " "last retrieved. Leave blank to abort.", load_config_help[] = "\n" - "For various reasons, one may wish to keep several different\n" + "For various reasons, one may wish to keep several different kernel\n" "configurations available on a single machine.\n" "\n" "If you have saved a previous configuration in a file other than the\n" - "default, entering the name of the file here will allow you\n" + "kernel's default, entering the name of the file here will allow you\n" "to modify that configuration.\n" "\n" "If you are uncertain, then you have probably never used alternate\n" "configuration files. You should therefor leave this blank to abort.\n", save_config_text[] = "Enter a filename to which this configuration should be saved " "as an alternate. Leave blank to abort.", save_config_help[] = "\n" - "For various reasons, one may wish to keep different\n" + "For various reasons, one may wish to keep different kernel\n" "configurations available on a single machine.\n" "\n" "Entering a file name here will allow you to later retrieve, modify\n" "and use the current configuration as an alternate to whatever\n" "configuration options you have selected at that time.\n" "\n" "If you are uncertain what all this means then you should probably\n" "leave this blank.\n" ; static char buf[4096], *bufptr = buf; static char input_buf[4096]; +static char filename[PATH_MAX+1] = ".config"; static char *args[1024], **argptr = args; static int indent = 0; +static struct termios ios_org; static int rows, cols; static struct menu *current_menu; static int child_count; static int do_resize; +static int single_menu_mode; static void conf(struct menu *menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); static void conf_load(void); static void conf_save(void); static void show_textbox(const char *title, const char *text, int r, int c); static void show_helptext(const char *title, const char *text); static void show_help(struct menu *menu); static void show_readme(void); static void cprint_init(void); static int cprint1(const char *fmt, ...); static void cprint_done(void); static int cprint(const char *fmt, ...); static void init_wsize(void) { struct winsize ws; + char *env; if (ioctl(1, TIOCGWINSZ, &ws) == -1) { rows = 24; cols = 80; } else { rows = ws.ws_row; cols = ws.ws_col; + if (!rows) { + env = getenv("LINES"); + if (env) + rows = atoi(env); + if (!rows) + rows = 24; + } + if (!cols) { + env = getenv("COLUMNS"); + if (env) + cols = atoi(env); + if (!cols) + cols = 80; + } } if (rows < 19 || cols < 80) { fprintf(stderr, "Your display is too small to run Menuconfig!\n"); fprintf(stderr, "It must be at least 19 lines by 80 columns.\n"); exit(1); } rows -= 4; cols -= 5; } static void cprint_init(void) { bufptr = buf; argptr = args; memset(args, 0, sizeof(args)); indent = 0; child_count = 0; cprint("./scripts/lxdialog/lxdialog"); cprint("--backtitle"); cprint(menu_backtitle); } static int cprint1(const char *fmt, ...) { va_list ap; int res; if (!*argptr) *argptr = bufptr; va_start(ap, fmt); res = vsprintf(bufptr, fmt, ap); va_end(ap); bufptr += res; return res; } static void cprint_done(void) { *bufptr++ = 0; argptr++; } static int cprint(const char *fmt, ...) { va_list ap; int res; *argptr++ = bufptr; va_start(ap, fmt); res = vsprintf(bufptr, fmt, ap); va_end(ap); bufptr += res; *bufptr++ = 0; return res; } pid_t pid; static void winch_handler(int sig) { @@ -213,499 +236,545 @@ static int exec_conf(void) close(pipefd[1]); bufptr = input_buf; while (1) { size = input_buf + sizeof(input_buf) - bufptr; size = read(pipefd[0], bufptr, size); if (size <= 0) { if (size < 0) { if (errno == EINTR || errno == EAGAIN) continue; perror("read"); } break; } bufptr += size; } *bufptr++ = 0; close(pipefd[0]); waitpid(pid, &stat, 0); if (do_resize) { init_wsize(); do_resize = 0; sigprocmask(SIG_SETMASK, &osset, NULL); return -1; } if (WIFSIGNALED(stat)) { printf("\finterrupted(%d)\n", WTERMSIG(stat)); exit(1); } #if 0 printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf); sleep(1); #endif sigpending(&sset); if (sigismember(&sset, SIGINT)) { printf("\finterrupted\n"); exit(1); } sigprocmask(SIG_SETMASK, &osset, NULL); return WEXITSTATUS(stat); } static void build_conf(struct menu *menu) { struct symbol *sym; struct property *prop; struct menu *child; int type, tmp, doint = 2; tristate val; char ch; if (!menu_is_visible(menu)) return; sym = menu->sym; prop = menu->prompt; if (!sym) { if (prop && menu != current_menu) { const char *prompt = menu_get_prompt(menu); switch (prop->type) { case P_MENU: child_count++; cprint("m%p", menu); - if (menu->parent != &rootmenu) - cprint1(" %*c", indent + 1, ' '); - cprint1("%s --->", prompt); + + if (single_menu_mode) { + cprint1("%s%*c%s", + menu->data ? "-->" : "++>", + indent + 1, ' ', prompt); + } else { + if (menu->parent != &rootmenu) + cprint1(" %*c", indent + 1, ' '); + cprint1("%s --->", prompt); + } + cprint_done(); + if (single_menu_mode && menu->data) + goto conf_childs; return; default: if (prompt) { child_count++; cprint(":%p", menu); cprint("---%*c%s", indent + 1, ' ', prompt); } } } else doint = 0; goto conf_childs; } type = sym_get_type(sym); if (sym_is_choice(sym)) { struct symbol *def_sym = sym_get_choice_value(sym); struct menu *def_menu = NULL; child_count++; for (child = menu->list; child; child = child->next) { if (menu_is_visible(child) && child->sym == def_sym) def_menu = child; } val = sym_get_tristate_value(sym); if (sym_is_changable(sym)) { cprint("t%p", menu); switch (type) { case S_BOOLEAN: cprint1("[%c]", val == no ? ' ' : '*'); break; case S_TRISTATE: switch (val) { case yes: ch = '*'; break; case mod: ch = 'M'; break; default: ch = ' '; break; } cprint1("<%c>", ch); break; } } else { cprint("%c%p", def_menu ? 't' : ':', menu); cprint1(" "); } cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu)); if (val == yes) { if (def_menu) { cprint1(" (%s)", menu_get_prompt(def_menu)); cprint1(" --->"); cprint_done(); if (def_menu->list) { indent += 2; build_conf(def_menu); indent -= 2; } } else cprint_done(); return; } cprint_done(); } else { child_count++; val = sym_get_tristate_value(sym); if (sym_is_choice_value(sym) && val == yes) { cprint(":%p", menu); cprint1(" "); } else { switch (type) { case S_BOOLEAN: cprint("t%p", menu); cprint1("[%c]", val == no ? ' ' : '*'); break; case S_TRISTATE: cprint("t%p", menu); switch (val) { case yes: ch = '*'; break; case mod: ch = 'M'; break; default: ch = ' '; break; } cprint1("<%c>", ch); break; default: cprint("s%p", menu); tmp = cprint1("(%s)", sym_get_string_value(sym)); tmp = indent - tmp + 4; if (tmp < 0) tmp = 0; cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu), sym_has_value(sym) ? "" : " (NEW)"); cprint_done(); goto conf_childs; } } cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), sym_has_value(sym) ? "" : " (NEW)"); cprint_done(); } conf_childs: indent += doint; for (child = menu->list; child; child = child->next) build_conf(child); indent -= doint; } static void conf(struct menu *menu) { struct menu *submenu; const char *prompt = menu_get_prompt(menu); struct symbol *sym; char active_entry[40]; int stat, type, i; + unlink("lxdialog.scrltmp"); active_entry[0] = 0; while (1) { cprint_init(); cprint("--title"); cprint("%s", prompt ? prompt : "Main Menu"); cprint("--menu"); cprint(menu_instructions); cprint("%d", rows); cprint("%d", cols); cprint("%d", rows - 10); cprint("%s", active_entry); current_menu = menu; build_conf(menu); if (!child_count) break; if (menu == &rootmenu) { cprint(":"); cprint("--- "); cprint("L"); cprint("Load an Alternate Configuration File"); cprint("S"); cprint("Save Configuration to an Alternate File"); } stat = exec_conf(); if (stat < 0) continue; if (stat == 1 || stat == 255) break; type = input_buf[0]; if (!type) continue; for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++) ; if (i >= sizeof(active_entry)) i = sizeof(active_entry) - 1; input_buf[i] = 0; strcpy(active_entry, input_buf); sym = NULL; submenu = NULL; if (sscanf(input_buf + 1, "%p", &submenu) == 1) sym = submenu->sym; switch (stat) { case 0: switch (type) { case 'm': - conf(submenu); + if (single_menu_mode) + submenu->data = (void *) !submenu->data; + else + conf(submenu); break; case 't': if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes) conf_choice(submenu); break; case 's': conf_string(submenu); break; case 'L': conf_load(); break; case 'S': conf_save(); break; } break; case 2: if (sym) show_help(submenu); else show_readme(); break; case 3: if (type == 't') { if (sym_set_tristate_value(sym, yes)) break; if (sym_set_tristate_value(sym, mod)) show_textbox(NULL, setmod_text, 6, 74); } break; case 4: if (type == 't') sym_set_tristate_value(sym, no); break; case 5: if (type == 't') sym_set_tristate_value(sym, mod); break; case 6: if (type == 't') sym_toggle_tristate_value(sym); + else if (type == 'm') + conf(submenu); break; } } } static void show_textbox(const char *title, const char *text, int r, int c) { int fd; fd = creat(".help.tmp", 0777); write(fd, text, strlen(text)); close(fd); do { cprint_init(); if (title) { cprint("--title"); cprint("%s", title); } cprint("--textbox"); cprint(".help.tmp"); cprint("%d", r); cprint("%d", c); } while (exec_conf() < 0); unlink(".help.tmp"); } static void show_helptext(const char *title, const char *text) { show_textbox(title, text, rows, cols); } static void show_help(struct menu *menu) { const char *help; + char *helptext; + struct symbol *sym = menu->sym; - help = menu->sym->help; + help = sym->help; if (!help) help = nohelp_text; - show_helptext(menu_get_prompt(menu), help); + if (sym->name) { + helptext = malloc(strlen(sym->name) + strlen(help) + 16); + sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help); + show_helptext(menu_get_prompt(menu), helptext); + free(helptext); + } else + show_helptext(menu_get_prompt(menu), help); } static void show_readme(void) { do { cprint_init(); cprint("--textbox"); cprint("scripts/README.Menuconfig"); cprint("%d", rows); cprint("%d", cols); } while (exec_conf() == -1); } static void conf_choice(struct menu *menu) { const char *prompt = menu_get_prompt(menu); struct menu *child; struct symbol *active; int stat; while (1) { cprint_init(); cprint("--title"); cprint("%s", prompt ? prompt : "Main Menu"); cprint("--radiolist"); cprint(radiolist_instructions); cprint("15"); cprint("70"); cprint("6"); current_menu = menu; active = sym_get_choice_value(menu->sym); for (child = menu->list; child; child = child->next) { if (!menu_is_visible(child)) continue; cprint("%p", child); cprint("%s", menu_get_prompt(child)); cprint(child->sym == active ? "ON" : "OFF"); } stat = exec_conf(); switch (stat) { case 0: if (sscanf(input_buf, "%p", &menu) != 1) break; sym_set_tristate_value(menu->sym, yes); return; case 1: show_help(menu); break; case 255: return; } } } static void conf_string(struct menu *menu) { const char *prompt = menu_get_prompt(menu); int stat; while (1) { cprint_init(); cprint("--title"); cprint("%s", prompt ? prompt : "Main Menu"); cprint("--inputbox"); switch (sym_get_type(menu->sym)) { case S_INT: cprint(inputbox_instructions_int); break; case S_HEX: cprint(inputbox_instructions_hex); break; case S_STRING: cprint(inputbox_instructions_string); break; default: /* panic? */; } cprint("10"); cprint("75"); cprint("%s", sym_get_string_value(menu->sym)); stat = exec_conf(); switch (stat) { case 0: if (sym_set_string_value(menu->sym, input_buf)) return; show_textbox(NULL, "You have made an invalid entry.", 5, 43); break; case 1: show_help(menu); break; case 255: return; } } } static void conf_load(void) { int stat; while (1) { cprint_init(); cprint("--inputbox"); cprint(load_config_text); cprint("11"); cprint("55"); - cprint("%s", conf_filename); + cprint("%s", filename); stat = exec_conf(); switch(stat) { case 0: if (!input_buf[0]) return; if (!conf_read(input_buf)) return; show_textbox(NULL, "File does not exist!", 5, 38); break; case 1: show_helptext("Load Alternate Configuration", load_config_help); break; case 255: return; } } } static void conf_save(void) { int stat; while (1) { cprint_init(); cprint("--inputbox"); cprint(save_config_text); cprint("11"); cprint("55"); - cprint("%s", conf_filename); + cprint("%s", filename); stat = exec_conf(); switch(stat) { case 0: if (!input_buf[0]) return; if (!conf_write(input_buf)) return; show_textbox(NULL, "Can't create file! Probably a nonexistent directory.", 5, 60); break; case 1: show_helptext("Save Alternate Configuration", save_config_help); break; case 255: return; } } } +static void conf_cleanup(void) +{ + tcsetattr(1, TCSAFLUSH, &ios_org); + unlink(".help.tmp"); + unlink("lxdialog.scrltmp"); +} + int main(int ac, char **av) { + struct symbol *sym; + char *mode; int stat; + conf_parse(av[1]); conf_read(NULL); - sprintf(menu_backtitle, "Configuration"); + sym = sym_lookup("KERNELRELEASE", 0); + sym_calc_value(sym); + sprintf(menu_backtitle, "Linux Kernel v%s Configuration", + sym_get_string_value(sym)); + + mode = getenv("MENUCONFIG_MODE"); + if (mode) { + if (!strcasecmp(mode, "single_menu")) + single_menu_mode = 1; + } + tcgetattr(1, &ios_org); + atexit(conf_cleanup); init_wsize(); conf(&rootmenu); do { cprint_init(); cprint("--yesno"); cprint("Do you wish to save your new configuration?"); cprint("5"); cprint("60"); stat = exec_conf(); } while (stat < 0); if (stat == 0) { conf_write(NULL); printf("\n\n" - "*** End of configuration.\n" - "*** Check the top-level Makefile for additional configuration.\n"); + "*** End of Linux kernel configuration.\n" + "*** Check the top-level Makefile for additional configuration.\n" + "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'.\n\n"); } else - printf("\n\nYour configuration changes were NOT saved.\n\n"); + printf("\n\nYour kernel configuration changes were NOT saved.\n\n"); return 0; } diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 4595110..24be0ec 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -229,81 +229,81 @@ void menu_finalize(struct menu *parent) bool menu_is_visible(struct menu *menu) { tristate visible; if (!menu->prompt) return false; if (menu->sym) { sym_calc_value(menu->sym); visible = E_TRI(menu->prompt->visible); } else visible = E_CALC(menu->prompt->visible); return visible != no; } const char *menu_get_prompt(struct menu *menu) { if (menu->prompt) return menu->prompt->text; else if (menu->sym) return menu->sym->name; return NULL; } struct menu *menu_get_root_menu(struct menu *menu) { return &rootmenu; } struct menu *menu_get_parent_menu(struct menu *menu) { enum prop_type type; while (menu != &rootmenu) { menu = menu->parent; type = menu->prompt ? menu->prompt->type : 0; if (type == P_MENU || type == P_ROOTMENU) break; } return menu; } struct file *file_lookup(const char *name) { struct file *file; for (file = file_list; file; file = file->next) { if (!strcmp(name, file->name)) return file; } file = malloc(sizeof(*file)); memset(file, 0, sizeof(*file)); file->name = strdup(name); file->next = file_list; file_list = file; return file; } int file_write_dep(const char *name) { struct file *file; FILE *out; if (!name) - name = "..config.cmd"; + name = ".config.cmd"; 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.config include/linux/autoconf.h: $(deps_config)\n\n$(deps_config):\n"); fclose(out); rename("..config.tmp", name); return 0; } diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index feefa1c..bed541d 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -1,1073 +1,1203 @@ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ #include <qapplication.h> #include <qmainwindow.h> #include <qtoolbar.h> #include <qvbox.h> #include <qsplitter.h> #include <qlistview.h> #include <qtextview.h> #include <qlineedit.h> #include <qmenubar.h> #include <qmessagebox.h> #include <qaction.h> #include <qheader.h> #include <qfiledialog.h> #include <qregexp.h> +#if QT_VERSION >= 300 +#include <qsettings.h> +#endif + #include <stdlib.h> #include "lkc.h" #include "qconf.h" #include "qconf.moc" #include "images.c" static QApplication *configApp; +#if QT_VERSION >= 300 +static QSettings *configSettings; +#endif /* * update all the children of a menu entry * removes/adds the entries from the parent widget as necessary * * parent: either the menu list widget or a menu entry widget * menu: entry to be updated */ template <class P> static void updateMenuList(P* parent, struct menu* menu) { struct menu* child; ConfigList* list = parent->listView(); ConfigItem* item; ConfigItem* last; bool visible; bool showAll = list->showAll; enum listMode mode = list->mode; enum prop_type type; if (!menu) { while ((item = parent->firstChild())) delete item; return; } last = 0; for (child = menu->list; child; child = child->next) { item = last ? last->nextSibling() : parent->firstChild(); type = child->prompt ? child->prompt->type : P_UNKNOWN; switch (mode) { case menuMode: if (type != P_ROOTMENU) goto hide; break; case symbolMode: if (type == P_ROOTMENU) goto hide; break; default: break; } visible = menu_is_visible(child); if (showAll || visible) { if (!item || item->menu != child) - item = new ConfigItem(parent, last, child); - item->visible = visible; - item->updateMenu(); + item = new ConfigItem(parent, last, child, visible); + else { + item->visible = visible; + if (item->updateNeeded()) { + ConfigItem* i = (ConfigItem*)child->data; + for (; i; i = i->nextItem) { + i->updateMenu(); + } + } else if (list->updateAll) + item->updateMenu(); + } if (mode == fullMode || mode == menuMode || (type != P_MENU && type != P_ROOTMENU)) updateMenuList(item, child); else updateMenuList(item, 0); last = item; continue; } hide: if (item && item->menu == child) { last = parent->firstChild(); if (last == item) last = 0; else while (last->nextSibling() != item) last = last->nextSibling(); delete item; } } } #if QT_VERSION >= 300 /* * set the new data * TODO check the value */ void ConfigItem::okRename(int col) { Parent::okRename(col); sym_set_string_value(menu->sym, text(dataColIdx).latin1()); } #endif /* * update the displayed of a menu entry */ void ConfigItem::updateMenu(void) { ConfigList* list; struct symbol* sym; QString prompt; int type; enum prop_type ptype; tristate expr; - bool update; list = listView(); - update = doInit; - if (update) - doInit = false; - else - update = list->updateAll; sym = menu->sym; if (!sym) { - if (update) { - setText(promptColIdx, menu_get_prompt(menu)); - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if ((ptype == P_ROOTMENU || ptype == P_MENU) && - (list->mode == singleMode || list->mode == symbolMode)) - setPixmap(promptColIdx, list->menuPix); - else - setPixmap(promptColIdx, 0); - } + setText(promptColIdx, menu_get_prompt(menu)); + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if ((ptype == P_ROOTMENU || ptype == P_MENU) && + (list->mode == singleMode || list->mode == symbolMode)) + setPixmap(promptColIdx, list->menuPix); + else + setPixmap(promptColIdx, 0); return; } - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_CHANGED) && !update) - return; - - sym->flags &= ~SYMBOL_CHANGED; - - setText(nameColIdx, menu->sym->name); + setText(nameColIdx, sym->name); type = sym_get_type(sym); switch (type) { case S_BOOLEAN: case S_TRISTATE: char ch; prompt = menu_get_prompt(menu); if (!sym_is_changable(sym) && !list->showAll) { setText(noColIdx, 0); setText(modColIdx, 0); setText(yesColIdx, 0); break; } expr = sym_get_tristate_value(sym); switch (expr) { case yes: if (sym_is_choice_value(sym) && type == S_BOOLEAN) setPixmap(promptColIdx, list->choiceYesPix); else setPixmap(promptColIdx, list->symbolYesPix); setText(yesColIdx, "Y"); ch = 'Y'; break; case mod: setPixmap(promptColIdx, list->symbolModPix); setText(modColIdx, "M"); ch = 'M'; break; default: if (sym_is_choice_value(sym) && type == S_BOOLEAN) setPixmap(promptColIdx, list->choiceNoPix); else setPixmap(promptColIdx, list->symbolNoPix); setText(noColIdx, "N"); ch = 'N'; break; } if (expr != no) setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); if (expr != mod) setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); if (expr != yes) setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); setText(dataColIdx, QChar(ch)); break; case S_INT: case S_HEX: case S_STRING: const char* data; data = sym_get_string_value(sym); #if QT_VERSION >= 300 - setRenameEnabled(list->mapIdx(dataColIdx), TRUE); + int i = list->mapIdx(dataColIdx); + if (i >= 0) + setRenameEnabled(i, TRUE); #endif setText(dataColIdx, data); if (type == S_STRING) prompt.sprintf("%s: %s", menu_get_prompt(menu), data); else prompt.sprintf("(%s) %s", data, menu_get_prompt(menu)); break; } if (!sym_has_value(sym) && visible) prompt += " (NEW)"; setText(promptColIdx, prompt); } +bool ConfigItem::updateNeeded(void) +{ + struct symbol* sym = menu->sym; + if (sym) + sym_calc_value(sym); + if (menu->flags & MENU_CHANGED) { + menu->flags &= ~MENU_CHANGED; + return true; + } + return false; +} + void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align) { ConfigList* list = listView(); if (visible) { if (isSelected() && !list->hasFocus() && list->mode == menuMode) Parent::paintCell(p, list->inactivedColorGroup, column, width, align); else Parent::paintCell(p, cg, column, width, align); } else Parent::paintCell(p, list->disabledColorGroup, column, width, align); } /* * construct a menu entry */ void ConfigItem::init(void) { ConfigList* list = listView(); -#if QT_VERSION < 300 - visible = TRUE; -#endif - //menu->data = this; + nextItem = (ConfigItem*)menu->data; + menu->data = this; + if (list->mode != fullMode) setOpen(TRUE); - doInit= true; + if (menu->sym) + sym_calc_value(menu->sym); + updateMenu(); } /* * destruct a menu entry */ ConfigItem::~ConfigItem(void) { - //menu->data = 0; + ConfigItem** ip = &(ConfigItem*)menu->data; + for (; *ip; ip = &(*ip)->nextItem) { + if (*ip == this) { + *ip = nextItem; + break; + } + } } void ConfigLineEdit::show(ConfigItem* i) { item = i; if (sym_get_string_value(item->menu->sym)) setText(sym_get_string_value(item->menu->sym)); else setText(0); Parent::show(); setFocus(); } void ConfigLineEdit::keyPressEvent(QKeyEvent* e) { switch (e->key()) { case Key_Escape: break; case Key_Return: case Key_Enter: sym_set_string_value(item->menu->sym, text().latin1()); - emit lineChanged(item); + parent()->updateList(item); break; default: Parent::keyPressEvent(e); return; } e->accept(); + parent()->list->setFocus(); hide(); } -ConfigList::ConfigList(QWidget* p, ConfigView* cv) +ConfigList::ConfigList(ConfigView* p, ConfigMainWindow* cv) : Parent(p), cview(cv), updateAll(false), symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), menuPix(xpm_menu), menuInvPix(xpm_menu_inv), showAll(false), showName(false), showRange(false), showData(false), rootEntry(0) { int i; setSorting(-1); setRootIsDecorated(TRUE); disabledColorGroup = palette().active(); disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text()); inactivedColorGroup = palette().active(); inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight()); connect(this, SIGNAL(selectionChanged(void)), SLOT(updateSelection(void))); for (i = 0; i < colNr; i++) colMap[i] = colRevMap[i] = -1; addColumn(promptColIdx, "Option"); reinit(); } void ConfigList::reinit(void) { removeColumn(dataColIdx); removeColumn(yesColIdx); removeColumn(modColIdx); removeColumn(noColIdx); removeColumn(nameColIdx); if (showName) addColumn(nameColIdx, "Name"); if (showRange) { addColumn(noColIdx, "N"); addColumn(modColIdx, "M"); addColumn(yesColIdx, "Y"); } if (showData) addColumn(dataColIdx, "Value"); updateListAll(); } void ConfigList::updateSelection(void) { struct menu *menu; enum prop_type type; ConfigItem* item = (ConfigItem*)selectedItem(); if (!item) return; cview->setHelp(item); menu = item->menu; type = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (mode == menuMode && (type == P_MENU || type == P_ROOTMENU)) emit menuSelected(menu); } void ConfigList::updateList(ConfigItem* item) { (void)item; // unused so far updateMenuList(this, rootEntry); + triggerUpdate(); } void ConfigList::setAllOpen(bool open) { QListViewItemIterator it(this); for (; it.current(); it++) it.current()->setOpen(open); } void ConfigList::setValue(ConfigItem* item, tristate val) { struct symbol* sym; int type; tristate oldval; sym = item->menu->sym; if (!sym) return; type = sym_get_type(sym); switch (type) { case S_BOOLEAN: case S_TRISTATE: oldval = sym_get_tristate_value(sym); if (!sym_set_tristate_value(sym, val)) return; if (oldval == no && item->menu->list) item->setOpen(TRUE); - emit symbolChanged(item); + parent()->updateList(item); break; } } void ConfigList::changeValue(ConfigItem* item) { struct symbol* sym; struct menu* menu; int type, oldexpr, newexpr; menu = item->menu; sym = menu->sym; if (!sym) { if (item->menu->list) item->setOpen(!item->isOpen()); return; } type = sym_get_type(sym); switch (type) { case S_BOOLEAN: case S_TRISTATE: oldexpr = sym_get_tristate_value(sym); newexpr = sym_toggle_tristate_value(sym); if (item->menu->list) { if (oldexpr == newexpr) item->setOpen(!item->isOpen()); else if (oldexpr == no) item->setOpen(TRUE); } if (oldexpr != newexpr) - emit symbolChanged(item); + parent()->updateList(item); break; case S_INT: case S_HEX: case S_STRING: #if QT_VERSION >= 300 if (colMap[dataColIdx] >= 0) item->startRename(colMap[dataColIdx]); else #endif - lineEdit->show(item); + parent()->lineEdit->show(item); break; } } void ConfigList::setRootMenu(struct menu *menu) { enum prop_type type; if (rootEntry == menu) return; type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; if (type != P_MENU && type != P_ROOTMENU) return; updateMenuList(this, 0); rootEntry = menu; updateListAll(); setSelected(currentItem(), hasFocus()); } void ConfigList::setParentMenu(void) { ConfigItem* item; struct menu *oldroot, *newroot; oldroot = rootEntry; newroot = menu_get_parent_menu(oldroot); if (newroot == oldroot) return; setRootMenu(newroot); QListViewItemIterator it(this); for (; (item = (ConfigItem*)it.current()); it++) { if (item->menu == oldroot) { setCurrentItem(item); ensureItemVisible(item); break; } } } void ConfigList::keyPressEvent(QKeyEvent* ev) { QListViewItem* i = currentItem(); ConfigItem* item; struct menu *menu; enum prop_type type; if (ev->key() == Key_Escape && mode != fullMode) { emit parentSelected(); ev->accept(); return; } if (!i) { Parent::keyPressEvent(ev); return; } item = (ConfigItem*)i; switch (ev->key()) { case Key_Return: case Key_Enter: menu = item->menu; type = menu->prompt ? menu->prompt->type : P_UNKNOWN; if ((type == P_MENU || type == P_ROOTMENU) && mode != fullMode) { emit menuSelected(menu); break; } case Key_Space: changeValue(item); break; case Key_N: setValue(item, no); break; case Key_M: setValue(item, mod); break; case Key_Y: setValue(item, yes); break; default: Parent::keyPressEvent(ev); return; } ev->accept(); } void ConfigList::contentsMousePressEvent(QMouseEvent* e) { //QPoint p(contentsToViewport(e->pos())); //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y()); - QListView::contentsMousePressEvent(e); + Parent::contentsMousePressEvent(e); } void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e) { QPoint p(contentsToViewport(e->pos())); ConfigItem* item = (ConfigItem*)itemAt(p); struct menu *menu; const QPixmap* pm; int idx, x; if (!item) goto skip; menu = item->menu; x = header()->offset() + p.x(); idx = colRevMap[header()->sectionAt(x)]; switch (idx) { case promptColIdx: pm = item->pixmap(promptColIdx); if (pm) { int off = header()->sectionPos(0) + itemMargin() + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); if (x >= off && x < off + pm->width()) { if (menu->sym) changeValue(item); else emit menuSelected(menu); } } break; case noColIdx: setValue(item, no); break; case modColIdx: setValue(item, mod); break; case yesColIdx: setValue(item, yes); break; case dataColIdx: changeValue(item); break; } skip: //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y()); - QListView::contentsMouseReleaseEvent(e); + Parent::contentsMouseReleaseEvent(e); } void ConfigList::contentsMouseMoveEvent(QMouseEvent* e) { //QPoint p(contentsToViewport(e->pos())); //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y()); - QListView::contentsMouseMoveEvent(e); + Parent::contentsMouseMoveEvent(e); } void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e) { QPoint p(contentsToViewport(e->pos())); ConfigItem* item = (ConfigItem*)itemAt(p); struct menu *menu; enum prop_type ptype; if (!item) goto skip; menu = item->menu; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; if ((ptype == P_ROOTMENU || ptype == P_MENU) && (mode == singleMode || mode == symbolMode)) emit menuSelected(menu); + else if (menu->sym) + changeValue(item); skip: //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y()); - QListView::contentsMouseDoubleClickEvent(e); + Parent::contentsMouseDoubleClickEvent(e); } void ConfigList::focusInEvent(QFocusEvent *e) { Parent::focusInEvent(e); QListViewItem* item = currentItem(); if (!item) return; setSelected(item, TRUE); emit gotFocus(); } +ConfigView* ConfigView::viewList; + +ConfigView::ConfigView(QWidget* parent, ConfigMainWindow* cview) + : Parent(parent) +{ + list = new ConfigList(this, cview); + lineEdit = new ConfigLineEdit(this); + lineEdit->hide(); + + this->nextView = viewList; + viewList = this; +} + +ConfigView::~ConfigView(void) +{ + ConfigView** vp; + + for (vp = &viewList; *vp; vp = &(*vp)->nextView) { + if (*vp == this) { + *vp = nextView; + break; + } + } +} + +void ConfigView::updateList(ConfigItem* item) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateList(item); +} + +void ConfigView::updateListAll(void) +{ + ConfigView* v; + + for (v = viewList; v; v = v->nextView) + v->list->updateListAll(); +} + /* * Construct the complete config widget */ -ConfigView::ConfigView(void) +ConfigMainWindow::ConfigMainWindow(void) { + ConfigView* view; QMenuBar* menu; QSplitter* split1; QSplitter* split2; + bool ok; + int x, y, width, height; + + QWidget *d = configApp->desktop(); + +#if QT_VERSION >= 300 + width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64); + height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64); + resize(width, height); + x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok); + if (ok) + y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok); + if (ok) + move(x, y); +#else + width = d->width() - 64; + height = d->height() - 64; + resize(width, height); +#endif showDebug = false; split1 = new QSplitter(this); split1->setOrientation(QSplitter::Horizontal); setCentralWidget(split1); - menuList = new ConfigList(split1, this); + view = new ConfigView(split1, this); + menuList = view->list; split2 = new QSplitter(split1); split2->setOrientation(QSplitter::Vertical); // create config tree - QVBox* box = new QVBox(split2); - configList = new ConfigList(box, this); - configList->lineEdit = new ConfigLineEdit(box); - configList->lineEdit->hide(); - configList->connect(configList, SIGNAL(symbolChanged(ConfigItem*)), - configList, SLOT(updateList(ConfigItem*))); - configList->connect(configList, SIGNAL(symbolChanged(ConfigItem*)), - menuList, SLOT(updateList(ConfigItem*))); - configList->connect(configList->lineEdit, SIGNAL(lineChanged(ConfigItem*)), - SLOT(updateList(ConfigItem*))); + view = new ConfigView(split2, this); + configList = view->list; helpText = new QTextView(split2); helpText->setTextFormat(Qt::RichText); setTabOrder(configList, helpText); configList->setFocus(); menu = menuBar(); toolBar = new QToolBar("Tools", this); backAction = new QAction("Back", QPixmap(xpm_back), "Back", 0, this); connect(backAction, SIGNAL(activated()), SLOT(goBack())); backAction->setEnabled(FALSE); QAction *quitAction = new QAction("Quit", "&Quit", CTRL+Key_Q, this); connect(quitAction, SIGNAL(activated()), SLOT(close())); QAction *loadAction = new QAction("Load", QPixmap(xpm_load), "&Load", CTRL+Key_L, this); connect(loadAction, SIGNAL(activated()), SLOT(loadConfig())); QAction *saveAction = new QAction("Save", QPixmap(xpm_save), "&Save", CTRL+Key_S, this); connect(saveAction, SIGNAL(activated()), SLOT(saveConfig())); QAction *saveAsAction = new QAction("Save As...", "Save &As...", 0, this); connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs())); QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), "Split View", 0, this); connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView())); QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), "Split View", 0, this); connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView())); QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), "Full View", 0, this); connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView())); QAction *showNameAction = new QAction(NULL, "Show Name", 0, this); showNameAction->setToggleAction(TRUE); showNameAction->setOn(configList->showName); connect(showNameAction, SIGNAL(toggled(bool)), SLOT(setShowName(bool))); QAction *showRangeAction = new QAction(NULL, "Show Range", 0, this); showRangeAction->setToggleAction(TRUE); showRangeAction->setOn(configList->showRange); connect(showRangeAction, SIGNAL(toggled(bool)), SLOT(setShowRange(bool))); QAction *showDataAction = new QAction(NULL, "Show Data", 0, this); showDataAction->setToggleAction(TRUE); showDataAction->setOn(configList->showData); connect(showDataAction, SIGNAL(toggled(bool)), SLOT(setShowData(bool))); QAction *showAllAction = new QAction(NULL, "Show All Options", 0, this); showAllAction->setToggleAction(TRUE); showAllAction->setOn(configList->showAll); connect(showAllAction, SIGNAL(toggled(bool)), SLOT(setShowAll(bool))); QAction *showDebugAction = new QAction(NULL, "Show Debug Info", 0, this); showDebugAction->setToggleAction(TRUE); showDebugAction->setOn(showDebug); connect(showDebugAction, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); + QAction *showIntroAction = new QAction(NULL, "Introduction", 0, this); + connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro())); + QAction *showAboutAction = new QAction(NULL, "About", 0, this); + connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout())); + // init tool bar backAction->addTo(toolBar); toolBar->addSeparator(); loadAction->addTo(toolBar); saveAction->addTo(toolBar); toolBar->addSeparator(); singleViewAction->addTo(toolBar); splitViewAction->addTo(toolBar); fullViewAction->addTo(toolBar); // create config menu QPopupMenu* config = new QPopupMenu(this); menu->insertItem("&File", config); loadAction->addTo(config); saveAction->addTo(config); saveAsAction->addTo(config); config->insertSeparator(); quitAction->addTo(config); // create options menu QPopupMenu* optionMenu = new QPopupMenu(this); menu->insertItem("&Option", optionMenu); showNameAction->addTo(optionMenu); showRangeAction->addTo(optionMenu); showDataAction->addTo(optionMenu); optionMenu->insertSeparator(); showAllAction->addTo(optionMenu); showDebugAction->addTo(optionMenu); + // create help menu + QPopupMenu* helpMenu = new QPopupMenu(this); + menu->insertSeparator(); + menu->insertItem("&Help", helpMenu); + showIntroAction->addTo(helpMenu); + showAboutAction->addTo(helpMenu); + connect(configList, SIGNAL(menuSelected(struct menu *)), SLOT(changeMenu(struct menu *))); connect(configList, SIGNAL(parentSelected()), SLOT(goBack())); connect(menuList, SIGNAL(menuSelected(struct menu *)), SLOT(changeMenu(struct menu *))); connect(configList, SIGNAL(gotFocus(void)), SLOT(listFocusChanged(void))); connect(menuList, SIGNAL(gotFocus(void)), SLOT(listFocusChanged(void))); //showFullView(); showSplitView(); } static QString print_filter(const char *str) { QRegExp re("[<>&\"\\n]"); QString res = str; for (int i = 0; (i = res.find(re, i)) >= 0;) { switch (res[i].latin1()) { case '<': res.replace(i, 1, "<"); i += 4; break; case '>': res.replace(i, 1, ">"); i += 4; break; case '&': res.replace(i, 1, "&"); i += 5; break; case '"': res.replace(i, 1, """); i += 6; break; case '\n': res.replace(i, 1, "<br>"); i += 4; break; } } return res; } static void expr_print_help(void *data, const char *str) { ((QString*)data)->append(print_filter(str)); } /* * display a new help entry as soon as a new menu entry is selected */ -void ConfigView::setHelp(QListViewItem* item) +void ConfigMainWindow::setHelp(QListViewItem* item) { struct symbol* sym; struct menu* menu; - configList->lineEdit->hide(); + configList->parent()->lineEdit->hide(); if (item) { QString head, debug, help; menu = ((ConfigItem*)item)->menu; sym = menu->sym; if (sym) { if (menu->prompt) { head += "<big><b>"; head += print_filter(menu->prompt->text); head += "</b></big>"; if (sym->name) { head += " ("; head += print_filter(sym->name); head += ")"; } } else if (sym->name) { head += "<big><b>"; head += print_filter(sym->name); head += "</b></big>"; } head += "<br><br>"; if (showDebug) { debug += "type: "; debug += print_filter(sym_type_name(sym->type)); debug += "<br>"; for (struct property *prop = sym->prop; prop; prop = prop->next) { switch (prop->type) { case P_PROMPT: debug += "prompt: "; debug += print_filter(prop->text); debug += "<br>"; if (prop->visible.expr) { debug += " dep: "; expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); debug += "<br>"; } break; case P_DEFAULT: debug += "default: "; if (sym_is_choice(sym)) debug += print_filter(prop->def->name); else { sym_calc_value(prop->def); debug += print_filter(sym_get_string_value(prop->def)); } debug += "<br>"; if (prop->visible.expr) { debug += " dep: "; expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); debug += "<br>"; } break; case P_CHOICE: break; default: debug += "unknown property: "; debug += prop_get_type_name(prop->type); debug += "<br>"; } } debug += "<br>"; } help = print_filter(sym->help); } else if (menu->prompt) { head += "<big><b>"; head += print_filter(menu->prompt->text); head += "</b></big><br><br>"; if (showDebug) { if (menu->prompt->visible.expr) { debug += " dep: "; expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); debug += "<br>"; } } } helpText->setText(head + debug + help); return; } helpText->setText(NULL); } -void ConfigView::loadConfig(void) +void ConfigMainWindow::loadConfig(void) { QString s = QFileDialog::getOpenFileName(".config", NULL, this); if (s.isNull()) return; if (conf_read(s.latin1())) QMessageBox::information(this, "qconf", "Unable to load configuration!"); + ConfigView::updateListAll(); } -void ConfigView::saveConfig(void) +void ConfigMainWindow::saveConfig(void) { if (conf_write(NULL)) QMessageBox::information(this, "qconf", "Unable to save configuration!"); } -void ConfigView::saveConfigAs(void) +void ConfigMainWindow::saveConfigAs(void) { QString s = QFileDialog::getSaveFileName(".config", NULL, this); if (s.isNull()) return; if (conf_write(s.latin1())) QMessageBox::information(this, "qconf", "Unable to save configuration!"); } -void ConfigView::changeMenu(struct menu *menu) +void ConfigMainWindow::changeMenu(struct menu *menu) { configList->setRootMenu(menu); backAction->setEnabled(TRUE); } -void ConfigView::listFocusChanged(void) +void ConfigMainWindow::listFocusChanged(void) { if (menuList->hasFocus()) { if (menuList->mode == menuMode) configList->clearSelection(); setHelp(menuList->selectedItem()); } else if (configList->hasFocus()) { setHelp(configList->selectedItem()); } } -void ConfigView::goBack(void) +void ConfigMainWindow::goBack(void) { ConfigItem* item; configList->setParentMenu(); if (configList->rootEntry == &rootmenu) backAction->setEnabled(FALSE); item = (ConfigItem*)menuList->selectedItem(); while (item) { if (item->menu == configList->rootEntry) { menuList->setSelected(item, TRUE); break; } item = (ConfigItem*)item->parent(); } } -void ConfigView::showSingleView(void) +void ConfigMainWindow::showSingleView(void) { menuList->hide(); menuList->setRootMenu(0); configList->mode = singleMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(TRUE); configList->setFocus(); } -void ConfigView::showSplitView(void) +void ConfigMainWindow::showSplitView(void) { configList->mode = symbolMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(TRUE); configApp->processEvents(); menuList->mode = menuMode; menuList->setRootMenu(&rootmenu); menuList->show(); menuList->setAllOpen(TRUE); menuList->setFocus(); } -void ConfigView::showFullView(void) +void ConfigMainWindow::showFullView(void) { menuList->hide(); menuList->setRootMenu(0); configList->mode = fullMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(FALSE); configList->setFocus(); } -void ConfigView::setShowAll(bool b) +void ConfigMainWindow::setShowAll(bool b) { if (configList->showAll == b) return; configList->showAll = b; configList->updateListAll(); menuList->showAll = b; menuList->updateListAll(); } -void ConfigView::setShowDebug(bool b) +void ConfigMainWindow::setShowDebug(bool b) { if (showDebug == b) return; showDebug = b; } -void ConfigView::setShowName(bool b) +void ConfigMainWindow::setShowName(bool b) { if (configList->showName == b) return; configList->showName = b; configList->reinit(); } -void ConfigView::setShowRange(bool b) +void ConfigMainWindow::setShowRange(bool b) { if (configList->showRange == b) return; configList->showRange = b; configList->reinit(); } -void ConfigView::setShowData(bool b) +void ConfigMainWindow::setShowData(bool b) { if (configList->showData == b) return; configList->showData = b; configList->reinit(); } /* * ask for saving configuration before quitting * TODO ask only when something changed */ -void ConfigView::closeEvent(QCloseEvent* e) +void ConfigMainWindow::closeEvent(QCloseEvent* e) { if (!sym_change_count) { e->accept(); return; } QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning, QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); mb.setButtonText(QMessageBox::Yes, "&Save Changes"); mb.setButtonText(QMessageBox::No, "&Discard Changes"); mb.setButtonText(QMessageBox::Cancel, "Cancel Exit"); switch (mb.exec()) { case QMessageBox::Yes: conf_write(NULL); case QMessageBox::No: e->accept(); break; case QMessageBox::Cancel: e->ignore(); break; } } +void ConfigMainWindow::showIntro(void) +{ + static char str[] = "Welcome to the qconf graphical kernel configuration tool for Linux.\n\n" + "For each option, a blank box indicates the feature is disabled, a check\n" + "indicates it is enabled, and a dot indicates that it is to be compiled\n" + "as a module. Clicking on the box will cycle through the three states.\n\n" + "If you do not see an option (e.g., a device driver) that you believe\n" + "should be present, try turning on Show All Options under the Options menu.\n" + "Although there is no cross reference yet to help you figure out what other\n" + "options must be enabled to support the option you are interested in, you can\n" + "still view the help of a grayed-out option.\n\n" + "Toggling Show Debug Info under the Options menu will show the dependencies,\n" + "which you can then match by examining other options.\n\n"; + + QMessageBox::information(this, "qconf", str); +} + +void ConfigMainWindow::showAbout(void) +{ + static char str[] = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"; + + QMessageBox::information(this, "qconf", str); +} + void fixup_rootmenu(struct menu *menu) { struct menu *child; if (!menu->prompt || menu->prompt->type != P_MENU) return; menu->prompt->type = P_ROOTMENU; for (child = menu->list; child; child = child->next) fixup_rootmenu(child); } int main(int ac, char** av) { - ConfigView* v; + ConfigMainWindow* v; const char *name; #ifndef LKC_DIRECT_LINK kconfig_load(); #endif configApp = new QApplication(ac, av); +#if QT_VERSION >= 300 + configSettings = new QSettings; +#endif if (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { case 'a': //showAll = 1; break; case 'h': case '?': printf("%s <config>\n", av[0]); exit(0); } name = av[2]; } else name = av[1]; conf_parse(name); fixup_rootmenu(&rootmenu); conf_read(NULL); //zconfdump(stdout); - v = new ConfigView(); + + v = new ConfigMainWindow(); //zconfdump(stdout); v->show(); configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit())); configApp->exec(); + +#if QT_VERSION >= 300 + configSettings->writeEntry("/kconfig/qconf/window x", v->pos().x()); + configSettings->writeEntry("/kconfig/qconf/window y", v->pos().y()); + configSettings->writeEntry("/kconfig/qconf/window width", v->size().width()); + configSettings->writeEntry("/kconfig/qconf/window height", v->size().height()); + delete configSettings; +#endif return 0; } diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index f8f3669..6f096b4 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -1,201 +1,226 @@ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ #include <qlistview.h> -class ConfigLineEdit; +class ConfigList; class ConfigItem; -class ConfigView; +class ConfigLineEdit; +class ConfigMainWindow; + +class ConfigView : public QVBox { + Q_OBJECT + typedef class QVBox Parent; +public: + ConfigView(QWidget* parent, ConfigMainWindow* cview); + ~ConfigView(void); + static void updateList(ConfigItem* item); + static void updateListAll(void); + +public: + ConfigList* list; + ConfigLineEdit* lineEdit; + + static ConfigView* viewList; + ConfigView* nextView; +}; enum colIdx { promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr }; enum listMode { singleMode, menuMode, symbolMode, fullMode }; class ConfigList : public QListView { Q_OBJECT typedef class QListView Parent; public: - ConfigList(QWidget* p, ConfigView* cview); + ConfigList(ConfigView* p, ConfigMainWindow* cview); void reinit(void); + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } - ConfigLineEdit* lineEdit; protected: - ConfigView* cview; + ConfigMainWindow* cview; void keyPressEvent(QKeyEvent *e); void contentsMousePressEvent(QMouseEvent *e); void contentsMouseReleaseEvent(QMouseEvent *e); void contentsMouseMoveEvent(QMouseEvent *e); void contentsMouseDoubleClickEvent(QMouseEvent *e); void focusInEvent(QFocusEvent *e); public slots: void setRootMenu(struct menu *menu); void updateList(ConfigItem *item); void setValue(ConfigItem* item, tristate val); void changeValue(ConfigItem* item); void updateSelection(void); signals: void menuSelected(struct menu *menu); void parentSelected(void); - void symbolChanged(ConfigItem* item); void gotFocus(void); public: void updateListAll(void) { updateAll = true; updateList(NULL); updateAll = false; } ConfigList* listView() { return this; } ConfigItem* firstChild() const { return (ConfigItem *)Parent::firstChild(); } int mapIdx(colIdx idx) { return colMap[idx]; } void addColumn(colIdx idx, const QString& label) { colMap[idx] = Parent::addColumn(label); colRevMap[colMap[idx]] = idx; } void removeColumn(colIdx idx) { int col = colMap[idx]; if (col >= 0) { Parent::removeColumn(col); colRevMap[col] = colMap[idx] = -1; } } void setAllOpen(bool open); void setParentMenu(void); bool updateAll; QPixmap symbolYesPix, symbolModPix, symbolNoPix; QPixmap choiceYesPix, choiceNoPix, menuPix, menuInvPix; bool showAll, showName, showRange, showData; enum listMode mode; struct menu *rootEntry; QColorGroup disabledColorGroup; QColorGroup inactivedColorGroup; private: int colMap[colNr]; int colRevMap[colNr]; }; class ConfigItem : public QListViewItem { typedef class QListViewItem Parent; public: - ConfigItem(QListView *parent, ConfigItem *after, struct menu *m) - : Parent(parent, after), menu(m) + ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v) { init(); } - ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m) - : Parent(parent, after), menu(m) + ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v) + : Parent(parent, after), menu(m), visible(v) { init(); } ~ConfigItem(void); void init(void); #if QT_VERSION >= 300 void okRename(int col); #endif void updateMenu(void); + bool updateNeeded(void); ConfigList* listView() const { return (ConfigList*)Parent::listView(); } ConfigItem* firstChild() const { return (ConfigItem *)Parent::firstChild(); } ConfigItem* nextSibling() const { return (ConfigItem *)Parent::nextSibling(); } void setText(colIdx idx, const QString& text) { Parent::setText(listView()->mapIdx(idx), text); } QString text(colIdx idx) const { return Parent::text(listView()->mapIdx(idx)); } void setPixmap(colIdx idx, const QPixmap& pm) { Parent::setPixmap(listView()->mapIdx(idx), pm); } const QPixmap* pixmap(colIdx idx) const { return Parent::pixmap(listView()->mapIdx(idx)); } void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align); + ConfigItem* nextItem; struct menu *menu; bool visible; - bool doInit; }; class ConfigLineEdit : public QLineEdit { Q_OBJECT typedef class QLineEdit Parent; public: - ConfigLineEdit(QWidget * parent) - : QLineEdit(parent) + ConfigLineEdit(ConfigView* parent) + : Parent(parent) { } + ConfigView* parent(void) const + { + return (ConfigView*)Parent::parent(); + } void show(ConfigItem *i); void keyPressEvent(QKeyEvent *e); -signals: - void lineChanged(ConfigItem *item); public: ConfigItem *item; }; -class ConfigView : public QMainWindow { +class ConfigMainWindow : public QMainWindow { Q_OBJECT public: - ConfigView(void); + ConfigMainWindow(void); public slots: void setHelp(QListViewItem* item); void changeMenu(struct menu *); void listFocusChanged(void); void goBack(void); void loadConfig(void); void saveConfig(void); void saveConfigAs(void); void showSingleView(void); void showSplitView(void); void showFullView(void); void setShowAll(bool); void setShowDebug(bool); void setShowRange(bool); void setShowName(bool); void setShowData(bool); + void showIntro(void); + void showAbout(void); protected: void closeEvent(QCloseEvent *e); ConfigList *menuList; ConfigList *configList; QTextView *helpText; QToolBar *toolBar; QAction *backAction; bool showDebug; }; diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 59c88d2..845d8a3 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -88,531 +88,542 @@ int sym_get_type(struct symbol *sym) if (sym_is_choice_value(sym) && sym->visible == yes) type = S_BOOLEAN; else { sym_calc_value(modules_sym); if (S_TRI(modules_sym->curr) == no) type = S_BOOLEAN; } } return type; } const char *sym_type_name(int type) { switch (type) { case S_BOOLEAN: return "boolean"; case S_TRISTATE: return "tristate"; case S_INT: return "integer"; case S_HEX: return "hex"; case S_STRING: return "string"; case S_UNKNOWN: return "unknown"; } return "???"; } struct property *sym_get_choice_prop(struct symbol *sym) { struct property *prop; for_all_choices(sym, prop) return prop; return NULL; } struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; tristate visible; for_all_defaults(sym, prop) { visible = E_CALC(prop->visible); if (visible != no) return prop; } return NULL; } void sym_calc_visibility(struct symbol *sym) { struct property *prop; tristate visible, oldvisible; /* any prompt visible? */ oldvisible = sym->visible; visible = no; for_all_prompts(sym, prop) visible = E_OR(visible, E_CALC(prop->visible)); if (oldvisible != visible) { sym->visible = visible; - sym->flags |= SYMBOL_CHANGED; + sym_set_changed(sym); } } void sym_calc_value(struct symbol *sym) { struct symbol_value newval, oldval; struct property *prop, *def_prop; struct symbol *def_sym; struct expr *e; if (sym->flags & SYMBOL_VALID) return; oldval = sym->curr; switch (sym->type) { case S_INT: case S_HEX: case S_STRING: newval = symbol_empty.curr; break; case S_BOOLEAN: case S_TRISTATE: newval = symbol_no.curr; break; default: S_VAL(newval) = sym->name; S_TRI(newval) = no; if (sym->flags & SYMBOL_CONST) { goto out; } //newval = symbol_empty.curr; // generate warning somewhere here later //S_TRI(newval) = yes; goto out; } sym->flags |= SYMBOL_VALID; if (!sym_is_choice_value(sym)) sym->flags &= ~SYMBOL_WRITE; sym_calc_visibility(sym); /* set default if recursively called */ sym->curr = newval; if (sym->visible != no) { sym->flags |= SYMBOL_WRITE; if (!sym_has_value(sym)) { if (!sym_is_choice(sym)) { prop = sym_get_default_prop(sym); if (prop) { sym_calc_value(prop->def); newval = prop->def->curr; } - } + } else + S_TRI(newval) = S_TRI(sym->def); } else newval = sym->def; S_TRI(newval) = E_AND(S_TRI(newval), sym->visible); /* if the symbol is visible and not optionial, * possibly ignore old user choice. */ if (!sym_is_optional(sym) && S_TRI(newval) == no) S_TRI(newval) = sym->visible; if (sym_is_choice_value(sym) && sym->visible == yes) { prop = sym_get_choice_prop(sym); S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no; } } else { prop = sym_get_default_prop(sym); if (prop) { sym->flags |= SYMBOL_WRITE; sym_calc_value(prop->def); newval = prop->def->curr; } } switch (sym_get_type(sym)) { case S_TRISTATE: if (S_TRI(newval) != mod) break; sym_calc_value(modules_sym); if (S_TRI(modules_sym->curr) == no) S_TRI(newval) = yes; break; case S_BOOLEAN: if (S_TRI(newval) == mod) S_TRI(newval) = yes; } out: sym->curr = newval; if (sym_is_choice(sym) && S_TRI(newval) == yes) { def_sym = S_VAL(sym->def); if (def_sym) { sym_calc_visibility(def_sym); if (def_sym->visible == no) def_sym = NULL; } if (!def_sym) { for_all_defaults(sym, def_prop) { if (E_CALC(def_prop->visible) == no) continue; sym_calc_visibility(def_prop->def); if (def_prop->def->visible != no) { def_sym = def_prop->def; break; } } } if (!def_sym) { prop = sym_get_choice_prop(sym); for (e = prop->dep; e; e = e->left.expr) { sym_calc_visibility(e->right.sym); if (e->right.sym->visible != no) { def_sym = e->right.sym; break; } } } S_VAL(newval) = def_sym; } if (memcmp(&oldval, &newval, sizeof(newval))) - sym->flags |= SYMBOL_CHANGED; + sym_set_changed(sym); sym->curr = newval; if (sym_is_choice(sym)) { int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); prop = sym_get_choice_prop(sym); - for (e = prop->dep; e; e = e->left.expr) + for (e = prop->dep; e; e = e->left.expr) { e->right.sym->flags |= flags; + if (flags & SYMBOL_CHANGED) + sym_set_changed(e->right.sym); + } } } void sym_clear_all_valid(void) { struct symbol *sym; int i; for_all_symbols(i, sym) sym->flags &= ~SYMBOL_VALID; sym_change_count++; } +void sym_set_changed(struct symbol *sym) +{ + struct property *prop; + + sym->flags |= SYMBOL_CHANGED; + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->menu) + prop->menu->flags |= MENU_CHANGED; + } +} + void sym_set_all_changed(void) { struct symbol *sym; int i; for_all_symbols(i, sym) - sym->flags |= SYMBOL_CHANGED; + sym_set_changed(sym); } bool sym_tristate_within_range(struct symbol *sym, tristate val) { int type = sym_get_type(sym); if (sym->visible == no) return false; if (type != S_BOOLEAN && type != S_TRISTATE) return false; switch (val) { case no: if (sym_is_choice_value(sym) && sym->visible == yes) return false; return sym_is_optional(sym); case mod: if (sym_is_choice_value(sym) && sym->visible == yes) return false; return type == S_TRISTATE; case yes: return type == S_BOOLEAN || sym->visible == yes; } return false; } bool sym_set_tristate_value(struct symbol *sym, tristate val) { tristate oldval = sym_get_tristate_value(sym); if (oldval != val && !sym_tristate_within_range(sym, val)) return false; if (sym->flags & SYMBOL_NEW) { sym->flags &= ~SYMBOL_NEW; - sym->flags |= SYMBOL_CHANGED; + sym_set_changed(sym); } if (sym_is_choice_value(sym) && val == yes) { struct property *prop = sym_get_choice_prop(sym); S_VAL(prop->def->def) = sym; prop->def->flags &= ~SYMBOL_NEW; } S_TRI(sym->def) = val; if (oldval != val) { sym_clear_all_valid(); if (sym == modules_sym) sym_set_all_changed(); } return true; } tristate sym_toggle_tristate_value(struct symbol *sym) { tristate oldval, newval; oldval = newval = sym_get_tristate_value(sym); do { switch (newval) { case no: newval = mod; break; case mod: newval = yes; break; case yes: newval = no; break; } if (sym_set_tristate_value(sym, newval)) break; } while (oldval != newval); return newval; } bool sym_string_valid(struct symbol *sym, const char *str) { char ch; switch (sym->type) { case S_STRING: return true; case S_INT: ch = *str++; if (ch == '-') ch = *str++; if (!isdigit(ch)) return false; if (ch == '0' && *str != 0) return false; while ((ch = *str++)) { if (!isdigit(ch)) return false; } return true; case S_HEX: if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) str += 2; ch = *str++; do { if (!isxdigit(ch)) return false; } while ((ch = *str++)); return true; case S_BOOLEAN: case S_TRISTATE: switch (str[0]) { case 'y': case 'Y': return sym_tristate_within_range(sym, yes); case 'm': case 'M': return sym_tristate_within_range(sym, mod); case 'n': case 'N': return sym_tristate_within_range(sym, no); } return false; default: return false; } } bool sym_set_string_value(struct symbol *sym, const char *newval) { const char *oldval; char *val; int size; switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: switch (newval[0]) { case 'y': case 'Y': return sym_set_tristate_value(sym, yes); case 'm': case 'M': return sym_set_tristate_value(sym, mod); case 'n': case 'N': return sym_set_tristate_value(sym, no); } return false; default: ; } if (!sym_string_valid(sym, newval)) return false; if (sym->flags & SYMBOL_NEW) { sym->flags &= ~SYMBOL_NEW; - sym->flags |= SYMBOL_CHANGED; + sym_set_changed(sym); } oldval = S_VAL(sym->def); size = strlen(newval) + 1; if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { size += 2; S_VAL(sym->def) = val = malloc(size); *val++ = '0'; *val++ = 'x'; } else if (!oldval || strcmp(oldval, newval)) S_VAL(sym->def) = val = malloc(size); else return true; strcpy(val, newval); free((void *)oldval); sym_clear_all_valid(); return true; } const char *sym_get_string_value(struct symbol *sym) { tristate val; switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: val = sym_get_tristate_value(sym); switch (val) { case no: return "n"; case mod: return "m"; case yes: return "y"; } break; default: ; } return (const char *)S_VAL(sym->curr); } bool sym_is_changable(struct symbol *sym) { if (sym->visible == no) return false; /* at least 'n' and 'y'/'m' is selectable */ if (sym_is_optional(sym)) return true; /* no 'n', so 'y' and 'm' must be selectable */ if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes) return true; return false; } struct symbol *sym_lookup(const char *name, int isconst) { struct symbol *symbol; const char *ptr; char *new_name; int hash = 0; - //printf("lookup: %s -> ", name); if (name) { if (name[0] && !name[1]) { switch (name[0]) { case 'y': return &symbol_yes; case 'm': return &symbol_mod; case 'n': return &symbol_no; } } for (ptr = name; *ptr; ptr++) hash += *ptr; hash &= 0xff; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { if (!strcmp(symbol->name, name)) { if ((isconst && symbol->flags & SYMBOL_CONST) || - (!isconst && !(symbol->flags & SYMBOL_CONST))) { - //printf("h:%p\n", symbol); + (!isconst && !(symbol->flags & SYMBOL_CONST))) return symbol; - } } } new_name = strdup(name); } else { new_name = NULL; hash = 256; } symbol = malloc(sizeof(*symbol)); memset(symbol, 0, sizeof(*symbol)); symbol->name = new_name; symbol->type = S_UNKNOWN; symbol->flags = SYMBOL_NEW; if (isconst) symbol->flags |= SYMBOL_CONST; symbol->next = symbol_hash[hash]; symbol_hash[hash] = symbol; - //printf("n:%p\n", symbol); return symbol; } struct symbol *sym_find(const char *name) { struct symbol *symbol = NULL; const char *ptr; int hash = 0; if (!name) return NULL; if (name[0] && !name[1]) { switch (name[0]) { case 'y': return &symbol_yes; case 'm': return &symbol_mod; case 'n': return &symbol_no; } } for (ptr = name; *ptr; ptr++) hash += *ptr; hash &= 0xff; for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { if (!strcmp(symbol->name, name) && !(symbol->flags & SYMBOL_CONST)) break; } return symbol; } const char *prop_get_type_name(enum prop_type type) { switch (type) { case P_PROMPT: return "prompt"; case P_COMMENT: return "comment"; case P_MENU: return "menu"; case P_ROOTMENU: return "rootmenu"; case P_DEFAULT: return "default"; case P_CHOICE: return "choice"; default: return "unknown"; } } diff --git a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l index 6d81e5e..1471630 100644 --- a/scripts/kconfig/zconf.l +++ b/scripts/kconfig/zconf.l @@ -1,323 +1,359 @@ -%option backup nostdinit noyywrap full ecs +%option backup nostdinit noyywrap never-interactive full ecs %option 8bit backup nodefault perf-report perf-report %x COMMAND HELP STRING PARAM %{ /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> * Released under the terms of the GNU GPL v2.0. */ +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define LKC_DIRECT_LINK #include "lkc.h" -#include "zconf.tab.h" #define START_STRSIZE 16 char *text; static char *text_ptr; static int text_size, text_asize; struct buffer { struct buffer *parent; YY_BUFFER_STATE state; }; struct buffer *current_buf; static int last_ts, first_ts; static void zconf_endhelp(void); static struct buffer *zconf_endfile(void); void new_string(void) { text = malloc(START_STRSIZE); text_asize = START_STRSIZE; text_ptr = text; text_size = 0; *text_ptr = 0; } void append_string(const char *str, int size) { int new_size = text_size + size + 1; if (new_size > text_asize) { text = realloc(text, new_size); text_asize = new_size; text_ptr = text + text_size; } memcpy(text_ptr, str, size); text_ptr += size; text_size += size; *text_ptr = 0; } void alloc_string(const char *str, int size) { text = malloc(size + 1); memcpy(text, str, size); text[size] = 0; } %} ws [ \n\t] n [A-Za-z0-9_] %% int str = 0; int ts, i; [ \t]*#.*\n current_file->lineno++; [ \t]*#.* [ \t]*\n current_file->lineno++; return T_EOL; [ \t]+ { BEGIN(COMMAND); } . { unput(yytext[0]); - //printf("new config: "); - //symbol_end(NULL); BEGIN(COMMAND); } <COMMAND>{ "mainmenu" BEGIN(PARAM); return T_MAINMENU; "menu" BEGIN(PARAM); return T_MENU; "endmenu" BEGIN(PARAM); return T_ENDMENU; "source" BEGIN(PARAM); return T_SOURCE; "choice" BEGIN(PARAM); return T_CHOICE; "endchoice" BEGIN(PARAM); return T_ENDCHOICE; "comment" BEGIN(PARAM); return T_COMMENT; "config" BEGIN(PARAM); return T_CONFIG; "help" BEGIN(PARAM); return T_HELP; "if" BEGIN(PARAM); return T_IF; "endif" BEGIN(PARAM); return T_ENDIF; "depends" BEGIN(PARAM); return T_DEPENDS; "requires" BEGIN(PARAM); return T_REQUIRES; "optional" BEGIN(PARAM); return T_OPTIONAL; "default" BEGIN(PARAM); return T_DEFAULT; "prompt" BEGIN(PARAM); return T_PROMPT; "tristate" BEGIN(PARAM); return T_TRISTATE; "bool" BEGIN(PARAM); return T_BOOLEAN; "boolean" BEGIN(PARAM); return T_BOOLEAN; "int" BEGIN(PARAM); return T_INT; "hex" BEGIN(PARAM); return T_HEX; "string" BEGIN(PARAM); return T_STRING; {n}+ { alloc_string(yytext, yyleng); zconflval.string = text; return T_WORD; } . \n current_file->lineno++; BEGIN(INITIAL); } <PARAM>{ "&&" return T_AND; "||" return T_OR; "(" return T_OPEN_PAREN; ")" return T_CLOSE_PAREN; "!" return T_NOT; "=" return T_EQUAL; "!=" return T_UNEQUAL; "if" return T_IF; "on" return T_ON; \"|\' { str = yytext[0]; new_string(); BEGIN(STRING); } \n BEGIN(INITIAL); current_file->lineno++; return T_EOL; --- /* ignore */ ({n}|[-/.])+ { alloc_string(yytext, yyleng); zconflval.string = text; return T_WORD; } + \\\n current_file->lineno++; . + <<EOF>> { + BEGIN(INITIAL); + } } <STRING>{ - [^'"\n\\]+ { + [^'"\\\n]+/\n { + append_string(yytext, yyleng); + zconflval.string = text; + return T_STRING; + } + [^'"\\\n]+ { append_string(yytext, yyleng); } + \\.?/\n { + append_string(yytext + 1, yyleng - 1); + zconflval.string = text; + return T_STRING; + } + \\.? { + append_string(yytext + 1, yyleng - 1); + } \'|\" { if (str == yytext[0]) { BEGIN(PARAM); zconflval.string = text; - //printf("s:%s\n", text); return T_STRING; } else append_string(yytext, 1); } - \\[ \t]*\n append_string(yytext+yyleng-1, 1); current_file->lineno++; - \\[ \t]* append_string(yytext+1, yyleng-1); - \\. append_string(yytext+1, 1); \n { - //printf(":%d: open string!\n", current_file->lineno+1); - exit(0); + printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); + current_file->lineno++; + BEGIN(INITIAL); + return T_EOL; } <<EOF>> { - //printf(":%d: open string!\n", current_file->lineno+1); - exit(0); + BEGIN(INITIAL); } } <HELP>{ [ \t]+ { ts = 0; for (i = 0; i < yyleng; i++) { if (yytext[i] == '\t') ts = (ts & ~7) + 8; else ts++; } last_ts = ts; if (first_ts) { if (ts < first_ts) { zconf_endhelp(); return T_HELPTEXT; } ts -= first_ts; while (ts > 8) { append_string(" ", 8); ts -= 8; } append_string(" ", ts); } } \n/[^ \t\n] { current_file->lineno++; zconf_endhelp(); return T_HELPTEXT; } [ \t]*\n { current_file->lineno++; append_string("\n", 1); } [^ \t\n].* { append_string(yytext, yyleng); if (!first_ts) first_ts = last_ts; } <<EOF>> { zconf_endhelp(); return T_HELPTEXT; } } <<EOF>> { if (current_buf) { zconf_endfile(); return T_EOF; } + fclose(yyin); yyterminate(); } %% void zconf_starthelp(void) { new_string(); last_ts = first_ts = 0; BEGIN(HELP); } static void zconf_endhelp(void) { zconflval.string = text; BEGIN(INITIAL); } + +/* + * Try to open specified file with following names: + * ./name + * $(srctree)/name + * The latter is used when srctree is separate from objtree + * when compiling the kernel. + * Return NULL if file is not found. + */ +FILE *zconf_fopen(const char *name) +{ + char *env, fullname[PATH_MAX+1]; + FILE *f; + + f = fopen(name, "r"); + if (!f && name[0] != '/') { + env = getenv(SRCTREE); + if (env) { + sprintf(fullname, "%s/%s", env, name); + f = fopen(fullname, "r"); + } + } + return f; +} + void zconf_initscan(const char *name) { - yyin = fopen(name, "r"); + yyin = zconf_fopen(name); if (!yyin) { printf("can't find file %s\n", name); exit(1); } - //fprintf(stderr, "zconf_initscan: %s\n", name); current_buf = malloc(sizeof(*current_buf)); memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); current_file->lineno = 1; current_file->flags = FILE_BUSY; } void zconf_nextfile(const char *name) { struct file *file = file_lookup(name); struct buffer *buf = malloc(sizeof(*buf)); memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; - yyin = fopen(name, "r"); + yyin = zconf_fopen(name); if (!yyin) { printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); buf->parent = current_buf; current_buf = buf; - //fprintf(stderr, "zconf_nextfile: %s\n", name); - if (file->flags & FILE_BUSY) { printf("recursive scan (%s)?\n", name); exit(1); } if (file->flags & FILE_SCANNED) { printf("file %s already scanned?\n", name); exit(1); } file->flags |= FILE_BUSY; file->lineno = 1; file->parent = current_file; current_file = file; } static struct buffer *zconf_endfile(void) { struct buffer *parent; current_file->flags |= FILE_SCANNED; current_file->flags &= ~FILE_BUSY; current_file = current_file->parent; parent = current_buf->parent; if (parent) { + fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(parent->state); } free(current_buf); current_buf = parent; return parent; } int zconf_lineno(void) { if (current_buf) return current_file->lineno; else return 0; } char *zconf_curname(void) { if (current_buf) return current_file->name; else return "<none>"; } diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index c3f1bd0..996b10a 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -166,147 +166,145 @@ config_option: T_PROMPT prompt if_expr { menu_add_prop(P_PROMPT, $2, NULL, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; config_option: T_DEFAULT symbol if_expr { menu_add_prop(P_DEFAULT, NULL, $2, $3); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); }; /* choice entry */ choice: T_CHOICE { struct symbol *sym = sym_lookup(NULL, 0); sym->flags |= SYMBOL_CHOICE; menu_add_entry(sym); menu_add_prop(P_CHOICE, NULL, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); }; choice_entry: choice T_EOL choice_option_list { menu_end_entry(); menu_add_menu(); }; choice_end: end { if (zconf_endtoken($1, T_CHOICE, T_ENDCHOICE)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); } }; choice_stmt: choice_entry choice_block choice_end T_EOL | choice_entry choice_block { printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno); zconfnerrs++; }; choice_option_list: /* empty */ | choice_option_list choice_option T_EOL | choice_option_list depends T_EOL | choice_option_list help | choice_option_list T_EOL ; choice_option: T_PROMPT prompt if_expr { menu_add_prop(P_PROMPT, $2, NULL, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; choice_option: T_OPTIONAL { current_entry->sym->flags |= SYMBOL_OPTIONAL; printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); }; -choice_option: T_DEFAULT symbol +choice_option: T_DEFAULT symbol if_expr { - menu_add_prop(P_DEFAULT, NULL, $2, NULL); - //current_choice->prop->def = $2; + menu_add_prop(P_DEFAULT, NULL, $2, $3); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); }; choice_block: /* empty */ | choice_block common_block ; /* if entry */ if: T_IF expr { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); - //current_entry->prompt = menu_add_prop(T_IF, NULL, NULL, $2); menu_add_dep($2); menu_end_entry(); menu_add_menu(); }; if_end: end { if (zconf_endtoken($1, T_IF, T_ENDIF)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); } }; if_stmt: if T_EOL if_block if_end T_EOL | if T_EOL if_block { printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno); zconfnerrs++; }; if_block: /* empty */ | if_block common_block | if_block menu_stmt | if_block choice_stmt ; /* menu entry */ menu: T_MENU prompt { menu_add_entry(NULL); menu_add_prop(P_MENU, $2, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); }; menu_entry: menu T_EOL depends_list { menu_end_entry(); menu_add_menu(); }; menu_end: end { if (zconf_endtoken($1, T_MENU, T_ENDMENU)) { menu_end_menu(); printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); } }; menu_stmt: menu_entry menu_block menu_end T_EOL | menu_entry menu_block { printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno); zconfnerrs++; }; menu_block: /* empty */ | menu_block common_block | menu_block menu_stmt | menu_block choice_stmt |