Browse Source

pull kconfig from linux-3.11

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Bernhard Reutner-Fischer 10 years ago
parent
commit
e286a67441
49 changed files with 6943 additions and 2047 deletions
  1. 32 23
      Makefile.in
  2. 19 14
      Rules.mak
  3. 5 1
      extra/Configs/Config.in
  4. 5 2
      extra/config/.gitignore
  5. 17 23
      extra/config/Makefile
  6. 161 128
      extra/config/Makefile.kconfig
  7. 1 1
      extra/config/README.uClibc
  8. 1 1
      extra/config/check.sh
  9. 247 110
      extra/config/conf.c
  10. 578 231
      extra/config/confdata.c
  11. 77 15
      extra/config/expr.c
  12. 21 11
      extra/config/expr.h
  13. 64 154
      extra/config/gconf.c
  14. 23 10
      extra/config/gconf.glade
  15. 17 6
      extra/config/kconfig-language.txt
  16. BIN
      extra/config/kconfig-to-uclibc.patch.gz
  17. BIN
      extra/config/kconfig-to-uclibc.tar.gz
  18. 0 35
      extra/config/kconfig_load.c
  19. 15 9
      extra/config/kxgettext.c
  20. 131 0
      extra/config/list.h
  21. 45 12
      extra/config/lkc.h
  22. 13 1
      extra/config/lkc_proto.h
  23. 8 7
      extra/config/lxdialog/check-lxdialog.sh
  24. 16 8
      extra/config/lxdialog/checklist.c
  25. 31 3
      extra/config/lxdialog/dialog.h
  26. 100 36
      extra/config/lxdialog/inputbox.c
  27. 30 26
      extra/config/lxdialog/menubox.c
  28. 102 84
      extra/config/lxdialog/textbox.c
  29. 78 19
      extra/config/lxdialog/util.c
  30. 6 5
      extra/config/lxdialog/yesno.c
  31. 321 212
      extra/config/mconf.c
  32. 249 12
      extra/config/menu.c
  33. 150 0
      extra/config/merge_config.sh
  34. 1557 0
      extra/config/nconf.c
  35. 656 0
      extra/config/nconf.gui.c
  36. 96 0
      extra/config/nconf.h
  37. 185 154
      extra/config/qconf.cc
  38. 49 46
      extra/config/qconf.h
  39. 640 0
      extra/config/streamline_config.pl
  40. 483 75
      extra/config/symbol.c
  41. 58 10
      extra/config/util.c
  42. 3 0
      extra/config/zconf.gperf
  43. 160 111
      extra/config/zconf.hash.c_shipped
  44. 34 29
      extra/config/zconf.l
  45. 37 33
      extra/config/zconf.lex.c_shipped
  46. 354 357
      extra/config/zconf.tab.c_shipped
  47. 64 30
      extra/config/zconf.y
  48. 1 0
      include/.gitignore
  49. 3 3
      test/Makefile

+ 32 - 23
Makefile.in

@@ -46,6 +46,7 @@ include $(top_srcdir)libc/Makefile.in
 
 
 conf := $(top_builddir)extra/config/conf
 conf := $(top_builddir)extra/config/conf
 mconf := $(top_builddir)extra/config/mconf
 mconf := $(top_builddir)extra/config/mconf
+nconf := $(top_builddir)extra/config/nconf
 
 
 ifeq ($(HAVE_DOT_CONFIG),y)
 ifeq ($(HAVE_DOT_CONFIG),y)
 # If the .config changes then we have to make sure that our includes are
 # If the .config changes then we have to make sure that our includes are
@@ -53,9 +54,9 @@ ifeq ($(HAVE_DOT_CONFIG),y)
 # have uClibc_config.h as prerequisite but since we _symlink_ the headers
 # have uClibc_config.h as prerequisite but since we _symlink_ the headers
 # and do not (?) want to rely on 'make -L' we better update them right here,
 # and do not (?) want to rely on 'make -L' we better update them right here,
 # on spot to save us from alot of hazzle.
 # on spot to save us from alot of hazzle.
-$(top_builddir)include/bits/uClibc_config.h: $(conf) $(KCONFIG_CONFIG) $(top_srcdir)extra/scripts/conf-header.sh | $(top_builddir)include/bits $(top_builddir)include/config
+$(top_builddir)include/bits/uClibc_config.h: $(conf) $(KCONFIG_CONFIG) $(top_srcdir)extra/scripts/conf-header.sh | $(top_builddir)include/bits
 	@$(disp_gen)
 	@$(disp_gen)
-	$(Q)$< -s $(top_srcdir)extra/Configs/Config.in
+	$(Q)$< -s $(Kconfig)
 	$(Q)$(top_srcdir)extra/scripts/conf-header.sh $(KCONFIG_CONFIG) > $@
 	$(Q)$(top_srcdir)extra/scripts/conf-header.sh $(KCONFIG_CONFIG) > $@
 	$(Q)$(MAKE) headers-y
 	$(Q)$(MAKE) headers-y
 
 
@@ -217,6 +218,8 @@ $(top_builddir)extra/scripts/unifdef: $(top_srcdir)extra/scripts/unifdef.c
 # a "y" here means the feature is enabled and so we should *not* rm it.
 # a "y" here means the feature is enabled and so we should *not* rm it.
 # if the option expands to nothing though, we can punt the headers.
 # if the option expands to nothing though, we can punt the headers.
 HEADERS_RM- := \
 HEADERS_RM- := \
+	config \
+	generated \
 	internal \
 	internal \
 	cancel.h \
 	cancel.h \
 	dl-osinfo.h \
 	dl-osinfo.h \
@@ -440,48 +443,56 @@ hostutils: | pregen
 install_hostutils: hostutils
 install_hostutils: hostutils
 	$(Q)$(MAKE) CROSS_COMPILE="$(CROSS_COMPILE)" CC="$(CC)" HOSTCC="$(HOSTCC)" DOTHOST=.host -C utils utils_install
 	$(Q)$(MAKE) CROSS_COMPILE="$(CROSS_COMPILE)" CC="$(CC)" HOSTCC="$(HOSTCC)" DOTHOST=.host -C utils utils_install
 
 
-$(addprefix $(top_builddir),include include/bits include/sys include/config lib extra/config/lxdialog extra/locale extra/scripts $(subdirs)):
+$(addprefix $(top_builddir),include include/bits include/sys include/config include/generated lib extra/config/lxdialog extra/locale extra/scripts $(subdirs)):
 	$(do_mkdir)
 	$(do_mkdir)
 
 
 # configuration
 # configuration
 # ---------------------------------------------------------------------------
 # ---------------------------------------------------------------------------
-$(conf) $(mconf): | $(top_builddir)include/config $(top_builddir)extra/config/lxdialog
+$(conf) $(mconf) $(nconf): | $(top_builddir)include/config $(top_builddir)include/generated $(top_builddir)extra/config/lxdialog
 	$(Q)$(MAKE) -C extra/config $(@F)
 	$(Q)$(MAKE) -C extra/config $(@F)
 
 
 arch-defconfigs := $(notdir $(wildcard $(top_srcdir)extra/Configs/defconfigs/$(ARCH)/*_defconfig))
 arch-defconfigs := $(notdir $(wildcard $(top_srcdir)extra/Configs/defconfigs/$(ARCH)/*_defconfig))
 
 
 menuconfig: $(mconf)
 menuconfig: $(mconf)
-	$(Q)$< extra/Configs/Config.in
-
+	$(Q)$< $(Kconfig)
 config: $(conf)
 config: $(conf)
-	$(Q)$< extra/Configs/Config.in
-
-oldconfig: $(conf)
-	$(Q)$< -o extra/Configs/Config.in
+	$(Q)$< $(Kconfig)
+nconfig: $(nconf)
+	$(Q)$< $(Kconfig)
 
 
+oldaskconfig: $(conf)
+	$(Q)$< -a $(Kconfig)
 silentoldconfig: $(conf)
 silentoldconfig: $(conf)
-	$(Q)$< -s extra/Configs/Config.in
-
-randconfig: $(conf)
-	$(Q)$< -r extra/Configs/Config.in
-
+	$(Q)$< -s $(Kconfig)
+oldconfig: $(conf)
+	$(Q)$< -o $(Kconfig)
+allnoconfig: $(conf)
+	$(Q)$< -n $(Kconfig)
 allyesconfig: $(conf)
 allyesconfig: $(conf)
-	$(Q)$< -y extra/Configs/Config.in
+	$(Q)$< -y $(Kconfig)
 	$(SED) -i -e "s/^DODEBUG=.*/# DODEBUG is not set/" \
 	$(SED) -i -e "s/^DODEBUG=.*/# DODEBUG is not set/" \
 		-e "s/^DOASSERTS=.*/# DOASSERTS is not set/" \
 		-e "s/^DOASSERTS=.*/# DOASSERTS is not set/" \
 		-e "s/^SUPPORT_LD_DEBUG_EARLY=.*/# SUPPORT_LD_DEBUG_EARLY is not set/" \
 		-e "s/^SUPPORT_LD_DEBUG_EARLY=.*/# SUPPORT_LD_DEBUG_EARLY is not set/" \
 		-e "s/^SUPPORT_LD_DEBUG=.*/# SUPPORT_LD_DEBUG is not set/" \
 		-e "s/^SUPPORT_LD_DEBUG=.*/# SUPPORT_LD_DEBUG is not set/" \
 		-e "s/^UCLIBC_MJN3_ONLY=.*/# UCLIBC_MJN3_ONLY is not set/" \
 		-e "s/^UCLIBC_MJN3_ONLY=.*/# UCLIBC_MJN3_ONLY is not set/" \
 		$(KCONFIG_CONFIG)
 		$(KCONFIG_CONFIG)
-	$(Q)$< -o extra/Configs/Config.in
-
-allnoconfig: $(conf)
-	$(Q)$< -n extra/Configs/Config.in
+	$(Q)$< -o $(Kconfig)
+alldefconfig: $(conf)
+	$(Q)$< -A $(Kconfig)
+randconfig: $(conf)
+	$(Q)$< -r $(Kconfig)
 
 
-cmd_defconfig = $(Q)$< -D extra/Configs/defconfigs/$(ARCH)/$@ extra/Configs/Config.in
+cmd_defconfig = $(Q)$< -D extra/Configs/defconfigs/$(ARCH)/$@ $(Kconfig)
 defconfig: $(conf)   ; $(cmd_defconfig)
 defconfig: $(conf)   ; $(cmd_defconfig)
 %_defconfig: $(conf) ; $(cmd_defconfig)
 %_defconfig: $(conf) ; $(cmd_defconfig)
 
 
+savedefconfig: $(conf)
+	$(Q)$< -S $(KCONFIG_CONFIG) $(Kconfig)
+listnewconfig: $(conf)
+	$(Q)$< -l $(Kconfig)
+olddefconfig: $(conf)
+	$(Q)$< -d $(Kconfig)
+
 menuconfig-clean-y:
 menuconfig-clean-y:
 	$(Q)$(MAKE) -C extra/config CLEAN_extra/config
 	$(Q)$(MAKE) -C extra/config CLEAN_extra/config
 
 
@@ -516,10 +527,8 @@ dist release:
 
 
 test check: test_compile
 test check: test_compile
 	$(Q)$(MAKE) -C test \
 	$(Q)$(MAKE) -C test \
-		KCONFIG_CONFIG=$(__ABS_KCONFIG_CONFIG) \
 		$(if $(O),top_builddir=$(O)/)
 		$(if $(O),top_builddir=$(O)/)
 
 
 test_compile: $(LOCAL_INSTALL_PATH)
 test_compile: $(LOCAL_INSTALL_PATH)
 	$(Q)$(MAKE) -C test compile \
 	$(Q)$(MAKE) -C test compile \
-		KCONFIG_CONFIG=$(__ABS_KCONFIG_CONFIG) \
 		$(if $(O),top_builddir=$(O)/)
 		$(if $(O),top_builddir=$(O)/)

+ 19 - 14
Rules.mak

@@ -29,9 +29,11 @@ endif
 
 
 clean_targets := clean realclean distclean \
 clean_targets := clean realclean distclean \
 	objclean-y headers_clean-y CLEAN_utils
 	objclean-y headers_clean-y CLEAN_utils
-noconfig_targets := menuconfig config oldconfig silentoldconfig randconfig \
-	defconfig allyesconfig allnoconfig \
-	xconfig gconfig update-po-config mconf qconf gconf conf \
+noconfig_targets := menuconfig config nconfig \
+	oldaskconfig silentoldconfig oldconfig allnoconfig allyesconfig \
+	alldefconfig randconfig defconfig savedefconfig listnewconfig \
+	olddefconfig \
+	xconfig gconfig update-po-config mconf qconf gconf nconf conf \
 	release dist tags help
 	release dist tags help
 
 
 
 
@@ -70,7 +72,7 @@ STRIP_FLAGS ?= -x -R .note -R .comment
 
 
 # Select the compiler needed to build binaries for your development system
 # Select the compiler needed to build binaries for your development system
 HOSTCC     = gcc
 HOSTCC     = gcc
-BUILD_CFLAGS = -Os -Wall
+BUILD_CFLAGS = -Os
 
 
 #---------------------------------------------------------
 #---------------------------------------------------------
 # Nothing beyond this point should ever be touched by mere
 # Nothing beyond this point should ever be touched by mere
@@ -81,20 +83,23 @@ BUILD_CFLAGS = -Os -Wall
 qstrip = $(strip $(subst ",,$(1)))
 qstrip = $(strip $(subst ",,$(1)))
 #"))
 #"))
 
 
+# kconfig stuff
 KCONFIG_CONFIG ?= $(top_builddir).config
 KCONFIG_CONFIG ?= $(top_builddir).config
+KCONFIG_CONFIG := $(abspath $(KCONFIG_CONFIG))
+export KCONFIG_CONFIG
+KCONFIG_AUTOCONFIG := $(dir $(KCONFIG_CONFIG))include/config/auto.conf
+export KCONFIG_AUTOCONFIG
+KCONFIG_TRISTATE := $(dir $(KCONFIG_CONFIG))include/config/tristate.conf
+export KCONFIG_TRISTATE
+srctree := $(abspath $(top_srcdir))
+export srctree
+KCONFIG_AUTOHEADER := $(dir $(KCONFIG_CONFIG))include/generated/autoconf.h
+export KCONFIG_AUTOHEADER
+Kconfig := $(abspath $(top_srcdir)extra/Configs/Config.in)
 
 
 # Pull in the user's uClibc configuration
 # Pull in the user's uClibc configuration
 ifeq ($(filter $(noconfig_targets) clean CLEAN_%,$(MAKECMDGOALS)),)
 ifeq ($(filter $(noconfig_targets) clean CLEAN_%,$(MAKECMDGOALS)),)
-# Prevent make from searching
-__ABS_KCONFIG_CONFIG ?= $(abspath $(KCONFIG_CONFIG))
--include $(__ABS_KCONFIG_CONFIG)
-else
-# else we have to tell config where to write .config
-export KCONFIG_CONFIG
-endif
-ifeq ($(HAVE_DOT_CONFIG),y)
-# tell config where our .config lives
-export KCONFIG_CONFIG
+-include $(KCONFIG_CONFIG)
 endif
 endif
 
 
 TARGET_ARCH:=$(call qstrip,$(TARGET_ARCH))
 TARGET_ARCH:=$(call qstrip,$(TARGET_ARCH))

+ 5 - 1
extra/Configs/Config.in

@@ -3,12 +3,16 @@
 # see extra/config/Kconfig-language.txt
 # see extra/config/Kconfig-language.txt
 #
 #
 
 
-mainmenu "uClibc C Library Configuration"
+mainmenu "uClibc $VERSION C Library Configuration"
 
 
 config DESIRED_TARGET_ARCH
 config DESIRED_TARGET_ARCH
 	string
 	string
 	option env="ARCH"
 	option env="ARCH"
 
 
+config VERSION
+	string
+	option env="VERSION"
+
 choice
 choice
 	prompt "Target Architecture"
 	prompt "Target Architecture"
 	default TARGET_alpha if DESIRED_TARGET_ARCH = "alpha"
 	default TARGET_alpha if DESIRED_TARGET_ARCH = "alpha"

+ 5 - 2
extra/config/.gitignore

@@ -2,18 +2,21 @@
 # Generated files
 # Generated files
 #
 #
 config*
 config*
-lex.*.c
+*.lex.c
 *.tab.c
 *.tab.c
 *.tab.h
 *.tab.h
 zconf.hash.c
 zconf.hash.c
 *.moc
 *.moc
-lkc_defs.h
+gconf.glade.h
+*.pot
+*.mo
 
 
 #
 #
 # configuration programs
 # configuration programs
 #
 #
 conf
 conf
 mconf
 mconf
+nconf
 qconf
 qconf
 gconf
 gconf
 kxgettext
 kxgettext

+ 17 - 23
extra/config/Makefile

@@ -12,7 +12,6 @@ include $(top_srcdir)Makerules
 # ugh
 # ugh
 top_srcdir:=$(shell cd $(top_srcdir) && pwd)/
 top_srcdir:=$(shell cd $(top_srcdir) && pwd)/
 
 
-srctree := $(top_srcdir)
 src := extra/config
 src := extra/config
 obj := $(top_builddir)$(src)
 obj := $(top_builddir)$(src)
 
 
@@ -20,29 +19,23 @@ generated := $(patsubst %_shipped,%,$(wildcard *_shipped))
 generated := $(addprefix $(obj)/,$(generated:.c=.o))
 generated := $(addprefix $(obj)/,$(generated:.c=.o))
 
 
 include $(top_srcdir)extra/config/Makefile.kconfig
 include $(top_srcdir)extra/config/Makefile.kconfig
-PHONY += $(always)
-chk-lxdialog := $(top_srcdir)$(src)/lxdialog/check-lxdialog.sh
-check-lxdialog := cd $(obj) && $(CONFIG_SHELL) $(chk-lxdialog)
-HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) -c '$(check-lxdialog) -ccflags')
-HOST_LOADLIBES   = $(shell $(CONFIG_SHELL) -c '$(check-lxdialog) -ldflags $(HOSTCC)')
-HOST_EXTRACFLAGS += -DLOCALE
-HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) -c '$(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)')
+HOST_EXTRACFLAGS += -DCONFIG_='""'
 
 
 # do not create temporary object in the readonly srctree
 # do not create temporary object in the readonly srctree
-$(obj)/dochecklxdialog:
-	$(Q)cd $(obj) && $(CONFIG_SHELL) $(chk-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOST_LOADLIBES)
-HOSTCFLAGS_lex.zconf.o	:= -I$(top_srcdir)$(src)
+$(obj)/dochecklxdialog: CONFIG_SHELL:=cd $(obj) && $(CONFIG_SHELL)
+HOSTCFLAGS_zconf.lex.o	:= -I$(top_srcdir)$(src)
 HOSTCFLAGS_zconf.tab.o	:= -I$(top_srcdir)$(src)
 HOSTCFLAGS_zconf.tab.o	:= -I$(top_srcdir)$(src)
 conf-objs := $(addprefix $(obj)/,$(conf-objs))
 conf-objs := $(addprefix $(obj)/,$(conf-objs))
 mconf-objs := $(addprefix $(obj)/,$(mconf-objs))
 mconf-objs := $(addprefix $(obj)/,$(mconf-objs))
+nconf-objs := $(addprefix $(obj)/,$(nconf-objs))
 kxgettext-objs := $(addprefix $(obj)/,$(kxgettext-objs))
 kxgettext-objs := $(addprefix $(obj)/,$(kxgettext-objs))
 
 
 ifeq ($(findstring mconf,$(MAKECMDGOALS)),mconf)
 ifeq ($(findstring mconf,$(MAKECMDGOALS)),mconf)
 hostprogs-y += mconf
 hostprogs-y += mconf
 endif
 endif
-
-#BUILD_CFLAGS-config = -W -Wall -pedantic
-#BUILD_CFLAGS-lxdialog = -W -Wall -pedantic
+ifeq ($(findstring nconf,$(MAKECMDGOALS)),nconf)
+hostprogs-y += nconf
+endif
 
 
 __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
 __hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
 host-csingle:= $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
 host-csingle:= $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
@@ -50,16 +43,18 @@ host-cmulti := $(foreach m,$(__hostprogs),\
            $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
            $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
 host-cobjs  := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
 host-cobjs  := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
 
 
-conf mconf kxgettext: %: $(obj)/%
-$(obj)/conf $(obj)/mconf $(obj)/kxgettext: BUILD_LDFLAGS=$(HOST_LOADLIBES)
+conf mconf nconf kxgettext: %: $(obj)/%
+$(obj)/conf $(obj)/mconf $(obj)/nconf $(obj)/kxgettext: BUILD_LDFLAGS=$(HOSTLOADLIBES_$(@F))
 $(obj)/conf: $(conf-objs)
 $(obj)/conf: $(conf-objs)
 	$(hcompile.u)
 	$(hcompile.u)
 $(obj)/mconf: $(mconf-objs)
 $(obj)/mconf: $(mconf-objs)
 	$(hcompile.u)
 	$(hcompile.u)
+$(obj)/nconf: $(nconf-objs)
+	$(hcompile.u)
 $(obj)/kxgettext: $(kxgettext-objs)
 $(obj)/kxgettext: $(kxgettext-objs)
 	$(hcompile.u)
 	$(hcompile.u)
 
 
-$(host-csingle) $(host-cmulti) $(host-cobjs): BUILD_CFLAGS=$(HOST_EXTRACFLAGS) \
+$(host-csingle) $(host-cmulti) $(host-cobjs): BUILD_CFLAGS+=$(HOST_EXTRACFLAGS) \
 					$(HOSTCFLAGS) $(HOSTCFLAGS_$(@F))
 					$(HOSTCFLAGS) $(HOSTCFLAGS_$(@F))
 
 
 host-cobjs.nogen := $(filter-out $(generated),$(host-cobjs))
 host-cobjs.nogen := $(filter-out $(generated),$(host-cobjs))
@@ -70,19 +65,18 @@ $(host-cobjs.nogen): $(obj)/%.o: $(top_srcdir)$(src)/%.c
 $(host-cobjs.generated): $(obj)/%.o: $(obj)/%.c
 $(host-cobjs.generated): $(obj)/%.o: $(obj)/%.c
 	$(hcompile.o)
 	$(hcompile.o)
 
 
-ifndef LKC_GENPARSER
+# we use the pre-generated always
 $(obj)/%:: $(top_srcdir)$(src)/%_shipped
 $(obj)/%:: $(top_srcdir)$(src)/%_shipped
 	@$(disp_gen)
 	@$(disp_gen)
 	$(Q)cat $< > $@
 	$(Q)cat $< > $@
-endif
+
 CLEAN_extra/config menuconfig_clean:
 CLEAN_extra/config menuconfig_clean:
 	$(do_rm) $(clean-files) $(lxdialog) conf $(wildcard *.o)
 	$(do_rm) $(clean-files) $(lxdialog) conf $(wildcard *.o)
 distclean: CLEAN_extra/config
 distclean: CLEAN_extra/config
-	$(Q)$(RM) -r $(lxdialog) $(conf-objs) $(mconf-objs) \
+	$(Q)$(RM) -r $(lxdialog) $(conf-objs) $(mconf-objs) $(nconf-objs) \
 		$(kxgettext-objs) \
 		$(kxgettext-objs) \
 		$(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \
 		$(hostprogs-y) $(qconf-cxxobjs) $(qconf-objs) $(gconf-objs) \
 		.depend \
 		.depend \
-		$(top_builddir)include/config
+		$(top_builddir)include/config $(top_builddir)include/generated
 
 
-FORCE:
-.PHONY: FORCE clean distclean $(always)
+.PHONY: clean distclean $(PHONY)

+ 161 - 128
extra/config/Makefile.kconfig

@@ -2,14 +2,18 @@
 # Kernel configuration targets
 # Kernel configuration targets
 # These targets are used from top-level makefile
 # These targets are used from top-level makefile
 
 
-PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config
+PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
+	localmodconfig localyesconfig
 
 
 ifdef KBUILD_KCONFIG
 ifdef KBUILD_KCONFIG
 Kconfig := $(KBUILD_KCONFIG)
 Kconfig := $(KBUILD_KCONFIG)
 else
 else
-Kconfig := arch/$(SRCARCH)/Kconfig
+Kconfig := Kconfig
 endif
 endif
 
 
+# We need this, in case the user has it in its environment
+unexport CONFIG_
+
 xconfig: $(obj)/qconf
 xconfig: $(obj)/qconf
 	$< $(Kconfig)
 	$< $(Kconfig)
 
 
@@ -20,91 +24,121 @@ menuconfig: $(obj)/mconf
 	$< $(Kconfig)
 	$< $(Kconfig)
 
 
 config: $(obj)/conf
 config: $(obj)/conf
+	$< --oldaskconfig $(Kconfig)
+
+nconfig: $(obj)/nconf
 	$< $(Kconfig)
 	$< $(Kconfig)
 
 
 oldconfig: $(obj)/conf
 oldconfig: $(obj)/conf
-	$< -o $(Kconfig)
+	$< --$@ $(Kconfig)
 
 
 silentoldconfig: $(obj)/conf
 silentoldconfig: $(obj)/conf
-	$< -s $(Kconfig)
+	$(Q)mkdir -p include/generated
+	$< --$@ $(Kconfig)
+
+localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
+	$(Q)mkdir -p include/generated
+	$(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
+	$(Q)if [ -f .config ]; then 					\
+			cmp -s .tmp.config .config ||			\
+			(mv -f .config .config.old.1;			\
+			 mv -f .tmp.config .config;			\
+			 $(obj)/conf --silentoldconfig $(Kconfig);	\
+			 mv -f .config.old.1 .config.old)		\
+	else								\
+			mv -f .tmp.config .config;			\
+			$(obj)/conf --silentoldconfig $(Kconfig);	\
+	fi
+	$(Q)rm -f .tmp.config
 
 
 # Create new linux.pot file
 # Create new linux.pot file
 # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
 # Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
-# The symlink is used to repair a deficiency in arch/um
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
 update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h
-	$(Q)echo "  GEN config"
-	$(Q)xgettext --default-domain=linux              \
-	    --add-comments --keyword=_ --keyword=N_      \
-	    --from-code=UTF-8                            \
-	    --files-from=scripts/kconfig/POTFILES.in     \
+	$(Q)echo "  GEN     config.pot"
+	$(Q)xgettext --default-domain=linux                         \
+	    --add-comments --keyword=_ --keyword=N_                 \
+	    --from-code=UTF-8                                       \
+	    --files-from=$(srctree)/scripts/kconfig/POTFILES.in     \
+	    --directory=$(srctree) --directory=$(objtree)           \
 	    --output $(obj)/config.pot
 	    --output $(obj)/config.pot
 	$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
 	$(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
-	$(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
-	$(Q)(for i in `ls arch/*/Kconfig`;               \
+	$(Q)(for i in `ls $(srctree)/arch/*/Kconfig      \
+	    $(srctree)/arch/*/um/Kconfig`;               \
 	    do                                           \
 	    do                                           \
-		echo "  GEN $$i";                        \
+		echo "  GEN     $$i";                    \
 		$(obj)/kxgettext $$i                     \
 		$(obj)/kxgettext $$i                     \
 		     >> $(obj)/config.pot;               \
 		     >> $(obj)/config.pot;               \
 	    done )
 	    done )
+	$(Q)echo "  GEN     linux.pot"
 	$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
 	$(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
 	    --output $(obj)/linux.pot
 	    --output $(obj)/linux.pot
-	$(Q)rm -f arch/um/Kconfig.arch
 	$(Q)rm -f $(obj)/config.pot
 	$(Q)rm -f $(obj)/config.pot
 
 
-PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
+PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig
+
+allnoconfig allyesconfig allmodconfig alldefconfig randconfig: $(obj)/conf
+	$< --$@ $(Kconfig)
 
 
-randconfig: $(obj)/conf
-	$< -r $(Kconfig)
+PHONY += listnewconfig olddefconfig oldnoconfig savedefconfig defconfig
 
 
-allyesconfig: $(obj)/conf
-	$< -y $(Kconfig)
+listnewconfig olddefconfig: $(obj)/conf
+	$< --$@ $(Kconfig)
 
 
-allnoconfig: $(obj)/conf
-	$< -n $(Kconfig)
+# oldnoconfig is an alias of olddefconfig, because people already are dependent
+# on its behavior(sets new symbols to their default value but not 'n') with the
+# counter-intuitive name.
+oldnoconfig: $(obj)/conf
+	$< --olddefconfig $(Kconfig)
 
 
-allmodconfig: $(obj)/conf
-	$< -m $(Kconfig)
+savedefconfig: $(obj)/conf
+	$< --$@=defconfig $(Kconfig)
 
 
 defconfig: $(obj)/conf
 defconfig: $(obj)/conf
 ifeq ($(KBUILD_DEFCONFIG),)
 ifeq ($(KBUILD_DEFCONFIG),)
-	$< -d $(Kconfig)
+	$< --defconfig $(Kconfig)
 else
 else
 	@echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
 	@echo "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
-	$(Q)$< -D arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
+	$(Q)$< --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
 endif
 endif
 
 
 %_defconfig: $(obj)/conf
 %_defconfig: $(obj)/conf
-	$(Q)$< -D arch/$(SRCARCH)/configs/$@ $(Kconfig)
+	$(Q)$< --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
 
 
 # Help text used by make help
 # Help text used by make help
 help:
 help:
 	@echo  '  config	  - Update current config utilising a line-oriented program'
 	@echo  '  config	  - Update current config utilising a line-oriented program'
+	@echo  '  nconfig         - Update current config utilising a ncurses menu based program'
 	@echo  '  menuconfig	  - Update current config utilising a menu based program'
 	@echo  '  menuconfig	  - Update current config utilising a menu based program'
 	@echo  '  xconfig	  - Update current config utilising a QT based front-end'
 	@echo  '  xconfig	  - Update current config utilising a QT based front-end'
 	@echo  '  gconfig	  - Update current config utilising a GTK based front-end'
 	@echo  '  gconfig	  - Update current config utilising a GTK based front-end'
 	@echo  '  oldconfig	  - Update current config utilising a provided .config as base'
 	@echo  '  oldconfig	  - Update current config utilising a provided .config as base'
-	@echo  '  silentoldconfig - Same as oldconfig, but quietly'
-	@echo  '  randconfig	  - New config with random answer to all options'
-	@echo  '  defconfig	  - New config with default answer to all options'
-	@echo  '  allmodconfig	  - New config selecting modules when possible'
-	@echo  '  allyesconfig	  - New config where all options are accepted with yes'
+	@echo  '  localmodconfig  - Update current config disabling modules not loaded'
+	@echo  '  localyesconfig  - Update current config converting local mods to core'
+	@echo  '  silentoldconfig - Same as oldconfig, but quietly, additionally update deps'
+	@echo  '  defconfig	  - New config with default from ARCH supplied defconfig'
+	@echo  '  savedefconfig   - Save current config as ./defconfig (minimal config)'
 	@echo  '  allnoconfig	  - New config where all options are answered with no'
 	@echo  '  allnoconfig	  - New config where all options are answered with no'
+	@echo  '  allyesconfig	  - New config where all options are accepted with yes'
+	@echo  '  allmodconfig	  - New config selecting modules when possible'
+	@echo  '  alldefconfig    - New config with all symbols set to default'
+	@echo  '  randconfig	  - New config with random answer to all options'
+	@echo  '  listnewconfig   - List new options'
+	@echo  '  olddefconfig	  - Same as silentoldconfig but sets new symbols to their default value'
 
 
 # lxdialog stuff
 # lxdialog stuff
 check-lxdialog  := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
 check-lxdialog  := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
 
 
 # Use recursively expanded variables so we do not call gcc unless
 # Use recursively expanded variables so we do not call gcc unless
 # we really need to do so. (Do not call gcc as part of make mrproper)
 # we really need to do so. (Do not call gcc as part of make mrproper)
-HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
-HOST_LOADLIBES   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
-
-HOST_EXTRACFLAGS += -DLOCALE
-
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+                    -DLOCALE
 
 
 # ===========================================================================
 # ===========================================================================
 # Shared Makefile for the various kconfig executables:
 # Shared Makefile for the various kconfig executables:
 # conf:	  Used for defconfig, oldconfig and related targets
 # conf:	  Used for defconfig, oldconfig and related targets
-# mconf:  Used for the mconfig target.
+# nconf:  Used for the nconfig target.
+#         Utilizes ncurses
+# mconf:  Used for the menuconfig target
 #         Utilizes the lxdialog package
 #         Utilizes the lxdialog package
 # qconf:  Used for the xconfig target
 # qconf:  Used for the xconfig target
 #         Based on QT which needs to be installed to compile it
 #         Based on QT which needs to be installed to compile it
@@ -116,15 +150,27 @@ lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
 lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
 lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
 
 
 conf-objs	:= conf.o  zconf.tab.o
 conf-objs	:= conf.o  zconf.tab.o
-mconf-objs	:= mconf.o zconf.tab.o $(lxdialog)
+mconf-objs     := mconf.o zconf.tab.o $(lxdialog)
+nconf-objs     := nconf.o zconf.tab.o nconf.gui.o
 kxgettext-objs	:= kxgettext.o zconf.tab.o
 kxgettext-objs	:= kxgettext.o zconf.tab.o
+qconf-cxxobjs	:= qconf.o
+qconf-objs	:= zconf.tab.o
+gconf-objs	:= gconf.o zconf.tab.o
+
+hostprogs-y := conf
 
 
-hostprogs-y := conf qconf gconf kxgettext
+ifeq ($(MAKECMDGOALS),nconfig)
+	hostprogs-y += nconf
+endif
 
 
 ifeq ($(MAKECMDGOALS),menuconfig)
 ifeq ($(MAKECMDGOALS),menuconfig)
 	hostprogs-y += mconf
 	hostprogs-y += mconf
 endif
 endif
 
 
+ifeq ($(MAKECMDGOALS),update-po-config)
+	hostprogs-y += kxgettext
+endif
+
 ifeq ($(MAKECMDGOALS),xconfig)
 ifeq ($(MAKECMDGOALS),xconfig)
 	qconf-target := 1
 	qconf-target := 1
 endif
 endif
@@ -134,24 +180,23 @@ endif
 
 
 
 
 ifeq ($(qconf-target),1)
 ifeq ($(qconf-target),1)
-qconf-cxxobjs	:= qconf.o
-qconf-objs	:= kconfig_load.o zconf.tab.o
+	hostprogs-y += qconf
 endif
 endif
 
 
 ifeq ($(gconf-target),1)
 ifeq ($(gconf-target),1)
-gconf-objs	:= gconf.o kconfig_load.o zconf.tab.o
+	hostprogs-y += gconf
 endif
 endif
 
 
-clean-files	:= lkc_defs.h qconf.moc .tmp_qtcheck \
-		   .tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
-clean-files     += mconf qconf gconf
+clean-files	:= qconf.moc .tmp_qtcheck .tmp_gtkcheck
+clean-files	+= zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h
+clean-files     += mconf qconf gconf nconf
 clean-files     += config.pot linux.pot
 clean-files     += config.pot linux.pot
 
 
 # Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
 # Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
 PHONY += $(obj)/dochecklxdialog
 PHONY += $(obj)/dochecklxdialog
 $(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
 $(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
-#$(obj)/dochecklxdialog:
-#	$(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOST_LOADLIBES)
+$(obj)/dochecklxdialog:
+	$(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
 
 
 always := dochecklxdialog
 always := dochecklxdialog
 
 
@@ -159,16 +204,24 @@ always := dochecklxdialog
 HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
 HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
 
 
 # generated files seem to need this to find local include files
 # generated files seem to need this to find local include files
-HOSTCFLAGS_lex.zconf.o	:= -I$(src)
+HOSTCFLAGS_zconf.lex.o	:= -I$(src)
 HOSTCFLAGS_zconf.tab.o	:= -I$(src)
 HOSTCFLAGS_zconf.tab.o	:= -I$(src)
 
 
-HOSTLOADLIBES_qconf	= $(KC_QT_LIBS) -ldl
-HOSTCXXFLAGS_qconf.o	= $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+LEX_PREFIX_zconf	:= zconf
+YACC_PREFIX_zconf	:= zconf
+
+HOSTLOADLIBES_qconf	= $(KC_QT_LIBS)
+HOSTCXXFLAGS_qconf.o	= $(KC_QT_CFLAGS)
 
 
 HOSTLOADLIBES_gconf	= `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
 HOSTLOADLIBES_gconf	= `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
 HOSTCFLAGS_gconf.o	= `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
 HOSTCFLAGS_gconf.o	= `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
-                          -D LKC_DIRECT_LINK
+                          -Wno-missing-prototypes
 
 
+HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOSTLOADLIBES_nconf	= $(shell \
+				pkg-config --libs menu panel ncurses 2>/dev/null \
+				|| echo "-lmenu -lpanel -lncurses"  )
 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
 $(obj)/qconf.o: $(obj)/.tmp_qtcheck
 
 
 ifeq ($(qconf-target),1)
 ifeq ($(qconf-target),1)
@@ -178,40 +231,48 @@ $(obj)/.tmp_qtcheck: $(src)/Makefile
 # QT needs some extra effort...
 # QT needs some extra effort...
 $(obj)/.tmp_qtcheck:
 $(obj)/.tmp_qtcheck:
 	@set -e; echo "  CHECK   qt"; dir=""; pkg=""; \
 	@set -e; echo "  CHECK   qt"; dir=""; pkg=""; \
-	pkg-config --exists qt 2> /dev/null && pkg=qt; \
-	pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
-	if [ -n "$$pkg" ]; then \
-	  cflags="\$$(shell pkg-config $$pkg --cflags)"; \
-	  libs="\$$(shell pkg-config $$pkg --libs)"; \
-	  moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
-	  dir="$$(pkg-config $$pkg --variable=prefix)"; \
+	if ! pkg-config --exists QtCore 2> /dev/null; then \
+	    echo "* Unable to find the QT4 tool qmake. Trying to use QT3"; \
+	    pkg-config --exists qt 2> /dev/null && pkg=qt; \
+	    pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
+	    if [ -n "$$pkg" ]; then \
+	      cflags="\$$(shell pkg-config $$pkg --cflags)"; \
+	      libs="\$$(shell pkg-config $$pkg --libs)"; \
+	      moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
+	      dir="$$(pkg-config $$pkg --variable=prefix)"; \
+	    else \
+	      for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
+	        if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
+	      done; \
+	      if [ -z "$$dir" ]; then \
+	        echo >&2 "*"; \
+	        echo >&2 "* Unable to find any QT installation. Please make sure that"; \
+	        echo >&2 "* the QT4 or QT3 development package is correctly installed and"; \
+	        echo >&2 "* either qmake can be found or install pkg-config or set"; \
+	        echo >&2 "* the QTDIR environment variable to the correct location."; \
+	        echo >&2 "*"; \
+	        false; \
+	      fi; \
+	      libpath=$$dir/lib; lib=qt; osdir=""; \
+	      $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
+	        osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
+	      test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
+	      test -f $$libpath/libqt-mt.so && lib=qt-mt; \
+	      cflags="-I$$dir/include"; \
+	      libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
+	      moc="$$dir/bin/moc"; \
+	    fi; \
+	    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 "*"; \
+	      moc="/usr/bin/moc"; \
+	    fi; \
 	else \
 	else \
-	  for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
-	    if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
-	  done; \
-	  if [ -z "$$dir" ]; then \
-	    echo "*"; \
-	    echo "* Unable to find the QT3 installation. Please make sure that"; \
-	    echo "* the QT3 development package is correctly installed and"; \
-	    echo "* either install pkg-config or set the QTDIR environment"; \
-	    echo "* variable to the correct location."; \
-	    echo "*"; \
-	    false; \
-	  fi; \
-	  libpath=$$dir/lib; lib=qt; osdir=""; \
-	  $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
-	    osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
-	  test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
-	  test -f $$libpath/libqt-mt.so && lib=qt-mt; \
-	  cflags="-I$$dir/include"; \
-	  libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
-	  moc="$$dir/bin/moc"; \
-	fi; \
-	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 "*"; \
-	  moc="/usr/bin/moc"; \
+	  cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
+	  libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
+	  moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \
+	  [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \
 	fi; \
 	fi; \
 	echo "KC_QT_CFLAGS=$$cflags" > $@; \
 	echo "KC_QT_CFLAGS=$$cflags" > $@; \
 	echo "KC_QT_LIBS=$$libs" >> $@; \
 	echo "KC_QT_LIBS=$$libs" >> $@; \
@@ -229,61 +290,33 @@ $(obj)/.tmp_gtkcheck:
 		if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then			\
 		if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then			\
 			touch $@;								\
 			touch $@;								\
 		else									\
 		else									\
-			echo "*"; 							\
-			echo "* GTK+ is present but version >= 2.0.0 is required.";	\
-			echo "*";							\
+			echo >&2 "*"; 							\
+			echo >&2 "* GTK+ is present but version >= 2.0.0 is required.";	\
+			echo >&2 "*";							\
 			false;								\
 			false;								\
 		fi									\
 		fi									\
 	else										\
 	else										\
-		echo "*"; 								\
-		echo "* Unable to find the GTK+ installation. Please make sure that"; 	\
-		echo "* the GTK+ 2.0 development package is correctly installed..."; 	\
-		echo "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; 		\
-		echo "*"; 								\
+		echo >&2 "*"; 								\
+		echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; 	\
+		echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; 	\
+		echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; 		\
+		echo >&2 "*"; 								\
 		false;									\
 		false;									\
 	fi
 	fi
 endif
 endif
 
 
-$(obj)/zconf.tab.o: $(obj)/lex.zconf.c $(obj)/zconf.hash.c
-
-$(obj)/kconfig_load.o: $(obj)/lkc_defs.h
-
-$(obj)/qconf.o: $(obj)/qconf.moc $(obj)/lkc_defs.h
+$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c
 
 
-$(obj)/gconf.o: $(obj)/lkc_defs.h
+$(obj)/qconf.o: $(obj)/qconf.moc
 
 
-$(obj)/%.moc: $(src)/%.h
-	$(KC_QT_MOC) -i $< -o $@
+quiet_cmd_moc = MOC     $@
+      cmd_moc = $(KC_QT_MOC) -i $< -o $@
 
 
-$(obj)/lkc_defs.h: $(src)/lkc_proto.h
-	sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck
+	$(call cmd,moc)
 
 
 # Extract gconf menu items for I18N support
 # Extract gconf menu items for I18N support
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
 $(obj)/gconf.glade.h: $(obj)/gconf.glade
-	intltool-extract --type=gettext/glade $(obj)/gconf.glade
+	$(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \
+	$(obj)/gconf.glade
 
 
-###
-# The following requires flex/bison/gperf
-# 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: $(src)/zconf.y
-$(obj)/lex.zconf.c: $(src)/zconf.l
-$(obj)/zconf.hash.c: $(src)/zconf.gperf
-
-%.tab.c: %.y
-	bison -l -b $* -p $(notdir $*) $<
-	cp $@ $@_shipped
-
-lex.%.c: %.l
-	flex -L -P$(notdir $*) -o$@ $<
-	cp $@ $@_shipped
-
-%.hash.c: %.gperf
-	gperf < $< > $@
-	cp $@ $@_shipped
-
-endif

+ 1 - 1
extra/config/README.uClibc

@@ -5,7 +5,7 @@ To update:
 	cd extra/config.new
 	cd extra/config.new
 	cp /usr/src/linux/Documentation/kbuild/kconfig-language.txt .
 	cp /usr/src/linux/Documentation/kbuild/kconfig-language.txt .
 	mv Makefile Makefile.kconfig
 	mv Makefile Makefile.kconfig
-	zcat ../config/kconfig-to-uclibc.patch.gz | patch -p1
+	tar -O -xzf ../config/kconfig-to-uclibc.tar.gz | patch -p3
 	cp ../config/README.uClibc .
 	cp ../config/README.uClibc .
 	cp ../config/Makefile .
 	cp ../config/Makefile .
 	cd ..
 	cd ..

+ 1 - 1
extra/config/check.sh

@@ -1,6 +1,6 @@
 #!/bin/sh
 #!/bin/sh
 # Needed for systems without gettext
 # Needed for systems without gettext
-$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
+$* -x c -o /dev/null - > /dev/null 2>&1 << EOF
 #include <libintl.h>
 #include <libintl.h>
 int main()
 int main()
 {
 {

+ 247 - 110
extra/config/conf.c

@@ -10,42 +10,48 @@
 #include <string.h>
 #include <string.h>
 #include <time.h>
 #include <time.h>
 #include <unistd.h>
 #include <unistd.h>
+#include <getopt.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/time.h>
+#include <errno.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 static void conf(struct menu *menu);
 static void conf(struct menu *menu);
 static void check_conf(struct menu *menu);
 static void check_conf(struct menu *menu);
-
-enum {
-	ask_all,
-	ask_new,
-	ask_silent,
-	set_default,
-	set_yes,
-	set_mod,
-	set_no,
-	set_random
-} input_mode = ask_all;
-char *defconfig_file;
+static void xfgets(char *str, int size, FILE *in);
+
+enum input_mode {
+	oldaskconfig,
+	silentoldconfig,
+	oldconfig,
+	allnoconfig,
+	allyesconfig,
+	allmodconfig,
+	alldefconfig,
+	randconfig,
+	defconfig,
+	savedefconfig,
+	listnewconfig,
+	olddefconfig,
+} input_mode = oldaskconfig;
 
 
 static int indent = 1;
 static int indent = 1;
+static int tty_stdio;
 static int valid_stdin = 1;
 static int valid_stdin = 1;
 static int sync_kconfig;
 static int sync_kconfig;
 static int conf_cnt;
 static int conf_cnt;
 static char line[128];
 static char line[128];
 static struct menu *rootEntry;
 static struct menu *rootEntry;
 
 
-static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
-
-static const char *get_help(struct menu *menu)
+static void print_help(struct menu *menu)
 {
 {
-	if (menu_has_help(menu))
-		return _(menu_get_help(menu));
-	else
-		return nohelp_text;
+	struct gstr help = str_new();
+
+	menu_get_ext_help(menu, &help);
+
+	printf("\n%s\n", str_get(&help));
+	str_free(&help);
 }
 }
 
 
 static void strip(char *str)
 static void strip(char *str)
@@ -93,16 +99,19 @@ static int conf_askvalue(struct symbol *sym, const char *def)
 	}
 	}
 
 
 	switch (input_mode) {
 	switch (input_mode) {
-	case ask_new:
-	case ask_silent:
+	case oldconfig:
+	case silentoldconfig:
 		if (sym_has_value(sym)) {
 		if (sym_has_value(sym)) {
 			printf("%s\n", def);
 			printf("%s\n", def);
 			return 0;
 			return 0;
 		}
 		}
 		check_stdin();
 		check_stdin();
-	case ask_all:
+		/* fall through */
+	case oldaskconfig:
 		fflush(stdout);
 		fflush(stdout);
-		fgets(line, 128, stdin);
+		xfgets(line, 128, stdin);
+		if (!tty_stdio)
+			printf("\n");
 		return 1;
 		return 1;
 	default:
 	default:
 		break;
 		break;
@@ -121,7 +130,7 @@ static int conf_askvalue(struct symbol *sym, const char *def)
 	return 1;
 	return 1;
 }
 }
 
 
-int conf_string(struct menu *menu)
+static int conf_string(struct menu *menu)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
 	const char *def;
 	const char *def;
@@ -140,10 +149,11 @@ int conf_string(struct menu *menu)
 		case '?':
 		case '?':
 			/* print help */
 			/* print help */
 			if (line[1] == '\n') {
 			if (line[1] == '\n') {
-				printf("\n%s\n", get_help(menu));
+				print_help(menu);
 				def = NULL;
 				def = NULL;
 				break;
 				break;
 			}
 			}
+			/* fall through */
 		default:
 		default:
 			line[strlen(line)-1] = 0;
 			line[strlen(line)-1] = 0;
 			def = line;
 			def = line;
@@ -156,14 +166,12 @@ int conf_string(struct menu *menu)
 static int conf_sym(struct menu *menu)
 static int conf_sym(struct menu *menu)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
-	int type;
 	tristate oldval, newval;
 	tristate oldval, newval;
 
 
 	while (1) {
 	while (1) {
 		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
 		printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
 		if (sym->name)
 		if (sym->name)
 			printf("(%s) ", sym->name);
 			printf("(%s) ", sym->name);
-		type = sym_get_type(sym);
 		putchar('[');
 		putchar('[');
 		oldval = sym_get_tristate_value(sym);
 		oldval = sym_get_tristate_value(sym);
 		switch (oldval) {
 		switch (oldval) {
@@ -220,7 +228,7 @@ static int conf_sym(struct menu *menu)
 		if (sym_set_tristate_value(sym, newval))
 		if (sym_set_tristate_value(sym, newval))
 			return 0;
 			return 0;
 help:
 help:
-		printf("\n%s\n", get_help(menu));
+		print_help(menu);
 	}
 	}
 }
 }
 
 
@@ -228,11 +236,9 @@ static int conf_choice(struct menu *menu)
 {
 {
 	struct symbol *sym, *def_sym;
 	struct symbol *sym, *def_sym;
 	struct menu *child;
 	struct menu *child;
-	int type;
 	bool is_new;
 	bool is_new;
 
 
 	sym = menu->sym;
 	sym = menu->sym;
-	type = sym_get_type(sym);
 	is_new = !sym_has_value(sym);
 	is_new = !sym_has_value(sym);
 	if (sym_is_changable(sym)) {
 	if (sym_is_changable(sym)) {
 		conf_sym(menu);
 		conf_sym(menu);
@@ -294,20 +300,21 @@ static int conf_choice(struct menu *menu)
 			printf("?");
 			printf("?");
 		printf("]: ");
 		printf("]: ");
 		switch (input_mode) {
 		switch (input_mode) {
-		case ask_new:
-		case ask_silent:
+		case oldconfig:
+		case silentoldconfig:
 			if (!is_new) {
 			if (!is_new) {
 				cnt = def;
 				cnt = def;
 				printf("%d\n", cnt);
 				printf("%d\n", cnt);
 				break;
 				break;
 			}
 			}
 			check_stdin();
 			check_stdin();
-		case ask_all:
+			/* fall through */
+		case oldaskconfig:
 			fflush(stdout);
 			fflush(stdout);
-			fgets(line, 128, stdin);
+			xfgets(line, 128, stdin);
 			strip(line);
 			strip(line);
 			if (line[0] == '?') {
 			if (line[0] == '?') {
-				printf("\n%s\n", get_help(menu));
+				print_help(menu);
 				continue;
 				continue;
 			}
 			}
 			if (!line[0])
 			if (!line[0])
@@ -330,8 +337,8 @@ static int conf_choice(struct menu *menu)
 		}
 		}
 		if (!child)
 		if (!child)
 			continue;
 			continue;
-		if (line[strlen(line) - 1] == '?') {
-			printf("\n%s\n", get_help(child));
+		if (line[0] && line[strlen(line) - 1] == '?') {
+			print_help(child);
 			continue;
 			continue;
 		}
 		}
 		sym_set_choice_value(sym, child->sym);
 		sym_set_choice_value(sym, child->sym);
@@ -360,10 +367,14 @@ static void conf(struct menu *menu)
 
 
 		switch (prop->type) {
 		switch (prop->type) {
 		case P_MENU:
 		case P_MENU:
-			if (input_mode == ask_silent && rootEntry != menu) {
+			if ((input_mode == silentoldconfig ||
+			     input_mode == listnewconfig ||
+			     input_mode == olddefconfig) &&
+			    rootEntry != menu) {
 				check_conf(menu);
 				check_conf(menu);
 				return;
 				return;
 			}
 			}
+			/* fall through */
 		case P_COMMENT:
 		case P_COMMENT:
 			prompt = menu_get_prompt(menu);
 			prompt = menu_get_prompt(menu);
 			if (prompt)
 			if (prompt)
@@ -418,10 +429,16 @@ static void check_conf(struct menu *menu)
 	if (sym && !sym_has_value(sym)) {
 	if (sym && !sym_has_value(sym)) {
 		if (sym_is_changable(sym) ||
 		if (sym_is_changable(sym) ||
 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
 		    (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
-			if (!conf_cnt++)
-				printf(_("*\n* Restart config...\n*\n"));
-			rootEntry = menu_get_parent_menu(menu);
-			conf(rootEntry);
+			if (input_mode == listnewconfig) {
+				if (sym->name && !sym_is_choice_value(sym)) {
+					printf("%s%s\n", CONFIG_, sym->name);
+				}
+			} else if (input_mode != olddefconfig) {
+				if (!conf_cnt++)
+					printf(_("*\n* Restart config...\n*\n"));
+				rootEntry = menu_get_parent_menu(menu);
+				conf(rootEntry);
+			}
 		}
 		}
 	}
 	}
 
 
@@ -429,90 +446,170 @@ static void check_conf(struct menu *menu)
 		check_conf(child);
 		check_conf(child);
 }
 }
 
 
+#if 00 // || !defined __UCLIBC__ || \
+	(defined UCLIBC_HAS_GETOPT_LONG || defined UCLIBC_HAS_GNU_GETOPT)
+static struct option long_opts[] = {
+	{"oldaskconfig",    no_argument,       NULL, oldaskconfig},
+	{"oldconfig",       no_argument,       NULL, oldconfig},
+	{"silentoldconfig", no_argument,       NULL, silentoldconfig},
+	{"defconfig",       optional_argument, NULL, defconfig},
+	{"savedefconfig",   required_argument, NULL, savedefconfig},
+	{"allnoconfig",     no_argument,       NULL, allnoconfig},
+	{"allyesconfig",    no_argument,       NULL, allyesconfig},
+	{"allmodconfig",    no_argument,       NULL, allmodconfig},
+	{"alldefconfig",    no_argument,       NULL, alldefconfig},
+	{"randconfig",      no_argument,       NULL, randconfig},
+	{"listnewconfig",   no_argument,       NULL, listnewconfig},
+	{"olddefconfig",    no_argument,       NULL, olddefconfig},
+	/*
+	 * oldnoconfig is an alias of olddefconfig, because people already
+	 * are dependent on its behavior(sets new symbols to their default
+	 * value but not 'n') with the counter-intuitive name.
+	 */
+	{"oldnoconfig",     no_argument,       NULL, olddefconfig},
+	{NULL, 0, NULL, 0}
+};
+
+static void conf_usage(const char *progname)
+{
+
+	printf("Usage: %s [option] <kconfig-file>\n", progname);
+	printf("[option] is _one_ of the following:\n");
+	printf("  --listnewconfig         List new options\n");
+	printf("  --oldaskconfig          Start a new configuration using a line-oriented program\n");
+	printf("  --oldconfig             Update a configuration using a provided .config as base\n");
+	printf("  --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
+	printf("  --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
+	printf("  --oldnoconfig           An alias of olddefconfig\n");
+	printf("  --defconfig <file>      New config with default defined in <file>\n");
+	printf("  --savedefconfig <file>  Save the minimal current configuration to <file>\n");
+	printf("  --allnoconfig           New config where all options are answered with no\n");
+	printf("  --allyesconfig          New config where all options are answered with yes\n");
+	printf("  --allmodconfig          New config where all options are answered with mod\n");
+	printf("  --alldefconfig          New config with all symbols set to default\n");
+	printf("  --randconfig            New config with random answer to all options\n");
+}
+#else
+static void conf_usage(const char *progname)
+{
+
+	printf("Usage: %s [option] <kconfig-file>\n", progname);
+	printf("[option] is _one_ of the following:\n");
+	printf("  -a, --oldaskconfig          Start a new configuration using a line-oriented program\n");
+	printf("  -s, --silentoldconfig       Same as oldconfig, but quietly, additionally update deps\n");
+	printf("  -o, --oldconfig             Update a configuration using a provided .config as base\n");
+	printf("  -n, --allnoconfig           New config where all options are answered with no\n");
+	printf("  -y, --allyesconfig          New config where all options are answered with yes\n");
+	printf("  -m, --allmodconfig          New config where all options are answered with mod\n");
+	printf("  -A, --alldefconfig          New config with all symbols set to default\n");
+	printf("  -r, --randconfig            New config with random answer to all options\n");
+	printf("  -D, --defconfig <file>      New config with default defined in <file>\n");
+	printf("  -S, --savedefconfig <file>  Save the minimal current configuration to <file>\n");
+	printf("  -l, --listnewconfig         List new options\n");
+	printf("  -d, --olddefconfig          Same as silentoldconfig but sets new symbols to their default value\n");
+	printf("  --oldnoconfig           An alias of olddefconfig\n");
+
+}
+#endif
+
 int main(int ac, char **av)
 int main(int ac, char **av)
 {
 {
+	const char *progname = av[0];
 	int opt;
 	int opt;
-	const char *name;
-	const char *configname = conf_get_configname();
+	const char *name, *defconfig_file = NULL /* gcc uninit */;
 	struct stat tmpstat;
 	struct stat tmpstat;
 
 
 	setlocale(LC_ALL, "");
 	setlocale(LC_ALL, "");
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 	textdomain(PACKAGE);
 
 
-	while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
+	tty_stdio = isatty(0) && isatty(1) && isatty(2);
+
+#if 00// !defined __UCLIBC__ || \
+	(defined UCLIBC_HAS_GETOPT_LONG || defined UCLIBC_HAS_GNU_GETOPT)
+	while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1)
+#else
+	char *gch = "asonymArDSld";
+	while ((opt = getopt(ac, av, "asonymArD:S:ldh")) != -1)
+#endif
+	{
+		char *x = memchr(gch, opt, strlen(gch));
+		if (x == NULL)
+			opt = '?';
+		else
+			opt = x - gch;
+		input_mode = (enum input_mode)opt;
 		switch (opt) {
 		switch (opt) {
-		case 'o':
-			input_mode = ask_silent;
-			break;
-		case 's':
-			input_mode = ask_silent;
+		case silentoldconfig:
 			sync_kconfig = 1;
 			sync_kconfig = 1;
 			break;
 			break;
-		case 'd':
-			input_mode = set_default;
-			break;
-		case 'D':
-			input_mode = set_default;
+		case defconfig:
+		case savedefconfig:
 			defconfig_file = optarg;
 			defconfig_file = optarg;
 			break;
 			break;
-		case 'n':
-			input_mode = set_no;
-			break;
-		case 'm':
-			input_mode = set_mod;
-			break;
-		case 'y':
-			input_mode = set_yes;
-			break;
-		case 'r':
+		case randconfig:
 		{
 		{
 			struct timeval now;
 			struct timeval now;
 			unsigned int seed;
 			unsigned int seed;
+			char *seed_env;
 
 
 			/*
 			/*
 			 * Use microseconds derived seed,
 			 * Use microseconds derived seed,
 			 * compensate for systems where it may be zero
 			 * compensate for systems where it may be zero
 			 */
 			 */
 			gettimeofday(&now, NULL);
 			gettimeofday(&now, NULL);
-
 			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
 			seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
-			srand(seed);
 
 
-			input_mode = set_random;
+			seed_env = getenv("KCONFIG_SEED");
+			if( seed_env && *seed_env ) {
+				char *endp;
+				int tmp = (int)strtol(seed_env, &endp, 0);
+				if (*endp == '\0') {
+					seed = tmp;
+				}
+			}
+			fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
+			srand(seed);
 			break;
 			break;
 		}
 		}
-		case 'h':
-			printf(_("See README for usage info\n"));
-			exit(0);
+		case oldaskconfig:
+		case oldconfig:
+		case allnoconfig:
+		case allyesconfig:
+		case allmodconfig:
+		case alldefconfig:
+		case listnewconfig:
+		case olddefconfig:
 			break;
 			break;
-		default:
-			fprintf(stderr, _("See README for usage info\n"));
+		case '?':
+			conf_usage(progname);
 			exit(1);
 			exit(1);
+			break;
 		}
 		}
 	}
 	}
 	if (ac == optind) {
 	if (ac == optind) {
 		printf(_("%s: Kconfig file missing\n"), av[0]);
 		printf(_("%s: Kconfig file missing\n"), av[0]);
+		conf_usage(progname);
 		exit(1);
 		exit(1);
 	}
 	}
 	name = av[optind];
 	name = av[optind];
 	conf_parse(name);
 	conf_parse(name);
 	//zconfdump(stdout);
 	//zconfdump(stdout);
 	if (sync_kconfig) {
 	if (sync_kconfig) {
-		if (stat(configname, &tmpstat)) {
+		name = conf_get_configname();
+		if (stat(name, &tmpstat)) {
 			fprintf(stderr, _("***\n"
 			fprintf(stderr, _("***\n"
-				"*** You have not yet configured!\n"
-				"*** (missing .config file)\n"
+				"*** Configuration file \"%s\" not found!\n"
 				"***\n"
 				"***\n"
 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
 				"*** Please run some configurator (e.g. \"make oldconfig\" or\n"
 				"*** \"make menuconfig\" or \"make xconfig\").\n"
 				"*** \"make menuconfig\" or \"make xconfig\").\n"
-				"***\n"));
+				"***\n"), name);
 			exit(1);
 			exit(1);
 		}
 		}
 	}
 	}
 
 
 	switch (input_mode) {
 	switch (input_mode) {
-	case set_default:
+	case defconfig:
 		if (!defconfig_file)
 		if (!defconfig_file)
 			defconfig_file = conf_get_default_confname();
 			defconfig_file = conf_get_default_confname();
 		if (conf_read(defconfig_file)) {
 		if (conf_read(defconfig_file)) {
@@ -522,31 +619,46 @@ int main(int ac, char **av)
 			exit(1);
 			exit(1);
 		}
 		}
 		break;
 		break;
-	case ask_silent:
-	case ask_all:
-	case ask_new:
+	case savedefconfig:
+	case silentoldconfig:
+	case oldaskconfig:
+	case oldconfig:
+	case listnewconfig:
+	case olddefconfig:
 		conf_read(NULL);
 		conf_read(NULL);
 		break;
 		break;
-	case set_no:
-	case set_mod:
-	case set_yes:
-	case set_random:
+	case allnoconfig:
+	case allyesconfig:
+	case allmodconfig:
+	case alldefconfig:
+	case randconfig:
 		name = getenv("KCONFIG_ALLCONFIG");
 		name = getenv("KCONFIG_ALLCONFIG");
-		if (name && !stat(name, &tmpstat)) {
-			conf_read_simple(name, S_DEF_USER);
+		if (!name)
+			break;
+		if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
+			if (conf_read_simple(name, S_DEF_USER)) {
+				fprintf(stderr,
+					_("*** Can't read seed configuration \"%s\"!\n"),
+					name);
+				exit(1);
+			}
 			break;
 			break;
 		}
 		}
 		switch (input_mode) {
 		switch (input_mode) {
-		case set_no:	 name = "allno.config"; break;
-		case set_mod:	 name = "allmod.config"; break;
-		case set_yes:	 name = "allyes.config"; break;
-		case set_random: name = "allrandom.config"; break;
+		case allnoconfig:	name = "allno.config"; break;
+		case allyesconfig:	name = "allyes.config"; break;
+		case allmodconfig:	name = "allmod.config"; break;
+		case alldefconfig:	name = "alldef.config"; break;
+		case randconfig:	name = "allrandom.config"; break;
 		default: break;
 		default: break;
 		}
 		}
-		if (!stat(name, &tmpstat))
-			conf_read_simple(name, S_DEF_USER);
-		else if (!stat("all.config", &tmpstat))
-			conf_read_simple("all.config", S_DEF_USER);
+		if (conf_read_simple(name, S_DEF_USER) &&
+		    conf_read_simple("all.config", S_DEF_USER)) {
+			fprintf(stderr,
+				_("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"),
+				name);
+			exit(1);
+		}
 		break;
 		break;
 	default:
 	default:
 		break;
 		break;
@@ -557,41 +669,51 @@ int main(int ac, char **av)
 			name = getenv("KCONFIG_NOSILENTUPDATE");
 			name = getenv("KCONFIG_NOSILENTUPDATE");
 			if (name && *name) {
 			if (name && *name) {
 				fprintf(stderr,
 				fprintf(stderr,
-					_("\n*** configuration requires explicit update.\n\n"));
+					_("\n*** The configuration requires explicit update.\n\n"));
 				return 1;
 				return 1;
 			}
 			}
 		}
 		}
-		valid_stdin = isatty(0) && isatty(1) && isatty(2);
+		valid_stdin = tty_stdio;
 	}
 	}
 
 
 	switch (input_mode) {
 	switch (input_mode) {
-	case set_no:
+	case allnoconfig:
 		conf_set_all_new_symbols(def_no);
 		conf_set_all_new_symbols(def_no);
 		break;
 		break;
-	case set_yes:
+	case allyesconfig:
 		conf_set_all_new_symbols(def_yes);
 		conf_set_all_new_symbols(def_yes);
 		break;
 		break;
-	case set_mod:
+	case allmodconfig:
 		conf_set_all_new_symbols(def_mod);
 		conf_set_all_new_symbols(def_mod);
 		break;
 		break;
-	case set_random:
-		conf_set_all_new_symbols(def_random);
+	case alldefconfig:
+		conf_set_all_new_symbols(def_default);
+		break;
+	case randconfig:
+		/* Really nothing to do in this loop */
+		while (conf_set_all_new_symbols(def_random)) ;
 		break;
 		break;
-	case set_default:
+	case defconfig:
 		conf_set_all_new_symbols(def_default);
 		conf_set_all_new_symbols(def_default);
 		break;
 		break;
-	case ask_new:
-	case ask_all:
+	case savedefconfig:
+		break;
+	case oldaskconfig:
 		rootEntry = &rootmenu;
 		rootEntry = &rootmenu;
 		conf(&rootmenu);
 		conf(&rootmenu);
-		input_mode = ask_silent;
+		input_mode = silentoldconfig;
 		/* fall through */
 		/* fall through */
-	case ask_silent:
+	case oldconfig:
+	case listnewconfig:
+	case olddefconfig:
+	case silentoldconfig:
 		/* Update until a loop caused no more changes */
 		/* Update until a loop caused no more changes */
 		do {
 		do {
 			conf_cnt = 0;
 			conf_cnt = 0;
 			check_conf(&rootmenu);
 			check_conf(&rootmenu);
-		} while (conf_cnt);
+		} while (conf_cnt &&
+			 (input_mode != listnewconfig &&
+			  input_mode != olddefconfig));
 		break;
 		break;
 	}
 	}
 
 
@@ -607,7 +729,13 @@ int main(int ac, char **av)
 			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
 			fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
 			return 1;
 			return 1;
 		}
 		}
-	} else {
+	} else if (input_mode == savedefconfig) {
+		if (conf_write_defconfig(defconfig_file)) {
+			fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+			        defconfig_file);
+			return 1;
+		}
+	} else if (input_mode != listnewconfig) {
 		if (conf_write(NULL)) {
 		if (conf_write(NULL)) {
 			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
 			fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
 			exit(1);
 			exit(1);
@@ -615,3 +743,12 @@ int main(int ac, char **av)
 	}
 	}
 	return 0;
 	return 0;
 }
 }
+
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(char *str, int size, FILE *in)
+{
+	if (fgets(str, size, in) == NULL)
+		fprintf(stderr, "\nError in reading or end of file.\n");
+}

File diff suppressed because it is too large
+ 578 - 231
extra/config/confdata.c


+ 77 - 15
extra/config/expr.c

@@ -7,15 +7,13 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 #define DEBUG_EXPR	0
 #define DEBUG_EXPR	0
 
 
 struct expr *expr_alloc_symbol(struct symbol *sym)
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = E_SYMBOL;
 	e->type = E_SYMBOL;
 	e->left.sym = sym;
 	e->left.sym = sym;
 	return e;
 	return e;
@@ -23,8 +21,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym)
 
 
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = type;
 	e->type = type;
 	e->left.expr = ce;
 	e->left.expr = ce;
 	return e;
 	return e;
@@ -32,8 +29,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 
 
 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = type;
 	e->type = type;
 	e->left.expr = e1;
 	e->left.expr = e1;
 	e->right.expr = e2;
 	e->right.expr = e2;
@@ -42,8 +38,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 
 
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 {
 {
-	struct expr *e = malloc(sizeof(*e));
-	memset(e, 0, sizeof(*e));
+	struct expr *e = xcalloc(1, sizeof(*e));
 	e->type = type;
 	e->type = type;
 	e->left.sym = s1;
 	e->left.sym = s1;
 	e->right.sym = s2;
 	e->right.sym = s2;
@@ -64,14 +59,14 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
 	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 	return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 }
 }
 
 
-struct expr *expr_copy(struct expr *org)
+struct expr *expr_copy(const struct expr *org)
 {
 {
 	struct expr *e;
 	struct expr *e;
 
 
 	if (!org)
 	if (!org)
 		return NULL;
 		return NULL;
 
 
-	e = malloc(sizeof(*org));
+	e = xmalloc(sizeof(*org));
 	memcpy(e, org, sizeof(*org));
 	memcpy(e, org, sizeof(*org));
 	switch (org->type) {
 	switch (org->type) {
 	case E_SYMBOL:
 	case E_SYMBOL:
@@ -348,7 +343,7 @@ struct expr *expr_trans_bool(struct expr *e)
 /*
 /*
  * e1 || e2 -> ?
  * e1 || e2 -> ?
  */
  */
-struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
 {
 {
 	struct expr *tmp;
 	struct expr *tmp;
 	struct symbol *sym1, *sym2;
 	struct symbol *sym1, *sym2;
@@ -412,7 +407,7 @@ struct expr *expr_join_or(struct expr *e1, struct expr *e2)
 	return NULL;
 	return NULL;
 }
 }
 
 
-struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
 {
 {
 	struct expr *tmp;
 	struct expr *tmp;
 	struct symbol *sym1, *sym2;
 	struct symbol *sym1, *sym2;
@@ -1013,6 +1008,48 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2)
 #endif
 #endif
 }
 }
 
 
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+	if (e == NULL)
+		return NULL;
+
+	while (e->type != E_SYMBOL)
+		e = e->left.expr;
+
+	return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+	struct expr *ret;
+
+	switch (e1->type) {
+	case E_OR:
+		return expr_alloc_and(
+		    expr_simplify_unmet_dep(e1->left.expr, e2),
+		    expr_simplify_unmet_dep(e1->right.expr, e2));
+	case E_AND: {
+		struct expr *e;
+		e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+		e = expr_eliminate_dups(e);
+		ret = (!expr_eq(e, e1)) ? e1 : NULL;
+		expr_free(e);
+		break;
+		}
+	default:
+		ret = e1;
+		break;
+	}
+
+	return expr_get_leftmost_symbol(ret);
+}
+
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 {
 {
 	if (!e) {
 	if (!e) {
@@ -1087,7 +1124,7 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
 
 
 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 {
 {
-	fwrite(str, strlen(str), 1, data);
+	xfwrite(str, strlen(str), 1, data);
 }
 }
 
 
 void expr_fprint(struct expr *e, FILE *out)
 void expr_fprint(struct expr *e, FILE *out)
@@ -1097,7 +1134,32 @@ void expr_fprint(struct expr *e, FILE *out)
 
 
 static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
 static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
 {
 {
-	str_append((struct gstr*)data, str);
+	struct gstr *gs = (struct gstr*)data;
+	const char *sym_str = NULL;
+
+	if (sym)
+		sym_str = sym_get_string_value(sym);
+
+	if (gs->max_width) {
+		unsigned extra_length = strlen(str);
+		const char *last_cr = strrchr(gs->s, '\n');
+		unsigned last_line_length;
+
+		if (sym_str)
+			extra_length += 4 + strlen(sym_str);
+
+		if (!last_cr)
+			last_cr = gs->s;
+
+		last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+		if ((last_line_length + extra_length) > gs->max_width)
+			str_append(gs, "\\\n");
+	}
+
+	str_append(gs, str);
+	if (sym && sym->type != S_UNKNOWN)
+		str_printf(gs, " [=%s]", sym_str);
 }
 }
 
 
 void expr_gstr_print(struct expr *e, struct gstr *gs)
 void expr_gstr_print(struct expr *e, struct gstr *gs)

+ 21 - 11
extra/config/expr.h

@@ -10,7 +10,9 @@
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdio.h>
+#include "list.h"
 #ifndef __cplusplus
 #ifndef __cplusplus
 #include <stdbool.h>
 #include <stdbool.h>
 #endif
 #endif
@@ -18,14 +20,10 @@ extern "C" {
 struct file {
 struct file {
 	struct file *next;
 	struct file *next;
 	struct file *parent;
 	struct file *parent;
-	char *name;
+	const char *name;
 	int lineno;
 	int lineno;
-	int flags;
 };
 };
 
 
-#define FILE_BUSY		0x0001
-#define FILE_SCANNED		0x0002
-
 typedef enum tristate {
 typedef enum tristate {
 	no, mod, yes
 	no, mod, yes
 } tristate;
 } tristate;
@@ -83,10 +81,11 @@ struct symbol {
 	tristate visible;
 	tristate visible;
 	int flags;
 	int flags;
 	struct property *prop;
 	struct property *prop;
+	struct expr_value dir_dep;
 	struct expr_value rev_dep;
 	struct expr_value rev_dep;
 };
 };
 
 
-#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
 
 
 #define SYMBOL_CONST      0x0001  /* symbol is const */
 #define SYMBOL_CONST      0x0001  /* symbol is const */
 #define SYMBOL_CHECK      0x0008  /* used during dependency checking */
 #define SYMBOL_CHECK      0x0008  /* used during dependency checking */
@@ -107,9 +106,11 @@ struct symbol {
 #define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
 #define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
 #define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
 #define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
 
 
+/* choice values need to be set before calculating this symbol value */
+#define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000
+
 #define SYMBOL_MAXLENGTH	256
 #define SYMBOL_MAXLENGTH	256
-#define SYMBOL_HASHSIZE		257
-#define SYMBOL_HASHMASK		0xff
+#define SYMBOL_HASHSIZE		9973
 
 
 /* A property represent the config options that can be associated
 /* A property represent the config options that can be associated
  * with a config "symbol".
  * with a config "symbol".
@@ -132,6 +133,7 @@ enum prop_type {
 	P_SELECT,   /* select BAR */
 	P_SELECT,   /* select BAR */
 	P_RANGE,    /* range 7..100 (for a symbol) */
 	P_RANGE,    /* range 7..100 (for a symbol) */
 	P_ENV,      /* value from environment variable */
 	P_ENV,      /* value from environment variable */
+	P_SYMBOL,   /* where a symbol is defined */
 };
 };
 
 
 struct property {
 struct property {
@@ -163,6 +165,7 @@ struct menu {
 	struct menu *list;
 	struct menu *list;
 	struct symbol *sym;
 	struct symbol *sym;
 	struct property *prompt;
 	struct property *prompt;
+	struct expr *visibility;
 	struct expr *dep;
 	struct expr *dep;
 	unsigned int flags;
 	unsigned int flags;
 	char *help;
 	char *help;
@@ -174,7 +177,14 @@ struct menu {
 #define MENU_CHANGED		0x0001
 #define MENU_CHANGED		0x0001
 #define MENU_ROOT		0x0002
 #define MENU_ROOT		0x0002
 
 
-#ifndef SWIG
+struct jump_key {
+	struct list_head entries;
+	size_t offset;
+	struct menu *target;
+	int index;
+};
+
+#define JUMP_NB			9
 
 
 extern struct file *file_list;
 extern struct file *file_list;
 extern struct file *current_file;
 extern struct file *current_file;
@@ -190,7 +200,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
 struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
 struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
-struct expr *expr_copy(struct expr *org);
+struct expr *expr_copy(const struct expr *org);
 void expr_free(struct expr *e);
 void expr_free(struct expr *e);
 int expr_eq(struct expr *e1, struct expr *e2);
 int expr_eq(struct expr *e1, struct expr *e2);
 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
 void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
@@ -205,6 +215,7 @@ struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
 struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
 struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
 void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
 void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
 struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
 
 
 void expr_fprint(struct expr *e, FILE *out);
 void expr_fprint(struct expr *e, FILE *out);
 struct gstr; /* forward */
 struct gstr; /* forward */
@@ -219,7 +230,6 @@ static inline int expr_is_no(struct expr *e)
 {
 {
 	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 	return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
 }
 }
-#endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 64 - 154
extra/config/gconf.c

@@ -10,6 +10,7 @@
 #  include <config.h>
 #  include <config.h>
 #endif
 #endif
 
 
+#include <stdlib.h>
 #include "lkc.h"
 #include "lkc.h"
 #include "images.c"
 #include "images.c"
 
 
@@ -22,7 +23,6 @@
 #include <string.h>
 #include <string.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <time.h>
 #include <time.h>
-#include <stdlib.h>
 
 
 //#define DEBUG
 //#define DEBUG
 
 
@@ -30,13 +30,16 @@ enum {
 	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
 	SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
 };
 };
 
 
+enum {
+	OPT_NORMAL, OPT_ALL, OPT_PROMPT
+};
+
 static gint view_mode = FULL_VIEW;
 static gint view_mode = FULL_VIEW;
 static gboolean show_name = TRUE;
 static gboolean show_name = TRUE;
 static gboolean show_range = TRUE;
 static gboolean show_range = TRUE;
 static gboolean show_value = TRUE;
 static gboolean show_value = TRUE;
-static gboolean show_all = FALSE;
-static gboolean show_debug = FALSE;
 static gboolean resizeable = FALSE;
 static gboolean resizeable = FALSE;
+static int opt_mode = OPT_NORMAL;
 
 
 GtkWidget *main_wnd = NULL;
 GtkWidget *main_wnd = NULL;
 GtkWidget *tree1_w = NULL;	// left  frame
 GtkWidget *tree1_w = NULL;	// left  frame
@@ -76,36 +79,7 @@ static void conf_changed(void);
 
 
 /* Helping/Debugging Functions */
 /* Helping/Debugging Functions */
 
 
-
-const char *dbg_print_stype(int val)
-{
-	static char buf[256];
-
-	bzero(buf, 256);
-
-	if (val == S_UNKNOWN)
-		strcpy(buf, "unknown");
-	if (val == S_BOOLEAN)
-		strcpy(buf, "boolean");
-	if (val == S_TRISTATE)
-		strcpy(buf, "tristate");
-	if (val == S_INT)
-		strcpy(buf, "int");
-	if (val == S_HEX)
-		strcpy(buf, "hex");
-	if (val == S_STRING)
-		strcpy(buf, "string");
-	if (val == S_OTHER)
-		strcpy(buf, "other");
-
-#ifdef DEBUG
-	printf("%s", buf);
-#endif
-
-	return buf;
-}
-
-const char *dbg_print_flags(int val)
+const char *dbg_sym_flags(int val)
 {
 {
 	static char buf[256];
 	static char buf[256];
 
 
@@ -131,40 +105,10 @@ const char *dbg_print_flags(int val)
 		strcat(buf, "auto/");
 		strcat(buf, "auto/");
 
 
 	buf[strlen(buf) - 1] = '\0';
 	buf[strlen(buf) - 1] = '\0';
-#ifdef DEBUG
-	printf("%s", buf);
-#endif
 
 
 	return buf;
 	return buf;
 }
 }
 
 
-const char *dbg_print_ptype(int val)
-{
-	static char buf[256];
-
-	bzero(buf, 256);
-
-	if (val == P_UNKNOWN)
-		strcpy(buf, "unknown");
-	if (val == P_PROMPT)
-		strcpy(buf, "prompt");
-	if (val == P_COMMENT)
-		strcpy(buf, "comment");
-	if (val == P_MENU)
-		strcpy(buf, "menu");
-	if (val == P_DEFAULT)
-		strcpy(buf, "default");
-	if (val == P_CHOICE)
-		strcpy(buf, "choice");
-
-#ifdef DEBUG
-	printf("%s", buf);
-#endif
-
-	return buf;
-}
-
-
 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
 void replace_button_icon(GladeXML * xml, GdkDrawable * window,
 			 GtkStyle * style, gchar * btn_name, gchar ** xpm)
 			 GtkStyle * style, gchar * btn_name, gchar ** xpm)
 {
 {
@@ -189,7 +133,6 @@ void init_main_window(const gchar * glade_file)
 	GladeXML *xml;
 	GladeXML *xml;
 	GtkWidget *widget;
 	GtkWidget *widget;
 	GtkTextBuffer *txtbuf;
 	GtkTextBuffer *txtbuf;
-	char title[256];
 	GtkStyle *style;
 	GtkStyle *style;
 
 
 	xml = glade_xml_new(glade_file, "window1", NULL);
 	xml = glade_xml_new(glade_file, "window1", NULL);
@@ -266,9 +209,7 @@ void init_main_window(const gchar * glade_file)
 					  /*"style", PANGO_STYLE_OBLIQUE, */
 					  /*"style", PANGO_STYLE_OBLIQUE, */
 					  NULL);
 					  NULL);
 
 
-	sprintf(title, _("uClibc v%s Configuration"),
-		getenv("VERSION"));
-	gtk_window_set_title(GTK_WINDOW(main_wnd), title);
+	gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
 
 
 	gtk_widget_show(main_wnd);
 	gtk_widget_show(main_wnd);
 }
 }
@@ -312,7 +253,7 @@ void init_left_tree(void)
 
 
 	gtk_tree_view_set_model(view, model1);
 	gtk_tree_view_set_model(view, model1);
 	gtk_tree_view_set_headers_visible(view, TRUE);
 	gtk_tree_view_set_headers_visible(view, TRUE);
-	gtk_tree_view_set_rules_hint(view, FALSE);
+	gtk_tree_view_set_rules_hint(view, TRUE);
 
 
 	column = gtk_tree_view_column_new();
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_append_column(view, column);
 	gtk_tree_view_append_column(view, column);
@@ -344,8 +285,6 @@ void init_left_tree(void)
 static void renderer_edited(GtkCellRendererText * cell,
 static void renderer_edited(GtkCellRendererText * cell,
 			    const gchar * path_string,
 			    const gchar * path_string,
 			    const gchar * new_text, gpointer user_data);
 			    const gchar * new_text, gpointer user_data);
-static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
-			     gchar * arg1, gpointer user_data);
 
 
 void init_right_tree(void)
 void init_right_tree(void)
 {
 {
@@ -357,7 +296,7 @@ void init_right_tree(void)
 
 
 	gtk_tree_view_set_model(view, model2);
 	gtk_tree_view_set_model(view, model2);
 	gtk_tree_view_set_headers_visible(view, TRUE);
 	gtk_tree_view_set_headers_visible(view, TRUE);
-	gtk_tree_view_set_rules_hint(view, FALSE);
+	gtk_tree_view_set_rules_hint(view, TRUE);
 
 
 	column = gtk_tree_view_column_new();
 	column = gtk_tree_view_column_new();
 	gtk_tree_view_append_column(view, column);
 	gtk_tree_view_append_column(view, column);
@@ -379,8 +318,6 @@ void init_right_tree(void)
 					    "inconsistent", COL_BTNINC,
 					    "inconsistent", COL_BTNINC,
 					    "visible", COL_BTNVIS,
 					    "visible", COL_BTNVIS,
 					    "radio", COL_BTNRAD, NULL);
 					    "radio", COL_BTNRAD, NULL);
-	/*g_signal_connect(G_OBJECT(renderer), "toggled",
-	   G_CALLBACK(renderer_toggled), NULL); */
 	renderer = gtk_cell_renderer_text_new();
 	renderer = gtk_cell_renderer_text_new();
 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 	gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
 					renderer, FALSE);
 					renderer, FALSE);
@@ -456,19 +393,9 @@ static void text_insert_help(struct menu *menu)
 	GtkTextBuffer *buffer;
 	GtkTextBuffer *buffer;
 	GtkTextIter start, end;
 	GtkTextIter start, end;
 	const char *prompt = _(menu_get_prompt(menu));
 	const char *prompt = _(menu_get_prompt(menu));
-	gchar *name;
-	const char *help;
-
-	help = menu_get_help(menu);
-
-	/* Gettextize if the help text not empty */
-	if ((help != 0) && (help[0] != 0))
-		help = _(help);
+	struct gstr help = str_new();
 
 
-	if (menu->sym && menu->sym->name)
-		name = g_strdup_printf(menu->sym->name);
-	else
-		name = g_strdup("");
+	menu_get_ext_help(menu, &help);
 
 
 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
 	buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
 	gtk_text_buffer_get_bounds(buffer, &start, &end);
 	gtk_text_buffer_get_bounds(buffer, &start, &end);
@@ -478,14 +405,11 @@ static void text_insert_help(struct menu *menu)
 	gtk_text_buffer_get_end_iter(buffer, &end);
 	gtk_text_buffer_get_end_iter(buffer, &end);
 	gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
 	gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
 					 NULL);
 					 NULL);
-	gtk_text_buffer_insert_at_cursor(buffer, " ", 1);
-	gtk_text_buffer_get_end_iter(buffer, &end);
-	gtk_text_buffer_insert_with_tags(buffer, &end, name, -1, tag1,
-					 NULL);
 	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
 	gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
 	gtk_text_buffer_get_end_iter(buffer, &end);
 	gtk_text_buffer_get_end_iter(buffer, &end);
-	gtk_text_buffer_insert_with_tags(buffer, &end, help, -1, tag2,
+	gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
 					 NULL);
 					 NULL);
+	str_free(&help);
 }
 }
 
 
 
 
@@ -710,20 +634,29 @@ void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
 
 
 
 
 void
 void
-on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
+on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
 {
 {
-	show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
+	opt_mode = OPT_NORMAL;
+	gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);	/* instead of update_tree to speed-up */
+}
 
 
+
+void
+on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+	opt_mode = OPT_ALL;
 	gtk_tree_store_clear(tree2);
 	gtk_tree_store_clear(tree2);
-	display_tree(&rootmenu);	// instead of update_tree to speed-up
+	display_tree(&rootmenu);	/* instead of update_tree to speed-up */
 }
 }
 
 
 
 
 void
 void
-on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
+on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
 {
 {
-	show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
-	update_tree(&rootmenu, NULL);
+	opt_mode = OPT_PROMPT;
+	gtk_tree_store_clear(tree2);
+	display_tree(&rootmenu);	/* instead of update_tree to speed-up */
 }
 }
 
 
 
 
@@ -732,7 +665,6 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
 	GtkWidget *dialog;
 	GtkWidget *dialog;
 	const gchar *intro_text = _(
 	const gchar *intro_text = _(
 	    "Welcome to gkc, the GTK+ graphical configuration tool\n"
 	    "Welcome to gkc, the GTK+ graphical configuration tool\n"
-	    "for uClibc.\n"
 	    "For each option, a blank box indicates the feature is disabled, a\n"
 	    "For each option, a blank box indicates the feature is disabled, a\n"
 	    "check indicates it is enabled, and a dot indicates that it is to\n"
 	    "check indicates it is enabled, and a dot indicates that it is to\n"
 	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
 	    "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
@@ -751,7 +683,7 @@ void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_MESSAGE_INFO,
 					GTK_MESSAGE_INFO,
-					GTK_BUTTONS_CLOSE, intro_text);
+					GTK_BUTTONS_CLOSE, "%s", intro_text);
 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 				 G_CALLBACK(gtk_widget_destroy),
 				 G_CALLBACK(gtk_widget_destroy),
 				 GTK_OBJECT(dialog));
 				 GTK_OBJECT(dialog));
@@ -769,7 +701,7 @@ void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_MESSAGE_INFO,
 					GTK_MESSAGE_INFO,
-					GTK_BUTTONS_CLOSE, about_text);
+					GTK_BUTTONS_CLOSE, "%s", about_text);
 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 				 G_CALLBACK(gtk_widget_destroy),
 				 G_CALLBACK(gtk_widget_destroy),
 				 GTK_OBJECT(dialog));
 				 GTK_OBJECT(dialog));
@@ -788,7 +720,7 @@ void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 	dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_DIALOG_DESTROY_WITH_PARENT,
 					GTK_MESSAGE_INFO,
 					GTK_MESSAGE_INFO,
-					GTK_BUTTONS_CLOSE, license_text);
+					GTK_BUTTONS_CLOSE, "%s", license_text);
 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 	g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
 				 G_CALLBACK(gtk_widget_destroy),
 				 G_CALLBACK(gtk_widget_destroy),
 				 GTK_OBJECT(dialog));
 				 GTK_OBJECT(dialog));
@@ -820,7 +752,6 @@ void on_load_clicked(GtkButton * button, gpointer user_data)
 void on_single_clicked(GtkButton * button, gpointer user_data)
 void on_single_clicked(GtkButton * button, gpointer user_data)
 {
 {
 	view_mode = SINGLE_VIEW;
 	view_mode = SINGLE_VIEW;
-	gtk_paned_set_position(GTK_PANED(hpaned), 0);
 	gtk_widget_hide(tree1_w);
 	gtk_widget_hide(tree1_w);
 	current = &rootmenu;
 	current = &rootmenu;
 	display_tree_part();
 	display_tree_part();
@@ -846,7 +777,6 @@ void on_split_clicked(GtkButton * button, gpointer user_data)
 void on_full_clicked(GtkButton * button, gpointer user_data)
 void on_full_clicked(GtkButton * button, gpointer user_data)
 {
 {
 	view_mode = FULL_VIEW;
 	view_mode = FULL_VIEW;
-	gtk_paned_set_position(GTK_PANED(hpaned), 0);
 	gtk_widget_hide(tree1_w);
 	gtk_widget_hide(tree1_w);
 	if (tree2)
 	if (tree2)
 		gtk_tree_store_clear(tree2);
 		gtk_tree_store_clear(tree2);
@@ -900,7 +830,7 @@ static void renderer_edited(GtkCellRendererText * cell,
 static void change_sym_value(struct menu *menu, gint col)
 static void change_sym_value(struct menu *menu, gint col)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
-	tristate oldval, newval;
+	tristate newval;
 
 
 	if (!sym)
 	if (!sym)
 		return;
 		return;
@@ -917,7 +847,6 @@ static void change_sym_value(struct menu *menu, gint col)
 	switch (sym_get_type(sym)) {
 	switch (sym_get_type(sym)) {
 	case S_BOOLEAN:
 	case S_BOOLEAN:
 	case S_TRISTATE:
 	case S_TRISTATE:
-		oldval = sym_get_tristate_value(sym);
 		if (!sym_tristate_within_range(sym, newval))
 		if (!sym_tristate_within_range(sym, newval))
 			newval = yes;
 			newval = yes;
 		sym_set_tristate_value(sym, newval);
 		sym_set_tristate_value(sym, newval);
@@ -954,35 +883,6 @@ static void toggle_sym_value(struct menu *menu)
 		display_tree_part();	//fixme: keep exp/coll
 		display_tree_part();	//fixme: keep exp/coll
 }
 }
 
 
-static void renderer_toggled(GtkCellRendererToggle * cell,
-			     gchar * path_string, gpointer user_data)
-{
-	GtkTreePath *path, *sel_path = NULL;
-	GtkTreeIter iter, sel_iter;
-	GtkTreeSelection *sel;
-	struct menu *menu;
-
-	path = gtk_tree_path_new_from_string(path_string);
-	if (!gtk_tree_model_get_iter(model2, &iter, path))
-		return;
-
-	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
-	if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
-		sel_path = gtk_tree_model_get_path(model2, &sel_iter);
-	if (!sel_path)
-		goto out1;
-	if (gtk_tree_path_compare(path, sel_path))
-		goto out2;
-
-	gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
-	toggle_sym_value(menu);
-
-      out2:
-	gtk_tree_path_free(sel_path);
-      out1:
-	gtk_tree_path_free(path);
-}
-
 static gint column2index(GtkTreeViewColumn * column)
 static gint column2index(GtkTreeViewColumn * column)
 {
 {
 	gint i;
 	gint i;
@@ -1174,9 +1074,12 @@ static gchar **fill_row(struct menu *menu)
 
 
 	row[COL_OPTION] =
 	row[COL_OPTION] =
 	    g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
 	    g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
-			    sym && sym_has_value(sym) ? "(NEW)" : "");
+			    sym && !sym_has_value(sym) ? "(NEW)" : "");
 
 
-	if (show_all && !menu_is_visible(menu))
+	if (opt_mode == OPT_ALL && !menu_is_visible(menu))
+		row[COL_COLOR] = g_strdup("DarkGray");
+	else if (opt_mode == OPT_PROMPT &&
+			menu_has_prompt(menu) && !menu_is_visible(menu))
 		row[COL_COLOR] = g_strdup("DarkGray");
 		row[COL_COLOR] = g_strdup("DarkGray");
 	else
 	else
 		row[COL_COLOR] = g_strdup("Black");
 		row[COL_COLOR] = g_strdup("Black");
@@ -1235,6 +1138,7 @@ static gchar **fill_row(struct menu *menu)
 			row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
 			row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
 		if (sym_is_choice(sym))
 		if (sym_is_choice(sym))
 			break;
 			break;
+		/* fall through */
 	case S_TRISTATE:
 	case S_TRISTATE:
 		val = sym_get_tristate_value(sym);
 		val = sym_get_tristate_value(sym);
 		switch (val) {
 		switch (val) {
@@ -1373,7 +1277,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
 	gboolean valid;
 	gboolean valid;
 	GtkTreeIter *sibling;
 	GtkTreeIter *sibling;
 	struct symbol *sym;
 	struct symbol *sym;
-	struct property *prop;
 	struct menu *menu1, *menu2;
 	struct menu *menu1, *menu2;
 
 
 	if (src == &rootmenu)
 	if (src == &rootmenu)
@@ -1382,7 +1285,6 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
 	valid = gtk_tree_model_iter_children(model2, child2, dst);
 	valid = gtk_tree_model_iter_children(model2, child2, dst);
 	for (child1 = src->list; child1; child1 = child1->next) {
 	for (child1 = src->list; child1; child1 = child1->next) {
 
 
-		prop = child1->prompt;
 		sym = child1->sym;
 		sym = child1->sym;
 
 
 	      reparse:
 	      reparse:
@@ -1399,16 +1301,20 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
 		       menu2 ? menu_get_prompt(menu2) : "nil");
 		       menu2 ? menu_get_prompt(menu2) : "nil");
 #endif
 #endif
 
 
-		if (!menu_is_visible(child1) && !show_all) {	// remove node
+		if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
+		    (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
+		    (opt_mode == OPT_ALL    && !menu_get_prompt(child1))) {
+
+			/* remove node */
 			if (gtktree_iter_find_node(dst, menu1) != NULL) {
 			if (gtktree_iter_find_node(dst, menu1) != NULL) {
 				memcpy(&tmp, child2, sizeof(GtkTreeIter));
 				memcpy(&tmp, child2, sizeof(GtkTreeIter));
 				valid = gtk_tree_model_iter_next(model2,
 				valid = gtk_tree_model_iter_next(model2,
 								 child2);
 								 child2);
 				gtk_tree_store_remove(tree2, &tmp);
 				gtk_tree_store_remove(tree2, &tmp);
 				if (!valid)
 				if (!valid)
-					return;	// next parent
+					return;		/* next parent */
 				else
 				else
-					goto reparse;	// next child
+					goto reparse;	/* next child */
 			} else
 			} else
 				continue;
 				continue;
 		}
 		}
@@ -1477,17 +1383,19 @@ static void display_tree(struct menu *menu)
 		    && (tree == tree2))
 		    && (tree == tree2))
 			continue;
 			continue;
 
 
-		if (menu_is_visible(child) || show_all)
+		if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
+		    (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
+		    (opt_mode == OPT_ALL    && menu_get_prompt(child)))
 			place_node(child, fill_row(child));
 			place_node(child, fill_row(child));
 #ifdef DEBUG
 #ifdef DEBUG
 		printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
 		printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
 		printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
 		printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
-		dbg_print_ptype(ptype);
+		printf("%s", prop_get_type_name(ptype));
 		printf(" | ");
 		printf(" | ");
 		if (sym) {
 		if (sym) {
-			dbg_print_stype(sym->type);
+			printf("%s", sym_type_name(sym->type));
 			printf(" | ");
 			printf(" | ");
-			dbg_print_flags(sym->flags);
+			printf("%s", dbg_sym_flags(sym->flags));
 			printf("\n");
 			printf("\n");
 		} else
 		} else
 			printf("\n");
 			printf("\n");
@@ -1499,6 +1407,12 @@ static void display_tree(struct menu *menu)
                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
                 if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
 		    || (view_mode == FULL_VIEW)
 		    || (view_mode == FULL_VIEW)
 		    || (view_mode == SPLIT_VIEW))*/
 		    || (view_mode == SPLIT_VIEW))*/
+
+		/* Change paned position if the view is not in 'split mode' */
+		if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
+			gtk_paned_set_position(GTK_PANED(hpaned), 0);
+		}
+
 		if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
 		if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
 		    || (view_mode == FULL_VIEW)
 		    || (view_mode == FULL_VIEW)
 		    || (view_mode == SPLIT_VIEW)) {
 		    || (view_mode == SPLIT_VIEW)) {
@@ -1557,10 +1471,6 @@ int main(int ac, char *av[])
 	char *env;
 	char *env;
 	gchar *glade_file;
 	gchar *glade_file;
 
 
-#ifndef LKC_DIRECT_LINK
-	kconfig_load();
-#endif
-
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset(PACKAGE, "UTF-8");
 	bind_textdomain_codeset(PACKAGE, "UTF-8");
 	textdomain(PACKAGE);
 	textdomain(PACKAGE);
@@ -1582,12 +1492,6 @@ int main(int ac, char *av[])
 	else
 	else
 		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
 		glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
 
 
-	/* Load the interface and connect signals */
-	init_main_window(glade_file);
-	init_tree_model();
-	init_left_tree();
-	init_right_tree();
-
 	/* Conf stuffs */
 	/* Conf stuffs */
 	if (ac > 1 && av[1][0] == '-') {
 	if (ac > 1 && av[1][0] == '-') {
 		switch (av[1][1]) {
 		switch (av[1][1]) {
@@ -1607,6 +1511,12 @@ int main(int ac, char *av[])
 	fixup_rootmenu(&rootmenu);
 	fixup_rootmenu(&rootmenu);
 	conf_read(NULL);
 	conf_read(NULL);
 
 
+	/* Load the interface and connect signals */
+	init_main_window(glade_file);
+	init_tree_model();
+	init_left_tree();
+	init_right_tree();
+
 	switch (view_mode) {
 	switch (view_mode) {
 	case SINGLE_VIEW:
 	case SINGLE_VIEW:
 		display_tree_part();
 		display_tree_part();

+ 23 - 10
extra/config/gconf.glade

@@ -1,11 +1,10 @@
 <?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
 <?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
-<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
 
 
 <glade-interface>
 <glade-interface>
 
 
 <widget class="GtkWindow" id="window1">
 <widget class="GtkWindow" id="window1">
   <property name="visible">True</property>
   <property name="visible">True</property>
-  <property name="title" translatable="yes">Gtk uClibc Configurator</property>
+  <property name="title" translatable="yes">Gtk uCLibc Configurator</property>
   <property name="type">GTK_WINDOW_TOPLEVEL</property>
   <property name="type">GTK_WINDOW_TOPLEVEL</property>
   <property name="window_position">GTK_WIN_POS_NONE</property>
   <property name="window_position">GTK_WIN_POS_NONE</property>
   <property name="modal">False</property>
   <property name="modal">False</property>
@@ -190,26 +189,40 @@
 		  </child>
 		  </child>
 
 
 		  <child>
 		  <child>
-		    <widget class="GtkCheckMenuItem" id="show_all_options1">
+		    <widget class="GtkRadioMenuItem" id="set_option_mode1">
+		      <property name="visible">True</property>
+		      <property name="tooltip" translatable="yes">Show normal options</property>
+		      <property name="label" translatable="yes">Show normal options</property>
+		      <property name="use_underline">True</property>
+		      <property name="active">True</property>
+		      <signal name="activate" handler="on_set_option_mode1_activate"/>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkRadioMenuItem" id="set_option_mode2">
 		      <property name="visible">True</property>
 		      <property name="visible">True</property>
 		      <property name="tooltip" translatable="yes">Show all options</property>
 		      <property name="tooltip" translatable="yes">Show all options</property>
 		      <property name="label" translatable="yes">Show all _options</property>
 		      <property name="label" translatable="yes">Show all _options</property>
 		      <property name="use_underline">True</property>
 		      <property name="use_underline">True</property>
 		      <property name="active">False</property>
 		      <property name="active">False</property>
-		      <signal name="activate" handler="on_show_all_options1_activate"/>
+		      <property name="group">set_option_mode1</property>
+		      <signal name="activate" handler="on_set_option_mode2_activate"/>
 		    </widget>
 		    </widget>
 		  </child>
 		  </child>
 
 
 		  <child>
 		  <child>
-		    <widget class="GtkCheckMenuItem" id="show_debug_info1">
+		    <widget class="GtkRadioMenuItem" id="set_option_mode3">
 		      <property name="visible">True</property>
 		      <property name="visible">True</property>
-		      <property name="tooltip" translatable="yes">Show masked options</property>
-		      <property name="label" translatable="yes">Show _debug info</property>
+		      <property name="tooltip" translatable="yes">Show all options with prompts</property>
+		      <property name="label" translatable="yes">Show all prompt options</property>
 		      <property name="use_underline">True</property>
 		      <property name="use_underline">True</property>
 		      <property name="active">False</property>
 		      <property name="active">False</property>
-		      <signal name="activate" handler="on_show_debug_info1_activate"/>
+		      <property name="group">set_option_mode1</property>
+		      <signal name="activate" handler="on_set_option_mode3_activate"/>
 		    </widget>
 		    </widget>
 		  </child>
 		  </child>
+
 		</widget>
 		</widget>
 	      </child>
 	      </child>
 	    </widget>
 	    </widget>
@@ -547,7 +560,7 @@
 		  <property name="headers_visible">True</property>
 		  <property name="headers_visible">True</property>
 		  <property name="rules_hint">False</property>
 		  <property name="rules_hint">False</property>
 		  <property name="reorderable">False</property>
 		  <property name="reorderable">False</property>
-		  <property name="enable_search">True</property>
+		  <property name="enable_search">False</property>
 		  <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
 		  <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:58:22 GMT"/>
 		  <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
 		  <signal name="button_press_event" handler="on_treeview1_button_press_event" last_modification_time="Sun, 12 Jan 2003 16:03:52 GMT"/>
 		  <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
 		  <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 16:11:44 GMT"/>
@@ -582,7 +595,7 @@
 		      <property name="headers_visible">True</property>
 		      <property name="headers_visible">True</property>
 		      <property name="rules_hint">False</property>
 		      <property name="rules_hint">False</property>
 		      <property name="reorderable">False</property>
 		      <property name="reorderable">False</property>
-		      <property name="enable_search">True</property>
+		      <property name="enable_search">False</property>
 		      <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
 		      <signal name="cursor_changed" handler="on_treeview2_cursor_changed" last_modification_time="Sun, 12 Jan 2003 15:57:55 GMT"/>
 		      <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
 		      <signal name="button_press_event" handler="on_treeview2_button_press_event" last_modification_time="Sun, 12 Jan 2003 15:57:58 GMT"/>
 		      <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>
 		      <signal name="key_press_event" handler="on_treeview2_key_press_event" last_modification_time="Sun, 12 Jan 2003 15:58:01 GMT"/>

+ 17 - 6
extra/config/kconfig-language.txt

@@ -112,7 +112,13 @@ applicable everywhere (see syntax).
 	(no prompts anywhere) and for symbols with no dependencies.
 	(no prompts anywhere) and for symbols with no dependencies.
 	That will limit the usefulness but on the other hand avoid
 	That will limit the usefulness but on the other hand avoid
 	the illegal configurations all over.
 	the illegal configurations all over.
-	kconfig should one day warn about such things.
+
+- limiting menu display: "visible if" <expr>
+  This attribute is only applicable to menu blocks, if the condition is
+  false, the menu block is not displayed to the user (the symbols
+  contained there can still be selected by other symbols, though). It is
+  similar to a conditional "prompt" attribute for individual menu
+  entries. Default value of "visible" is true.
 
 
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
 - numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
   This allows to limit the range of possible input values for int
   This allows to limit the range of possible input values for int
@@ -181,7 +187,7 @@ Expressions are listed in decreasing order of precedence.
 (7) Returns the result of max(/expr/, /expr/).
 (7) Returns the result of max(/expr/, /expr/).
 
 
 An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
 An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
-respectively for calculations). A menu entry becomes visible when it's
+respectively for calculations). A menu entry becomes visible when its
 expression evaluates to 'm' or 'y'.
 expression evaluates to 'm' or 'y'.
 
 
 There are two types of symbols: constant and non-constant symbols.
 There are two types of symbols: constant and non-constant symbols.
@@ -268,7 +274,7 @@ separate list of options.
 
 
 choices:
 choices:
 
 
-	"choice"
+	"choice" [symbol]
 	<choice options>
 	<choice options>
 	<choice block>
 	<choice block>
 	"endchoice"
 	"endchoice"
@@ -282,6 +288,10 @@ single driver can be compiled/loaded into the kernel, but all drivers
 can be compiled as modules.
 can be compiled as modules.
 A choice accepts another option "optional", which allows to set the
 A choice accepts another option "optional", which allows to set the
 choice to 'n' and no entry needs to be selected.
 choice to 'n' and no entry needs to be selected.
+If no [symbol] is associated with a choice, then you can not have multiple
+definitions of that choice. If a [symbol] is associated to the choice,
+then you may define the same choice (ie. with the same entries) in another
+place.
 
 
 comment:
 comment:
 
 
@@ -300,7 +310,8 @@ menu:
 	"endmenu"
 	"endmenu"
 
 
 This defines a menu block, see "Menu structure" above for more
 This defines a menu block, see "Menu structure" above for more
-information. The only possible options are dependencies.
+information. The only possible options are dependencies and "visible"
+attributes.
 
 
 if:
 if:
 
 
@@ -322,7 +333,8 @@ mainmenu:
 	"mainmenu" <prompt>
 	"mainmenu" <prompt>
 
 
 This sets the config program's title bar if the config program chooses
 This sets the config program's title bar if the config program chooses
-to use it.
+to use it. It should be placed at the top of the configuration, before any
+other statement.
 
 
 
 
 Kconfig hints
 Kconfig hints
@@ -376,4 +388,3 @@ config FOO
 	depends on BAR && m
 	depends on BAR && m
 
 
 limits FOO to module (=m) or disabled (=n).
 limits FOO to module (=m) or disabled (=n).
-

BIN
extra/config/kconfig-to-uclibc.patch.gz


BIN
extra/config/kconfig-to-uclibc.tar.gz


+ 0 - 35
extra/config/kconfig_load.c

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

+ 15 - 9
extra/config/kxgettext.c

@@ -7,7 +7,6 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 static char *escape(const char* text, char *bf, int len)
 static char *escape(const char* text, char *bf, int len)
@@ -43,6 +42,10 @@ static char *escape(const char* text, char *bf, int len)
 			++text;
 			++text;
 			goto next;
 			goto next;
 		}
 		}
+		else if (*text == '\\') {
+			*bfp++ = '\\';
+			len--;
+		}
 		*bfp++ = *text++;
 		*bfp++ = *text++;
 next:
 next:
 		--len;
 		--len;
@@ -59,11 +62,11 @@ next:
 
 
 struct file_line {
 struct file_line {
 	struct file_line *next;
 	struct file_line *next;
-	char*		 file;
-	int		 lineno;
+	const char *file;
+	int lineno;
 };
 };
 
 
-static struct file_line *file_line__new(char *file, int lineno)
+static struct file_line *file_line__new(const char *file, int lineno)
 {
 {
 	struct file_line *self = malloc(sizeof(*self));
 	struct file_line *self = malloc(sizeof(*self));
 
 
@@ -86,7 +89,8 @@ struct message {
 
 
 static struct message *message__list;
 static struct message *message__list;
 
 
-static struct message *message__new(const char *msg, char *option, char *file, int lineno)
+static struct message *message__new(const char *msg, char *option,
+				    const char *file, int lineno)
 {
 {
 	struct message *self = malloc(sizeof(*self));
 	struct message *self = malloc(sizeof(*self));
 
 
@@ -126,7 +130,8 @@ static struct message *mesage__find(const char *msg)
 	return m;
 	return m;
 }
 }
 
 
-static int message__add_file_line(struct message *self, char *file, int lineno)
+static int message__add_file_line(struct message *self, const char *file,
+				  int lineno)
 {
 {
 	int rc = -1;
 	int rc = -1;
 	struct file_line *fl = file_line__new(file, lineno);
 	struct file_line *fl = file_line__new(file, lineno);
@@ -141,7 +146,8 @@ out:
 	return rc;
 	return rc;
 }
 }
 
 
-static int message__add(const char *msg, char *option, char *file, int lineno)
+static int message__add(const char *msg, char *option, const char *file,
+			int lineno)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	char bf[16384];
 	char bf[16384];
@@ -162,7 +168,7 @@ static int message__add(const char *msg, char *option, char *file, int lineno)
 	return rc;
 	return rc;
 }
 }
 
 
-void menu_build_message_list(struct menu *menu)
+static void menu_build_message_list(struct menu *menu)
 {
 {
 	struct menu *child;
 	struct menu *child;
 
 
@@ -207,7 +213,7 @@ static void message__print_gettext_msgid_msgstr(struct message *self)
 	       "msgstr \"\"\n", self->msg);
 	       "msgstr \"\"\n", self->msg);
 }
 }
 
 
-void menu__xgettext(void)
+static void menu__xgettext(void)
 {
 {
 	struct message *m = message__list;
 	struct message *m = message__list;
 
 

+ 131 - 0
extra/config/list.h

@@ -0,0 +1,131 @@
+#ifndef LIST_H
+#define LIST_H
+
+/*
+ * Copied from include/linux/...
+ */
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:        the pointer to the member.
+ * @type:       the type of the container struct this is embedded in.
+ * @member:     the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                      \
+	const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
+	(type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head);					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *_new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = _new;
+	_new->next = next;
+	_new->prev = prev;
+	prev->next = _new;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+	__list_add(_new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = (struct list_head*)LIST_POISON1;
+	entry->prev = (struct list_head*)LIST_POISON2;
+}
+#endif

+ 45 - 12
extra/config/lkc.h

@@ -14,29 +14,37 @@
 static inline const char *gettext(const char *txt) { return txt; }
 static inline const char *gettext(const char *txt) { return txt; }
 static inline void textdomain(const char *domainname) {}
 static inline void textdomain(const char *domainname) {}
 static inline void bindtextdomain(const char *name, const char *dir) {}
 static inline void bindtextdomain(const char *name, const char *dir) {}
+static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; }
 #endif
 #endif
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-#ifdef LKC_DIRECT_LINK
 #define P(name,type,arg)	extern type name arg
 #define P(name,type,arg)	extern type name arg
-#else
-#include "lkc_defs.h"
-#define P(name,type,arg)	extern type (*name ## _p) arg
-#endif
 #include "lkc_proto.h"
 #include "lkc_proto.h"
 #undef P
 #undef P
 
 
 #define SRCTREE "srctree"
 #define SRCTREE "srctree"
 
 
+#ifndef PACKAGE
 #define PACKAGE "linux"
 #define PACKAGE "linux"
+#endif
+
 #define LOCALEDIR "/usr/share/locale"
 #define LOCALEDIR "/usr/share/locale"
 
 
 #define _(text) gettext(text)
 #define _(text) gettext(text)
 #define N_(text) (text)
 #define N_(text) (text)
 
 
+#ifndef CONFIG_
+#define CONFIG_ "CONFIG_"
+#endif
+static inline const char *CONFIG_prefix(void)
+{
+	return getenv( "CONFIG_" ) ?: CONFIG_;
+}
+#undef CONFIG_
+#define CONFIG_ CONFIG_prefix()
 
 
 #define TF_COMMAND	0x0001
 #define TF_COMMAND	0x0001
 #define TF_PARAM	0x0002
 #define TF_PARAM	0x0002
@@ -61,35 +69,49 @@ struct kconf_id {
 	enum symbol_type stype;
 	enum symbol_type stype;
 };
 };
 
 
+extern int zconfdebug;
+
 int zconfparse(void);
 int zconfparse(void);
 void zconfdump(FILE *out);
 void zconfdump(FILE *out);
-
-extern int zconfdebug;
 void zconf_starthelp(void);
 void zconf_starthelp(void);
 FILE *zconf_fopen(const char *name);
 FILE *zconf_fopen(const char *name);
 void zconf_initscan(const char *name);
 void zconf_initscan(const char *name);
 void zconf_nextfile(const char *name);
 void zconf_nextfile(const char *name);
 int zconf_lineno(void);
 int zconf_lineno(void);
-char *zconf_curname(void);
+const char *zconf_curname(void);
 
 
 /* confdata.c */
 /* confdata.c */
 const char *conf_get_configname(void);
 const char *conf_get_configname(void);
+const char *conf_get_autoconfig_name(void);
 char *conf_get_default_confname(void);
 char *conf_get_default_confname(void);
 void sym_set_change_count(int count);
 void sym_set_change_count(int count);
 void sym_add_change_count(int count);
 void sym_add_change_count(int count);
-void conf_set_all_new_symbols(enum conf_def_mode mode);
+bool conf_set_all_new_symbols(enum conf_def_mode mode);
+void set_all_choice_values(struct symbol *csym);
+
+struct conf_printer {
+	void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
+	void (*print_comment)(FILE *, const char *, void *);
+};
+
+/* confdata.c and expr.c */
+static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out)
+{
+	assert(len != 0);
 
 
-/* kconfig_load.c */
-void kconfig_load(void);
+	if (fwrite(str, len, count, out) != count)
+		fprintf(stderr, "Error in writing or end of file.\n");
+}
 
 
 /* menu.c */
 /* menu.c */
-void menu_init(void);
+void _menu_init(void);
 void menu_warn(struct menu *menu, const char *fmt, ...);
 void menu_warn(struct menu *menu, const char *fmt, ...);
 struct menu *menu_add_menu(void);
 struct menu *menu_add_menu(void);
 void menu_end_menu(void);
 void menu_end_menu(void);
 void menu_add_entry(struct symbol *sym);
 void menu_add_entry(struct symbol *sym);
 void menu_end_entry(void);
 void menu_end_entry(void);
 void menu_add_dep(struct expr *dep);
 void menu_add_dep(struct expr *dep);
+void menu_add_visibility(struct expr *dep);
 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
 struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep);
 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
 struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep);
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep);
@@ -101,10 +123,19 @@ void menu_set_type(int type);
 /* util.c */
 /* util.c */
 struct file *file_lookup(const char *name);
 struct file *file_lookup(const char *name);
 int file_write_dep(const char *name);
 int file_write_dep(const char *name);
+void *xmalloc(size_t size);
+void *xcalloc(size_t nmemb, size_t size);
+char *dir_name(char *path);
+char *base_name(char *path);
 
 
 struct gstr {
 struct gstr {
 	size_t len;
 	size_t len;
 	char  *s;
 	char  *s;
+	/*
+	* when max_width is not zero long lines in string s (if any) get
+	* wrapped not to exceed the max_width value
+	*/
+	int max_width;
 };
 };
 struct gstr str_new(void);
 struct gstr str_new(void);
 struct gstr str_assign(const char *s);
 struct gstr str_assign(const char *s);
@@ -120,6 +151,8 @@ void sym_init(void);
 void sym_clear_all_valid(void);
 void sym_clear_all_valid(void);
 void sym_set_all_changed(void);
 void sym_set_all_changed(void);
 void sym_set_changed(struct symbol *sym);
 void sym_set_changed(struct symbol *sym);
+struct symbol *sym_choice_default(struct symbol *sym);
+const char *sym_get_string_default(struct symbol *sym);
 struct symbol *sym_check_deps(struct symbol *sym);
 struct symbol *sym_check_deps(struct symbol *sym);
 struct property *prop_alloc(enum prop_type type, struct symbol *sym);
 struct property *prop_alloc(enum prop_type type, struct symbol *sym);
 struct symbol *prop_get_symbol(struct property *prop);
 struct symbol *prop_get_symbol(struct property *prop);

+ 13 - 1
extra/config/lkc_proto.h

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

+ 8 - 7
extra/config/lxdialog/check-lxdialog.sh

@@ -4,7 +4,9 @@
 # What library to link
 # What library to link
 ldflags()
 ldflags()
 {
 {
-	for ext in so a dylib ; do
+	pkg-config --libs ncursesw 2>/dev/null && exit
+	pkg-config --libs ncurses 2>/dev/null && exit
+	for ext in so a dll.a dylib ; do
 		for lib in ncursesw ncurses curses ; do
 		for lib in ncursesw ncurses curses ; do
 			$cc -print-file-name=lib${lib}.${ext} | grep -q /
 			$cc -print-file-name=lib${lib}.${ext} | grep -q /
 			if [ $? -eq 0 ]; then
 			if [ $? -eq 0 ]; then
@@ -19,14 +21,13 @@ ldflags()
 # Where is ncurses.h?
 # Where is ncurses.h?
 ccflags()
 ccflags()
 {
 {
-	if [ -f /usr/include/ncursesw/ncurses.h ]; then
-		echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncurses.h>"'
-	elif [ -f /usr/include/ncursesw/curses.h ]; then
-		echo '-I/usr/include/ncursesw -DCURSES_LOC="<ncursesw/curses.h>"'
+	if [ -f /usr/include/ncursesw/curses.h ]; then
+		echo '-I/usr/include/ncursesw -DCURSES_LOC="<curses.h>"'
+		echo ' -DNCURSES_WIDECHAR=1'
 	elif [ -f /usr/include/ncurses/ncurses.h ]; then
 	elif [ -f /usr/include/ncurses/ncurses.h ]; then
 		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
 		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"'
 	elif [ -f /usr/include/ncurses/curses.h ]; then
 	elif [ -f /usr/include/ncurses/curses.h ]; then
-		echo '-I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"'
+		echo '-I/usr/include/ncurses -DCURSES_LOC="<curses.h>"'
 	elif [ -f /usr/include/ncurses.h ]; then
 	elif [ -f /usr/include/ncurses.h ]; then
 		echo '-DCURSES_LOC="<ncurses.h>"'
 		echo '-DCURSES_LOC="<ncurses.h>"'
 	else
 	else
@@ -40,7 +41,7 @@ trap "rm -f $tmp" 0 1 2 3 15
 
 
 # Check if we can link to ncurses
 # Check if we can link to ncurses
 check() {
 check() {
-        $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+        $cc -x c - -o $tmp 2>/dev/null <<'EOF'
 #include CURSES_LOC
 #include CURSES_LOC
 main() {}
 main() {}
 EOF
 EOF

+ 16 - 8
extra/config/lxdialog/checklist.c

@@ -17,7 +17,8 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 #include "dialog.h"
 #include "dialog.h"
@@ -30,6 +31,10 @@ static int list_width, check_x, item_x;
 static void print_item(WINDOW * win, int choice, int selected)
 static void print_item(WINDOW * win, int choice, int selected)
 {
 {
 	int i;
 	int i;
+	char *list_item = malloc(list_width + 1);
+
+	strncpy(list_item, item_str(), list_width - item_x);
+	list_item[list_width - item_x] = '\0';
 
 
 	/* Clear 'residue' of last item */
 	/* Clear 'residue' of last item */
 	wattrset(win, dlg.menubox.atr);
 	wattrset(win, dlg.menubox.atr);
@@ -40,16 +45,18 @@ static void print_item(WINDOW * win, int choice, int selected)
 	wmove(win, choice, check_x);
 	wmove(win, choice, check_x);
 	wattrset(win, selected ? dlg.check_selected.atr
 	wattrset(win, selected ? dlg.check_selected.atr
 		 : dlg.check.atr);
 		 : dlg.check.atr);
-	wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+	if (!item_is_tag(':'))
+		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
 
 
 	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
 	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
-	mvwaddch(win, choice, item_x, item_str()[0]);
+	mvwaddch(win, choice, item_x, list_item[0]);
 	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
 	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
-	waddstr(win, (char *)item_str() + 1);
+	waddstr(win, list_item + 1);
 	if (selected) {
 	if (selected) {
 		wmove(win, choice, check_x + 1);
 		wmove(win, choice, check_x + 1);
 		wrefresh(win);
 		wrefresh(win);
 	}
 	}
+	free(list_item);
 }
 }
 
 
 /*
 /*
@@ -125,16 +132,16 @@ int dialog_checklist(const char *title, const char *prompt, int height,
 	}
 	}
 
 
 do_resize:
 do_resize:
-	if (getmaxy(stdscr) < (height + 6))
+	if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
-	if (getmaxx(stdscr) < (width + 6))
+	if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
 
 
 	max_choice = MIN(list_height, item_count());
 	max_choice = MIN(list_height, item_count());
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
-	x = (COLS - width) / 2;
-	y = (LINES - height) / 2;
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
 
 
 	draw_shadow(stdscr, y, x, height, width);
 	draw_shadow(stdscr, y, x, height, width);
 
 
@@ -173,6 +180,7 @@ do_resize:
 	check_x = 0;
 	check_x = 0;
 	item_foreach()
 	item_foreach()
 		check_x = MAX(check_x, strlen(item_str()) + 4);
 		check_x = MAX(check_x, strlen(item_str()) + 4);
+	check_x = MIN(check_x, list_width);
 
 
 	check_x = (list_width - check_x) / 2;
 	check_x = (list_width - check_x) / 2;
 	item_x = check_x + 4;
 	item_x = check_x + 4;

+ 31 - 3
extra/config/lxdialog/dialog.h

@@ -14,7 +14,8 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 #include <sys/types.h>
 #include <sys/types.h>
@@ -105,8 +106,14 @@ struct dialog_color {
 	int hl;		/* highlight this item */
 	int hl;		/* highlight this item */
 };
 };
 
 
+struct subtitle_list {
+	struct subtitle_list *next;
+	const char *text;
+};
+
 struct dialog_info {
 struct dialog_info {
 	const char *backtitle;
 	const char *backtitle;
+	struct subtitle_list *subtitles;
 	struct dialog_color screen;
 	struct dialog_color screen;
 	struct dialog_color shadow;
 	struct dialog_color shadow;
 	struct dialog_color dialog;
 	struct dialog_color dialog;
@@ -143,6 +150,7 @@ struct dialog_info {
  */
  */
 extern struct dialog_info dlg;
 extern struct dialog_info dlg;
 extern char dialog_input_result[];
 extern char dialog_input_result[];
+extern int saved_x, saved_y;		/* Needed in signal handler in mconf.c */
 
 
 /*
 /*
  * Function prototypes
  * Function prototypes
@@ -192,8 +200,23 @@ int item_is_tag(char tag);
 int on_key_esc(WINDOW *win);
 int on_key_esc(WINDOW *win);
 int on_key_resize(void);
 int on_key_resize(void);
 
 
+/* minimum (re)size values */
+#define CHECKLIST_HEIGTH_MIN 6	/* For dialog_checklist() */
+#define CHECKLIST_WIDTH_MIN 6
+#define INPUTBOX_HEIGTH_MIN 2	/* For dialog_inputbox() */
+#define INPUTBOX_WIDTH_MIN 2
+#define MENUBOX_HEIGTH_MIN 15	/* For dialog_menu() */
+#define MENUBOX_WIDTH_MIN 65
+#define TEXTBOX_HEIGTH_MIN 8	/* For dialog_textbox() */
+#define TEXTBOX_WIDTH_MIN 8
+#define YESNO_HEIGTH_MIN 4	/* For dialog_yesno() */
+#define YESNO_WIDTH_MIN 4
+#define WINDOW_HEIGTH_MIN 19	/* For init_dialog() */
+#define WINDOW_WIDTH_MIN 80
+
 int init_dialog(const char *backtitle);
 int init_dialog(const char *backtitle);
 void set_dialog_backtitle(const char *backtitle);
 void set_dialog_backtitle(const char *backtitle);
+void set_dialog_subtitles(struct subtitle_list *subtitles);
 void end_dialog(int x, int y);
 void end_dialog(int x, int y);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
 void attr_clear(WINDOW * win, int height, int width, chtype attr);
 void dialog_clear(void);
 void dialog_clear(void);
@@ -208,12 +231,17 @@ int first_alpha(const char *string, const char *exempt);
 int dialog_yesno(const char *title, const char *prompt, int height, int width);
 int dialog_yesno(const char *title, const char *prompt, int height, int width);
 int dialog_msgbox(const char *title, const char *prompt, int height,
 int dialog_msgbox(const char *title, const char *prompt, int height,
 		  int width, int pause);
 		  int width, int pause);
-int dialog_textbox(const char *title, const char *file, int height, int width);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+			       *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data);
 int dialog_menu(const char *title, const char *prompt,
 int dialog_menu(const char *title, const char *prompt,
 		const void *selected, int *s_scroll);
 		const void *selected, int *s_scroll);
 int dialog_checklist(const char *title, const char *prompt, int height,
 int dialog_checklist(const char *title, const char *prompt, int height,
 		     int width, int list_height);
 		     int width, int list_height);
-extern char dialog_input_result[];
 int dialog_inputbox(const char *title, const char *prompt, int height,
 int dialog_inputbox(const char *title, const char *prompt, int height,
 		    int width, const char *init);
 		    int width, const char *init);
 
 

+ 100 - 36
extra/config/lxdialog/inputbox.c

@@ -15,7 +15,8 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 #include "dialog.h"
 #include "dialog.h"
@@ -44,7 +45,8 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
                     const char *init)
                     const char *init)
 {
 {
 	int i, x, y, box_y, box_x, box_width;
 	int i, x, y, box_y, box_x, box_width;
-	int input_x = 0, scroll = 0, key = 0, button = -1;
+	int input_x = 0, key = 0, button = -1;
+	int show_x, len, pos;
 	char *instr = dialog_input_result;
 	char *instr = dialog_input_result;
 	WINDOW *dialog;
 	WINDOW *dialog;
 
 
@@ -54,14 +56,14 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
 		strcpy(instr, init);
 		strcpy(instr, init);
 
 
 do_resize:
 do_resize:
-	if (getmaxy(stdscr) <= (height - 2))
+	if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
-	if (getmaxx(stdscr) <= (width - 2))
+	if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
-	x = (COLS - width) / 2;
-	y = (LINES - height) / 2;
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
 
 
 	draw_shadow(stdscr, y, x, height, width);
 	draw_shadow(stdscr, y, x, height, width);
 
 
@@ -96,14 +98,17 @@ do_resize:
 	wmove(dialog, box_y, box_x);
 	wmove(dialog, box_y, box_x);
 	wattrset(dialog, dlg.inputbox.atr);
 	wattrset(dialog, dlg.inputbox.atr);
 
 
-	input_x = strlen(instr);
+	len = strlen(instr);
+	pos = len;
 
 
-	if (input_x >= box_width) {
-		scroll = input_x - box_width + 1;
+	if (len >= box_width) {
+		show_x = len - box_width + 1;
 		input_x = box_width - 1;
 		input_x = box_width - 1;
 		for (i = 0; i < box_width - 1; i++)
 		for (i = 0; i < box_width - 1; i++)
-			waddch(dialog, instr[scroll + i]);
+			waddch(dialog, instr[show_x + i]);
 	} else {
 	} else {
+		show_x = 0;
+		input_x = len;
 		waddstr(dialog, instr);
 		waddstr(dialog, instr);
 	}
 	}
 
 
@@ -120,45 +125,104 @@ do_resize:
 			case KEY_UP:
 			case KEY_UP:
 			case KEY_DOWN:
 			case KEY_DOWN:
 				break;
 				break;
-			case KEY_LEFT:
-				continue;
-			case KEY_RIGHT:
-				continue;
 			case KEY_BACKSPACE:
 			case KEY_BACKSPACE:
 			case 127:
 			case 127:
-				if (input_x || scroll) {
+				if (pos) {
 					wattrset(dialog, dlg.inputbox.atr);
 					wattrset(dialog, dlg.inputbox.atr);
-					if (!input_x) {
-						scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
-						wmove(dialog, box_y, box_x);
-						for (i = 0; i < box_width; i++)
-							waddch(dialog,
-							       instr[scroll + input_x + i] ?
-							       instr[scroll + input_x + i] : ' ');
-						input_x = strlen(instr) - scroll;
+					if (input_x == 0) {
+						show_x--;
 					} else
 					} else
 						input_x--;
 						input_x--;
-					instr[scroll + input_x] = '\0';
-					mvwaddch(dialog, box_y, input_x + box_x, ' ');
+
+					if (pos < len) {
+						for (i = pos - 1; i < len; i++) {
+							instr[i] = instr[i+1];
+						}
+					}
+
+					pos--;
+					len--;
+					instr[len] = '\0';
+					wmove(dialog, box_y, box_x);
+					for (i = 0; i < box_width; i++) {
+						if (!instr[show_x + i]) {
+							waddch(dialog, ' ');
+							break;
+						}
+						waddch(dialog, instr[show_x + i]);
+					}
 					wmove(dialog, box_y, input_x + box_x);
 					wmove(dialog, box_y, input_x + box_x);
 					wrefresh(dialog);
 					wrefresh(dialog);
 				}
 				}
 				continue;
 				continue;
+			case KEY_LEFT:
+				if (pos > 0) {
+					if (input_x > 0) {
+						wmove(dialog, box_y, --input_x + box_x);
+					} else if (input_x == 0) {
+						show_x--;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, box_x);
+					}
+					pos--;
+				}
+				continue;
+			case KEY_RIGHT:
+				if (pos < len) {
+					if (input_x < box_width - 1) {
+						wmove(dialog, box_y, ++input_x + box_x);
+					} else if (input_x == box_width - 1) {
+						show_x++;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
+					}
+					pos++;
+				}
+				continue;
 			default:
 			default:
 				if (key < 0x100 && isprint(key)) {
 				if (key < 0x100 && isprint(key)) {
-					if (scroll + input_x < MAX_LEN) {
+					if (len < MAX_LEN) {
 						wattrset(dialog, dlg.inputbox.atr);
 						wattrset(dialog, dlg.inputbox.atr);
-						instr[scroll + input_x] = key;
-						instr[scroll + input_x + 1] = '\0';
+						if (pos < len) {
+							for (i = len; i > pos; i--)
+								instr[i] = instr[i-1];
+							instr[pos] = key;
+						} else {
+							instr[len] = key;
+						}
+						pos++;
+						len++;
+						instr[len] = '\0';
+
 						if (input_x == box_width - 1) {
 						if (input_x == box_width - 1) {
-							scroll++;
-							wmove(dialog, box_y, box_x);
-							for (i = 0; i < box_width - 1; i++)
-								waddch(dialog, instr [scroll + i]);
+							show_x++;
 						} else {
 						} else {
-							wmove(dialog, box_y, input_x++ + box_x);
-							waddch(dialog, key);
+							input_x++;
+						}
+
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
 						}
 						}
+						wmove(dialog, box_y, input_x + box_x);
 						wrefresh(dialog);
 						wrefresh(dialog);
 					} else
 					} else
 						flash();	/* Alarm user about overflow */
 						flash();	/* Alarm user about overflow */
@@ -179,7 +243,7 @@ do_resize:
 		case KEY_LEFT:
 		case KEY_LEFT:
 			switch (button) {
 			switch (button) {
 			case -1:
 			case -1:
-				button = 1;	/* Indicates "Cancel" button is selected */
+				button = 1;	/* Indicates "Help" button is selected */
 				print_buttons(dialog, height, width, 1);
 				print_buttons(dialog, height, width, 1);
 				break;
 				break;
 			case 0:
 			case 0:
@@ -203,7 +267,7 @@ do_resize:
 				print_buttons(dialog, height, width, 0);
 				print_buttons(dialog, height, width, 0);
 				break;
 				break;
 			case 0:
 			case 0:
-				button = 1;	/* Indicates "Cancel" button is selected */
+				button = 1;	/* Indicates "Help" button is selected */
 				print_buttons(dialog, height, width, 1);
 				print_buttons(dialog, height, width, 1);
 				break;
 				break;
 			case 1:
 			case 1:

+ 30 - 26
extra/config/lxdialog/menubox.c

@@ -15,7 +15,8 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 /*
 /*
@@ -153,12 +154,14 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
  */
  */
 static void print_buttons(WINDOW * win, int height, int width, int selected)
 static void print_buttons(WINDOW * win, int height, int width, int selected)
 {
 {
-	int x = width / 2 - 16;
+	int x = width / 2 - 28;
 	int y = height - 2;
 	int y = height - 2;
 
 
 	print_button(win, gettext("Select"), y, x, selected == 0);
 	print_button(win, gettext("Select"), y, x, selected == 0);
 	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
 	print_button(win, gettext(" Exit "), y, x + 12, selected == 1);
 	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
 	print_button(win, gettext(" Help "), y, x + 24, selected == 2);
+	print_button(win, gettext(" Save "), y, x + 36, selected == 3);
+	print_button(win, gettext(" Load "), y, x + 48, selected == 4);
 
 
 	wmove(win, y, x + 1 + 12 * selected);
 	wmove(win, y, x + 1 + 12 * selected);
 	wrefresh(win);
 	wrefresh(win);
@@ -190,7 +193,7 @@ int dialog_menu(const char *title, const char *prompt,
 do_resize:
 do_resize:
 	height = getmaxy(stdscr);
 	height = getmaxy(stdscr);
 	width = getmaxx(stdscr);
 	width = getmaxx(stdscr);
-	if (height < 15 || width < 65)
+	if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
 
 
 	height -= 4;
 	height -= 4;
@@ -200,8 +203,8 @@ do_resize:
 	max_choice = MIN(menu_height, item_count());
 	max_choice = MIN(menu_height, item_count());
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
-	x = (COLS - width) / 2;
-	y = (LINES - height) / 2;
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
 
 
 	draw_shadow(stdscr, y, x, height, width);
 	draw_shadow(stdscr, y, x, height, width);
 
 
@@ -300,10 +303,11 @@ do_resize:
 				}
 				}
 		}
 		}
 
 
-		if (i < max_choice ||
-		    key == KEY_UP || key == KEY_DOWN ||
-		    key == '-' || key == '+' ||
-		    key == KEY_PPAGE || key == KEY_NPAGE) {
+		if (item_count() != 0 &&
+		    (i < max_choice ||
+		     key == KEY_UP || key == KEY_DOWN ||
+		     key == '-' || key == '+' ||
+		     key == KEY_PPAGE || key == KEY_NPAGE)) {
 			/* Remove highligt of current item */
 			/* Remove highligt of current item */
 			print_item(scroll + choice, choice, FALSE);
 			print_item(scroll + choice, choice, FALSE);
 
 
@@ -371,7 +375,7 @@ do_resize:
 		case TAB:
 		case TAB:
 		case KEY_RIGHT:
 		case KEY_RIGHT:
 			button = ((key == KEY_LEFT ? --button : ++button) < 0)
 			button = ((key == KEY_LEFT ? --button : ++button) < 0)
-			    ? 2 : (button > 2 ? 0 : button);
+			    ? 4 : (button > 4 ? 0 : button);
 
 
 			print_buttons(dialog, height, width, button);
 			print_buttons(dialog, height, width, button);
 			wrefresh(menu);
 			wrefresh(menu);
@@ -382,6 +386,10 @@ do_resize:
 		case 'n':
 		case 'n':
 		case 'm':
 		case 'm':
 		case '/':
 		case '/':
+		case 'h':
+		case '?':
+		case 'z':
+		case '\n':
 			/* save scroll info */
 			/* save scroll info */
 			*s_scroll = scroll;
 			*s_scroll = scroll;
 			delwin(menu);
 			delwin(menu);
@@ -389,30 +397,26 @@ do_resize:
 			item_set(scroll + choice);
 			item_set(scroll + choice);
 			item_set_selected(1);
 			item_set_selected(1);
 			switch (key) {
 			switch (key) {
+			case 'h':
+			case '?':
+				return 2;
 			case 's':
 			case 's':
-				return 3;
 			case 'y':
 			case 'y':
-				return 3;
+				return 5;
 			case 'n':
 			case 'n':
-				return 4;
+				return 6;
 			case 'm':
 			case 'm':
-				return 5;
+				return 7;
 			case ' ':
 			case ' ':
-				return 6;
+				return 8;
 			case '/':
 			case '/':
-				return 7;
+				return 9;
+			case 'z':
+				return 10;
+			case '\n':
+				return button;
 			}
 			}
 			return 0;
 			return 0;
-		case 'h':
-		case '?':
-			button = 2;
-		case '\n':
-			*s_scroll = scroll;
-			delwin(menu);
-			delwin(dialog);
-			item_set(scroll + choice);
-			item_set_selected(1);
-			return button;
 		case 'e':
 		case 'e':
 		case 'x':
 		case 'x':
 			key = KEY_ESC;
 			key = KEY_ESC;

+ 102 - 84
extra/config/lxdialog/textbox.c

@@ -15,29 +15,32 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 #include "dialog.h"
 #include "dialog.h"
 
 
 static void back_lines(int n);
 static void back_lines(int n);
-static void print_page(WINDOW * win, int height, int width);
-static void print_line(WINDOW * win, int row, int width);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
 static char *get_line(void);
 static char *get_line(void);
 static void print_position(WINDOW * win);
 static void print_position(WINDOW * win);
 
 
 static int hscroll;
 static int hscroll;
 static int begin_reached, end_reached, page_length;
 static int begin_reached, end_reached, page_length;
-static const char *buf;
-static const char *page;
+static char *buf;
+static char *page;
 
 
 /*
 /*
  * refresh window content
  * refresh window content
  */
  */
 static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
 static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
-							  int cur_y, int cur_x)
+			     int cur_y, int cur_x, update_text_fn update_text,
+			     void *data)
 {
 {
-	print_page(box, boxh, boxw);
+	print_page(box, boxh, boxw, update_text, data);
 	print_position(dialog);
 	print_position(dialog);
 	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
 	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
 	wrefresh(dialog);
 	wrefresh(dialog);
@@ -46,14 +49,18 @@ static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
 
 
 /*
 /*
  * Display text from a file in a dialog box.
  * Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
  */
  */
-int dialog_textbox(const char *title, const char *tbuf,
-		   int initial_height, int initial_width)
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data)
 {
 {
 	int i, x, y, cur_x, cur_y, key = 0;
 	int i, x, y, cur_x, cur_y, key = 0;
 	int height, width, boxh, boxw;
 	int height, width, boxh, boxw;
-	int passed_end;
 	WINDOW *dialog, *box;
 	WINDOW *dialog, *box;
+	bool done = false;
 
 
 	begin_reached = 1;
 	begin_reached = 1;
 	end_reached = 0;
 	end_reached = 0;
@@ -62,9 +69,18 @@ int dialog_textbox(const char *title, const char *tbuf,
 	buf = tbuf;
 	buf = tbuf;
 	page = buf;	/* page is pointer to start of page to be displayed */
 	page = buf;	/* page is pointer to start of page to be displayed */
 
 
+	if (_vscroll && *_vscroll) {
+		begin_reached = 0;
+
+		for (i = 0; i < *_vscroll; i++)
+			get_line();
+	}
+	if (_hscroll)
+		hscroll = *_hscroll;
+
 do_resize:
 do_resize:
 	getmaxyx(stdscr, height, width);
 	getmaxyx(stdscr, height, width);
-	if (height < 8 || width < 8)
+	if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
 	if (initial_height != 0)
 	if (initial_height != 0)
 		height = initial_height;
 		height = initial_height;
@@ -82,8 +98,8 @@ do_resize:
 			width = 0;
 			width = 0;
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
-	x = (COLS - width) / 2;
-	y = (LINES - height) / 2;
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
 
 
 	draw_shadow(stdscr, y, x, height, width);
 	draw_shadow(stdscr, y, x, height, width);
 
 
@@ -119,25 +135,28 @@ do_resize:
 
 
 	/* Print first page of text */
 	/* Print first page of text */
 	attr_clear(box, boxh, boxw, dlg.dialog.atr);
 	attr_clear(box, boxh, boxw, dlg.dialog.atr);
-	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+			 data);
 
 
-	while ((key != KEY_ESC) && (key != '\n')) {
+	while (!done) {
 		key = wgetch(dialog);
 		key = wgetch(dialog);
 		switch (key) {
 		switch (key) {
 		case 'E':	/* Exit */
 		case 'E':	/* Exit */
 		case 'e':
 		case 'e':
 		case 'X':
 		case 'X':
 		case 'x':
 		case 'x':
-			delwin(box);
-			delwin(dialog);
-			return 0;
+		case 'q':
+		case '\n':
+			done = true;
+			break;
 		case 'g':	/* First page */
 		case 'g':	/* First page */
 		case KEY_HOME:
 		case KEY_HOME:
 			if (!begin_reached) {
 			if (!begin_reached) {
 				begin_reached = 1;
 				begin_reached = 1;
 				page = buf;
 				page = buf;
 				refresh_text_box(dialog, box, boxh, boxw,
 				refresh_text_box(dialog, box, boxh, boxw,
-						 cur_y, cur_x);
+						 cur_y, cur_x, update_text,
+						 data);
 			}
 			}
 			break;
 			break;
 		case 'G':	/* Last page */
 		case 'G':	/* Last page */
@@ -147,78 +166,48 @@ do_resize:
 			/* point to last char in buf */
 			/* point to last char in buf */
 			page = buf + strlen(buf);
 			page = buf + strlen(buf);
 			back_lines(boxh);
 			back_lines(boxh);
-			refresh_text_box(dialog, box, boxh, boxw,
-					 cur_y, cur_x);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'K':	/* Previous line */
 		case 'K':	/* Previous line */
 		case 'k':
 		case 'k':
 		case KEY_UP:
 		case KEY_UP:
-			if (!begin_reached) {
-				back_lines(page_length + 1);
-
-				/* We don't call print_page() here but use
-				 * scrolling to ensure faster screen update.
-				 * However, 'end_reached' and 'page_length'
-				 * should still be updated, and 'page' should
-				 * point to start of next page. This is done
-				 * by calling get_line() in the following
-				 * 'for' loop. */
-				scrollok(box, TRUE);
-				wscrl(box, -1);	/* Scroll box region down one line */
-				scrollok(box, FALSE);
-				page_length = 0;
-				passed_end = 0;
-				for (i = 0; i < boxh; i++) {
-					if (!i) {
-						/* print first line of page */
-						print_line(box, 0, boxw);
-						wnoutrefresh(box);
-					} else
-						/* Called to update 'end_reached' and 'page' */
-						get_line();
-					if (!passed_end)
-						page_length++;
-					if (end_reached && !passed_end)
-						passed_end = 1;
-				}
+			if (begin_reached)
+				break;
 
 
-				print_position(dialog);
-				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-				wrefresh(dialog);
-			}
+			back_lines(page_length + 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'B':	/* Previous page */
 		case 'B':	/* Previous page */
 		case 'b':
 		case 'b':
+		case 'u':
 		case KEY_PPAGE:
 		case KEY_PPAGE:
 			if (begin_reached)
 			if (begin_reached)
 				break;
 				break;
 			back_lines(page_length + boxh);
 			back_lines(page_length + boxh);
-			refresh_text_box(dialog, box, boxh, boxw,
-					 cur_y, cur_x);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'J':	/* Next line */
 		case 'J':	/* Next line */
 		case 'j':
 		case 'j':
 		case KEY_DOWN:
 		case KEY_DOWN:
-			if (!end_reached) {
-				begin_reached = 0;
-				scrollok(box, TRUE);
-				scroll(box);	/* Scroll box region up one line */
-				scrollok(box, FALSE);
-				print_line(box, boxh - 1, boxw);
-				wnoutrefresh(box);
-				print_position(dialog);
-				wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
-				wrefresh(dialog);
-			}
+			if (end_reached)
+				break;
+
+			back_lines(page_length - 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case KEY_NPAGE:	/* Next page */
 		case KEY_NPAGE:	/* Next page */
 		case ' ':
 		case ' ':
+		case 'd':
 			if (end_reached)
 			if (end_reached)
 				break;
 				break;
 
 
 			begin_reached = 0;
 			begin_reached = 0;
-			refresh_text_box(dialog, box, boxh, boxw,
-					 cur_y, cur_x);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case '0':	/* Beginning of line */
 		case '0':	/* Beginning of line */
 		case 'H':	/* Scroll left */
 		case 'H':	/* Scroll left */
@@ -233,8 +222,8 @@ do_resize:
 				hscroll--;
 				hscroll--;
 			/* Reprint current page to scroll horizontally */
 			/* Reprint current page to scroll horizontally */
 			back_lines(page_length);
 			back_lines(page_length);
-			refresh_text_box(dialog, box, boxh, boxw,
-					 cur_y, cur_x);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case 'L':	/* Scroll right */
 		case 'L':	/* Scroll right */
 		case 'l':
 		case 'l':
@@ -244,11 +233,12 @@ do_resize:
 			hscroll++;
 			hscroll++;
 			/* Reprint current page to scroll horizontally */
 			/* Reprint current page to scroll horizontally */
 			back_lines(page_length);
 			back_lines(page_length);
-			refresh_text_box(dialog, box, boxh, boxw,
-					 cur_y, cur_x);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
 			break;
 			break;
 		case KEY_ESC:
 		case KEY_ESC:
-			key = on_key_esc(dialog);
+			if (on_key_esc(dialog) == KEY_ESC)
+				done = true;
 			break;
 			break;
 		case KEY_RESIZE:
 		case KEY_RESIZE:
 			back_lines(height);
 			back_lines(height);
@@ -256,11 +246,31 @@ do_resize:
 			delwin(dialog);
 			delwin(dialog);
 			on_key_resize();
 			on_key_resize();
 			goto do_resize;
 			goto do_resize;
+		default:
+			for (i = 0; keys[i]; i++) {
+				if (key == keys[i]) {
+					done = true;
+					break;
+				}
+			}
 		}
 		}
 	}
 	}
 	delwin(box);
 	delwin(box);
 	delwin(dialog);
 	delwin(dialog);
-	return key;		/* ESC pressed */
+	if (_vscroll) {
+		const char *s;
+
+		s = buf;
+		*_vscroll = 0;
+		back_lines(page_length);
+		while (s < page && (s = strchr(s, '\n'))) {
+			(*_vscroll)++;
+			s++;
+		}
+	}
+	if (_hscroll)
+		*_hscroll = hscroll;
+	return key;
 }
 }
 
 
 /*
 /*
@@ -297,12 +307,23 @@ static void back_lines(int n)
 }
 }
 
 
 /*
 /*
- * Print a new page of text. Called by dialog_textbox().
+ * Print a new page of text.
  */
  */
-static void print_page(WINDOW * win, int height, int width)
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data)
 {
 {
 	int i, passed_end = 0;
 	int i, passed_end = 0;
 
 
+	if (update_text) {
+		char *end;
+
+		for (i = 0; i < height; i++)
+			get_line();
+		end = page;
+		back_lines(height);
+		update_text(buf, page - buf, end - buf, data);
+	}
+
 	page_length = 0;
 	page_length = 0;
 	for (i = 0; i < height; i++) {
 	for (i = 0; i < height; i++) {
 		print_line(win, i, width);
 		print_line(win, i, width);
@@ -315,11 +336,10 @@ static void print_page(WINDOW * win, int height, int width)
 }
 }
 
 
 /*
 /*
- * Print a new line of text. Called by dialog_textbox() and print_page().
+ * Print a new line of text.
  */
  */
 static void print_line(WINDOW * win, int row, int width)
 static void print_line(WINDOW * win, int row, int width)
 {
 {
-	int y, x;
 	char *line;
 	char *line;
 
 
 	line = get_line();
 	line = get_line();
@@ -328,10 +348,10 @@ static void print_line(WINDOW * win, int row, int width)
 	waddch(win, ' ');
 	waddch(win, ' ');
 	waddnstr(win, line, MIN(strlen(line), width - 2));
 	waddnstr(win, line, MIN(strlen(line), width - 2));
 
 
-	getyx(win, y, x);
 	/* Clear 'residue' of previous line */
 	/* Clear 'residue' of previous line */
 #if OLD_NCURSES
 #if OLD_NCURSES
 	{
 	{
+		int x = getcurx(win);
 		int i;
 		int i;
 		for (i = 0; i < width - x; i++)
 		for (i = 0; i < width - x; i++)
 			waddch(win, ' ');
 			waddch(win, ' ');
@@ -354,10 +374,8 @@ static char *get_line(void)
 	end_reached = 0;
 	end_reached = 0;
 	while (*page != '\n') {
 	while (*page != '\n') {
 		if (*page == '\0') {
 		if (*page == '\0') {
-			if (!end_reached) {
-				end_reached = 1;
-				break;
-			}
+			end_reached = 1;
+			break;
 		} else if (i < MAX_LEN)
 		} else if (i < MAX_LEN)
 			line[i++] = *(page++);
 			line[i++] = *(page++);
 		else {
 		else {
@@ -370,7 +388,7 @@ static char *get_line(void)
 	if (i <= MAX_LEN)
 	if (i <= MAX_LEN)
 		line[i] = '\0';
 		line[i] = '\0';
 	if (!end_reached)
 	if (!end_reached)
-		page++;		/* move pass '\n' */
+		page++;		/* move past '\n' */
 
 
 	return line;
 	return line;
 }
 }

+ 78 - 19
extra/config/lxdialog/util.c

@@ -15,11 +15,17 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
+#include <stdarg.h>
+
 #include "dialog.h"
 #include "dialog.h"
 
 
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
 struct dialog_info dlg;
 struct dialog_info dlg;
 
 
 static void set_mono_theme(void)
 static void set_mono_theme(void)
@@ -248,15 +254,56 @@ void attr_clear(WINDOW * win, int height, int width, chtype attr)
 
 
 void dialog_clear(void)
 void dialog_clear(void)
 {
 {
-	attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
+	int lines, columns;
+
+	lines = getmaxy(stdscr);
+	columns = getmaxx(stdscr);
+
+	attr_clear(stdscr, lines, columns, dlg.screen.atr);
 	/* Display background title if it exists ... - SLH */
 	/* Display background title if it exists ... - SLH */
 	if (dlg.backtitle != NULL) {
 	if (dlg.backtitle != NULL) {
-		int i;
+		int i, len = 0, skip = 0;
+		struct subtitle_list *pos;
 
 
 		wattrset(stdscr, dlg.screen.atr);
 		wattrset(stdscr, dlg.screen.atr);
 		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
 		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+
+		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+			/* 3 is for the arrow and spaces */
+			len += strlen(pos->text) + 3;
+		}
+
 		wmove(stdscr, 1, 1);
 		wmove(stdscr, 1, 1);
-		for (i = 1; i < COLS - 1; i++)
+		if (len > columns - 2) {
+			const char *ellipsis = "[...] ";
+			waddstr(stdscr, ellipsis);
+			skip = len - (columns - 2 - strlen(ellipsis));
+		}
+
+		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+			if (skip == 0)
+				waddch(stdscr, ACS_RARROW);
+			else
+				skip--;
+
+			if (skip == 0)
+				waddch(stdscr, ' ');
+			else
+				skip--;
+
+			if (skip < strlen(pos->text)) {
+				waddstr(stdscr, pos->text + skip);
+				skip = 0;
+			} else
+				skip -= strlen(pos->text);
+
+			if (skip == 0)
+				waddch(stdscr, ' ');
+			else
+				skip--;
+		}
+
+		for (i = len + 1; i < columns - 1; i++)
 			waddch(stdscr, ACS_HLINE);
 			waddch(stdscr, ACS_HLINE);
 	}
 	}
 	wnoutrefresh(stdscr);
 	wnoutrefresh(stdscr);
@@ -270,8 +317,12 @@ int init_dialog(const char *backtitle)
 	int height, width;
 	int height, width;
 
 
 	initscr();		/* Init curses */
 	initscr();		/* Init curses */
+
+	/* Get current cursor position for signal handler in mconf.c */
+	getyx(stdscr, saved_y, saved_x);
+
 	getmaxyx(stdscr, height, width);
 	getmaxyx(stdscr, height, width);
-	if (height < 19 || width < 80) {
+	if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
 		endwin();
 		endwin();
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
 	}
 	}
@@ -292,6 +343,11 @@ void set_dialog_backtitle(const char *backtitle)
 	dlg.backtitle = backtitle;
 	dlg.backtitle = backtitle;
 }
 }
 
 
+void set_dialog_subtitles(struct subtitle_list *subtitles)
+{
+	dlg.subtitles = subtitles;
+}
+
 /*
 /*
  * End using dialog functions.
  * End using dialog functions.
  */
  */
@@ -320,27 +376,19 @@ void print_title(WINDOW *dialog, const char *title, int width)
 /*
 /*
  * Print a string of text in a window, automatically wrap around to the
  * Print a string of text in a window, automatically wrap around to the
  * next line if the string is too long to fit on one line. Newline
  * next line if the string is too long to fit on one line. Newline
- * characters '\n' are replaced by spaces.  We start on a new line
+ * characters '\n' are propperly processed.  We start on a new line
  * if there is no room for at least 4 nonblanks following a double-space.
  * if there is no room for at least 4 nonblanks following a double-space.
  */
  */
 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 {
 {
 	int newl, cur_x, cur_y;
 	int newl, cur_x, cur_y;
-	int i, prompt_len, room, wlen;
-	char tempstr[MAX_LEN + 1], *word, *sp, *sp2;
+	int prompt_len, room, wlen;
+	char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
 
 
 	strcpy(tempstr, prompt);
 	strcpy(tempstr, prompt);
 
 
 	prompt_len = strlen(tempstr);
 	prompt_len = strlen(tempstr);
 
 
-	/*
-	 * Remove newlines
-	 */
-	for (i = 0; i < prompt_len; i++) {
-		if (tempstr[i] == '\n')
-			tempstr[i] = ' ';
-	}
-
 	if (prompt_len <= width - x * 2) {	/* If prompt is short */
 	if (prompt_len <= width - x * 2) {	/* If prompt is short */
 		wmove(win, y, (width - prompt_len) / 2);
 		wmove(win, y, (width - prompt_len) / 2);
 		waddstr(win, tempstr);
 		waddstr(win, tempstr);
@@ -350,7 +398,10 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 		newl = 1;
 		newl = 1;
 		word = tempstr;
 		word = tempstr;
 		while (word && *word) {
 		while (word && *word) {
-			sp = strchr(word, ' ');
+			sp = strpbrk(word, "\n ");
+			if (sp && *sp == '\n')
+				newline_separator = sp;
+
 			if (sp)
 			if (sp)
 				*sp++ = 0;
 				*sp++ = 0;
 
 
@@ -362,7 +413,7 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 			if (wlen > room ||
 			if (wlen > room ||
 			    (newl && wlen < 4 && sp
 			    (newl && wlen < 4 && sp
 			     && wlen + 1 + strlen(sp) > room
 			     && wlen + 1 + strlen(sp) > room
-			     && (!(sp2 = strchr(sp, ' '))
+			     && (!(sp2 = strpbrk(sp, "\n "))
 				 || wlen + 1 + (sp2 - sp) > room))) {
 				 || wlen + 1 + (sp2 - sp) > room))) {
 				cur_y++;
 				cur_y++;
 				cur_x = x;
 				cur_x = x;
@@ -370,7 +421,15 @@ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
 			wmove(win, cur_y, cur_x);
 			wmove(win, cur_y, cur_x);
 			waddstr(win, word);
 			waddstr(win, word);
 			getyx(win, cur_y, cur_x);
 			getyx(win, cur_y, cur_x);
-			cur_x++;
+
+			/* Move to the next line if the word separator was a newline */
+			if (newline_separator) {
+				cur_y++;
+				cur_x = x;
+				newline_separator = 0;
+			} else
+				cur_x++;
+
 			if (sp && *sp == ' ') {
 			if (sp && *sp == ' ') {
 				cur_x++;	/* double space */
 				cur_x++;	/* double space */
 				while (*++sp == ' ') ;
 				while (*++sp == ' ') ;

+ 6 - 5
extra/config/lxdialog/yesno.c

@@ -15,7 +15,8 @@
  *  GNU General Public License for more details.
  *  GNU General Public License for more details.
  *
  *
  *  You should have received a copy of the GNU General Public License
  *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
  */
 
 
 #include "dialog.h"
 #include "dialog.h"
@@ -44,14 +45,14 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
 	WINDOW *dialog;
 	WINDOW *dialog;
 
 
 do_resize:
 do_resize:
-	if (getmaxy(stdscr) < (height + 4))
+	if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
-	if (getmaxx(stdscr) < (width + 4))
+	if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
 		return -ERRDISPLAYTOOSMALL;
 		return -ERRDISPLAYTOOSMALL;
 
 
 	/* center dialog box on screen */
 	/* center dialog box on screen */
-	x = (COLS - width) / 2;
-	y = (LINES - height) / 2;
+	x = (getmaxx(stdscr) - width) / 2;
+	y = (getmaxy(stdscr) - height) / 2;
 
 
 	draw_shadow(stdscr, y, x, height, width);
 	draw_shadow(stdscr, y, x, height, width);
 
 

+ 321 - 212
extra/config/mconf.c

@@ -15,20 +15,19 @@
 #include <stdarg.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
+#include <signal.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <locale.h>
 #include <locale.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 #include "lxdialog/dialog.h"
 #include "lxdialog/dialog.h"
 
 
 static const char mconf_readme[] = N_(
 static const char mconf_readme[] = N_(
 "Overview\n"
 "Overview\n"
 "--------\n"
 "--------\n"
-"Some features may be built directly into uClibc.  Some features\n"
-"may be completely removed altogether.  There are also certain\n"
-"parameters which are not really features, but must be\n"
-"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"This interface let you select features and parameters for the build.\n"
+"Features can either be built-in, modularized, or ignored. Parameters\n"
+"must be entered in as decimal or hexadecimal numbers or text.\n"
 "\n"
 "\n"
 "Menu items beginning with following braces represent features that\n"
 "Menu items beginning with following braces represent features that\n"
 "  [ ] can be built in or removed\n"
 "  [ ] can be built in or removed\n"
@@ -49,7 +48,7 @@ static const char mconf_readme[] = N_(
 "----------\n"
 "----------\n"
 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
 "o  Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
 "   you wish to change or submenu wish to select and press <Enter>.\n"
 "   you wish to change or submenu wish to select and press <Enter>.\n"
-"   Submenus are designated by \"--->\".\n"
+"   Submenus are designated by \"--->\", empty ones by \"----\".\n"
 "\n"
 "\n"
 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
 "   Shortcut: Press the option's highlighted letter (hotkey).\n"
 "             Pressing a hotkey more than once will sequence\n"
 "             Pressing a hotkey more than once will sequence\n"
@@ -66,13 +65,15 @@ static const char mconf_readme[] = N_(
 "             there is a delayed response which you may find annoying.\n"
 "             there is a delayed response which you may find annoying.\n"
 "\n"
 "\n"
 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
 "   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
-"   <Exit> and <Help>\n"
+"   <Exit> and <Help>.\n"
 "\n"
 "\n"
 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
 "o  To get help with an item, use the cursor keys to highlight <Help>\n"
-"   and Press <ENTER>.\n"
+"   and press <ENTER>.\n"
 "\n"
 "\n"
 "   Shortcut: Press <H> or <?>.\n"
 "   Shortcut: Press <H> or <?>.\n"
 "\n"
 "\n"
+"o  To toggle the display of hidden options, press <Z>.\n"
+"\n"
 "\n"
 "\n"
 "Radiolists  (Choice lists)\n"
 "Radiolists  (Choice lists)\n"
 "-----------\n"
 "-----------\n"
@@ -104,10 +105,10 @@ static const char mconf_readme[] = N_(
 "Text Box    (Help Window)\n"
 "Text Box    (Help Window)\n"
 "--------\n"
 "--------\n"
 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
 "o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
-"   keys h,j,k,l function here as do <SPACE BAR> and <B> for those\n"
-"   who are familiar with less and lynx.\n"
+"   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for \n"
+"   those who are familiar with less and lynx.\n"
 "\n"
 "\n"
-"o  Press <E>, <X>, <Enter> or <Esc><Esc> to exit.\n"
+"o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
 "\n"
 "\n"
 "\n"
 "\n"
 "Alternate Configuration Files\n"
 "Alternate Configuration Files\n"
@@ -147,9 +148,9 @@ static const char mconf_readme[] = N_(
 "\n"
 "\n"
 "Optional personality available\n"
 "Optional personality available\n"
 "------------------------------\n"
 "------------------------------\n"
-"If you prefer to have all of the options listed in a single\n"
-"menu, rather than the default multimenu hierarchy, run the menuconfig\n"
-"with MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
+"If you prefer to have all of the options listed in a single menu, rather\n"
+"than the default multimenu hierarchy, run the menuconfig with\n"
+"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
 "\n"
 "\n"
 "make MENUCONFIG_MODE=single_menu menuconfig\n"
 "make MENUCONFIG_MODE=single_menu menuconfig\n"
 "\n"
 "\n"
@@ -175,11 +176,11 @@ static const char mconf_readme[] = N_(
 "\n"),
 "\n"),
 menu_instructions[] = N_(
 menu_instructions[] = N_(
 	"Arrow keys navigate the menu.  "
 	"Arrow keys navigate the menu.  "
-	"<Enter> selects submenus --->.  "
+	"<Enter> selects submenus ---> (or empty submenus ----).  "
 	"Highlighted letters are hotkeys.  "
 	"Highlighted letters are hotkeys.  "
-	"Pressing <Y> selectes a feature, while <N> will exclude a feature.  "
+	"Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
 	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
 	"Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
-	"Legend: [*] feature is selected  [ ] feature is excluded"),
+	"Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"),
 radiolist_instructions[] = N_(
 radiolist_instructions[] = N_(
 	"Use the arrow keys to navigate this window or "
 	"Use the arrow keys to navigate this window or "
 	"press the hotkey of the item you wish to select "
 	"press the hotkey of the item you wish to select "
@@ -198,8 +199,6 @@ inputbox_instructions_string[] = N_(
 setmod_text[] = N_(
 setmod_text[] = N_(
 	"This feature depends on another which has been configured as a module.\n"
 	"This feature depends on another which has been configured as a module.\n"
 	"As a result, this feature will be built as a module."),
 	"As a result, this feature will be built as a module."),
-nohelp_text[] = N_(
-	"There is no help available for this option.\n"),
 load_config_text[] = N_(
 load_config_text[] = N_(
 	"Enter the name of the configuration file you wish to load.  "
 	"Enter the name of the configuration file you wish to load.  "
 	"Accept the name shown to restore the configuration you "
 	"Accept the name shown to restore the configuration you "
@@ -210,18 +209,18 @@ load_config_help[] = N_(
 	"configurations available on a single machine.\n"
 	"configurations available on a single machine.\n"
 	"\n"
 	"\n"
 	"If you have saved a previous configuration in a file other than the\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"
-	"to modify that configuration.\n"
+	"default one, entering its name here will allow you to modify that\n"
+	"configuration.\n"
 	"\n"
 	"\n"
 	"If you are uncertain, then you have probably never used alternate\n"
 	"If you are uncertain, then you have probably never used alternate\n"
-	"configuration files.  You should therefor leave this blank to abort.\n"),
+	"configuration files. You should therefore leave this blank to abort.\n"),
 save_config_text[] = N_(
 save_config_text[] = N_(
 	"Enter a filename to which this configuration should be saved "
 	"Enter a filename to which this configuration should be saved "
 	"as an alternate.  Leave blank to abort."),
 	"as an alternate.  Leave blank to abort."),
 save_config_help[] = N_(
 save_config_help[] = N_(
 	"\n"
 	"\n"
-	"For various reasons, one may wish to keep different\n"
-	"configurations available on a single machine.\n"
+	"For various reasons, one may wish to keep different configurations\n"
+	"available on a single machine.\n"
 	"\n"
 	"\n"
 	"Entering a file name here will allow you to later retrieve, modify\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"
 	"and use the current configuration as an alternate to whatever\n"
@@ -231,32 +230,39 @@ save_config_help[] = N_(
 	"leave this blank.\n"),
 	"leave this blank.\n"),
 search_help[] = N_(
 search_help[] = N_(
 	"\n"
 	"\n"
-	"Search for CONFIG_ symbols and display their relations.\n"
+	"Search for symbols and display their relations.\n"
 	"Regular expressions are allowed.\n"
 	"Regular expressions are allowed.\n"
 	"Example: search for \"^FOO\"\n"
 	"Example: search for \"^FOO\"\n"
 	"Result:\n"
 	"Result:\n"
 	"-----------------------------------------------------------------\n"
 	"-----------------------------------------------------------------\n"
 	"Symbol: FOO [=m]\n"
 	"Symbol: FOO [=m]\n"
+	"Type  : tristate\n"
 	"Prompt: Foo bus is used to drive the bar HW\n"
 	"Prompt: Foo bus is used to drive the bar HW\n"
-	"Defined at drivers/pci/Kconfig:47\n"
-	"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
-	"Location:\n"
-	"  -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
-	"    -> PCI support (PCI [=y])\n"
-	"      -> PCI access mode (<choice> [=y])\n"
-	"Selects: LIBCRC32\n"
-	"Selected by: BAR\n"
+	"  Defined at drivers/pci/Kconfig:47\n"
+	"  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+	"  Location:\n"
+	"    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+	"      -> PCI support (PCI [=y])\n"
+	"(1)     -> PCI access mode (<choice> [=y])\n"
+	"  Selects: LIBCRC32\n"
+	"  Selected by: BAR\n"
 	"-----------------------------------------------------------------\n"
 	"-----------------------------------------------------------------\n"
+	"o The line 'Type:' shows the type of the configuration option for\n"
+	"  this symbol (boolean, tristate, string, ...)\n"
 	"o The line 'Prompt:' shows the text used in the menu structure for\n"
 	"o The line 'Prompt:' shows the text used in the menu structure for\n"
-	"  this CONFIG_ symbol\n"
+	"  this symbol\n"
 	"o The 'Defined at' line tell at what file / line number the symbol\n"
 	"o The 'Defined at' line tell at what file / line number the symbol\n"
 	"  is defined\n"
 	"  is defined\n"
 	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
 	"o The 'Depends on:' line tell what symbols needs to be defined for\n"
 	"  this symbol to be visible in the menu (selectable)\n"
 	"  this symbol to be visible in the menu (selectable)\n"
 	"o The 'Location:' lines tell where in the menu structure this symbol\n"
 	"o The 'Location:' lines tell where in the menu structure this symbol\n"
 	"  is located\n"
 	"  is located\n"
-	"    A location followed by a [=y] indicate that this is a selectable\n"
-	"    menu item - and current value is displayed inside brackets.\n"
+	"    A location followed by a [=y] indicates that this is a\n"
+	"    selectable menu item - and the current value is displayed inside\n"
+	"    brackets.\n"
+	"    Press the key in the (#) prefix to jump directly to that\n"
+	"    location. You will be returned to the current search results\n"
+	"    after exiting this new menu.\n"
 	"o The 'Selects:' line tell what symbol will be automatically\n"
 	"o The 'Selects:' line tell what symbol will be automatically\n"
 	"  selected if this symbol is selected (y or m)\n"
 	"  selected if this symbol is selected (y or m)\n"
 	"o The 'Selected by' line tell what symbol has selected this symbol\n"
 	"o The 'Selected by' line tell what symbol has selected this symbol\n"
@@ -264,131 +270,144 @@ search_help[] = N_(
 	"Only relevant lines are shown.\n"
 	"Only relevant lines are shown.\n"
 	"\n\n"
 	"\n\n"
 	"Search examples:\n"
 	"Search examples:\n"
-	"Examples: USB	=> find all CONFIG_ symbols containing USB\n"
-	"          ^USB => find all CONFIG_ symbols starting with USB\n"
-	"          USB$ => find all CONFIG_ symbols ending with USB\n"
+	"Examples: USB	=> find all symbols containing USB\n"
+	"          ^USB => find all symbols starting with USB\n"
+	"          USB$ => find all symbols ending with USB\n"
 	"\n");
 	"\n");
 
 
 static int indent;
 static int indent;
 static struct menu *current_menu;
 static struct menu *current_menu;
 static int child_count;
 static int child_count;
 static int single_menu_mode;
 static int single_menu_mode;
+static int show_all_options;
+static int save_and_exit;
 
 
-static void conf(struct menu *menu);
+static void conf(struct menu *menu, struct menu *active_menu);
 static void conf_choice(struct menu *menu);
 static void conf_choice(struct menu *menu);
 static void conf_string(struct menu *menu);
 static void conf_string(struct menu *menu);
 static void conf_load(void);
 static void conf_load(void);
 static void conf_save(void);
 static void conf_save(void);
+static int show_textbox_ext(const char *title, char *text, int r, int c,
+			    int *keys, int *vscroll, int *hscroll,
+			    update_text_fn update_text, void *data);
 static void show_textbox(const char *title, const char *text, int r, int c);
 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_helptext(const char *title, const char *text);
 static void show_help(struct menu *menu);
 static void show_help(struct menu *menu);
 
 
-static void get_prompt_str(struct gstr *r, struct property *prop)
+static char filename[PATH_MAX+1];
+static void set_config_filename(const char *config_filename)
 {
 {
-	int i, j;
-	struct menu *submenu[8], *menu;
-
-	str_printf(r, _("Prompt: %s\n"), _(prop->text));
-	str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
-		prop->menu->lineno);
-	if (!expr_is_yes(prop->visible.expr)) {
-		str_append(r, _("  Depends on: "));
-		expr_gstr_print(prop->visible.expr, r);
-		str_append(r, "\n");
+	static char menu_backtitle[PATH_MAX+128];
+	int size;
+
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+	                "%s - %s", config_filename, rootmenu.prompt->text);
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+	set_dialog_backtitle(menu_backtitle);
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+}
+
+struct subtitle_part {
+	struct list_head entries;
+	const char *text;
+};
+static LIST_HEAD(trail);
+
+static struct subtitle_list *subtitles;
+static void set_subtitle(void)
+{
+	struct subtitle_part *sp;
+	struct subtitle_list *pos, *tmp;
+
+	for (pos = subtitles; pos != NULL; pos = tmp) {
+		tmp = pos->next;
+		free(pos);
 	}
 	}
-	menu = prop->menu->parent;
-	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent)
-		submenu[i++] = menu;
-	if (i > 0) {
-		str_printf(r, _("  Location:\n"));
-		for (j = 4; --i >= 0; j += 2) {
-			menu = submenu[i];
-			str_printf(r, "%*c-> %s", j, ' ', _(menu_get_prompt(menu)));
-			if (menu->sym) {
-				str_printf(r, " (%s [=%s])", menu->sym->name ?
-					menu->sym->name : _("<choice>"),
-					sym_get_string_value(menu->sym));
+
+	subtitles = NULL;
+	list_for_each_entry(sp, &trail, entries) {
+		if (sp->text) {
+			if (pos) {
+				pos->next = xcalloc(sizeof(*pos), 1);
+				pos = pos->next;
+			} else {
+				subtitles = pos = xcalloc(sizeof(*pos), 1);
 			}
 			}
-			str_append(r, "\n");
+			pos->text = sp->text;
 		}
 		}
 	}
 	}
+
+	set_dialog_subtitles(subtitles);
 }
 }
 
 
-static void get_symbol_str(struct gstr *r, struct symbol *sym)
+static void reset_subtitle(void)
 {
 {
-	bool hit;
-	struct property *prop;
+	struct subtitle_list *pos, *tmp;
 
 
-	if (sym && sym->name)
-		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
-		                                    sym_get_string_value(sym));
-	for_all_prompts(sym, prop)
-		get_prompt_str(r, prop);
-	hit = false;
-	for_all_properties(sym, prop, P_SELECT) {
-		if (!hit) {
-			str_append(r, "  Selects: ");
-			hit = true;
-		} else
-			str_printf(r, " && ");
-		expr_gstr_print(prop->expr, r);
+	for (pos = subtitles; pos != NULL; pos = tmp) {
+		tmp = pos->next;
+		free(pos);
 	}
 	}
-	if (hit)
-		str_append(r, "\n");
-	if (sym->rev_dep.expr) {
-		str_append(r, _("  Selected by: "));
-		expr_gstr_print(sym->rev_dep.expr, r);
-		str_append(r, "\n");
-	}
-	str_append(r, "\n\n");
+	subtitles = NULL;
+	set_dialog_subtitles(subtitles);
 }
 }
 
 
-static struct gstr get_relations_str(struct symbol **sym_arr)
+struct search_data {
+	struct list_head *head;
+	struct menu **targets;
+	int *keys;
+};
+
+static void update_text(char *buf, size_t start, size_t end, void *_data)
 {
 {
-	struct symbol *sym;
-	struct gstr res = str_new();
-	int i;
+	struct search_data *data = _data;
+	struct jump_key *pos;
+	int k = 0;
 
 
-	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
-		get_symbol_str(&res, sym);
-	if (!i)
-		str_append(&res, _("No matches found.\n"));
-	return res;
-}
+	list_for_each_entry(pos, data->head, entries) {
+		if (pos->offset >= start && pos->offset < end) {
+			char header[4];
 
 
-static char filename[PATH_MAX+1];
-static void set_config_filename(const char *config_filename)
-{
-	static char menu_backtitle[PATH_MAX+128];
-	int size;
-	struct symbol *sym;
+			if (k < JUMP_NB) {
+				int key = '0' + (pos->index % JUMP_NB) + 1;
 
 
-	sym = sym_lookup("VERSION", 0);
-	sym_calc_value(sym);
-	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
-	                _("%s - uClibc v%s Configuration"),
-		        config_filename, sym_get_string_value(sym));
-	if (size >= sizeof(menu_backtitle))
-		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
-	set_dialog_backtitle(menu_backtitle);
+				sprintf(header, "(%c)", key);
+				data->keys[k] = key;
+				data->targets[k] = pos->target;
+				k++;
+			} else {
+				sprintf(header, "   ");
+			}
 
 
-	size = snprintf(filename, sizeof(filename), "%s", config_filename);
-	if (size >= sizeof(filename))
-		filename[sizeof(filename)-1] = '\0';
+			memcpy(buf + pos->offset, header, sizeof(header) - 1);
+		}
+	}
+	data->keys[k] = 0;
 }
 }
 
 
-
 static void search_conf(void)
 static void search_conf(void)
 {
 {
 	struct symbol **sym_arr;
 	struct symbol **sym_arr;
 	struct gstr res;
 	struct gstr res;
+	struct gstr title;
 	char *dialog_input;
 	char *dialog_input;
-	int dres;
+	int dres, vscroll = 0, hscroll = 0;
+	bool again;
+	struct gstr sttext;
+	struct subtitle_part stpart;
+
+	title = str_new();
+	str_printf( &title, _("Enter %s (sub)string or regexp to search for "
+			      "(with or without \"%s\")"), CONFIG_, CONFIG_);
+
 again:
 again:
 	dialog_clear();
 	dialog_clear();
 	dres = dialog_inputbox(_("Search Configuration Parameter"),
 	dres = dialog_inputbox(_("Search Configuration Parameter"),
-			      _("Enter CONFIG_ (sub)string to search for "
-				"(with or without \"CONFIG\")"),
+			      str_get(&title),
 			      10, 75, "");
 			      10, 75, "");
 	switch (dres) {
 	switch (dres) {
 	case 0:
 	case 0:
@@ -397,19 +416,52 @@ again:
 		show_helptext(_("Search Configuration"), search_help);
 		show_helptext(_("Search Configuration"), search_help);
 		goto again;
 		goto again;
 	default:
 	default:
+		str_free(&title);
 		return;
 		return;
 	}
 	}
 
 
-	/* strip CONFIG_ if necessary */
+	/* strip the prefix if necessary */
 	dialog_input = dialog_input_result;
 	dialog_input = dialog_input_result;
-	if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
-		dialog_input += 7;
+	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+		dialog_input += strlen(CONFIG_);
+
+	sttext = str_new();
+	str_printf(&sttext, "Search (%s)", dialog_input_result);
+	stpart.text = str_get(&sttext);
+	list_add_tail(&stpart.entries, &trail);
 
 
 	sym_arr = sym_re_search(dialog_input);
 	sym_arr = sym_re_search(dialog_input);
-	res = get_relations_str(sym_arr);
+	do {
+		LIST_HEAD(head);
+		struct menu *targets[JUMP_NB];
+		int keys[JUMP_NB + 1], i;
+		struct search_data data = {
+			.head = &head,
+			.targets = targets,
+			.keys = keys,
+		};
+		struct jump_key *pos, *tmp;
+
+		res = get_relations_str(sym_arr, &head);
+		set_subtitle();
+		dres = show_textbox_ext(_("Search Results"), (char *)
+					str_get(&res), 0, 0, keys, &vscroll,
+					&hscroll, &update_text, (void *)
+					&data);
+		again = false;
+		for (i = 0; i < JUMP_NB && keys[i]; i++)
+			if (dres == keys[i]) {
+				conf(targets[i]->parent, targets[i]);
+				again = true;
+			}
+		str_free(&res);
+		list_for_each_entry_safe(pos, tmp, &head, entries)
+			free(pos);
+	} while (again);
 	free(sym_arr);
 	free(sym_arr);
-	show_textbox(_("Search Results"), str_get(&res), 0, 0);
-	str_free(&res);
+	str_free(&title);
+	list_del(trail.prev);
+	str_free(&sttext);
 }
 }
 
 
 static void build_conf(struct menu *menu)
 static void build_conf(struct menu *menu)
@@ -420,8 +472,16 @@ static void build_conf(struct menu *menu)
 	int type, tmp, doint = 2;
 	int type, tmp, doint = 2;
 	tristate val;
 	tristate val;
 	char ch;
 	char ch;
+	bool visible;
 
 
-	if (!menu_is_visible(menu))
+	/*
+	 * note: menu_is_visible() has side effect that it will
+	 * recalc the value of the symbol.
+	 */
+	visible = menu_is_visible(menu);
+	if (show_all_options && !menu_has_prompt(menu))
+		return;
+	else if (!show_all_options && !visible)
 		return;
 		return;
 
 
 	sym = menu->sym;
 	sym = menu->sym;
@@ -438,8 +498,9 @@ static void build_conf(struct menu *menu)
 						  menu->data ? "-->" : "++>",
 						  menu->data ? "-->" : "++>",
 						  indent + 1, ' ', prompt);
 						  indent + 1, ' ', prompt);
 				} else
 				} else
-					item_make("   %*c%s  --->", indent + 1, ' ', prompt);
-
+					item_make("   %*c%s  %s",
+						  indent + 1, ' ', prompt,
+						  menu_is_empty(menu) ? "----" : "--->");
 				item_set_tag('m');
 				item_set_tag('m');
 				item_set_data(menu);
 				item_set_data(menu);
 				if (single_menu_mode && menu->data)
 				if (single_menu_mode && menu->data)
@@ -570,7 +631,7 @@ static void build_conf(struct menu *menu)
 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
 			  (sym_has_value(sym) || !sym_is_changable(sym)) ?
 			  "" : _(" (NEW)"));
 			  "" : _(" (NEW)"));
 		if (menu->prompt->type == P_MENU) {
 		if (menu->prompt->type == P_MENU) {
-			item_add_str("  --->");
+			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
 			return;
 			return;
 		}
 		}
 	}
 	}
@@ -582,40 +643,40 @@ conf_childs:
 	indent -= doint;
 	indent -= doint;
 }
 }
 
 
-static void conf(struct menu *menu)
+static void conf(struct menu *menu, struct menu *active_menu)
 {
 {
 	struct menu *submenu;
 	struct menu *submenu;
 	const char *prompt = menu_get_prompt(menu);
 	const char *prompt = menu_get_prompt(menu);
+	struct subtitle_part stpart;
 	struct symbol *sym;
 	struct symbol *sym;
-	struct menu *active_menu = NULL;
 	int res;
 	int res;
 	int s_scroll = 0;
 	int s_scroll = 0;
 
 
+	if (menu != &rootmenu)
+		stpart.text = menu_get_prompt(menu);
+	else
+		stpart.text = NULL;
+	list_add_tail(&stpart.entries, &trail);
+
 	while (1) {
 	while (1) {
 		item_reset();
 		item_reset();
 		current_menu = menu;
 		current_menu = menu;
 		build_conf(menu);
 		build_conf(menu);
 		if (!child_count)
 		if (!child_count)
 			break;
 			break;
-		if (menu == &rootmenu) {
-			item_make("--- ");
-			item_set_tag(':');
-			item_make(_("    Load an Alternate Configuration File"));
-			item_set_tag('L');
-			item_make(_("    Save an Alternate Configuration File"));
-			item_set_tag('S');
-		}
+		set_subtitle();
 		dialog_clear();
 		dialog_clear();
 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
 		res = dialog_menu(prompt ? _(prompt) : _("Main Menu"),
 				  _(menu_instructions),
 				  _(menu_instructions),
 				  active_menu, &s_scroll);
 				  active_menu, &s_scroll);
 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 		if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
 			break;
 			break;
-		if (!item_activate_selected())
-			continue;
-		if (!item_tag())
-			continue;
-
+		if (item_count() != 0) {
+			if (!item_activate_selected())
+				continue;
+			if (!item_tag())
+				continue;
+		}
 		submenu = item_data();
 		submenu = item_data();
 		active_menu = item_data();
 		active_menu = item_data();
 		if (submenu)
 		if (submenu)
@@ -630,32 +691,36 @@ static void conf(struct menu *menu)
 				if (single_menu_mode)
 				if (single_menu_mode)
 					submenu->data = (void *) (long) !submenu->data;
 					submenu->data = (void *) (long) !submenu->data;
 				else
 				else
-					conf(submenu);
+					conf(submenu, NULL);
 				break;
 				break;
 			case 't':
 			case 't':
 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
 					conf_choice(submenu);
 					conf_choice(submenu);
 				else if (submenu->prompt->type == P_MENU)
 				else if (submenu->prompt->type == P_MENU)
-					conf(submenu);
+					conf(submenu, NULL);
 				break;
 				break;
 			case 's':
 			case 's':
 				conf_string(submenu);
 				conf_string(submenu);
 				break;
 				break;
-			case 'L':
-				conf_load();
-				break;
-			case 'S':
-				conf_save();
-				break;
 			}
 			}
 			break;
 			break;
 		case 2:
 		case 2:
 			if (sym)
 			if (sym)
 				show_help(submenu);
 				show_help(submenu);
-			else
+			else {
+				reset_subtitle();
 				show_helptext(_("README"), _(mconf_readme));
 				show_helptext(_("README"), _(mconf_readme));
+			}
 			break;
 			break;
 		case 3:
 		case 3:
+			reset_subtitle();
+			conf_save();
+			break;
+		case 4:
+			reset_subtitle();
+			conf_load();
+			break;
+		case 5:
 			if (item_is_tag('t')) {
 			if (item_is_tag('t')) {
 				if (sym_set_tristate_value(sym, yes))
 				if (sym_set_tristate_value(sym, yes))
 					break;
 					break;
@@ -663,31 +728,45 @@ static void conf(struct menu *menu)
 					show_textbox(NULL, setmod_text, 6, 74);
 					show_textbox(NULL, setmod_text, 6, 74);
 			}
 			}
 			break;
 			break;
-		case 4:
+		case 6:
 			if (item_is_tag('t'))
 			if (item_is_tag('t'))
 				sym_set_tristate_value(sym, no);
 				sym_set_tristate_value(sym, no);
 			break;
 			break;
-		case 5:
+		case 7:
 			if (item_is_tag('t'))
 			if (item_is_tag('t'))
 				sym_set_tristate_value(sym, mod);
 				sym_set_tristate_value(sym, mod);
 			break;
 			break;
-		case 6:
+		case 8:
 			if (item_is_tag('t'))
 			if (item_is_tag('t'))
 				sym_toggle_tristate_value(sym);
 				sym_toggle_tristate_value(sym);
 			else if (item_is_tag('m'))
 			else if (item_is_tag('m'))
-				conf(submenu);
+				conf(submenu, NULL);
 			break;
 			break;
-		case 7:
+		case 9:
 			search_conf();
 			search_conf();
 			break;
 			break;
+		case 10:
+			show_all_options = !show_all_options;
+			break;
 		}
 		}
 	}
 	}
+
+	list_del(trail.prev);
 }
 }
 
 
-static void show_textbox(const char *title, const char *text, int r, int c)
+static int show_textbox_ext(const char *title, char *text, int r, int c, int
+			    *keys, int *vscroll, int *hscroll, update_text_fn
+			    update_text, void *data)
 {
 {
 	dialog_clear();
 	dialog_clear();
-	dialog_textbox(title, text, r, c);
+	return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
+			      update_text, data);
+}
+
+static void show_textbox(const char *title, const char *text, int r, int c)
+{
+	show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
+			 NULL, NULL);
 }
 }
 
 
 static void show_helptext(const char *title, const char *text)
 static void show_helptext(const char *title, const char *text)
@@ -695,25 +774,24 @@ static void show_helptext(const char *title, const char *text)
 	show_textbox(title, text, 0, 0);
 	show_textbox(title, text, 0, 0);
 }
 }
 
 
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+	char buf[PATH_MAX+1];
+
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	if (save_and_exit)
+		printf("%s", buf);
+	else
+		show_textbox(NULL, buf, 6, 60);
+}
+
 static void show_help(struct menu *menu)
 static void show_help(struct menu *menu)
 {
 {
 	struct gstr help = str_new();
 	struct gstr help = str_new();
-	struct symbol *sym = menu->sym;
 
 
-	if (menu_has_help(menu))
-	{
-		if (sym->name) {
-			str_printf(&help, "%s:\n\n", sym->name);
-		}
-		str_append(&help, _(menu_get_help(menu)));
-		str_append(&help, "\n");
-	} else if (menu_has_help(sym->prop->menu->parent)) {
-		str_append(&help, _(menu_get_help(sym->prop->menu->parent)));
-		str_append(&help, "\n");
-	} else {
-		str_append(&help, nohelp_text);
-	}
-	get_symbol_str(&help, sym);
+	help.max_width = getmaxx(stdscr) - 10;
+	menu_get_ext_help(menu, &help);
+
 	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
 	show_helptext(_(menu_get_prompt(menu)), str_get(&help));
 	str_free(&help);
 	str_free(&help);
 }
 }
@@ -734,7 +812,12 @@ static void conf_choice(struct menu *menu)
 		for (child = menu->list; child; child = child->next) {
 		for (child = menu->list; child; child = child->next) {
 			if (!menu_is_visible(child))
 			if (!menu_is_visible(child))
 				continue;
 				continue;
-			item_make("%s", _(menu_get_prompt(child)));
+			if (child->sym)
+				item_make("%s", _(menu_get_prompt(child)));
+			else {
+				item_make("*** %s ***", _(menu_get_prompt(child)));
+				item_set_tag(':');
+			}
 			item_set_data(child);
 			item_set_data(child);
 			if (child->sym == active)
 			if (child->sym == active)
 				item_set_selected(1);
 				item_set_selected(1);
@@ -744,12 +827,17 @@ static void conf_choice(struct menu *menu)
 		dialog_clear();
 		dialog_clear();
 		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
 		res = dialog_checklist(prompt ? _(prompt) : _("Main Menu"),
 					_(radiolist_instructions),
 					_(radiolist_instructions),
-					 15, 70, 6);
+					MENUBOX_HEIGTH_MIN,
+					MENUBOX_WIDTH_MIN,
+					CHECKLIST_HEIGTH_MIN);
 		selected = item_activate_selected();
 		selected = item_activate_selected();
 		switch (res) {
 		switch (res) {
 		case 0:
 		case 0:
 			if (selected) {
 			if (selected) {
 				child = item_data();
 				child = item_data();
+				if (!child->sym)
+					break;
+
 				sym_set_tristate_value(child->sym, yes);
 				sym_set_tristate_value(child->sym, yes);
 			}
 			}
 			return;
 			return;
@@ -863,9 +951,58 @@ static void conf_save(void)
 	}
 	}
 }
 }
 
 
+static int handle_exit(void)
+{
+	int res;
+
+	save_and_exit = 1;
+	reset_subtitle();
+	dialog_clear();
+	if (conf_get_changed())
+		res = dialog_yesno(NULL,
+				   _("Do you wish to save your new configuration?\n"
+				     "(Press <ESC><ESC> to continue configuration.)"),
+				   6, 60);
+	else
+		res = -1;
+
+	end_dialog(saved_x, saved_y);
+
+	switch (res) {
+	case 0:
+		if (conf_write(filename)) {
+			fprintf(stderr, _("\n\n"
+					  "Error while writing of the configuration.\n"
+					  "Your configuration changes were NOT saved."
+					  "\n\n"));
+			return 1;
+		}
+		/* fall through */
+	case -1:
+		printf(_("\n\n"
+			 "*** End of the configuration.\n"
+			 "*** Execute 'make' to start the build or try 'make help'."
+			 "\n\n"));
+		res = 0;
+		break;
+	default:
+		fprintf(stderr, _("\n\n"
+				  "Your configuration changes were NOT saved."
+				  "\n\n"));
+		if (res != KEY_ESC)
+			res = 0;
+	}
+
+	return res;
+}
+
+static void sig_handler(int signo)
+{
+	exit(handle_exit());
+}
+
 int main(int ac, char **av)
 int main(int ac, char **av)
 {
 {
-	int saved_x, saved_y;
 	char *mode;
 	char *mode;
 	int res;
 	int res;
 
 
@@ -873,6 +1010,8 @@ int main(int ac, char **av)
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 	textdomain(PACKAGE);
 
 
+	signal(SIGINT, sig_handler);
+
 	conf_parse(av[1]);
 	conf_parse(av[1]);
 	conf_read(NULL);
 	conf_read(NULL);
 
 
@@ -882,7 +1021,6 @@ int main(int ac, char **av)
 			single_menu_mode = 1;
 			single_menu_mode = 1;
 	}
 	}
 
 
-	getyx(stdscr, saved_y, saved_x);
 	if (init_dialog(NULL)) {
 	if (init_dialog(NULL)) {
 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
 		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
 		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
@@ -890,41 +1028,12 @@ int main(int ac, char **av)
 	}
 	}
 
 
 	set_config_filename(conf_get_configname());
 	set_config_filename(conf_get_configname());
+	conf_set_message_callback(conf_message_callback);
 	do {
 	do {
-		conf(&rootmenu);
-		dialog_clear();
-		if (conf_get_changed())
-			res = dialog_yesno(NULL,
-					   _("Do you wish to save your "
-					     "new configuration?\n"
-					     "<ESC><ESC> to continue."),
-					   6, 60);
-		else
-			res = -1;
+		conf(&rootmenu, NULL);
+		res = handle_exit();
 	} while (res == KEY_ESC);
 	} while (res == KEY_ESC);
-	end_dialog(saved_x, saved_y);
 
 
-	switch (res) {
-	case 0:
-		if (conf_write(filename)) {
-			fprintf(stderr, _("\n\n"
-				"Error during writing of the configuration.\n"
-				"Your configuration changes were NOT saved."
-				"\n\n"));
-			return 1;
-		}
-	case -1:
-		printf(_("\n\n"
-			"*** End of configuration.\n"
-			"*** Execute 'make' to build or try 'make help'."
-			"\n\n"));
-		break;
-	default:
-		fprintf(stderr, _("\n\n"
-			"Your configuration changes were NOT saved."
-			"\n\n"));
-	}
-
-	return conf_write_autoconf();
+	return res;
 }
 }
 
 

+ 249 - 12
extra/config/menu.c

@@ -3,12 +3,15 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
+#include <ctype.h>
+#include <stdarg.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
+static const char nohelp_text[] = "There is no help available for this option.";
+
 struct menu rootmenu;
 struct menu rootmenu;
 static struct menu **last_entry_ptr;
 static struct menu **last_entry_ptr;
 
 
@@ -35,7 +38,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...)
 	va_end(ap);
 	va_end(ap);
 }
 }
 
 
-void menu_init(void)
+void _menu_init(void)
 {
 {
 	current_entry = current_menu = &rootmenu;
 	current_entry = current_menu = &rootmenu;
 	last_entry_ptr = &rootmenu.list;
 	last_entry_ptr = &rootmenu.list;
@@ -45,7 +48,7 @@ void menu_add_entry(struct symbol *sym)
 {
 {
 	struct menu *menu;
 	struct menu *menu;
 
 
-	menu = malloc(sizeof(*menu));
+	menu = xmalloc(sizeof(*menu));
 	memset(menu, 0, sizeof(*menu));
 	memset(menu, 0, sizeof(*menu));
 	menu->sym = sym;
 	menu->sym = sym;
 	menu->parent = current_menu;
 	menu->parent = current_menu;
@@ -55,6 +58,8 @@ void menu_add_entry(struct symbol *sym)
 	*last_entry_ptr = menu;
 	*last_entry_ptr = menu;
 	last_entry_ptr = &menu->next;
 	last_entry_ptr = &menu->next;
 	current_entry = menu;
 	current_entry = menu;
+	if (sym)
+		menu_add_symbol(P_SYMBOL, sym, NULL);
 }
 }
 
 
 void menu_end_entry(void)
 void menu_end_entry(void)
@@ -74,7 +79,7 @@ void menu_end_menu(void)
 	current_menu = current_menu->parent;
 	current_menu = current_menu->parent;
 }
 }
 
 
-struct expr *menu_check_dep(struct expr *e)
+static struct expr *menu_check_dep(struct expr *e)
 {
 {
 	if (!e)
 	if (!e)
 		return e;
 		return e;
@@ -133,8 +138,35 @@ struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *e
 			while (isspace(*prompt))
 			while (isspace(*prompt))
 				prompt++;
 				prompt++;
 		}
 		}
-		if (current_entry->prompt)
+		if (current_entry->prompt && current_entry != &rootmenu)
 			prop_warn(prop, "prompt redefined");
 			prop_warn(prop, "prompt redefined");
+
+		/* Apply all upper menus' visibilities to actual prompts. */
+		if(type == P_PROMPT) {
+			struct menu *menu = current_entry;
+
+			while ((menu = menu->parent) != NULL) {
+				struct expr *dup_expr;
+
+				if (!menu->visibility)
+					continue;
+				/*
+				 * Do not add a reference to the
+				 * menu's visibility expression but
+				 * use a copy of it.  Otherwise the
+				 * expression reduction functions
+				 * will modify expressions that have
+				 * multiple references which can
+				 * cause unwanted side effects.
+				 */
+				dup_expr = expr_copy(menu->visibility);
+
+				prop->visible.expr
+					= expr_alloc_and(prop->visible.expr,
+							 dup_expr);
+			}
+		}
+
 		current_entry->prompt = prop;
 		current_entry->prompt = prop;
 	}
 	}
 	prop->text = prompt;
 	prop->text = prompt;
@@ -147,6 +179,12 @@ struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr
 	return menu_add_prop(type, prompt, NULL, dep);
 	return menu_add_prop(type, prompt, NULL, dep);
 }
 }
 
 
+void menu_add_visibility(struct expr *expr)
+{
+	current_entry->visibility = expr_alloc_and(current_entry->visibility,
+	    expr);
+}
+
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
 void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep)
 {
 {
 	menu_add_prop(type, NULL, expr, dep);
 	menu_add_prop(type, NULL, expr, dep);
@@ -178,13 +216,13 @@ void menu_add_option(int token, char *arg)
 	}
 	}
 }
 }
 
 
-static int menu_range_valid_sym(struct symbol *sym, struct symbol *sym2)
+static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
 {
 {
 	return sym2->type == S_INT || sym2->type == S_HEX ||
 	return sym2->type == S_INT || sym2->type == S_HEX ||
 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
 	       (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
 }
 }
 
 
-void sym_check_prop(struct symbol *sym)
+static void sym_check_prop(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
 	struct symbol *sym2;
 	struct symbol *sym2;
@@ -194,8 +232,17 @@ void sym_check_prop(struct symbol *sym)
 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
 			if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
 			    prop->expr->type != E_SYMBOL)
 			    prop->expr->type != E_SYMBOL)
 				prop_warn(prop,
 				prop_warn(prop,
-				    "default for config symbol '%'"
+				    "default for config symbol '%s'"
 				    " must be a single symbol", sym->name);
 				    " must be a single symbol", sym->name);
+			if (prop->expr->type != E_SYMBOL)
+				break;
+			sym2 = prop_get_symbol(prop);
+			if (sym->type == S_HEX || sym->type == S_INT) {
+				if (!menu_validate_number(sym, sym2))
+					prop_warn(prop,
+					    "'%s': number is invalid",
+					    sym->name);
+			}
 			break;
 			break;
 		case P_SELECT:
 		case P_SELECT:
 			sym2 = prop_get_symbol(prop);
 			sym2 = prop_get_symbol(prop);
@@ -215,8 +262,8 @@ void sym_check_prop(struct symbol *sym)
 			if (sym->type != S_INT && sym->type != S_HEX)
 			if (sym->type != S_INT && sym->type != S_HEX)
 				prop_warn(prop, "range is only allowed "
 				prop_warn(prop, "range is only allowed "
 				                "for int or hex symbols");
 				                "for int or hex symbols");
-			if (!menu_range_valid_sym(sym, prop->expr->left.sym) ||
-			    !menu_range_valid_sym(sym, prop->expr->right.sym))
+			if (!menu_validate_number(sym, prop->expr->left.sym) ||
+			    !menu_validate_number(sym, prop->expr->right.sym))
 				prop_warn(prop, "range is invalid");
 				prop_warn(prop, "range is invalid");
 			break;
 			break;
 		default:
 		default:
@@ -315,6 +362,8 @@ void menu_finalize(struct menu *parent)
 			parent->next = last_menu->next;
 			parent->next = last_menu->next;
 			last_menu->next = NULL;
 			last_menu->next = NULL;
 		}
 		}
+
+		sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep);
 	}
 	}
 	for (menu = parent->list; menu; menu = menu->next) {
 	for (menu = parent->list; menu; menu = menu->next) {
 		if (sym && sym_is_choice(sym) &&
 		if (sym && sym_is_choice(sym) &&
@@ -387,6 +436,29 @@ void menu_finalize(struct menu *parent)
 	}
 	}
 }
 }
 
 
+bool menu_has_prompt(struct menu *menu)
+{
+	if (!menu->prompt)
+		return false;
+	return true;
+}
+
+/*
+ * Determine if a menu is empty.
+ * A menu is considered empty if it contains no or only
+ * invisible entries.
+ */
+bool menu_is_empty(struct menu *menu)
+{
+	struct menu *child;
+
+	for (child = menu->list; child; child = child->next) {
+		if (menu_is_visible(child))
+			return(false);
+	}
+	return(true);
+}
+
 bool menu_is_visible(struct menu *menu)
 bool menu_is_visible(struct menu *menu)
 {
 {
 	struct menu *child;
 	struct menu *child;
@@ -395,6 +467,12 @@ bool menu_is_visible(struct menu *menu)
 
 
 	if (!menu->prompt)
 	if (!menu->prompt)
 		return false;
 		return false;
+
+	if (menu->visibility) {
+		if (expr_calc_value(menu->visibility) == no)
+			return no;
+	}
+
 	sym = menu->sym;
 	sym = menu->sym;
 	if (sym) {
 	if (sym) {
 		sym_calc_value(sym);
 		sym_calc_value(sym);
@@ -404,12 +482,18 @@ bool menu_is_visible(struct menu *menu)
 
 
 	if (visible != no)
 	if (visible != no)
 		return true;
 		return true;
+
 	if (!sym || sym_get_tristate_value(menu->sym) == no)
 	if (!sym || sym_get_tristate_value(menu->sym) == no)
 		return false;
 		return false;
 
 
-	for (child = menu->list; child; child = child->next)
-		if (menu_is_visible(child))
+	for (child = menu->list; child; child = child->next) {
+		if (menu_is_visible(child)) {
+			if (sym)
+				sym->flags |= SYMBOL_DEF_USER;
 			return true;
 			return true;
+		}
+	}
+
 	return false;
 	return false;
 }
 }
 
 
@@ -451,3 +535,156 @@ const char *menu_get_help(struct menu *menu)
 	else
 	else
 		return "";
 		return "";
 }
 }
+
+static void get_prompt_str(struct gstr *r, struct property *prop,
+			   struct list_head *head)
+{
+	int i, j;
+	struct menu *submenu[8], *menu, *location = NULL;
+	struct jump_key *jump;
+
+	str_printf(r, _("Prompt: %s\n"), _(prop->text));
+	menu = prop->menu->parent;
+	for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
+		bool accessible = menu_is_visible(menu);
+
+		submenu[i++] = menu;
+		if (location == NULL && accessible)
+			location = menu;
+	}
+	if (head && location) {
+		jump = xmalloc(sizeof(struct jump_key));
+
+		if (menu_is_visible(prop->menu)) {
+			/*
+			 * There is not enough room to put the hint at the
+			 * beginning of the "Prompt" line. Put the hint on the
+			 * last "Location" line even when it would belong on
+			 * the former.
+			 */
+			jump->target = prop->menu;
+		} else
+			jump->target = location;
+
+		if (list_empty(head))
+			jump->index = 0;
+		else
+			jump->index = list_entry(head->prev, struct jump_key,
+						 entries)->index + 1;
+
+		list_add_tail(&jump->entries, head);
+	}
+
+	if (i > 0) {
+		str_printf(r, _("  Location:\n"));
+		for (j = 4; --i >= 0; j += 2) {
+			menu = submenu[i];
+			if (head && location && menu == location)
+				jump->offset = r->len - 1;
+			str_printf(r, "%*c-> %s", j, ' ',
+				   _(menu_get_prompt(menu)));
+			if (menu->sym) {
+				str_printf(r, " (%s [=%s])", menu->sym->name ?
+					menu->sym->name : _("<choice>"),
+					sym_get_string_value(menu->sym));
+			}
+			str_append(r, "\n");
+		}
+	}
+}
+
+/*
+ * get peoperty of type P_SYMBOL
+ */
+static struct property *get_symbol_prop(struct symbol *sym)
+{
+	struct property *prop = NULL;
+
+	for_all_properties(sym, prop, P_SYMBOL)
+		break;
+	return prop;
+}
+
+/*
+ * head is optional and may be NULL
+ */
+void get_symbol_str(struct gstr *r, struct symbol *sym,
+		    struct list_head *head)
+{
+	bool hit;
+	struct property *prop;
+
+	if (sym && sym->name) {
+		str_printf(r, "Symbol: %s [=%s]\n", sym->name,
+			   sym_get_string_value(sym));
+		str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
+		if (sym->type == S_INT || sym->type == S_HEX) {
+			prop = sym_get_range_prop(sym);
+			if (prop) {
+				str_printf(r, "Range : ");
+				expr_gstr_print(prop->expr, r);
+				str_append(r, "\n");
+			}
+		}
+	}
+	for_all_prompts(sym, prop)
+		get_prompt_str(r, prop, head);
+
+	prop = get_symbol_prop(sym);
+	if (prop) {
+		str_printf(r, _("  Defined at %s:%d\n"), prop->menu->file->name,
+			prop->menu->lineno);
+		if (!expr_is_yes(prop->visible.expr)) {
+			str_append(r, _("  Depends on: "));
+			expr_gstr_print(prop->visible.expr, r);
+			str_append(r, "\n");
+		}
+	}
+
+	hit = false;
+	for_all_properties(sym, prop, P_SELECT) {
+		if (!hit) {
+			str_append(r, "  Selects: ");
+			hit = true;
+		} else
+			str_printf(r, " && ");
+		expr_gstr_print(prop->expr, r);
+	}
+	if (hit)
+		str_append(r, "\n");
+	if (sym->rev_dep.expr) {
+		str_append(r, _("  Selected by: "));
+		expr_gstr_print(sym->rev_dep.expr, r);
+		str_append(r, "\n");
+	}
+	str_append(r, "\n\n");
+}
+
+struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head)
+{
+	struct symbol *sym;
+	struct gstr res = str_new();
+	int i;
+
+	for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+		get_symbol_str(&res, sym, head);
+	if (!i)
+		str_append(&res, _("No matches found.\n"));
+	return res;
+}
+
+
+void menu_get_ext_help(struct menu *menu, struct gstr *help)
+{
+	struct symbol *sym = menu->sym;
+	const char *help_text = nohelp_text;
+
+	if (menu_has_help(menu)) {
+		if (sym->name)
+			str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
+		help_text = menu_get_help(menu);
+	}
+	str_printf(help, "%s\n", _(help_text));
+	if (sym)
+		get_symbol_str(help, sym, NULL);
+}

+ 150 - 0
extra/config/merge_config.sh

@@ -0,0 +1,150 @@
+#!/bin/sh
+#  merge_config.sh - Takes a list of config fragment values, and merges
+#  them one by one. Provides warnings on overridden values, and specified
+#  values that did not make it to the resulting .config file (due to missed
+#  dependencies or config symbol removal).
+#
+#  Portions reused from kconf_check and generate_cfg:
+#  http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
+#  http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
+#
+#  Copyright (c) 2009-2010 Wind River Systems, Inc.
+#  Copyright 2011 Linaro
+#
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License version 2 as
+#  published by the Free Software Foundation.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#  See the GNU General Public License for more details.
+
+clean_up() {
+	rm -f $TMP_FILE
+	exit
+}
+trap clean_up HUP INT TERM
+
+usage() {
+	echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
+	echo "  -h    display this help text"
+	echo "  -m    only merge the fragments, do not execute the make command"
+	echo "  -n    use allnoconfig instead of alldefconfig"
+	echo "  -r    list redundant entries when merging fragments"
+	echo "  -O    dir to put generated output files"
+}
+
+MAKE=true
+ALLTARGET=alldefconfig
+WARNREDUN=false
+OUTPUT=.
+
+while true; do
+	case $1 in
+	"-n")
+		ALLTARGET=allnoconfig
+		shift
+		continue
+		;;
+	"-m")
+		MAKE=false
+		shift
+		continue
+		;;
+	"-h")
+		usage
+		exit
+		;;
+	"-r")
+		WARNREDUN=true
+		shift
+		continue
+		;;
+	"-O")
+		if [ -d $2 ];then
+			OUTPUT=$(echo $2 | sed 's/\/*$//')
+		else
+			echo "output directory $2 does not exist" 1>&2
+			exit 1
+		fi
+		shift 2
+		continue
+		;;
+	*)
+		break
+		;;
+	esac
+done
+
+INITFILE=$1
+shift;
+
+MERGE_LIST=$*
+SED_CONFIG_EXP="s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p"
+TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
+
+echo "Using $INITFILE as base"
+cat $INITFILE > $TMP_FILE
+
+# Merge files, printing warnings on overrided values
+for MERGE_FILE in $MERGE_LIST ; do
+	echo "Merging $MERGE_FILE"
+	CFG_LIST=$(sed -n "$SED_CONFIG_EXP" $MERGE_FILE)
+
+	for CFG in $CFG_LIST ; do
+		grep -q -w $CFG $TMP_FILE
+		if [ $? -eq 0 ] ; then
+			PREV_VAL=$(grep -w $CFG $TMP_FILE)
+			NEW_VAL=$(grep -w $CFG $MERGE_FILE)
+			if [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
+			echo Value of $CFG is redefined by fragment $MERGE_FILE:
+			echo Previous  value: $PREV_VAL
+			echo New value:       $NEW_VAL
+			echo
+			elif [ "$WARNREDUN" = "true" ]; then
+			echo Value of $CFG is redundant by fragment $MERGE_FILE:
+			fi
+			sed -i "/$CFG[ =]/d" $TMP_FILE
+		fi
+	done
+	cat $MERGE_FILE >> $TMP_FILE
+done
+
+if [ "$MAKE" = "false" ]; then
+	cp $TMP_FILE $OUTPUT/.config
+	echo "#"
+	echo "# merged configuration written to $OUTPUT/.config (needs make)"
+	echo "#"
+	clean_up
+	exit
+fi
+
+# If we have an output dir, setup the O= argument, otherwise leave
+# it blank, since O=. will create an unnecessary ./source softlink
+OUTPUT_ARG=""
+if [ "$OUTPUT" != "." ] ; then
+	OUTPUT_ARG="O=$OUTPUT"
+fi
+
+
+# Use the merged file as the starting point for:
+# alldefconfig: Fills in any missing symbols with Kconfig default
+# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
+make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
+
+
+# Check all specified config values took (might have missed-dependency issues)
+for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
+
+	REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
+	ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config)
+	if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
+		echo "Value requested for $CFG not in final .config"
+		echo "Requested value:  $REQUESTED_VAL"
+		echo "Actual value:     $ACTUAL_VAL"
+		echo ""
+	fi
+done
+
+clean_up

+ 1557 - 0
extra/config/nconf.c

@@ -0,0 +1,1557 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdlib.h>
+
+#include "lkc.h"
+#include "nconf.h"
+#include <ctype.h>
+
+static const char nconf_global_help[] = N_(
+"Help windows\n"
+"------------\n"
+"o  Global help:  Unless in a data entry window, pressing <F1> will give \n"
+"   you the global help window, which you are just reading.\n"
+"\n"
+"o  A short version of the global help is available by pressing <F3>.\n"
+"\n"
+"o  Local help:  To get help related to the current menu entry, use any\n"
+"   of <?> <h>, or if in a data entry window then press <F1>.\n"
+"\n"
+"\n"
+"Menu entries\n"
+"------------\n"
+"This interface lets you select features and parameters for the \n"
+"build.  Features can either be built-in, modularized, or removed.\n"
+"Parameters must be entered as text or decimal or hexadecimal numbers.\n"
+"\n"
+"Menu entries beginning with following braces represent features that\n"
+"  [ ]  can be built in or removed\n"
+"  < >  can be built in, modularized or removed\n"
+"  { }  can be built in or modularized, are selected by another feature\n"
+"  - -  are selected by another feature\n"
+"  XXX  cannot be selected.  Symbol Info <F2> tells you why.\n"
+"*, M or whitespace inside braces means to build in, build as a module\n"
+"or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the movement keys\n"
+"listed below and press <y> to build it in, <m> to make it a module or\n"
+"<n> to remove it.  You may press the <Space> key to cycle through the\n"
+"available options.\n"
+"\n"
+"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
+"empty submenu.\n"
+"\n"
+"Menu navigation keys\n"
+"----------------------------------------------------------------------\n"
+"Linewise up                 <Up>\n"
+"Linewise down               <Down>\n"
+"Pagewise up                 <Page Up>\n"
+"Pagewise down               <Page Down>\n"
+"First entry                 <Home>\n"
+"Last entry                  <End>\n"
+"Enter a submenu             <Right>  <Enter>\n"
+"Go back to parent menu      <Left>   <Esc>  <F5>\n"
+"Close a help window         <Enter>  <Esc>  <F5>\n"
+"Close entry window, apply   <Enter>\n"
+"Close entry window, forget  <Esc>  <F5>\n"
+"Start incremental, case-insensitive search for STRING in menu entries,\n"
+"    no regex support, STRING is displayed in upper left corner\n"
+"                            </>STRING\n"
+"    Remove last character   <Backspace>\n"
+"    Jump to next hit        <Down>\n"
+"    Jump to previous hit    <Up>\n"
+"Exit menu search mode       </>  <Esc>\n"
+"Search for configuration variables with or without leading CONFIG_\n"
+"                            <F8>RegExpr<Enter>\n"
+"Verbose search help         <F8><F1>\n"
+"----------------------------------------------------------------------\n"
+"\n"
+"Unless in a data entry window, key <1> may be used instead of <F1>,\n"
+"<2> instead of <F2>, etc.\n"
+"\n"
+"\n"
+"Radiolist (Choice list)\n"
+"-----------------------\n"
+"Use the movement keys listed above to select the option you wish to set\n"
+"and press <Space>.\n"
+"\n"
+"\n"
+"Data entry\n"
+"----------\n"
+"Enter the requested information and press <Enter>.  Hexadecimal values\n"
+"may be entered without the \"0x\" prefix.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"----------------------\n"
+"Use movement keys as listed in table above.\n"
+"\n"
+"Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
+"\n"
+"\n"
+"Alternate configuration files\n"
+"-----------------------------\n"
+"nconfig supports switching between different configurations.\n"
+"Press <F6> to save your current configuration.  Press <F7> and enter\n"
+"a file name to load a previously saved configuration.\n"
+"\n"
+"\n"
+"Terminal configuration\n"
+"----------------------\n"
+"If you use nconfig in a xterm window, make sure your TERM environment\n"
+"variable specifies a terminal configuration which supports at least\n"
+"16 colors.  Otherwise nconfig will look rather bad.\n"
+"\n"
+"If the \"stty size\" command reports the current terminalsize correctly,\n"
+"nconfig will adapt to sizes larger than the traditional 80x25 \"standard\"\n"
+"and display longer menus properly.\n"
+"\n"
+"\n"
+"Single menu mode\n"
+"----------------\n"
+"If you prefer to have all of the menu entries listed in a single menu,\n"
+"rather than the default multimenu hierarchy, run nconfig with\n"
+"NCONFIG_MODE environment variable set to single_menu.  Example:\n"
+"\n"
+"make NCONFIG_MODE=single_menu nconfig\n"
+"\n"
+"<Enter> will then unfold the appropriate category, or fold it if it\n"
+"is already unfolded.  Folded menu entries will be designated by a\n"
+"leading \"++>\" and unfolded entries by a leading \"-->\".\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive than\n"
+"the default mode, especially with a larger number of unfolded submenus.\n"
+"\n"),
+menu_no_f_instructions[] = N_(
+"Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
+"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
+"\n"
+"Use the following keys to navigate the menus:\n"
+"Move up or down with <Up> and <Down>.\n"
+"Enter a submenu with <Enter> or <Right>.\n"
+"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
+"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
+"Pressing <Space> cycles through the available options.\n"
+"To search for menu entries press </>.\n"
+"<Esc> always leaves the current window.\n"
+"\n"
+"You do not have function keys support.\n"
+"Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
+"For verbose global help use key <1>.\n"
+"For help related to the current menu entry press <?> or <h>.\n"),
+menu_instructions[] = N_(
+"Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
+"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
+"\n"
+"Use the following keys to navigate the menus:\n"
+"Move up or down with <Up> or <Down>.\n"
+"Enter a submenu with <Enter> or <Right>.\n"
+"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
+"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
+"Pressing <Space> cycles through the available options.\n"
+"To search for menu entries press </>.\n"
+"<Esc> always leaves the current window.\n"
+"\n"
+"Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
+"For verbose global help press <F1>.\n"
+"For help related to the current menu entry press <?> or <h>.\n"),
+radiolist_instructions[] = N_(
+"Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
+"with <Space>.\n"
+"For help related to the current entry press <?> or <h>.\n"
+"For global help press <F1>.\n"),
+inputbox_instructions_int[] = N_(
+"Please enter a decimal value.\n"
+"Fractions will not be accepted.\n"
+"Press <Enter> to apply, <Esc> to cancel."),
+inputbox_instructions_hex[] = N_(
+"Please enter a hexadecimal value.\n"
+"Press <Enter> to apply, <Esc> to cancel."),
+inputbox_instructions_string[] = N_(
+"Please enter a string value.\n"
+"Press <Enter> to apply, <Esc> to cancel."),
+setmod_text[] = N_(
+"This feature depends on another feature which has been configured as a\n"
+"module.  As a result, the current feature will be built as a module too."),
+load_config_text[] = N_(
+"Enter the name of the configuration file you wish to load.\n"
+"Accept the name shown to restore the configuration you last\n"
+"retrieved.  Leave empty to abort."),
+load_config_help[] = N_(
+"For various reasons, one may wish to keep several different\n"
+"configurations available on a single machine.\n"
+"\n"
+"If you have saved a previous configuration in a file other than the\n"
+"default one, entering its name here will allow you to load and modify\n"
+"that configuration.\n"
+"\n"
+"Leave empty to abort.\n"),
+save_config_text[] = N_(
+"Enter a filename to which this configuration should be saved\n"
+"as an alternate.  Leave empty to abort."),
+save_config_help[] = N_(
+"For various reasons, one may wish to keep several different\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"
+"Leave empty to abort.\n"),
+search_help[] = N_(
+"Search for symbols (configuration variable names CONFIG_*) and display\n"
+"their relations.  Regular expressions are supported.\n"
+"Example:  Search for \"^FOO\".\n"
+"Result:\n"
+"-----------------------------------------------------------------\n"
+"Symbol: FOO [ = m]\n"
+"Prompt: Foo bus is used to drive the bar HW\n"
+"Defined at drivers/pci/Kconfig:47\n"
+"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+"Location:\n"
+"  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
+"    -> PCI support (PCI [ = y])\n"
+"      -> PCI access mode (<choice> [ = y])\n"
+"Selects: LIBCRC32\n"
+"Selected by: BAR\n"
+"-----------------------------------------------------------------\n"
+"o  The line 'Prompt:' shows the text displayed for this symbol in\n"
+"   the menu hierarchy.\n"
+"o  The 'Defined at' line tells at what file / line number the symbol is\n"
+"   defined.\n"
+"o  The 'Depends on:' line lists symbols that need to be defined for\n"
+"   this symbol to be visible and selectable in the menu.\n"
+"o  The 'Location:' lines tell, where in the menu structure this symbol\n"
+"   is located.  A location followed by a [ = y] indicates that this is\n"
+"   a selectable menu item, and the current value is displayed inside\n"
+"   brackets.\n"
+"o  The 'Selects:' line tells, what symbol will be automatically selected\n"
+"   if this symbol is selected (y or m).\n"
+"o  The 'Selected by' line tells what symbol has selected this symbol.\n"
+"\n"
+"Only relevant lines are shown.\n"
+"\n\n"
+"Search examples:\n"
+"USB  => find all symbols containing USB\n"
+"^USB => find all symbols starting with USB\n"
+"USB$ => find all symbols ending with USB\n"
+"\n");
+
+struct mitem {
+	char str[256];
+	char tag;
+	void *usrptr;
+	int is_visible;
+};
+
+#define MAX_MENU_ITEMS 4096
+static int show_all_items;
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+/* the window in which all information appears */
+static WINDOW *main_window;
+/* the largest size of the menu window */
+static int mwin_max_lines;
+static int mwin_max_cols;
+/* the window in which we show option buttons */
+static MENU *curses_menu;
+static ITEM *curses_menu_items[MAX_MENU_ITEMS];
+static struct mitem k_menu_items[MAX_MENU_ITEMS];
+static int items_num;
+static int global_exit;
+/* the currently selected button */
+const char *current_instructions = menu_instructions;
+
+static char *dialog_input_result;
+static int dialog_input_result_len;
+
+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_help(struct menu *menu);
+static int do_exit(void);
+static void setup_windows(void);
+static void search_conf(void);
+
+typedef void (*function_key_handler_t)(int *key, struct menu *menu);
+static void handle_f1(int *key, struct menu *current_item);
+static void handle_f2(int *key, struct menu *current_item);
+static void handle_f3(int *key, struct menu *current_item);
+static void handle_f4(int *key, struct menu *current_item);
+static void handle_f5(int *key, struct menu *current_item);
+static void handle_f6(int *key, struct menu *current_item);
+static void handle_f7(int *key, struct menu *current_item);
+static void handle_f8(int *key, struct menu *current_item);
+static void handle_f9(int *key, struct menu *current_item);
+
+struct function_keys {
+	const char *key_str;
+	const char *func;
+	function_key key;
+	function_key_handler_t handler;
+};
+
+static const int function_keys_num = 9;
+struct function_keys function_keys[] = {
+	{
+		.key_str = "F1",
+		.func = "Help",
+		.key = F_HELP,
+		.handler = handle_f1,
+	},
+	{
+		.key_str = "F2",
+		.func = "SymInfo",
+		.key = F_SYMBOL,
+		.handler = handle_f2,
+	},
+	{
+		.key_str = "F3",
+		.func = "Help 2",
+		.key = F_INSTS,
+		.handler = handle_f3,
+	},
+	{
+		.key_str = "F4",
+		.func = "ShowAll",
+		.key = F_CONF,
+		.handler = handle_f4,
+	},
+	{
+		.key_str = "F5",
+		.func = "Back",
+		.key = F_BACK,
+		.handler = handle_f5,
+	},
+	{
+		.key_str = "F6",
+		.func = "Save",
+		.key = F_SAVE,
+		.handler = handle_f6,
+	},
+	{
+		.key_str = "F7",
+		.func = "Load",
+		.key = F_LOAD,
+		.handler = handle_f7,
+	},
+	{
+		.key_str = "F8",
+		.func = "SymSearch",
+		.key = F_SEARCH,
+		.handler = handle_f8,
+	},
+	{
+		.key_str = "F9",
+		.func = "Exit",
+		.key = F_EXIT,
+		.handler = handle_f9,
+	},
+};
+
+static void print_function_line(void)
+{
+	int i;
+	int offset = 1;
+	const int skip = 1;
+	int lines = getmaxy(stdscr);
+
+	for (i = 0; i < function_keys_num; i++) {
+		(void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+		mvwprintw(main_window, lines-3, offset,
+				"%s",
+				function_keys[i].key_str);
+		(void) wattrset(main_window, attributes[FUNCTION_TEXT]);
+		offset += strlen(function_keys[i].key_str);
+		mvwprintw(main_window, lines-3,
+				offset, "%s",
+				function_keys[i].func);
+		offset += strlen(function_keys[i].func) + skip;
+	}
+	(void) wattrset(main_window, attributes[NORMAL]);
+}
+
+/* help */
+static void handle_f1(int *key, struct menu *current_item)
+{
+	show_scroll_win(main_window,
+			_("Global help"), _(nconf_global_help));
+	return;
+}
+
+/* symbole help */
+static void handle_f2(int *key, struct menu *current_item)
+{
+	show_help(current_item);
+	return;
+}
+
+/* instructions */
+static void handle_f3(int *key, struct menu *current_item)
+{
+	show_scroll_win(main_window,
+			_("Short help"),
+			_(current_instructions));
+	return;
+}
+
+/* config */
+static void handle_f4(int *key, struct menu *current_item)
+{
+	int res = btn_dialog(main_window,
+			_("Show all symbols?"),
+			2,
+			"   <Show All>   ",
+			"<Don't show all>");
+	if (res == 0)
+		show_all_items = 1;
+	else if (res == 1)
+		show_all_items = 0;
+
+	return;
+}
+
+/* back */
+static void handle_f5(int *key, struct menu *current_item)
+{
+	*key = KEY_LEFT;
+	return;
+}
+
+/* save */
+static void handle_f6(int *key, struct menu *current_item)
+{
+	conf_save();
+	return;
+}
+
+/* load */
+static void handle_f7(int *key, struct menu *current_item)
+{
+	conf_load();
+	return;
+}
+
+/* search */
+static void handle_f8(int *key, struct menu *current_item)
+{
+	search_conf();
+	return;
+}
+
+/* exit */
+static void handle_f9(int *key, struct menu *current_item)
+{
+	do_exit();
+	return;
+}
+
+/* return != 0 to indicate the key was handles */
+static int process_special_keys(int *key, struct menu *menu)
+{
+	int i;
+
+	if (*key == KEY_RESIZE) {
+		setup_windows();
+		return 1;
+	}
+
+	for (i = 0; i < function_keys_num; i++) {
+		if (*key == KEY_F(function_keys[i].key) ||
+		    *key == '0' + function_keys[i].key){
+			function_keys[i].handler(key, menu);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static void clean_items(void)
+{
+	int i;
+	for (i = 0; curses_menu_items[i]; i++)
+		free_item(curses_menu_items[i]);
+	bzero(curses_menu_items, sizeof(curses_menu_items));
+	bzero(k_menu_items, sizeof(k_menu_items));
+	items_num = 0;
+}
+
+typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
+	FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
+
+/* return the index of the matched item, or -1 if no such item exists */
+static int get_mext_match(const char *match_str, match_f flag)
+{
+	int match_start = item_index(current_item(curses_menu));
+	int index;
+
+	if (flag == FIND_NEXT_MATCH_DOWN)
+		++match_start;
+	else if (flag == FIND_NEXT_MATCH_UP)
+		--match_start;
+
+	index = match_start;
+	index = (index + items_num) % items_num;
+	while (true) {
+		char *str = k_menu_items[index].str;
+		if (strcasestr(str, match_str) != 0)
+			return index;
+		if (flag == FIND_NEXT_MATCH_UP ||
+		    flag == MATCH_TINKER_PATTERN_UP)
+			--index;
+		else
+			++index;
+		index = (index + items_num) % items_num;
+		if (index == match_start)
+			return -1;
+	}
+}
+
+/* Make a new item. */
+static void item_make(struct menu *menu, char tag, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (items_num > MAX_MENU_ITEMS-1)
+		return;
+
+	bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
+	k_menu_items[items_num].tag = tag;
+	k_menu_items[items_num].usrptr = menu;
+	if (menu != NULL)
+		k_menu_items[items_num].is_visible =
+			menu_is_visible(menu);
+	else
+		k_menu_items[items_num].is_visible = 1;
+
+	va_start(ap, fmt);
+	vsnprintf(k_menu_items[items_num].str,
+		  sizeof(k_menu_items[items_num].str),
+		  fmt, ap);
+	va_end(ap);
+
+	if (!k_menu_items[items_num].is_visible)
+		memcpy(k_menu_items[items_num].str, "XXX", 3);
+
+	curses_menu_items[items_num] = new_item(
+			k_menu_items[items_num].str,
+			k_menu_items[items_num].str);
+	set_item_userptr(curses_menu_items[items_num],
+			&k_menu_items[items_num]);
+	/*
+	if (!k_menu_items[items_num].is_visible)
+		item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
+	*/
+
+	items_num++;
+	curses_menu_items[items_num] = NULL;
+}
+
+/* very hackish. adds a string to the last item added */
+static void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+	int index = items_num-1;
+	char new_str[256];
+	char tmp_str[256];
+
+	if (index < 0)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(new_str, sizeof(new_str), fmt, ap);
+	va_end(ap);
+	snprintf(tmp_str, sizeof(tmp_str), "%s%s",
+			k_menu_items[index].str, new_str);
+	strncpy(k_menu_items[index].str,
+		tmp_str,
+		sizeof(k_menu_items[index].str));
+
+	free_item(curses_menu_items[index]);
+	curses_menu_items[index] = new_item(
+			k_menu_items[index].str,
+			k_menu_items[index].str);
+	set_item_userptr(curses_menu_items[index],
+			&k_menu_items[index]);
+}
+
+/* get the tag of the currently selected item */
+static char item_tag(void)
+{
+	ITEM *cur;
+	struct mitem *mcur;
+
+	cur = current_item(curses_menu);
+	if (cur == NULL)
+		return 0;
+	mcur = (struct mitem *) item_userptr(cur);
+	return mcur->tag;
+}
+
+static int curses_item_index(void)
+{
+	return  item_index(current_item(curses_menu));
+}
+
+static void *item_data(void)
+{
+	ITEM *cur;
+	struct mitem *mcur;
+
+	cur = current_item(curses_menu);
+	if (!cur)
+		return NULL;
+	mcur = (struct mitem *) item_userptr(cur);
+	return mcur->usrptr;
+
+}
+
+static int item_is_tag(char tag)
+{
+	return item_tag() == tag;
+}
+
+static char filename[PATH_MAX+1];
+static char menu_backtitle[PATH_MAX+128];
+static const char *set_config_filename(const char *config_filename)
+{
+	int size;
+
+	size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+			"%s - %s", config_filename, rootmenu.prompt->text);
+	if (size >= sizeof(menu_backtitle))
+		menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+
+	size = snprintf(filename, sizeof(filename), "%s", config_filename);
+	if (size >= sizeof(filename))
+		filename[sizeof(filename)-1] = '\0';
+	return menu_backtitle;
+}
+
+/* return = 0 means we are successful.
+ * -1 means go on doing what you were doing
+ */
+static int do_exit(void)
+{
+	int res;
+	if (!conf_get_changed()) {
+		global_exit = 1;
+		return 0;
+	}
+	res = btn_dialog(main_window,
+			_("Do you wish to save your new configuration?\n"
+				"<ESC> to cancel and resume nconfig."),
+			2,
+			"   <save>   ",
+			"<don't save>");
+	if (res == KEY_EXIT) {
+		global_exit = 0;
+		return -1;
+	}
+
+	/* if we got here, the user really wants to exit */
+	switch (res) {
+	case 0:
+		res = conf_write(filename);
+		if (res)
+			btn_dialog(
+				main_window,
+				_("Error during writing of configuration.\n"
+				  "Your configuration changes were NOT saved."),
+				  1,
+				  "<OK>");
+		break;
+	default:
+		btn_dialog(
+			main_window,
+			_("Your configuration changes were NOT saved."),
+			1,
+			"<OK>");
+		break;
+	}
+	global_exit = 1;
+	return 0;
+}
+
+
+static void search_conf(void)
+{
+	struct symbol **sym_arr;
+	struct gstr res;
+	struct gstr title;
+	char *dialog_input;
+	int dres;
+
+	title = str_new();
+	str_printf( &title, _("Enter %s (sub)string or regexp to search for "
+			      "(with or without \"%s\")"), CONFIG_, CONFIG_);
+
+again:
+	dres = dialog_inputbox(main_window,
+			_("Search Configuration Parameter"),
+			str_get(&title),
+			"", &dialog_input_result, &dialog_input_result_len);
+	switch (dres) {
+	case 0:
+		break;
+	case 1:
+		show_scroll_win(main_window,
+				_("Search Configuration"), search_help);
+		goto again;
+	default:
+		str_free(&title);
+		return;
+	}
+
+	/* strip the prefix if necessary */
+	dialog_input = dialog_input_result;
+	if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
+		dialog_input += strlen(CONFIG_);
+
+	sym_arr = sym_re_search(dialog_input);
+	res = get_relations_str(sym_arr, NULL);
+	free(sym_arr);
+	show_scroll_win(main_window,
+			_("Search Results"), str_get(&res));
+	str_free(&res);
+	str_free(&title);
+}
+
+
+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 || (!show_all_items && !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);
+			enum prop_type ptype;
+			ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+			switch (ptype) {
+			case P_MENU:
+				child_count++;
+				prompt = _(prompt);
+				if (single_menu_mode) {
+					item_make(menu, 'm',
+						"%s%*c%s",
+						menu->data ? "-->" : "++>",
+						indent + 1, ' ', prompt);
+				} else
+					item_make(menu, 'm',
+						  "   %*c%s  %s",
+						  indent + 1, ' ', prompt,
+						  menu_is_empty(menu) ? "----" : "--->");
+
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
+				return;
+			case P_COMMENT:
+				if (prompt) {
+					child_count++;
+					item_make(menu, ':',
+						"   %*c*** %s ***",
+						indent + 1, ' ',
+						_(prompt));
+				}
+				break;
+			default:
+				if (prompt) {
+					child_count++;
+					item_make(menu, ':', "---%*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)) {
+			switch (type) {
+			case S_BOOLEAN:
+				item_make(menu, 't', "[%c]",
+						val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes:
+					ch = '*';
+					break;
+				case mod:
+					ch = 'M';
+					break;
+				default:
+					ch = ' ';
+					break;
+				}
+				item_make(menu, 't', "<%c>", ch);
+				break;
+			}
+		} else {
+			item_make(menu, def_menu ? 't' : ':', "   ");
+		}
+
+		item_add_str("%*c%s", indent + 1,
+				' ', _(menu_get_prompt(menu)));
+		if (val == yes) {
+			if (def_menu) {
+				item_add_str(" (%s)",
+					_(menu_get_prompt(def_menu)));
+				item_add_str("  --->");
+				if (def_menu->list) {
+					indent += 2;
+					build_conf(def_menu);
+					indent -= 2;
+				}
+			}
+			return;
+		}
+	} else {
+		if (menu == current_menu) {
+			item_make(menu, ':',
+				"---%*c%s", indent + 1,
+				' ', _(menu_get_prompt(menu)));
+			goto conf_childs;
+		}
+		child_count++;
+		val = sym_get_tristate_value(sym);
+		if (sym_is_choice_value(sym) && val == yes) {
+			item_make(menu, ':', "   ");
+		} else {
+			switch (type) {
+			case S_BOOLEAN:
+				if (sym_is_changable(sym))
+					item_make(menu, 't', "[%c]",
+						val == no ? ' ' : '*');
+				else
+					item_make(menu, 't', "-%c-",
+						val == no ? ' ' : '*');
+				break;
+			case S_TRISTATE:
+				switch (val) {
+				case yes:
+					ch = '*';
+					break;
+				case mod:
+					ch = 'M';
+					break;
+				default:
+					ch = ' ';
+					break;
+				}
+				if (sym_is_changable(sym)) {
+					if (sym->rev_dep.tri == mod)
+						item_make(menu,
+							't', "{%c}", ch);
+					else
+						item_make(menu,
+							't', "<%c>", ch);
+				} else
+					item_make(menu, 't', "-%c-", ch);
+				break;
+			default:
+				tmp = 2 + strlen(sym_get_string_value(sym));
+				item_make(menu, 's', "    (%s)",
+						sym_get_string_value(sym));
+				tmp = indent - tmp + 4;
+				if (tmp < 0)
+					tmp = 0;
+				item_add_str("%*c%s%s", tmp, ' ',
+						_(menu_get_prompt(menu)),
+						(sym_has_value(sym) ||
+						 !sym_is_changable(sym)) ? "" :
+						_(" (NEW)"));
+				goto conf_childs;
+			}
+		}
+		item_add_str("%*c%s%s", indent + 1, ' ',
+				_(menu_get_prompt(menu)),
+				(sym_has_value(sym) || !sym_is_changable(sym)) ?
+				"" : _(" (NEW)"));
+		if (menu->prompt && menu->prompt->type == P_MENU) {
+			item_add_str("  %s", menu_is_empty(menu) ? "----" : "--->");
+			return;
+		}
+	}
+
+conf_childs:
+	indent += doint;
+	for (child = menu->list; child; child = child->next)
+		build_conf(child);
+	indent -= doint;
+}
+
+static void reset_menu(void)
+{
+	unpost_menu(curses_menu);
+	clean_items();
+}
+
+/* adjust the menu to show this item.
+ * prefer not to scroll the menu if possible*/
+static void center_item(int selected_index, int *last_top_row)
+{
+	int toprow;
+
+	set_top_row(curses_menu, *last_top_row);
+	toprow = top_row(curses_menu);
+	if (selected_index < toprow ||
+	    selected_index >= toprow+mwin_max_lines) {
+		toprow = max(selected_index-mwin_max_lines/2, 0);
+		if (toprow >= item_count(curses_menu)-mwin_max_lines)
+			toprow = item_count(curses_menu)-mwin_max_lines;
+		set_top_row(curses_menu, toprow);
+	}
+	set_current_item(curses_menu,
+			curses_menu_items[selected_index]);
+	*last_top_row = toprow;
+	post_menu(curses_menu);
+	refresh_all_windows(main_window);
+}
+
+/* this function assumes reset_menu has been called before */
+static void show_menu(const char *prompt, const char *instructions,
+		int selected_index, int *last_top_row)
+{
+	int maxx, maxy;
+	WINDOW *menu_window;
+
+	current_instructions = instructions;
+
+	clear();
+	(void) wattrset(main_window, attributes[NORMAL]);
+	print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
+			menu_backtitle,
+			attributes[MAIN_HEADING]);
+
+	(void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
+	box(main_window, 0, 0);
+	(void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+	mvwprintw(main_window, 0, 3, " %s ", prompt);
+	(void) wattrset(main_window, attributes[NORMAL]);
+
+	set_menu_items(curses_menu, curses_menu_items);
+
+	/* position the menu at the middle of the screen */
+	scale_menu(curses_menu, &maxy, &maxx);
+	maxx = min(maxx, mwin_max_cols-2);
+	maxy = mwin_max_lines;
+	menu_window = derwin(main_window,
+			maxy,
+			maxx,
+			2,
+			(mwin_max_cols-maxx)/2);
+	keypad(menu_window, TRUE);
+	set_menu_win(curses_menu, menu_window);
+	set_menu_sub(curses_menu, menu_window);
+
+	/* must reassert this after changing items, otherwise returns to a
+	 * default of 16
+	 */
+	set_menu_format(curses_menu, maxy, 1);
+	center_item(selected_index, last_top_row);
+	set_menu_format(curses_menu, maxy, 1);
+
+	print_function_line();
+
+	/* Post the menu */
+	post_menu(curses_menu);
+	refresh_all_windows(main_window);
+}
+
+static void adj_match_dir(match_f *match_direction)
+{
+	if (*match_direction == FIND_NEXT_MATCH_DOWN)
+		*match_direction =
+			MATCH_TINKER_PATTERN_DOWN;
+	else if (*match_direction == FIND_NEXT_MATCH_UP)
+		*match_direction =
+			MATCH_TINKER_PATTERN_UP;
+	/* else, do no change.. */
+}
+
+struct match_state
+{
+	int in_search;
+	match_f match_direction;
+	char pattern[256];
+};
+
+/* Return 0 means I have handled the key. In such a case, ans should hold the
+ * item to center, or -1 otherwise.
+ * Else return -1 .
+ */
+static int do_match(int key, struct match_state *state, int *ans)
+{
+	char c = (char) key;
+	int terminate_search = 0;
+	*ans = -1;
+	if (key == '/' || (state->in_search && key == 27)) {
+		move(0, 0);
+		refresh();
+		clrtoeol();
+		state->in_search = 1-state->in_search;
+		bzero(state->pattern, sizeof(state->pattern));
+		state->match_direction = MATCH_TINKER_PATTERN_DOWN;
+		return 0;
+	} else if (!state->in_search)
+		return 1;
+
+	if (isalnum(c) || isgraph(c) || c == ' ') {
+		state->pattern[strlen(state->pattern)] = c;
+		state->pattern[strlen(state->pattern)] = '\0';
+		adj_match_dir(&state->match_direction);
+		*ans = get_mext_match(state->pattern,
+				state->match_direction);
+	} else if (key == KEY_DOWN) {
+		state->match_direction = FIND_NEXT_MATCH_DOWN;
+		*ans = get_mext_match(state->pattern,
+				state->match_direction);
+	} else if (key == KEY_UP) {
+		state->match_direction = FIND_NEXT_MATCH_UP;
+		*ans = get_mext_match(state->pattern,
+				state->match_direction);
+	} else if (key == KEY_BACKSPACE || key == 127) {
+		state->pattern[strlen(state->pattern)-1] = '\0';
+		adj_match_dir(&state->match_direction);
+	} else
+		terminate_search = 1;
+
+	if (terminate_search) {
+		state->in_search = 0;
+		bzero(state->pattern, sizeof(state->pattern));
+		move(0, 0);
+		refresh();
+		clrtoeol();
+		return -1;
+	}
+	return 0;
+}
+
+static void conf(struct menu *menu)
+{
+	struct menu *submenu = 0;
+	const char *prompt = menu_get_prompt(menu);
+	struct symbol *sym;
+	int res;
+	int current_index = 0;
+	int last_top_row = 0;
+	struct match_state match_state = {
+		.in_search = 0,
+		.match_direction = MATCH_TINKER_PATTERN_DOWN,
+		.pattern = "",
+	};
+
+	while (!global_exit) {
+		reset_menu();
+		current_menu = menu;
+		build_conf(menu);
+		if (!child_count)
+			break;
+
+		show_menu(prompt ? _(prompt) : _("Main Menu"),
+				_(menu_instructions),
+				current_index, &last_top_row);
+		keypad((menu_win(curses_menu)), TRUE);
+		while (!global_exit) {
+			if (match_state.in_search) {
+				mvprintw(0, 0,
+					"searching: %s", match_state.pattern);
+				clrtoeol();
+			}
+			refresh_all_windows(main_window);
+			res = wgetch(menu_win(curses_menu));
+			if (!res)
+				break;
+			if (do_match(res, &match_state, &current_index) == 0) {
+				if (current_index != -1)
+					center_item(current_index,
+						    &last_top_row);
+				continue;
+			}
+			if (process_special_keys(&res,
+						(struct menu *) item_data()))
+				break;
+			switch (res) {
+			case KEY_DOWN:
+				menu_driver(curses_menu, REQ_DOWN_ITEM);
+				break;
+			case KEY_UP:
+				menu_driver(curses_menu, REQ_UP_ITEM);
+				break;
+			case KEY_NPAGE:
+				menu_driver(curses_menu, REQ_SCR_DPAGE);
+				break;
+			case KEY_PPAGE:
+				menu_driver(curses_menu, REQ_SCR_UPAGE);
+				break;
+			case KEY_HOME:
+				menu_driver(curses_menu, REQ_FIRST_ITEM);
+				break;
+			case KEY_END:
+				menu_driver(curses_menu, REQ_LAST_ITEM);
+				break;
+			case 'h':
+			case '?':
+				show_help((struct menu *) item_data());
+				break;
+			}
+			if (res == 10 || res == 27 ||
+				res == 32 || res == 'n' || res == 'y' ||
+				res == KEY_LEFT || res == KEY_RIGHT ||
+				res == 'm')
+				break;
+			refresh_all_windows(main_window);
+		}
+
+		refresh_all_windows(main_window);
+		/* if ESC or left*/
+		if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
+			break;
+
+		/* remember location in the menu */
+		last_top_row = top_row(curses_menu);
+		current_index = curses_item_index();
+
+		if (!item_tag())
+			continue;
+
+		submenu = (struct menu *) item_data();
+		if (!submenu || !menu_is_visible(submenu))
+			continue;
+		sym = submenu->sym;
+
+		switch (res) {
+		case ' ':
+			if (item_is_tag('t'))
+				sym_toggle_tristate_value(sym);
+			else if (item_is_tag('m'))
+				conf(submenu);
+			break;
+		case KEY_RIGHT:
+		case 10: /* ENTER WAS PRESSED */
+			switch (item_tag()) {
+			case 'm':
+				if (single_menu_mode)
+					submenu->data =
+						(void *) (long) !submenu->data;
+				else
+					conf(submenu);
+				break;
+			case 't':
+				if (sym_is_choice(sym) &&
+				    sym_get_tristate_value(sym) == yes)
+					conf_choice(submenu);
+				else if (submenu->prompt &&
+					 submenu->prompt->type == P_MENU)
+					conf(submenu);
+				else if (res == 10)
+					sym_toggle_tristate_value(sym);
+				break;
+			case 's':
+				conf_string(submenu);
+				break;
+			}
+			break;
+		case 'y':
+			if (item_is_tag('t')) {
+				if (sym_set_tristate_value(sym, yes))
+					break;
+				if (sym_set_tristate_value(sym, mod))
+					btn_dialog(main_window, setmod_text, 0);
+			}
+			break;
+		case 'n':
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, no);
+			break;
+		case 'm':
+			if (item_is_tag('t'))
+				sym_set_tristate_value(sym, mod);
+			break;
+		}
+	}
+}
+
+static void conf_message_callback(const char *fmt, va_list ap)
+{
+	char buf[1024];
+
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	btn_dialog(main_window, buf, 1, "<OK>");
+}
+
+static void show_help(struct menu *menu)
+{
+	struct gstr help;
+
+	if (!menu)
+		return;
+
+	help = str_new();
+	menu_get_ext_help(menu, &help);
+	show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
+	str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+	const char *prompt = _(menu_get_prompt(menu));
+	struct menu *child = 0;
+	struct symbol *active;
+	int selected_index = 0;
+	int last_top_row = 0;
+	int res, i = 0;
+	struct match_state match_state = {
+		.in_search = 0,
+		.match_direction = MATCH_TINKER_PATTERN_DOWN,
+		.pattern = "",
+	};
+
+	active = sym_get_choice_value(menu->sym);
+	/* this is mostly duplicated from the conf() function. */
+	while (!global_exit) {
+		reset_menu();
+
+		for (i = 0, child = menu->list; child; child = child->next) {
+			if (!show_all_items && !menu_is_visible(child))
+				continue;
+
+			if (child->sym == sym_get_choice_value(menu->sym))
+				item_make(child, ':', "<X> %s",
+						_(menu_get_prompt(child)));
+			else if (child->sym)
+				item_make(child, ':', "    %s",
+						_(menu_get_prompt(child)));
+			else
+				item_make(child, ':', "*** %s ***",
+						_(menu_get_prompt(child)));
+
+			if (child->sym == active){
+				last_top_row = top_row(curses_menu);
+				selected_index = i;
+			}
+			i++;
+		}
+		show_menu(prompt ? _(prompt) : _("Choice Menu"),
+				_(radiolist_instructions),
+				selected_index,
+				&last_top_row);
+		while (!global_exit) {
+			if (match_state.in_search) {
+				mvprintw(0, 0, "searching: %s",
+					 match_state.pattern);
+				clrtoeol();
+			}
+			refresh_all_windows(main_window);
+			res = wgetch(menu_win(curses_menu));
+			if (!res)
+				break;
+			if (do_match(res, &match_state, &selected_index) == 0) {
+				if (selected_index != -1)
+					center_item(selected_index,
+						    &last_top_row);
+				continue;
+			}
+			if (process_special_keys(
+						&res,
+						(struct menu *) item_data()))
+				break;
+			switch (res) {
+			case KEY_DOWN:
+				menu_driver(curses_menu, REQ_DOWN_ITEM);
+				break;
+			case KEY_UP:
+				menu_driver(curses_menu, REQ_UP_ITEM);
+				break;
+			case KEY_NPAGE:
+				menu_driver(curses_menu, REQ_SCR_DPAGE);
+				break;
+			case KEY_PPAGE:
+				menu_driver(curses_menu, REQ_SCR_UPAGE);
+				break;
+			case KEY_HOME:
+				menu_driver(curses_menu, REQ_FIRST_ITEM);
+				break;
+			case KEY_END:
+				menu_driver(curses_menu, REQ_LAST_ITEM);
+				break;
+			case 'h':
+			case '?':
+				show_help((struct menu *) item_data());
+				break;
+			}
+			if (res == 10 || res == 27 || res == ' ' ||
+					res == KEY_LEFT){
+				break;
+			}
+			refresh_all_windows(main_window);
+		}
+		/* if ESC or left */
+		if (res == 27 || res == KEY_LEFT)
+			break;
+
+		child = item_data();
+		if (!child || !menu_is_visible(child) || !child->sym)
+			continue;
+		switch (res) {
+		case ' ':
+		case  10:
+		case KEY_RIGHT:
+			sym_set_tristate_value(child->sym, yes);
+			return;
+		case 'h':
+		case '?':
+			show_help(child);
+			active = child->sym;
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+static void conf_string(struct menu *menu)
+{
+	const char *prompt = menu_get_prompt(menu);
+
+	while (1) {
+		int res;
+		const char *heading;
+
+		switch (sym_get_type(menu->sym)) {
+		case S_INT:
+			heading = _(inputbox_instructions_int);
+			break;
+		case S_HEX:
+			heading = _(inputbox_instructions_hex);
+			break;
+		case S_STRING:
+			heading = _(inputbox_instructions_string);
+			break;
+		default:
+			heading = _("Internal nconf error!");
+		}
+		res = dialog_inputbox(main_window,
+				prompt ? _(prompt) : _("Main Menu"),
+				heading,
+				sym_get_string_value(menu->sym),
+				&dialog_input_result,
+				&dialog_input_result_len);
+		switch (res) {
+		case 0:
+			if (sym_set_string_value(menu->sym,
+						dialog_input_result))
+				return;
+			btn_dialog(main_window,
+				_("You have made an invalid entry."), 0);
+			break;
+		case 1:
+			show_help(menu);
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+static void conf_load(void)
+{
+	while (1) {
+		int res;
+		res = dialog_inputbox(main_window,
+				NULL, load_config_text,
+				filename,
+				&dialog_input_result,
+				&dialog_input_result_len);
+		switch (res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			if (!conf_read(dialog_input_result)) {
+				set_config_filename(dialog_input_result);
+				sym_set_change_count(1);
+				return;
+			}
+			btn_dialog(main_window, _("File does not exist!"), 0);
+			break;
+		case 1:
+			show_scroll_win(main_window,
+					_("Load Alternate Configuration"),
+					load_config_help);
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+static void conf_save(void)
+{
+	while (1) {
+		int res;
+		res = dialog_inputbox(main_window,
+				NULL, save_config_text,
+				filename,
+				&dialog_input_result,
+				&dialog_input_result_len);
+		switch (res) {
+		case 0:
+			if (!dialog_input_result[0])
+				return;
+			res = conf_write(dialog_input_result);
+			if (!res) {
+				set_config_filename(dialog_input_result);
+				return;
+			}
+			btn_dialog(main_window, _("Can't create file! "
+				"Probably a nonexistent directory."),
+				1, "<OK>");
+			break;
+		case 1:
+			show_scroll_win(main_window,
+				_("Save Alternate Configuration"),
+				save_config_help);
+			break;
+		case KEY_EXIT:
+			return;
+		}
+	}
+}
+
+void setup_windows(void)
+{
+	int lines, columns;
+
+	getmaxyx(stdscr, lines, columns);
+
+	if (main_window != NULL)
+		delwin(main_window);
+
+	/* set up the menu and menu window */
+	main_window = newwin(lines-2, columns-2, 2, 1);
+	keypad(main_window, TRUE);
+	mwin_max_lines = lines-7;
+	mwin_max_cols = columns-6;
+
+	/* panels order is from bottom to top */
+	new_panel(main_window);
+}
+
+int main(int ac, char **av)
+{
+	int lines, columns;
+	char *mode;
+
+	setlocale(LC_ALL, "");
+	bindtextdomain(PACKAGE, LOCALEDIR);
+	textdomain(PACKAGE);
+
+	conf_parse(av[1]);
+	conf_read(NULL);
+
+	mode = getenv("NCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
+
+	/* Initialize curses */
+	initscr();
+	/* set color theme */
+	set_colors();
+
+	cbreak();
+	noecho();
+	keypad(stdscr, TRUE);
+	curs_set(0);
+
+	getmaxyx(stdscr, lines, columns);
+	if (columns < 75 || lines < 20) {
+		endwin();
+		printf("Your terminal should have at "
+			"least 20 lines and 75 columns\n");
+		return 1;
+	}
+
+	notimeout(stdscr, FALSE);
+#if NCURSES_REENTRANT
+	set_escdelay(1);
+#else
+	ESCDELAY = 1;
+#endif
+
+	/* set btns menu */
+	curses_menu = new_menu(curses_menu_items);
+	menu_opts_off(curses_menu, O_SHOWDESC);
+	menu_opts_on(curses_menu, O_SHOWMATCH);
+	menu_opts_on(curses_menu, O_ONEVALUE);
+	menu_opts_on(curses_menu, O_NONCYCLIC);
+	menu_opts_on(curses_menu, O_IGNORECASE);
+	set_menu_mark(curses_menu, " ");
+	set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
+	set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
+	set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
+
+	set_config_filename(conf_get_configname());
+	setup_windows();
+
+	/* check for KEY_FUNC(1) */
+	if (has_key(KEY_F(1)) == FALSE) {
+		show_scroll_win(main_window,
+				_("Instructions"),
+				_(menu_no_f_instructions));
+	}
+
+	conf_set_message_callback(conf_message_callback);
+	/* do the work */
+	while (!global_exit) {
+		conf(&rootmenu);
+		if (!global_exit && do_exit() == 0)
+			break;
+	}
+	/* ok, we are done */
+	unpost_menu(curses_menu);
+	free_menu(curses_menu);
+	delwin(main_window);
+	clear();
+	refresh();
+	endwin();
+	return 0;
+}
+

+ 656 - 0
extra/config/nconf.gui.c

@@ -0,0 +1,656 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#include "nconf.h"
+
+/* a list of all the different widgets we use */
+attributes_t attributes[ATTR_MAX+1] = {0};
+
+/* available colors:
+   COLOR_BLACK   0
+   COLOR_RED     1
+   COLOR_GREEN   2
+   COLOR_YELLOW  3
+   COLOR_BLUE    4
+   COLOR_MAGENTA 5
+   COLOR_CYAN    6
+   COLOR_WHITE   7
+   */
+static void set_normal_colors(void)
+{
+	init_pair(NORMAL, -1, -1);
+	init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
+
+	/* FORE is for the selected item */
+	init_pair(MAIN_MENU_FORE, -1, -1);
+	/* BACK for all the rest */
+	init_pair(MAIN_MENU_BACK, -1, -1);
+	init_pair(MAIN_MENU_GREY, -1, -1);
+	init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
+	init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
+
+	init_pair(SCROLLWIN_TEXT, -1, -1);
+	init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
+	init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
+
+	init_pair(DIALOG_TEXT, -1, -1);
+	init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
+	init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
+	init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
+
+	init_pair(INPUT_BOX, COLOR_YELLOW, -1);
+	init_pair(INPUT_HEADING, COLOR_GREEN, -1);
+	init_pair(INPUT_TEXT, -1, -1);
+	init_pair(INPUT_FIELD, -1, -1);
+
+	init_pair(FUNCTION_HIGHLIGHT, -1, -1);
+	init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1);
+}
+
+/* available attributes:
+   A_NORMAL        Normal display (no highlight)
+   A_STANDOUT      Best highlighting mode of the terminal.
+   A_UNDERLINE     Underlining
+   A_REVERSE       Reverse video
+   A_BLINK         Blinking
+   A_DIM           Half bright
+   A_BOLD          Extra bright or bold
+   A_PROTECT       Protected mode
+   A_INVIS         Invisible or blank mode
+   A_ALTCHARSET    Alternate character set
+   A_CHARTEXT      Bit-mask to extract a character
+   COLOR_PAIR(n)   Color-pair number n
+   */
+static void normal_color_theme(void)
+{
+	/* automatically add color... */
+#define mkattr(name, attr) do { \
+attributes[name] = attr | COLOR_PAIR(name); } while (0)
+	mkattr(NORMAL, NORMAL);
+	mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+	mkattr(MAIN_MENU_FORE, A_REVERSE);
+	mkattr(MAIN_MENU_BACK, A_NORMAL);
+	mkattr(MAIN_MENU_GREY, A_NORMAL);
+	mkattr(MAIN_MENU_HEADING, A_BOLD);
+	mkattr(MAIN_MENU_BOX, A_NORMAL);
+
+	mkattr(SCROLLWIN_TEXT, A_NORMAL);
+	mkattr(SCROLLWIN_HEADING, A_BOLD);
+	mkattr(SCROLLWIN_BOX, A_BOLD);
+
+	mkattr(DIALOG_TEXT, A_BOLD);
+	mkattr(DIALOG_BOX, A_BOLD);
+	mkattr(DIALOG_MENU_FORE, A_STANDOUT);
+	mkattr(DIALOG_MENU_BACK, A_NORMAL);
+
+	mkattr(INPUT_BOX, A_NORMAL);
+	mkattr(INPUT_HEADING, A_BOLD);
+	mkattr(INPUT_TEXT, A_NORMAL);
+	mkattr(INPUT_FIELD, A_UNDERLINE);
+
+	mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
+	mkattr(FUNCTION_TEXT, A_REVERSE);
+}
+
+static void no_colors_theme(void)
+{
+	/* automatically add highlight, no color */
+#define mkattrn(name, attr) { attributes[name] = attr; }
+
+	mkattrn(NORMAL, NORMAL);
+	mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+	mkattrn(MAIN_MENU_FORE, A_STANDOUT);
+	mkattrn(MAIN_MENU_BACK, A_NORMAL);
+	mkattrn(MAIN_MENU_GREY, A_NORMAL);
+	mkattrn(MAIN_MENU_HEADING, A_BOLD);
+	mkattrn(MAIN_MENU_BOX, A_NORMAL);
+
+	mkattrn(SCROLLWIN_TEXT, A_NORMAL);
+	mkattrn(SCROLLWIN_HEADING, A_BOLD);
+	mkattrn(SCROLLWIN_BOX, A_BOLD);
+
+	mkattrn(DIALOG_TEXT, A_NORMAL);
+	mkattrn(DIALOG_BOX, A_BOLD);
+	mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
+	mkattrn(DIALOG_MENU_BACK, A_NORMAL);
+
+	mkattrn(INPUT_BOX, A_BOLD);
+	mkattrn(INPUT_HEADING, A_BOLD);
+	mkattrn(INPUT_TEXT, A_NORMAL);
+	mkattrn(INPUT_FIELD, A_UNDERLINE);
+
+	mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
+	mkattrn(FUNCTION_TEXT, A_REVERSE);
+}
+
+void set_colors()
+{
+	start_color();
+	use_default_colors();
+	set_normal_colors();
+	if (has_colors()) {
+		normal_color_theme();
+	} else {
+		/* give defaults */
+		no_colors_theme();
+	}
+}
+
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+		int starty,
+		int startx,
+		int width,
+		const char *string,
+		chtype color)
+{      int length, x, y;
+	float temp;
+
+
+	if (win == NULL)
+		win = stdscr;
+	getyx(win, y, x);
+	if (startx != 0)
+		x = startx;
+	if (starty != 0)
+		y = starty;
+	if (width == 0)
+		width = 80;
+
+	length = strlen(string);
+	temp = (width - length) / 2;
+	x = startx + (int)temp;
+	(void) wattrset(win, color);
+	mvwprintw(win, y, x, "%s", string);
+	refresh();
+}
+
+int get_line_no(const char *text)
+{
+	int i;
+	int total = 1;
+
+	if (!text)
+		return 0;
+
+	for (i = 0; text[i] != '\0'; i++)
+		if (text[i] == '\n')
+			total++;
+	return total;
+}
+
+const char *get_line(const char *text, int line_no)
+{
+	int i;
+	int lines = 0;
+
+	if (!text)
+		return 0;
+
+	for (i = 0; text[i] != '\0' && lines < line_no; i++)
+		if (text[i] == '\n')
+			lines++;
+	return text+i;
+}
+
+int get_line_length(const char *line)
+{
+	int res = 0;
+	while (*line != '\0' && *line != '\n') {
+		line++;
+		res++;
+	}
+	return res;
+}
+
+/* print all lines to the window. */
+void fill_window(WINDOW *win, const char *text)
+{
+	int x, y;
+	int total_lines = get_line_no(text);
+	int i;
+
+	getmaxyx(win, y, x);
+	/* do not go over end of line */
+	total_lines = min(total_lines, y);
+	for (i = 0; i < total_lines; i++) {
+		char tmp[x+10];
+		const char *line = get_line(text, i);
+		int len = get_line_length(line);
+		strncpy(tmp, line, min(len, x));
+		tmp[len] = '\0';
+		mvwprintw(win, i, 0, "%s", tmp);
+	}
+}
+
+/* get the message, and buttons.
+ * each button must be a char*
+ * return the selected button
+ *
+ * this dialog is used for 2 different things:
+ * 1) show a text box, no buttons.
+ * 2) show a dialog, with horizontal buttons
+ */
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
+{
+	va_list ap;
+	char *btn;
+	int btns_width = 0;
+	int msg_lines = 0;
+	int msg_width = 0;
+	int total_width;
+	int win_rows = 0;
+	WINDOW *win;
+	WINDOW *msg_win;
+	WINDOW *menu_win;
+	MENU *menu;
+	ITEM *btns[btn_num+1];
+	int i, x, y;
+	int res = -1;
+
+
+	va_start(ap, btn_num);
+	for (i = 0; i < btn_num; i++) {
+		btn = va_arg(ap, char *);
+		btns[i] = new_item(btn, "");
+		btns_width += strlen(btn)+1;
+	}
+	va_end(ap);
+	btns[btn_num] = NULL;
+
+	/* find the widest line of msg: */
+	msg_lines = get_line_no(msg);
+	for (i = 0; i < msg_lines; i++) {
+		const char *line = get_line(msg, i);
+		int len = get_line_length(line);
+		if (msg_width < len)
+			msg_width = len;
+	}
+
+	total_width = max(msg_width, btns_width);
+	/* place dialog in middle of screen */
+	y = (getmaxy(stdscr)-(msg_lines+4))/2;
+	x = (getmaxx(stdscr)-(total_width+4))/2;
+
+
+	/* create the windows */
+	if (btn_num > 0)
+		win_rows = msg_lines+4;
+	else
+		win_rows = msg_lines+2;
+
+	win = newwin(win_rows, total_width+4, y, x);
+	keypad(win, TRUE);
+	menu_win = derwin(win, 1, btns_width, win_rows-2,
+			1+(total_width+2-btns_width)/2);
+	menu = new_menu(btns);
+	msg_win = derwin(win, win_rows-2, msg_width, 1,
+			1+(total_width+2-msg_width)/2);
+
+	set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
+	set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
+
+	(void) wattrset(win, attributes[DIALOG_BOX]);
+	box(win, 0, 0);
+
+	/* print message */
+	(void) wattrset(msg_win, attributes[DIALOG_TEXT]);
+	fill_window(msg_win, msg);
+
+	set_menu_win(menu, win);
+	set_menu_sub(menu, menu_win);
+	set_menu_format(menu, 1, btn_num);
+	menu_opts_off(menu, O_SHOWDESC);
+	menu_opts_off(menu, O_SHOWMATCH);
+	menu_opts_on(menu, O_ONEVALUE);
+	menu_opts_on(menu, O_NONCYCLIC);
+	set_menu_mark(menu, "");
+	post_menu(menu);
+
+
+	touchwin(win);
+	refresh_all_windows(main_window);
+	while ((res = wgetch(win))) {
+		switch (res) {
+		case KEY_LEFT:
+			menu_driver(menu, REQ_LEFT_ITEM);
+			break;
+		case KEY_RIGHT:
+			menu_driver(menu, REQ_RIGHT_ITEM);
+			break;
+		case 10: /* ENTER */
+		case 27: /* ESCAPE */
+		case ' ':
+		case KEY_F(F_BACK):
+		case KEY_F(F_EXIT):
+			break;
+		}
+		touchwin(win);
+		refresh_all_windows(main_window);
+
+		if (res == 10 || res == ' ') {
+			res = item_index(current_item(menu));
+			break;
+		} else if (res == 27 || res == KEY_F(F_BACK) ||
+				res == KEY_F(F_EXIT)) {
+			res = KEY_EXIT;
+			break;
+		}
+	}
+
+	unpost_menu(menu);
+	free_menu(menu);
+	for (i = 0; i < btn_num; i++)
+		free_item(btns[i]);
+
+	delwin(win);
+	return res;
+}
+
+int dialog_inputbox(WINDOW *main_window,
+		const char *title, const char *prompt,
+		const char *init, char **resultp, int *result_len)
+{
+	int prompt_lines = 0;
+	int prompt_width = 0;
+	WINDOW *win;
+	WINDOW *prompt_win;
+	WINDOW *form_win;
+	PANEL *panel;
+	int i, x, y;
+	int res = -1;
+	int cursor_position = strlen(init);
+	int cursor_form_win;
+	char *result = *resultp;
+
+	if (strlen(init)+1 > *result_len) {
+		*result_len = strlen(init)+1;
+		*resultp = result = realloc(result, *result_len);
+	}
+
+	/* find the widest line of msg: */
+	prompt_lines = get_line_no(prompt);
+	for (i = 0; i < prompt_lines; i++) {
+		const char *line = get_line(prompt, i);
+		int len = get_line_length(line);
+		prompt_width = max(prompt_width, len);
+	}
+
+	if (title)
+		prompt_width = max(prompt_width, strlen(title));
+
+	/* place dialog in middle of screen */
+	y = (getmaxy(stdscr)-(prompt_lines+4))/2;
+	x = (getmaxx(stdscr)-(prompt_width+4))/2;
+
+	strncpy(result, init, *result_len);
+
+	/* create the windows */
+	win = newwin(prompt_lines+6, prompt_width+7, y, x);
+	prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
+	form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
+	keypad(form_win, TRUE);
+
+	(void) wattrset(form_win, attributes[INPUT_FIELD]);
+
+	(void) wattrset(win, attributes[INPUT_BOX]);
+	box(win, 0, 0);
+	(void) wattrset(win, attributes[INPUT_HEADING]);
+	if (title)
+		mvwprintw(win, 0, 3, "%s", title);
+
+	/* print message */
+	(void) wattrset(prompt_win, attributes[INPUT_TEXT]);
+	fill_window(prompt_win, prompt);
+
+	mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+	cursor_form_win = min(cursor_position, prompt_width-1);
+	mvwprintw(form_win, 0, 0, "%s",
+		  result + cursor_position-cursor_form_win);
+
+	/* create panels */
+	panel = new_panel(win);
+
+	/* show the cursor */
+	curs_set(1);
+
+	touchwin(win);
+	refresh_all_windows(main_window);
+	while ((res = wgetch(form_win))) {
+		int len = strlen(result);
+		switch (res) {
+		case 10: /* ENTER */
+		case 27: /* ESCAPE */
+		case KEY_F(F_HELP):
+		case KEY_F(F_EXIT):
+		case KEY_F(F_BACK):
+			break;
+		case 127:
+		case KEY_BACKSPACE:
+			if (cursor_position > 0) {
+				memmove(&result[cursor_position-1],
+						&result[cursor_position],
+						len-cursor_position+1);
+				cursor_position--;
+				cursor_form_win--;
+				len--;
+			}
+			break;
+		case KEY_DC:
+			if (cursor_position >= 0 && cursor_position < len) {
+				memmove(&result[cursor_position],
+						&result[cursor_position+1],
+						len-cursor_position+1);
+				len--;
+			}
+			break;
+		case KEY_UP:
+		case KEY_RIGHT:
+			if (cursor_position < len) {
+				cursor_position++;
+				cursor_form_win++;
+			}
+			break;
+		case KEY_DOWN:
+		case KEY_LEFT:
+			if (cursor_position > 0) {
+				cursor_position--;
+				cursor_form_win--;
+			}
+			break;
+		case KEY_HOME:
+			cursor_position = 0;
+			cursor_form_win = 0;
+			break;
+		case KEY_END:
+			cursor_position = len;
+			cursor_form_win = min(cursor_position, prompt_width-1);
+			break;
+		default:
+			if ((isgraph(res) || isspace(res))) {
+				/* one for new char, one for '\0' */
+				if (len+2 > *result_len) {
+					*result_len = len+2;
+					*resultp = result = realloc(result,
+								*result_len);
+				}
+				/* insert the char at the proper position */
+				memmove(&result[cursor_position+1],
+						&result[cursor_position],
+						len-cursor_position+1);
+				result[cursor_position] = res;
+				cursor_position++;
+				cursor_form_win++;
+				len++;
+			} else {
+				mvprintw(0, 0, "unknown key: %d\n", res);
+			}
+			break;
+		}
+		if (cursor_form_win < 0)
+			cursor_form_win = 0;
+		else if (cursor_form_win > prompt_width-1)
+			cursor_form_win = prompt_width-1;
+
+		wmove(form_win, 0, 0);
+		wclrtoeol(form_win);
+		mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+		mvwprintw(form_win, 0, 0, "%s",
+			result + cursor_position-cursor_form_win);
+		wmove(form_win, 0, cursor_form_win);
+		touchwin(win);
+		refresh_all_windows(main_window);
+
+		if (res == 10) {
+			res = 0;
+			break;
+		} else if (res == 27 || res == KEY_F(F_BACK) ||
+				res == KEY_F(F_EXIT)) {
+			res = KEY_EXIT;
+			break;
+		} else if (res == KEY_F(F_HELP)) {
+			res = 1;
+			break;
+		}
+	}
+
+	/* hide the cursor */
+	curs_set(0);
+	del_panel(panel);
+	delwin(prompt_win);
+	delwin(form_win);
+	delwin(win);
+	return res;
+}
+
+/* refresh all windows in the correct order */
+void refresh_all_windows(WINDOW *main_window)
+{
+	update_panels();
+	touchwin(main_window);
+	refresh();
+}
+
+/* layman's scrollable window... */
+void show_scroll_win(WINDOW *main_window,
+		const char *title,
+		const char *text)
+{
+	int res;
+	int total_lines = get_line_no(text);
+	int x, y, lines, columns;
+	int start_x = 0, start_y = 0;
+	int text_lines = 0, text_cols = 0;
+	int total_cols = 0;
+	int win_cols = 0;
+	int win_lines = 0;
+	int i = 0;
+	WINDOW *win;
+	WINDOW *pad;
+	PANEL *panel;
+
+	getmaxyx(stdscr, lines, columns);
+
+	/* find the widest line of msg: */
+	total_lines = get_line_no(text);
+	for (i = 0; i < total_lines; i++) {
+		const char *line = get_line(text, i);
+		int len = get_line_length(line);
+		total_cols = max(total_cols, len+2);
+	}
+
+	/* create the pad */
+	pad = newpad(total_lines+10, total_cols+10);
+	(void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
+	fill_window(pad, text);
+
+	win_lines = min(total_lines+4, lines-2);
+	win_cols = min(total_cols+2, columns-2);
+	text_lines = max(win_lines-4, 0);
+	text_cols = max(win_cols-2, 0);
+
+	/* place window in middle of screen */
+	y = (lines-win_lines)/2;
+	x = (columns-win_cols)/2;
+
+	win = newwin(win_lines, win_cols, y, x);
+	keypad(win, TRUE);
+	/* show the help in the help window, and show the help panel */
+	(void) wattrset(win, attributes[SCROLLWIN_BOX]);
+	box(win, 0, 0);
+	(void) wattrset(win, attributes[SCROLLWIN_HEADING]);
+	mvwprintw(win, 0, 3, " %s ", title);
+	panel = new_panel(win);
+
+	/* handle scrolling */
+	do {
+
+		copywin(pad, win, start_y, start_x, 2, 2, text_lines,
+				text_cols, 0);
+		print_in_middle(win,
+				text_lines+2,
+				0,
+				text_cols,
+				"<OK>",
+				attributes[DIALOG_MENU_FORE]);
+		wrefresh(win);
+
+		res = wgetch(win);
+		switch (res) {
+		case KEY_NPAGE:
+		case ' ':
+		case 'd':
+			start_y += text_lines-2;
+			break;
+		case KEY_PPAGE:
+		case 'u':
+			start_y -= text_lines+2;
+			break;
+		case KEY_HOME:
+			start_y = 0;
+			break;
+		case KEY_END:
+			start_y = total_lines-text_lines;
+			break;
+		case KEY_DOWN:
+		case 'j':
+			start_y++;
+			break;
+		case KEY_UP:
+		case 'k':
+			start_y--;
+			break;
+		case KEY_LEFT:
+		case 'h':
+			start_x--;
+			break;
+		case KEY_RIGHT:
+		case 'l':
+			start_x++;
+			break;
+		}
+		if (res == 10 || res == 27 || res == 'q' ||
+			res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
+			res == KEY_F(F_EXIT))
+			break;
+		if (start_y < 0)
+			start_y = 0;
+		if (start_y >= total_lines-text_lines)
+			start_y = total_lines-text_lines;
+		if (start_x < 0)
+			start_x = 0;
+		if (start_x >= total_cols-text_cols)
+			start_x = total_cols-text_cols;
+	} while (res);
+
+	del_panel(panel);
+	delwin(win);
+	refresh_all_windows(main_window);
+}

+ 96 - 0
extra/config/nconf.h

@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <curses.h>
+#include <menu.h>
+#include <panel.h>
+#include <form.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "ncurses.h"
+
+#define max(a, b) ({\
+		typeof(a) _a = a;\
+		typeof(b) _b = b;\
+		_a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+		typeof(a) _a = a;\
+		typeof(b) _b = b;\
+		_a < _b ? _a : _b; })
+
+typedef enum {
+	NORMAL = 1,
+	MAIN_HEADING,
+	MAIN_MENU_BOX,
+	MAIN_MENU_FORE,
+	MAIN_MENU_BACK,
+	MAIN_MENU_GREY,
+	MAIN_MENU_HEADING,
+	SCROLLWIN_TEXT,
+	SCROLLWIN_HEADING,
+	SCROLLWIN_BOX,
+	DIALOG_TEXT,
+	DIALOG_MENU_FORE,
+	DIALOG_MENU_BACK,
+	DIALOG_BOX,
+	INPUT_BOX,
+	INPUT_HEADING,
+	INPUT_TEXT,
+	INPUT_FIELD,
+	FUNCTION_TEXT,
+	FUNCTION_HIGHLIGHT,
+	ATTR_MAX
+} attributes_t;
+extern attributes_t attributes[];
+
+typedef enum {
+	F_HELP = 1,
+	F_SYMBOL = 2,
+	F_INSTS = 3,
+	F_CONF = 4,
+	F_BACK = 5,
+	F_SAVE = 6,
+	F_LOAD = 7,
+	F_SEARCH = 8,
+	F_EXIT = 9,
+} function_key;
+
+void set_colors(void);
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+		int starty,
+		int startx,
+		int width,
+		const char *string,
+		chtype color);
+int get_line_length(const char *line);
+int get_line_no(const char *text);
+const char *get_line(const char *text, int line_no);
+void fill_window(WINDOW *win, const char *text);
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
+int dialog_inputbox(WINDOW *main_window,
+		const char *title, const char *prompt,
+		const char *init, char **resultp, int *result_len);
+void refresh_all_windows(WINDOW *main_window);
+void show_scroll_win(WINDOW *main_window,
+		const char *title,
+		const char *text);

+ 185 - 154
extra/config/qconf.cc

@@ -3,24 +3,43 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
-#include <qapplication.h>
+#include <qglobal.h>
+
+#if QT_VERSION < 0x040000
+#include <stddef.h>
 #include <qmainwindow.h>
 #include <qmainwindow.h>
+#include <qvbox.h>
+#include <qvaluelist.h>
+#include <qtextbrowser.h>
+#include <qaction.h>
+#include <qheader.h>
+#include <qfiledialog.h>
+#include <qdragobject.h>
+#include <qpopupmenu.h>
+#else
+#include <q3mainwindow.h>
+#include <q3vbox.h>
+#include <q3valuelist.h>
+#include <q3textbrowser.h>
+#include <q3action.h>
+#include <q3header.h>
+#include <q3filedialog.h>
+#include <q3dragobject.h>
+#include <q3popupmenu.h>
+#endif
+
+#include <qapplication.h>
+#include <qdesktopwidget.h>
 #include <qtoolbar.h>
 #include <qtoolbar.h>
 #include <qlayout.h>
 #include <qlayout.h>
-#include <qvbox.h>
 #include <qsplitter.h>
 #include <qsplitter.h>
-#include <qlistview.h>
-#include <qtextbrowser.h>
 #include <qlineedit.h>
 #include <qlineedit.h>
 #include <qlabel.h>
 #include <qlabel.h>
 #include <qpushbutton.h>
 #include <qpushbutton.h>
 #include <qmenubar.h>
 #include <qmenubar.h>
 #include <qmessagebox.h>
 #include <qmessagebox.h>
-#include <qaction.h>
-#include <qheader.h>
-#include <qfiledialog.h>
-#include <qdragobject.h>
 #include <qregexp.h>
 #include <qregexp.h>
+#include <qevent.h>
 
 
 #include <stdlib.h>
 #include <stdlib.h>
 
 
@@ -38,7 +57,7 @@
 static QApplication *configApp;
 static QApplication *configApp;
 static ConfigSettings *configSettings;
 static ConfigSettings *configSettings;
 
 
-QAction *ConfigMainWindow::saveAction;
+Q3Action *ConfigMainWindow::saveAction;
 
 
 static inline QString qgettext(const char* str)
 static inline QString qgettext(const char* str)
 {
 {
@@ -53,15 +72,14 @@ static inline QString qgettext(const QString& str)
 /**
 /**
  * Reads a list of integer values from the application settings.
  * Reads a list of integer values from the application settings.
  */
  */
-QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
 {
 {
-	QValueList<int> result;
+	Q3ValueList<int> result;
 	QStringList entryList = readListEntry(key, ok);
 	QStringList entryList = readListEntry(key, ok);
-	if (ok) {
-		QStringList::Iterator it;
-		for (it = entryList.begin(); it != entryList.end(); ++it)
-			result.push_back((*it).toInt());
-	}
+	QStringList::Iterator it;
+
+	for (it = entryList.begin(); it != entryList.end(); ++it)
+		result.push_back((*it).toInt());
 
 
 	return result;
 	return result;
 }
 }
@@ -69,10 +87,10 @@ QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
 /**
 /**
  * Writes a list of integer values to the application settings.
  * Writes a list of integer values to the application settings.
  */
  */
-bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value)
+bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& value)
 {
 {
 	QStringList stringList;
 	QStringList stringList;
-	QValueList<int>::ConstIterator it;
+	Q3ValueList<int>::ConstIterator it;
 
 
 	for (it = value.begin(); it != value.end(); ++it)
 	for (it = value.begin(); it != value.end(); ++it)
 		stringList.push_back(QString::number(*it));
 		stringList.push_back(QString::number(*it));
@@ -80,7 +98,6 @@ bool ConfigSettings::writeSizes(const QString& key, const QValueList<int>& value
 }
 }
 
 
 
 
-#if QT_VERSION >= 300
 /*
 /*
  * set the new data
  * set the new data
  * TODO check the value
  * TODO check the value
@@ -91,7 +108,6 @@ void ConfigItem::okRename(int col)
 	sym_set_string_value(menu->sym, text(dataColIdx).latin1());
 	sym_set_string_value(menu->sym, text(dataColIdx).latin1());
 	listView()->updateList(this);
 	listView()->updateList(this);
 }
 }
-#endif
 
 
 /*
 /*
  * update the displayed of a menu entry
  * update the displayed of a menu entry
@@ -148,7 +164,7 @@ void ConfigItem::updateMenu(void)
 	case S_TRISTATE:
 	case S_TRISTATE:
 		char ch;
 		char ch;
 
 
-		if (!sym_is_changable(sym) && !list->showAll) {
+		if (!sym_is_changable(sym) && list->optMode == normalOpt) {
 			setPixmap(promptColIdx, 0);
 			setPixmap(promptColIdx, 0);
 			setText(noColIdx, QString::null);
 			setText(noColIdx, QString::null);
 			setText(modColIdx, QString::null);
 			setText(modColIdx, QString::null);
@@ -195,11 +211,9 @@ void ConfigItem::updateMenu(void)
 
 
 		data = sym_get_string_value(sym);
 		data = sym_get_string_value(sym);
 
 
-#if QT_VERSION >= 300
 		int i = list->mapIdx(dataColIdx);
 		int i = list->mapIdx(dataColIdx);
 		if (i >= 0)
 		if (i >= 0)
 			setRenameEnabled(i, TRUE);
 			setRenameEnabled(i, TRUE);
-#endif
 		setText(dataColIdx, data);
 		setText(dataColIdx, data);
 		if (type == S_STRING)
 		if (type == S_STRING)
 			prompt = QString("%1: %2").arg(prompt).arg(data);
 			prompt = QString("%1: %2").arg(prompt).arg(data);
@@ -297,10 +311,10 @@ void ConfigLineEdit::show(ConfigItem* i)
 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
 void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
 {
 {
 	switch (e->key()) {
 	switch (e->key()) {
-	case Key_Escape:
+	case Qt::Key_Escape:
 		break;
 		break;
-	case Key_Return:
-	case Key_Enter:
+	case Qt::Key_Return:
+	case Qt::Key_Enter:
 		sym_set_string_value(item->menu->sym, text().latin1());
 		sym_set_string_value(item->menu->sym, text().latin1());
 		parent()->updateList(item);
 		parent()->updateList(item);
 		break;
 		break;
@@ -319,7 +333,7 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
 	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
 	  symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
 	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
 	  choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
 	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
 	  menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
-	  showAll(false), showName(false), showRange(false), showData(false),
+	  showName(false), showRange(false), showData(false), optMode(normalOpt),
 	  rootEntry(0), headerPopup(0)
 	  rootEntry(0), headerPopup(0)
 {
 {
 	int i;
 	int i;
@@ -336,10 +350,10 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
 
 
 	if (name) {
 	if (name) {
 		configSettings->beginGroup(name);
 		configSettings->beginGroup(name);
-		showAll = configSettings->readBoolEntry("/showAll", false);
 		showName = configSettings->readBoolEntry("/showName", false);
 		showName = configSettings->readBoolEntry("/showName", false);
 		showRange = configSettings->readBoolEntry("/showRange", false);
 		showRange = configSettings->readBoolEntry("/showRange", false);
 		showData = configSettings->readBoolEntry("/showData", false);
 		showData = configSettings->readBoolEntry("/showData", false);
+		optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
 		configSettings->endGroup();
 		configSettings->endGroup();
 		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
 		connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
 	}
 	}
@@ -351,6 +365,17 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
 	reinit();
 	reinit();
 }
 }
 
 
+bool ConfigList::menuSkip(struct menu *menu)
+{
+	if (optMode == normalOpt && menu_is_visible(menu))
+		return false;
+	if (optMode == promptOpt && menu_has_prompt(menu))
+		return false;
+	if (optMode == allOpt)
+		return false;
+	return true;
+}
+
 void ConfigList::reinit(void)
 void ConfigList::reinit(void)
 {
 {
 	removeColumn(dataColIdx);
 	removeColumn(dataColIdx);
@@ -379,7 +404,7 @@ void ConfigList::saveSettings(void)
 		configSettings->writeEntry("/showName", showName);
 		configSettings->writeEntry("/showName", showName);
 		configSettings->writeEntry("/showRange", showRange);
 		configSettings->writeEntry("/showRange", showRange);
 		configSettings->writeEntry("/showData", showData);
 		configSettings->writeEntry("/showData", showData);
-		configSettings->writeEntry("/showAll", showAll);
+		configSettings->writeEntry("/optionMode", (int)optMode);
 		configSettings->endGroup();
 		configSettings->endGroup();
 	}
 	}
 }
 }
@@ -421,7 +446,7 @@ void ConfigList::updateList(ConfigItem* item)
 	if (!rootEntry) {
 	if (!rootEntry) {
 		if (mode != listMode)
 		if (mode != listMode)
 			goto update;
 			goto update;
-		QListViewItemIterator it(this);
+		Q3ListViewItemIterator it(this);
 		ConfigItem* item;
 		ConfigItem* item;
 
 
 		for (; it.current(); ++it) {
 		for (; it.current(); ++it) {
@@ -516,11 +541,9 @@ void ConfigList::changeValue(ConfigItem* item)
 	case S_INT:
 	case S_INT:
 	case S_HEX:
 	case S_HEX:
 	case S_STRING:
 	case S_STRING:
-#if QT_VERSION >= 300
 		if (colMap[dataColIdx] >= 0)
 		if (colMap[dataColIdx] >= 0)
 			item->startRename(colMap[dataColIdx]);
 			item->startRename(colMap[dataColIdx]);
 		else
 		else
-#endif
 			parent()->lineEdit->show(item);
 			parent()->lineEdit->show(item);
 		break;
 		break;
 	}
 	}
@@ -552,7 +575,7 @@ void ConfigList::setParentMenu(void)
 		return;
 		return;
 	setRootMenu(menu_get_parent_menu(rootEntry->parent));
 	setRootMenu(menu_get_parent_menu(rootEntry->parent));
 
 
-	QListViewItemIterator it(this);
+	Q3ListViewItemIterator it(this);
 	for (; (item = (ConfigItem*)it.current()); it++) {
 	for (; (item = (ConfigItem*)it.current()); it++) {
 		if (item->menu == oldroot) {
 		if (item->menu == oldroot) {
 			setCurrentItem(item);
 			setCurrentItem(item);
@@ -605,7 +628,7 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
 		}
 		}
 
 
 		visible = menu_is_visible(child);
 		visible = menu_is_visible(child);
-		if (showAll || visible) {
+		if (!menuSkip(child)) {
 			if (!child->sym && !child->list && !child->prompt)
 			if (!child->sym && !child->list && !child->prompt)
 				continue;
 				continue;
 			if (!item || item->menu != child)
 			if (!item || item->menu != child)
@@ -634,12 +657,12 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
 
 
 void ConfigList::keyPressEvent(QKeyEvent* ev)
 void ConfigList::keyPressEvent(QKeyEvent* ev)
 {
 {
-	QListViewItem* i = currentItem();
+	Q3ListViewItem* i = currentItem();
 	ConfigItem* item;
 	ConfigItem* item;
 	struct menu *menu;
 	struct menu *menu;
 	enum prop_type type;
 	enum prop_type type;
 
 
-	if (ev->key() == Key_Escape && mode != fullMode && mode != listMode) {
+	if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != listMode) {
 		emit parentSelected();
 		emit parentSelected();
 		ev->accept();
 		ev->accept();
 		return;
 		return;
@@ -652,8 +675,8 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
 	item = (ConfigItem*)i;
 	item = (ConfigItem*)i;
 
 
 	switch (ev->key()) {
 	switch (ev->key()) {
-	case Key_Return:
-	case Key_Enter:
+	case Qt::Key_Return:
+	case Qt::Key_Enter:
 		if (item->goParent) {
 		if (item->goParent) {
 			emit parentSelected();
 			emit parentSelected();
 			break;
 			break;
@@ -667,16 +690,16 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
 			emit menuSelected(menu);
 			emit menuSelected(menu);
 			break;
 			break;
 		}
 		}
-	case Key_Space:
+	case Qt::Key_Space:
 		changeValue(item);
 		changeValue(item);
 		break;
 		break;
-	case Key_N:
+	case Qt::Key_N:
 		setValue(item, no);
 		setValue(item, no);
 		break;
 		break;
-	case Key_M:
+	case Qt::Key_M:
 		setValue(item, mod);
 		setValue(item, mod);
 		break;
 		break;
-	case Key_Y:
+	case Qt::Key_Y:
 		setValue(item, yes);
 		setValue(item, yes);
 		break;
 		break;
 	default:
 	default:
@@ -800,10 +823,10 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
 {
 {
 	if (e->y() <= header()->geometry().bottom()) {
 	if (e->y() <= header()->geometry().bottom()) {
 		if (!headerPopup) {
 		if (!headerPopup) {
-			QAction *action;
+			Q3Action *action;
 
 
-			headerPopup = new QPopupMenu(this);
-			action = new QAction(NULL, _("Show Name"), 0, this);
+			headerPopup = new Q3PopupMenu(this);
+			action = new Q3Action(NULL, _("Show Name"), 0, this);
 			  action->setToggleAction(TRUE);
 			  action->setToggleAction(TRUE);
 			  connect(action, SIGNAL(toggled(bool)),
 			  connect(action, SIGNAL(toggled(bool)),
 				  parent(), SLOT(setShowName(bool)));
 				  parent(), SLOT(setShowName(bool)));
@@ -811,7 +834,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
 				  action, SLOT(setOn(bool)));
 				  action, SLOT(setOn(bool)));
 			  action->setOn(showName);
 			  action->setOn(showName);
 			  action->addTo(headerPopup);
 			  action->addTo(headerPopup);
-			action = new QAction(NULL, _("Show Range"), 0, this);
+			action = new Q3Action(NULL, _("Show Range"), 0, this);
 			  action->setToggleAction(TRUE);
 			  action->setToggleAction(TRUE);
 			  connect(action, SIGNAL(toggled(bool)),
 			  connect(action, SIGNAL(toggled(bool)),
 				  parent(), SLOT(setShowRange(bool)));
 				  parent(), SLOT(setShowRange(bool)));
@@ -819,7 +842,7 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
 				  action, SLOT(setOn(bool)));
 				  action, SLOT(setOn(bool)));
 			  action->setOn(showRange);
 			  action->setOn(showRange);
 			  action->addTo(headerPopup);
 			  action->addTo(headerPopup);
-			action = new QAction(NULL, _("Show Data"), 0, this);
+			action = new Q3Action(NULL, _("Show Data"), 0, this);
 			  action->setToggleAction(TRUE);
 			  action->setToggleAction(TRUE);
 			  connect(action, SIGNAL(toggled(bool)),
 			  connect(action, SIGNAL(toggled(bool)),
 				  parent(), SLOT(setShowData(bool)));
 				  parent(), SLOT(setShowData(bool)));
@@ -834,7 +857,10 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
 		e->ignore();
 		e->ignore();
 }
 }
 
 
-ConfigView* ConfigView::viewList;
+ConfigView*ConfigView::viewList;
+QAction *ConfigView::showNormalAction;
+QAction *ConfigView::showAllAction;
+QAction *ConfigView::showPromptAction;
 
 
 ConfigView::ConfigView(QWidget* parent, const char *name)
 ConfigView::ConfigView(QWidget* parent, const char *name)
 	: Parent(parent, name)
 	: Parent(parent, name)
@@ -859,13 +885,16 @@ ConfigView::~ConfigView(void)
 	}
 	}
 }
 }
 
 
-void ConfigView::setShowAll(bool b)
+void ConfigView::setOptionMode(QAction *act)
 {
 {
-	if (list->showAll != b) {
-		list->showAll = b;
-		list->updateListAll();
-		emit showAllChanged(b);
-	}
+	if (act == showNormalAction)
+		list->optMode = normalOpt;
+	else if (act == showAllAction)
+		list->optMode = allOpt;
+	else
+		list->optMode = promptOpt;
+
+	list->updateListAll();
 }
 }
 
 
 void ConfigView::setShowName(bool b)
 void ConfigView::setShowName(bool b)
@@ -897,7 +926,7 @@ void ConfigView::setShowData(bool b)
 
 
 void ConfigList::setAllOpen(bool open)
 void ConfigList::setAllOpen(bool open)
 {
 {
-	QListViewItemIterator it(this);
+	Q3ListViewItemIterator it(this);
 
 
 	for (; it.current(); it++)
 	for (; it.current(); it++)
 		it.current()->setOpen(open);
 		it.current()->setOpen(open);
@@ -920,7 +949,7 @@ void ConfigView::updateListAll(void)
 }
 }
 
 
 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
 ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
-	: Parent(parent, name), menu(0), sym(0)
+	: Parent(parent, name), sym(0), _menu(0)
 {
 {
 	if (name) {
 	if (name) {
 		configSettings->beginGroup(name);
 		configSettings->beginGroup(name);
@@ -943,7 +972,7 @@ void ConfigInfoView::setShowDebug(bool b)
 {
 {
 	if (_showDebug != b) {
 	if (_showDebug != b) {
 		_showDebug = b;
 		_showDebug = b;
-		if (menu)
+		if (_menu)
 			menuInfo();
 			menuInfo();
 		else if (sym)
 		else if (sym)
 			symbolInfo();
 			symbolInfo();
@@ -953,44 +982,16 @@ void ConfigInfoView::setShowDebug(bool b)
 
 
 void ConfigInfoView::setInfo(struct menu *m)
 void ConfigInfoView::setInfo(struct menu *m)
 {
 {
-	if (menu == m)
+	if (_menu == m)
 		return;
 		return;
-	menu = m;
+	_menu = m;
 	sym = NULL;
 	sym = NULL;
-	if (!menu)
+	if (!_menu)
 		clear();
 		clear();
 	else
 	else
 		menuInfo();
 		menuInfo();
 }
 }
 
 
-void ConfigInfoView::setSource(const QString& name)
-{
-	const char *p = name.latin1();
-
-	menu = NULL;
-	sym = NULL;
-
-	switch (p[0]) {
-	case 'm':
-		struct menu *m;
-
-		if (sscanf(p, "m%p", &m) == 1 && menu != m) {
-			menu = m;
-			menuInfo();
-			emit menuSelected(menu);
-		}
-		break;
-	case 's':
-		struct symbol *s;
-
-		if (sscanf(p, "s%p", &s) == 1 && sym != s) {
-			sym = s;
-			symbolInfo();
-		}
-		break;
-	}
-}
-
 void ConfigInfoView::symbolInfo(void)
 void ConfigInfoView::symbolInfo(void)
 {
 {
 	QString str;
 	QString str;
@@ -1012,11 +1013,11 @@ void ConfigInfoView::menuInfo(void)
 	struct symbol* sym;
 	struct symbol* sym;
 	QString head, debug, help;
 	QString head, debug, help;
 
 
-	sym = menu->sym;
+	sym = _menu->sym;
 	if (sym) {
 	if (sym) {
-		if (menu->prompt) {
+		if (_menu->prompt) {
 			head += "<big><b>";
 			head += "<big><b>";
-			head += print_filter(_(menu->prompt->text));
+			head += print_filter(_(_menu->prompt->text));
 			head += "</b></big>";
 			head += "</b></big>";
 			if (sym->name) {
 			if (sym->name) {
 				head += " (";
 				head += " (";
@@ -1041,26 +1042,24 @@ void ConfigInfoView::menuInfo(void)
 		if (showDebug())
 		if (showDebug())
 			debug = debug_info(sym);
 			debug = debug_info(sym);
 
 
-		help = menu_get_help(menu);
-		/* Gettextize if the help text not empty */
-		if (help.isEmpty())
-			help = print_filter(menu_get_help(menu));
-		else
-			help = print_filter(_(menu_get_help(menu)));
-	} else if (menu->prompt) {
+		struct gstr help_gstr = str_new();
+		menu_get_ext_help(_menu, &help_gstr);
+		help = print_filter(str_get(&help_gstr));
+		str_free(&help_gstr);
+	} else if (_menu->prompt) {
 		head += "<big><b>";
 		head += "<big><b>";
-		head += print_filter(_(menu->prompt->text));
+		head += print_filter(_(_menu->prompt->text));
 		head += "</b></big><br><br>";
 		head += "</b></big><br><br>";
 		if (showDebug()) {
 		if (showDebug()) {
-			if (menu->prompt->visible.expr) {
+			if (_menu->prompt->visible.expr) {
 				debug += "&nbsp;&nbsp;dep: ";
 				debug += "&nbsp;&nbsp;dep: ";
-				expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
+				expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE);
 				debug += "<br><br>";
 				debug += "<br><br>";
 			}
 			}
 		}
 		}
 	}
 	}
 	if (showDebug())
 	if (showDebug())
-		debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno);
+		debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno);
 
 
 	setText(head + debug + help);
 	setText(head + debug + help);
 }
 }
@@ -1163,10 +1162,10 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
 		*text += str2;
 		*text += str2;
 }
 }
 
 
-QPopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
 {
 {
-	QPopupMenu* popup = Parent::createPopupMenu(pos);
-	QAction* action = new QAction(NULL, _("Show Debug Info"), 0, popup);
+	Q3PopupMenu* popup = Parent::createPopupMenu(pos);
+	Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup);
 	  action->setToggleAction(TRUE);
 	  action->setToggleAction(TRUE);
 	  connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
 	  connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
 	  connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
 	  connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
@@ -1199,7 +1198,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam
 	layout1->addLayout(layout2);
 	layout1->addLayout(layout2);
 
 
 	split = new QSplitter(this);
 	split = new QSplitter(this);
-	split->setOrientation(QSplitter::Vertical);
+	split->setOrientation(Qt::Vertical);
 	list = new ConfigView(split, name);
 	list = new ConfigView(split, name);
 	list->list->mode = listMode;
 	list->list->mode = listMode;
 	info = new ConfigInfoView(split, name);
 	info = new ConfigInfoView(split, name);
@@ -1223,7 +1222,7 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam
 			y = configSettings->readNumEntry("/window y", 0, &ok);
 			y = configSettings->readNumEntry("/window y", 0, &ok);
 		if (ok)
 		if (ok)
 			move(x, y);
 			move(x, y);
-		QValueList<int> sizes = configSettings->readSizes("/split", &ok);
+		Q3ValueList<int> sizes = configSettings->readSizes("/split", &ok);
 		if (ok)
 		if (ok)
 			split->setSizes(sizes);
 			split->setSizes(sizes);
 		configSettings->endGroup();
 		configSettings->endGroup();
@@ -1275,9 +1274,15 @@ ConfigMainWindow::ConfigMainWindow(void)
 	int x, y, width, height;
 	int x, y, width, height;
 	char title[256];
 	char title[256];
 
 
-	QWidget *d = configApp->desktop();
-	snprintf(title, sizeof(title), _("uClibc v%s Configuration"),
-		getenv("VERSION"));
+	QDesktopWidget *d = configApp->desktop();
+	snprintf(title, sizeof(title), "%s%s",
+		rootmenu.prompt->text,
+#if QT_VERSION < 0x040000
+		" (Qt3)"
+#else
+		""
+#endif
+		);
 	setCaption(title);
 	setCaption(title);
 
 
 	width = configSettings->readNumEntry("/window width", d->width() - 64);
 	width = configSettings->readNumEntry("/window width", d->width() - 64);
@@ -1290,14 +1295,14 @@ ConfigMainWindow::ConfigMainWindow(void)
 		move(x, y);
 		move(x, y);
 
 
 	split1 = new QSplitter(this);
 	split1 = new QSplitter(this);
-	split1->setOrientation(QSplitter::Horizontal);
+	split1->setOrientation(Qt::Horizontal);
 	setCentralWidget(split1);
 	setCentralWidget(split1);
 
 
 	menuView = new ConfigView(split1, "menu");
 	menuView = new ConfigView(split1, "menu");
 	menuList = menuView->list;
 	menuList = menuView->list;
 
 
 	split2 = new QSplitter(split1);
 	split2 = new QSplitter(split1);
-	split2->setOrientation(QSplitter::Vertical);
+	split2->setOrientation(Qt::Vertical);
 
 
 	// create config tree
 	// create config tree
 	configView = new ConfigView(split2, "config");
 	configView = new ConfigView(split2, "config");
@@ -1310,60 +1315,79 @@ ConfigMainWindow::ConfigMainWindow(void)
 	configList->setFocus();
 	configList->setFocus();
 
 
 	menu = menuBar();
 	menu = menuBar();
-	toolBar = new QToolBar("Tools", this);
+	toolBar = new Q3ToolBar("Tools", this);
 
 
-	backAction = new QAction("Back", QPixmap(xpm_back), _("Back"), 0, this);
+	backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this);
 	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
 	  connect(backAction, SIGNAL(activated()), SLOT(goBack()));
 	  backAction->setEnabled(FALSE);
 	  backAction->setEnabled(FALSE);
-	QAction *quitAction = new QAction("Quit", _("&Quit"), CTRL+Key_Q, this);
+	Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
 	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
 	  connect(quitAction, SIGNAL(activated()), SLOT(close()));
-	QAction *loadAction = new QAction("Load", QPixmap(xpm_load), _("&Load"), CTRL+Key_L, this);
+	Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
 	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
 	  connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
-	saveAction = new QAction("Save", QPixmap(xpm_save), _("&Save"), CTRL+Key_S, this);
+	saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
 	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
 	  connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
 	conf_set_changed_callback(conf_changed);
 	conf_set_changed_callback(conf_changed);
 	// Set saveAction's initial state
 	// Set saveAction's initial state
 	conf_changed();
 	conf_changed();
-	QAction *saveAsAction = new QAction("Save As...", _("Save &As..."), 0, this);
+	Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this);
 	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
 	  connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
-	QAction *searchAction = new QAction("Find", _("&Find"), CTRL+Key_F, this);
+	Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
 	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
 	  connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
-	QAction *singleViewAction = new QAction("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
+	Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
 	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
 	  connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
-	QAction *splitViewAction = new QAction("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
+	Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
 	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
 	  connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
-	QAction *fullViewAction = new QAction("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
+	Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
 	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
 	  connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
 
 
-	QAction *showNameAction = new QAction(NULL, _("Show Name"), 0, this);
+	Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this);
 	  showNameAction->setToggleAction(TRUE);
 	  showNameAction->setToggleAction(TRUE);
 	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
 	  connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
 	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
 	  connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
 	  showNameAction->setOn(configView->showName());
 	  showNameAction->setOn(configView->showName());
-	QAction *showRangeAction = new QAction(NULL, _("Show Range"), 0, this);
+	Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this);
 	  showRangeAction->setToggleAction(TRUE);
 	  showRangeAction->setToggleAction(TRUE);
 	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
 	  connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
 	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
 	  connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
 	  showRangeAction->setOn(configList->showRange);
 	  showRangeAction->setOn(configList->showRange);
-	QAction *showDataAction = new QAction(NULL, _("Show Data"), 0, this);
+	Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this);
 	  showDataAction->setToggleAction(TRUE);
 	  showDataAction->setToggleAction(TRUE);
 	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
 	  connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
 	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
 	  connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
 	  showDataAction->setOn(configList->showData);
 	  showDataAction->setOn(configList->showData);
-	QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this);
-	  showAllAction->setToggleAction(TRUE);
-	  connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
-	  connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
-	  showAllAction->setOn(configList->showAll);
-	QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this);
+
+	QActionGroup *optGroup = new QActionGroup(this);
+	optGroup->setExclusive(TRUE);
+	connect(optGroup, SIGNAL(selected(QAction *)), configView,
+		SLOT(setOptionMode(QAction *)));
+	connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+		SLOT(setOptionMode(QAction *)));
+
+#if QT_VERSION >= 0x040000
+	configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
+	configView->showAllAction = new QAction(_("Show All Options"), optGroup);
+	configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
+#else
+	configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup);
+	configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup);
+	configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup);
+#endif
+	configView->showNormalAction->setToggleAction(TRUE);
+	configView->showNormalAction->setOn(configList->optMode == normalOpt);
+	configView->showAllAction->setToggleAction(TRUE);
+	configView->showAllAction->setOn(configList->optMode == allOpt);
+	configView->showPromptAction->setToggleAction(TRUE);
+	configView->showPromptAction->setOn(configList->optMode == promptOpt);
+
+	Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this);
 	  showDebugAction->setToggleAction(TRUE);
 	  showDebugAction->setToggleAction(TRUE);
 	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
 	  connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
 	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
 	  connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
 	  showDebugAction->setOn(helpText->showDebug());
 	  showDebugAction->setOn(helpText->showDebug());
 
 
-	QAction *showIntroAction = new QAction(NULL, _("Introduction"), 0, this);
+	Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this);
 	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
 	  connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
-	QAction *showAboutAction = new QAction(NULL, _("About"), 0, this);
+	Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this);
 	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
 	  connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
 
 
 	// init tool bar
 	// init tool bar
@@ -1377,7 +1401,7 @@ ConfigMainWindow::ConfigMainWindow(void)
 	fullViewAction->addTo(toolBar);
 	fullViewAction->addTo(toolBar);
 
 
 	// create config menu
 	// create config menu
-	QPopupMenu* config = new QPopupMenu(this);
+	Q3PopupMenu* config = new Q3PopupMenu(this);
 	menu->insertItem(_("&File"), config);
 	menu->insertItem(_("&File"), config);
 	loadAction->addTo(config);
 	loadAction->addTo(config);
 	saveAction->addTo(config);
 	saveAction->addTo(config);
@@ -1386,22 +1410,22 @@ ConfigMainWindow::ConfigMainWindow(void)
 	quitAction->addTo(config);
 	quitAction->addTo(config);
 
 
 	// create edit menu
 	// create edit menu
-	QPopupMenu* editMenu = new QPopupMenu(this);
+	Q3PopupMenu* editMenu = new Q3PopupMenu(this);
 	menu->insertItem(_("&Edit"), editMenu);
 	menu->insertItem(_("&Edit"), editMenu);
 	searchAction->addTo(editMenu);
 	searchAction->addTo(editMenu);
 
 
 	// create options menu
 	// create options menu
-	QPopupMenu* optionMenu = new QPopupMenu(this);
+	Q3PopupMenu* optionMenu = new Q3PopupMenu(this);
 	menu->insertItem(_("&Option"), optionMenu);
 	menu->insertItem(_("&Option"), optionMenu);
 	showNameAction->addTo(optionMenu);
 	showNameAction->addTo(optionMenu);
 	showRangeAction->addTo(optionMenu);
 	showRangeAction->addTo(optionMenu);
 	showDataAction->addTo(optionMenu);
 	showDataAction->addTo(optionMenu);
 	optionMenu->insertSeparator();
 	optionMenu->insertSeparator();
-	showAllAction->addTo(optionMenu);
-	showDebugAction->addTo(optionMenu);
+	optGroup->addTo(optionMenu);
+	optionMenu->insertSeparator();
 
 
 	// create help menu
 	// create help menu
-	QPopupMenu* helpMenu = new QPopupMenu(this);
+	Q3PopupMenu* helpMenu = new Q3PopupMenu(this);
 	menu->insertSeparator();
 	menu->insertSeparator();
 	menu->insertItem(_("&Help"), helpMenu);
 	menu->insertItem(_("&Help"), helpMenu);
 	showIntroAction->addTo(helpMenu);
 	showIntroAction->addTo(helpMenu);
@@ -1436,7 +1460,7 @@ ConfigMainWindow::ConfigMainWindow(void)
 		showSplitView();
 		showSplitView();
 
 
 	// UI setup done, restore splitter positions
 	// UI setup done, restore splitter positions
-	QValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+	Q3ValueList<int> sizes = configSettings->readSizes("/split1", &ok);
 	if (ok)
 	if (ok)
 		split1->setSizes(sizes);
 		split1->setSizes(sizes);
 
 
@@ -1447,7 +1471,7 @@ ConfigMainWindow::ConfigMainWindow(void)
 
 
 void ConfigMainWindow::loadConfig(void)
 void ConfigMainWindow::loadConfig(void)
 {
 {
-	QString s = QFileDialog::getOpenFileName(".config", NULL, this);
+	QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this);
 	if (s.isNull())
 	if (s.isNull())
 		return;
 		return;
 	if (conf_read(QFile::encodeName(s)))
 	if (conf_read(QFile::encodeName(s)))
@@ -1455,19 +1479,21 @@ void ConfigMainWindow::loadConfig(void)
 	ConfigView::updateListAll();
 	ConfigView::updateListAll();
 }
 }
 
 
-void ConfigMainWindow::saveConfig(void)
+bool ConfigMainWindow::saveConfig(void)
 {
 {
-	if (conf_write(NULL))
+	if (conf_write(NULL)) {
 		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
 		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+		return false;
+	}
+	return true;
 }
 }
 
 
 void ConfigMainWindow::saveConfigAs(void)
 void ConfigMainWindow::saveConfigAs(void)
 {
 {
-	QString s = QFileDialog::getSaveFileName(".config", NULL, this);
+	QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
 	if (s.isNull())
 	if (s.isNull())
 		return;
 		return;
-	if (conf_write(QFile::encodeName(s)))
-		QMessageBox::information(this, "qconf", _("Unable to save configuration!"));
+	saveConfig();
 }
 }
 
 
 void ConfigMainWindow::searchConfig(void)
 void ConfigMainWindow::searchConfig(void)
@@ -1492,7 +1518,7 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
 	ConfigList* list = NULL;
 	ConfigList* list = NULL;
 	ConfigItem* item;
 	ConfigItem* item;
 
 
-	if (!menu_is_visible(menu) && !configView->showAll())
+	if (configList->menuSkip(menu))
 		return;
 		return;
 
 
 	switch (configList->mode) {
 	switch (configList->mode) {
@@ -1524,6 +1550,8 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
 	case fullMode:
 	case fullMode:
 		list = configList;
 		list = configList;
 		break;
 		break;
+	default:
+		break;
 	}
 	}
 
 
 	if (list) {
 	if (list) {
@@ -1618,7 +1646,11 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
 	mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
 	mb.setButtonText(QMessageBox::Cancel, _("Cancel Exit"));
 	switch (mb.exec()) {
 	switch (mb.exec()) {
 	case QMessageBox::Yes:
 	case QMessageBox::Yes:
-		conf_write(NULL);
+		if (saveConfig())
+			e->accept();
+		else
+			e->ignore();
+		break;
 	case QMessageBox::No:
 	case QMessageBox::No:
 		e->accept();
 		e->accept();
 		break;
 		break;
@@ -1630,7 +1662,7 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
 
 
 void ConfigMainWindow::showIntro(void)
 void ConfigMainWindow::showIntro(void)
 {
 {
-	static const QString str = _("Welcome to the qconf graphical configuration tool for uClibc.\n\n"
+	static const QString str = _("Welcome to the qconf graphical configuration tool.\n\n"
 		"For each option, a blank box indicates the feature is disabled, a check\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"
 		"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"
 		"as a module.  Clicking on the box will cycle through the three states.\n\n"
@@ -1648,7 +1680,7 @@ void ConfigMainWindow::showIntro(void)
 void ConfigMainWindow::showAbout(void)
 void ConfigMainWindow::showAbout(void)
 {
 {
 	static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
 	static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
-		"Bug reports and feature request can also be entered at https://bugs.uClibc.org/\n");
+		"Bug reports and feature request can also be entered at http://bugs.uClibc.org/\n");
 
 
 	QMessageBox::information(this, "qconf", str);
 	QMessageBox::information(this, "qconf", str);
 }
 }
@@ -1673,6 +1705,9 @@ void ConfigMainWindow::saveSettings(void)
 	case fullMode :
 	case fullMode :
 		entry = "full";
 		entry = "full";
 		break;
 		break;
+
+	default:
+		break;
 	}
 	}
 	configSettings->writeEntry("/listMode", entry);
 	configSettings->writeEntry("/listMode", entry);
 
 
@@ -1718,10 +1753,6 @@ int main(int ac, char** av)
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	bindtextdomain(PACKAGE, LOCALEDIR);
 	textdomain(PACKAGE);
 	textdomain(PACKAGE);
 
 
-#ifndef LKC_DIRECT_LINK
-	kconfig_load();
-#endif
-
 	progname = av[0];
 	progname = av[0];
 	configApp = new QApplication(ac, av);
 	configApp = new QApplication(ac, av);
 	if (ac > 1 && av[1][0] == '-') {
 	if (ac > 1 && av[1][0] == '-') {

+ 49 - 46
extra/config/qconf.h

@@ -3,26 +3,25 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
+#if QT_VERSION < 0x040000
 #include <qlistview.h>
 #include <qlistview.h>
-#if QT_VERSION >= 300
-#include <qsettings.h>
 #else
 #else
-class QSettings {
-public:
-	void beginGroup(const QString& group) { }
-	void endGroup(void) { }
-	bool readBoolEntry(const QString& key, bool def = FALSE, bool* ok = 0) const
-	{ if (ok) *ok = FALSE; return def; }
-	int readNumEntry(const QString& key, int def = 0, bool* ok = 0) const
-	{ if (ok) *ok = FALSE; return def; }
-	QString readEntry(const QString& key, const QString& def = QString::null, bool* ok = 0) const
-	{ if (ok) *ok = FALSE; return def; }
-	QStringList readListEntry(const QString& key, bool* ok = 0) const
-	{ if (ok) *ok = FALSE; return QStringList(); }
-	template <class t>
-	bool writeEntry(const QString& key, t value)
-	{ return TRUE; }
-};
+#include <q3listview.h>
+#endif
+#include <qsettings.h>
+
+#if QT_VERSION < 0x040000
+#define Q3ValueList             QValueList
+#define Q3PopupMenu             QPopupMenu
+#define Q3ListView              QListView
+#define Q3ListViewItem          QListViewItem
+#define Q3VBox                  QVBox
+#define Q3TextBrowser           QTextBrowser
+#define Q3MainWindow            QMainWindow
+#define Q3Action                QAction
+#define Q3ToolBar               QToolBar
+#define Q3ListViewItemIterator  QListViewItemIterator
+#define Q3FileDialog            QFileDialog
 #endif
 #endif
 
 
 class ConfigView;
 class ConfigView;
@@ -31,11 +30,10 @@ class ConfigItem;
 class ConfigLineEdit;
 class ConfigLineEdit;
 class ConfigMainWindow;
 class ConfigMainWindow;
 
 
-
 class ConfigSettings : public QSettings {
 class ConfigSettings : public QSettings {
 public:
 public:
-	QValueList<int> readSizes(const QString& key, bool *ok);
-	bool writeSizes(const QString& key, const QValueList<int>& value);
+	Q3ValueList<int> readSizes(const QString& key, bool *ok);
+	bool writeSizes(const QString& key, const Q3ValueList<int>& value);
 };
 };
 
 
 enum colIdx {
 enum colIdx {
@@ -44,10 +42,13 @@ enum colIdx {
 enum listMode {
 enum listMode {
 	singleMode, menuMode, symbolMode, fullMode, listMode
 	singleMode, menuMode, symbolMode, fullMode, listMode
 };
 };
+enum optionMode {
+	normalOpt = 0, allOpt, promptOpt
+};
 
 
-class ConfigList : public QListView {
+class ConfigList : public Q3ListView {
 	Q_OBJECT
 	Q_OBJECT
-	typedef class QListView Parent;
+	typedef class Q3ListView Parent;
 public:
 public:
 	ConfigList(ConfigView* p, const char *name = 0);
 	ConfigList(ConfigView* p, const char *name = 0);
 	void reinit(void);
 	void reinit(void);
@@ -115,6 +116,8 @@ public:
 	void setAllOpen(bool open);
 	void setAllOpen(bool open);
 	void setParentMenu(void);
 	void setParentMenu(void);
 
 
+	bool menuSkip(struct menu *);
+
 	template <class P>
 	template <class P>
 	void updateMenuList(P*, struct menu*);
 	void updateMenuList(P*, struct menu*);
 
 
@@ -124,22 +127,23 @@ public:
 	QPixmap choiceYesPix, choiceNoPix;
 	QPixmap choiceYesPix, choiceNoPix;
 	QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
 	QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
 
 
-	bool showAll, showName, showRange, showData;
+	bool showName, showRange, showData;
 	enum listMode mode;
 	enum listMode mode;
+	enum optionMode optMode;
 	struct menu *rootEntry;
 	struct menu *rootEntry;
 	QColorGroup disabledColorGroup;
 	QColorGroup disabledColorGroup;
 	QColorGroup inactivedColorGroup;
 	QColorGroup inactivedColorGroup;
-	QPopupMenu* headerPopup;
+	Q3PopupMenu* headerPopup;
 
 
 private:
 private:
 	int colMap[colNr];
 	int colMap[colNr];
 	int colRevMap[colNr];
 	int colRevMap[colNr];
 };
 };
 
 
-class ConfigItem : public QListViewItem {
-	typedef class QListViewItem Parent;
+class ConfigItem : public Q3ListViewItem {
+	typedef class Q3ListViewItem Parent;
 public:
 public:
-	ConfigItem(QListView *parent, ConfigItem *after, struct menu *m, bool v)
+	ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
 	: Parent(parent, after), menu(m), visible(v), goParent(false)
 	: Parent(parent, after), menu(m), visible(v), goParent(false)
 	{
 	{
 		init();
 		init();
@@ -149,16 +153,14 @@ public:
 	{
 	{
 		init();
 		init();
 	}
 	}
-	ConfigItem(QListView *parent, ConfigItem *after, bool v)
+	ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
 	: Parent(parent, after), menu(0), visible(v), goParent(true)
 	: Parent(parent, after), menu(0), visible(v), goParent(true)
 	{
 	{
 		init();
 		init();
 	}
 	}
 	~ConfigItem(void);
 	~ConfigItem(void);
 	void init(void);
 	void init(void);
-#if QT_VERSION >= 300
 	void okRename(int col);
 	void okRename(int col);
-#endif
 	void updateMenu(void);
 	void updateMenu(void);
 	void testUpdateMenu(bool v);
 	void testUpdateMenu(bool v);
 	ConfigList* listView() const
 	ConfigList* listView() const
@@ -213,26 +215,24 @@ public:
 	ConfigItem *item;
 	ConfigItem *item;
 };
 };
 
 
-class ConfigView : public QVBox {
+class ConfigView : public Q3VBox {
 	Q_OBJECT
 	Q_OBJECT
-	typedef class QVBox Parent;
+	typedef class Q3VBox Parent;
 public:
 public:
 	ConfigView(QWidget* parent, const char *name = 0);
 	ConfigView(QWidget* parent, const char *name = 0);
 	~ConfigView(void);
 	~ConfigView(void);
 	static void updateList(ConfigItem* item);
 	static void updateList(ConfigItem* item);
 	static void updateListAll(void);
 	static void updateListAll(void);
 
 
-	bool showAll(void) const { return list->showAll; }
 	bool showName(void) const { return list->showName; }
 	bool showName(void) const { return list->showName; }
 	bool showRange(void) const { return list->showRange; }
 	bool showRange(void) const { return list->showRange; }
 	bool showData(void) const { return list->showData; }
 	bool showData(void) const { return list->showData; }
 public slots:
 public slots:
-	void setShowAll(bool);
 	void setShowName(bool);
 	void setShowName(bool);
 	void setShowRange(bool);
 	void setShowRange(bool);
 	void setShowData(bool);
 	void setShowData(bool);
+	void setOptionMode(QAction *);
 signals:
 signals:
-	void showAllChanged(bool);
 	void showNameChanged(bool);
 	void showNameChanged(bool);
 	void showRangeChanged(bool);
 	void showRangeChanged(bool);
 	void showDataChanged(bool);
 	void showDataChanged(bool);
@@ -242,11 +242,15 @@ public:
 
 
 	static ConfigView* viewList;
 	static ConfigView* viewList;
 	ConfigView* nextView;
 	ConfigView* nextView;
+
+	static QAction *showNormalAction;
+	static QAction *showAllAction;
+	static QAction *showPromptAction;
 };
 };
 
 
-class ConfigInfoView : public QTextBrowser {
+class ConfigInfoView : public Q3TextBrowser {
 	Q_OBJECT
 	Q_OBJECT
-	typedef class QTextBrowser Parent;
+	typedef class Q3TextBrowser Parent;
 public:
 public:
 	ConfigInfoView(QWidget* parent, const char *name = 0);
 	ConfigInfoView(QWidget* parent, const char *name = 0);
 	bool showDebug(void) const { return _showDebug; }
 	bool showDebug(void) const { return _showDebug; }
@@ -254,7 +258,6 @@ public:
 public slots:
 public slots:
 	void setInfo(struct menu *menu);
 	void setInfo(struct menu *menu);
 	void saveSettings(void);
 	void saveSettings(void);
-	void setSource(const QString& name);
 	void setShowDebug(bool);
 	void setShowDebug(bool);
 
 
 signals:
 signals:
@@ -267,11 +270,11 @@ protected:
 	QString debug_info(struct symbol *sym);
 	QString debug_info(struct symbol *sym);
 	static QString print_filter(const QString &str);
 	static QString print_filter(const QString &str);
 	static void expr_print_help(void *data, struct symbol *sym, const char *str);
 	static void expr_print_help(void *data, struct symbol *sym, const char *str);
-	QPopupMenu* createPopupMenu(const QPoint& pos);
+	Q3PopupMenu* createPopupMenu(const QPoint& pos);
 	void contentsContextMenuEvent(QContextMenuEvent *e);
 	void contentsContextMenuEvent(QContextMenuEvent *e);
 
 
 	struct symbol *sym;
 	struct symbol *sym;
-	struct menu *menu;
+	struct menu *_menu;
 	bool _showDebug;
 	bool _showDebug;
 };
 };
 
 
@@ -295,10 +298,10 @@ protected:
 	struct symbol **result;
 	struct symbol **result;
 };
 };
 
 
-class ConfigMainWindow : public QMainWindow {
+class ConfigMainWindow : public Q3MainWindow {
 	Q_OBJECT
 	Q_OBJECT
 
 
-	static QAction *saveAction;
+	static Q3Action *saveAction;
 	static void conf_changed(void);
 	static void conf_changed(void);
 public:
 public:
 	ConfigMainWindow(void);
 	ConfigMainWindow(void);
@@ -308,7 +311,7 @@ public slots:
 	void listFocusChanged(void);
 	void listFocusChanged(void);
 	void goBack(void);
 	void goBack(void);
 	void loadConfig(void);
 	void loadConfig(void);
-	void saveConfig(void);
+	bool saveConfig(void);
 	void saveConfigAs(void);
 	void saveConfigAs(void);
 	void searchConfig(void);
 	void searchConfig(void);
 	void showSingleView(void);
 	void showSingleView(void);
@@ -327,8 +330,8 @@ protected:
 	ConfigView *configView;
 	ConfigView *configView;
 	ConfigList *configList;
 	ConfigList *configList;
 	ConfigInfoView *helpText;
 	ConfigInfoView *helpText;
-	QToolBar *toolBar;
-	QAction *backAction;
+	Q3ToolBar *toolBar;
+	Q3Action *backAction;
 	QSplitter* split1;
 	QSplitter* split1;
 	QSplitter* split2;
 	QSplitter* split2;
 };
 };

+ 640 - 0
extra/config/streamline_config.pl

@@ -0,0 +1,640 @@
+#!/usr/bin/perl -w
+#
+# Copyright 2005-2009 - Steven Rostedt
+# Licensed under the terms of the GNU GPL License version 2
+#
+#  It's simple enough to figure out how this works.
+#  If not, then you can ask me at stripconfig@goodmis.org
+#
+# What it does?
+#
+#   If you have installed a Linux kernel from a distribution
+#   that turns on way too many modules than you need, and
+#   you only want the modules you use, then this program
+#   is perfect for you.
+#
+#   It gives you the ability to turn off all the modules that are
+#   not loaded on your system.
+#
+# Howto:
+#
+#  1. Boot up the kernel that you want to stream line the config on.
+#  2. Change directory to the directory holding the source of the
+#       kernel that you just booted.
+#  3. Copy the configuraton file to this directory as .config
+#  4. Have all your devices that you need modules for connected and
+#      operational (make sure that their corresponding modules are loaded)
+#  5. Run this script redirecting the output to some other file
+#       like config_strip.
+#  6. Back up your old config (if you want too).
+#  7. copy the config_strip file to .config
+#  8. Run "make oldconfig"
+#
+#  Now your kernel is ready to be built with only the modules that
+#  are loaded.
+#
+# Here's what I did with my Debian distribution.
+#
+#    cd /usr/src/linux-2.6.10
+#    cp /boot/config-2.6.10-1-686-smp .config
+#    ~/bin/streamline_config > config_strip
+#    mv .config config_sav
+#    mv config_strip .config
+#    make oldconfig
+#
+use strict;
+use Getopt::Long;
+
+# set the environment variable LOCALMODCONFIG_DEBUG to get
+# debug output.
+my $debugprint = 0;
+$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
+
+sub dprint {
+    return if (!$debugprint);
+    print STDERR @_;
+}
+
+my $config = ".config";
+
+my $uname = `uname -r`;
+chomp $uname;
+
+my @searchconfigs = (
+	{
+	    "file" => ".config",
+	    "exec" => "cat",
+	},
+	{
+	    "file" => "/proc/config.gz",
+	    "exec" => "zcat",
+	},
+	{
+	    "file" => "/boot/config-$uname",
+	    "exec" => "cat",
+	},
+	{
+	    "file" => "/boot/vmlinuz-$uname",
+	    "exec" => "scripts/extract-ikconfig",
+	    "test" => "scripts/extract-ikconfig",
+	},
+	{
+	    "file" => "vmlinux",
+	    "exec" => "scripts/extract-ikconfig",
+	    "test" => "scripts/extract-ikconfig",
+	},
+	{
+	    "file" => "/lib/modules/$uname/kernel/kernel/configs.ko",
+	    "exec" => "scripts/extract-ikconfig",
+	    "test" => "scripts/extract-ikconfig",
+	},
+	{
+	    "file" => "kernel/configs.ko",
+	    "exec" => "scripts/extract-ikconfig",
+	    "test" => "scripts/extract-ikconfig",
+	},
+	{
+	    "file" => "kernel/configs.o",
+	    "exec" => "scripts/extract-ikconfig",
+	    "test" => "scripts/extract-ikconfig",
+	},
+);
+
+sub read_config {
+    foreach my $conf (@searchconfigs) {
+	my $file = $conf->{"file"};
+
+	next if ( ! -f "$file");
+
+	if (defined($conf->{"test"})) {
+	    `$conf->{"test"} $conf->{"file"} 2>/dev/null`;
+	    next if ($?);
+	}
+
+	my $exec = $conf->{"exec"};
+
+	print STDERR "using config: '$file'\n";
+
+	open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
+	my @x = <$infile>;
+	close $infile;
+	return @x;
+    }
+    die "No config file found";
+}
+
+my @config_file = read_config;
+
+# Parse options
+my $localmodconfig = 0;
+my $localyesconfig = 0;
+
+GetOptions("localmodconfig" => \$localmodconfig,
+	   "localyesconfig" => \$localyesconfig);
+
+# Get the build source and top level Kconfig file (passed in)
+my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
+my $kconfig = $ARGV[1];
+my $lsmod_file = $ENV{'LSMOD'};
+
+my @makefiles = `find $ksource -name Makefile 2>/dev/null`;
+chomp @makefiles;
+
+my %depends;
+my %selects;
+my %prompts;
+my %objects;
+my $var;
+my $iflevel = 0;
+my @ifdeps;
+
+# prevent recursion
+my %read_kconfigs;
+
+sub read_kconfig {
+    my ($kconfig) = @_;
+
+    my $state = "NONE";
+    my $config;
+
+    my $cont = 0;
+    my $line;
+
+    my $source = "$ksource/$kconfig";
+    my $last_source = "";
+
+    # Check for any environment variables used
+    while ($source =~ /\$(\w+)/ && $last_source ne $source) {
+	my $env = $1;
+	$last_source = $source;
+	$source =~ s/\$$env/$ENV{$env}/;
+    }
+
+    open(my $kinfile, '<', $source) || die "Can't open $kconfig";
+    while (<$kinfile>) {
+	chomp;
+
+	# Make sure that lines ending with \ continue
+	if ($cont) {
+	    $_ = $line . " " . $_;
+	}
+
+	if (s/\\$//) {
+	    $cont = 1;
+	    $line = $_;
+	    next;
+	}
+
+	$cont = 0;
+
+	# collect any Kconfig sources
+	if (/^source\s*"(.*)"/) {
+	    my $kconfig = $1;
+	    # prevent reading twice.
+	    if (!defined($read_kconfigs{$kconfig})) {
+		$read_kconfigs{$kconfig} = 1;
+		read_kconfig($kconfig);
+	    }
+	    next;
+	}
+
+	# configs found
+	if (/^\s*(menu)?config\s+(\S+)\s*$/) {
+	    $state = "NEW";
+	    $config = $2;
+
+	    # Add depends for 'if' nesting
+	    for (my $i = 0; $i < $iflevel; $i++) {
+		if ($i) {
+		    $depends{$config} .= " " . $ifdeps[$i];
+		} else {
+		    $depends{$config} = $ifdeps[$i];
+		}
+		$state = "DEP";
+	    }
+
+	# collect the depends for the config
+	} elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
+	    $state = "DEP";
+	    $depends{$config} = $1;
+	} elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
+	    $depends{$config} .= " " . $1;
+
+	# Get the configs that select this config
+	} elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
+	    my $conf = $1;
+	    if (defined($selects{$conf})) {
+		$selects{$conf} .= " " . $config;
+	    } else {
+		$selects{$conf} = $config;
+	    }
+
+	# configs without prompts must be selected
+	} elsif ($state ne "NONE" && /^\s*tristate\s\S/) {
+	    # note if the config has a prompt
+	    $prompts{$config} = 1;
+
+	# Check for if statements
+	} elsif (/^if\s+(.*\S)\s*$/) {
+	    my $deps = $1;
+	    # remove beginning and ending non text
+	    $deps =~ s/^[^a-zA-Z0-9_]*//;
+	    $deps =~ s/[^a-zA-Z0-9_]*$//;
+
+	    my @deps = split /[^a-zA-Z0-9_]+/, $deps;
+
+	    $ifdeps[$iflevel++] = join ':', @deps;
+
+	} elsif (/^endif/) {
+
+	    $iflevel-- if ($iflevel);
+
+	# stop on "help"
+	} elsif (/^\s*help\s*$/) {
+	    $state = "NONE";
+	}
+    }
+    close($kinfile);
+}
+
+if ($kconfig) {
+    read_kconfig($kconfig);
+}
+
+# Makefiles can use variables to define their dependencies
+sub convert_vars {
+    my ($line, %vars) = @_;
+
+    my $process = "";
+
+    while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
+	my $start = $1;
+	my $variable = $2;
+	my $var = $3;
+
+	if (defined($vars{$var})) {
+	    $process .= $start . $vars{$var};
+	} else {
+	    $process .= $start . $variable;
+	}
+    }
+
+    $process .= $line;
+
+    return $process;
+}
+
+# Read all Makefiles to map the configs to the objects
+foreach my $makefile (@makefiles) {
+
+    my $line = "";
+    my %make_vars;
+
+    open(my $infile, '<', $makefile) || die "Can't open $makefile";
+    while (<$infile>) {
+	# if this line ends with a backslash, continue
+	chomp;
+	if (/^(.*)\\$/) {
+	    $line .= $1;
+	    next;
+	}
+
+	$line .= $_;
+	$_ = $line;
+	$line = "";
+
+	my $objs;
+
+	# Convert variables in a line (could define configs)
+	$_ = convert_vars($_, %make_vars);
+
+	# collect objects after obj-$(CONFIG_FOO_BAR)
+	if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
+	    $var = $1;
+	    $objs = $2;
+
+	# check if variables are set
+	} elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
+	    $make_vars{$1} = $2;
+	}
+	if (defined($objs)) {
+	    foreach my $obj (split /\s+/,$objs) {
+		$obj =~ s/-/_/g;
+		if ($obj =~ /(.*)\.o$/) {
+		    # Objects may be enabled by more than one config.
+		    # Store configs in an array.
+		    my @arr;
+
+		    if (defined($objects{$1})) {
+			@arr = @{$objects{$1}};
+		    }
+
+		    $arr[$#arr+1] = $var;
+
+		    # The objects have a hash mapping to a reference
+		    # of an array of configs.
+		    $objects{$1} = \@arr;
+		}
+	    }
+	}
+    }
+    close($infile);
+}
+
+my %modules;
+my $linfile;
+
+if (defined($lsmod_file)) {
+    if ( ! -f $lsmod_file) {
+	if ( -f $ENV{'objtree'}."/".$lsmod_file) {
+	    $lsmod_file = $ENV{'objtree'}."/".$lsmod_file;
+	} else {
+		die "$lsmod_file not found";
+	}
+    }
+
+    my $otype = ( -x $lsmod_file) ? '-|' : '<';
+    open($linfile, $otype, $lsmod_file);
+
+} else {
+
+    # see what modules are loaded on this system
+    my $lsmod;
+
+    foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
+	if ( -x "$dir/lsmod" ) {
+	    $lsmod = "$dir/lsmod";
+	    last;
+	}
+}
+    if (!defined($lsmod)) {
+	# try just the path
+	$lsmod = "lsmod";
+    }
+
+    open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
+}
+
+while (<$linfile>) {
+	next if (/^Module/);  # Skip the first line.
+	if (/^(\S+)/) {
+		$modules{$1} = 1;
+	}
+}
+close ($linfile);
+
+# add to the configs hash all configs that are needed to enable
+# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
+# where we know we need bar.o so we add FOO to the list.
+my %configs;
+foreach my $module (keys(%modules)) {
+    if (defined($objects{$module})) {
+	my @arr = @{$objects{$module}};
+	foreach my $conf (@arr) {
+	    $configs{$conf} = $module;
+	    dprint "$conf added by direct ($module)\n";
+	    if ($debugprint) {
+		my $c=$conf;
+		$c =~ s/^CONFIG_//;
+		if (defined($depends{$c})) {
+		    dprint " deps = $depends{$c}\n";
+		} else {
+		    dprint " no deps\n";
+		}
+	    }
+	}
+    } else {
+	# Most likely, someone has a custom (binary?) module loaded.
+	print STDERR "$module config not found!!\n";
+    }
+}
+
+# Read the current config, and see what is enabled. We want to
+# ignore configs that we would not enable anyway.
+
+my %orig_configs;
+my $valid = "A-Za-z_0-9";
+
+foreach my $line (@config_file) {
+    $_ = $line;
+
+    if (/(CONFIG_[$valid]*)=(m|y)/) {
+	$orig_configs{$1} = $2;
+    }
+}
+
+my $repeat = 1;
+
+my $depconfig;
+
+#
+# Note, we do not care about operands (like: &&, ||, !) we want to add any
+# config that is in the depend list of another config. This script does
+# not enable configs that are not already enabled. If we come across a
+# config A that depends on !B, we can still add B to the list of depends
+# to keep on. If A was on in the original config, B would not have been
+# and B would not be turned on by this script.
+#
+sub parse_config_depends
+{
+    my ($p) = @_;
+
+    while ($p =~ /[$valid]/) {
+
+	if ($p =~ /^[^$valid]*([$valid]+)/) {
+	    my $conf = "CONFIG_" . $1;
+
+	    $p =~ s/^[^$valid]*[$valid]+//;
+
+	    # We only need to process if the depend config is a module
+	    if (!defined($orig_configs{$conf}) || !$orig_configs{conf} eq "m") {
+		next;
+	    }
+
+	    if (!defined($configs{$conf})) {
+		# We must make sure that this config has its
+		# dependencies met.
+		$repeat = 1; # do again
+		dprint "$conf selected by depend $depconfig\n";
+		$configs{$conf} = 1;
+	    }
+	} else {
+	    die "this should never happen";
+	}
+    }
+}
+
+# Select is treated a bit differently than depends. We call this
+# when a config has no prompt and requires another config to be
+# selected. We use to just select all configs that selected this
+# config, but found that that can balloon into enabling hundreds
+# of configs that we do not care about.
+#
+# The idea is we look at all the configs that select it. If one
+# is already in our list of configs to enable, then there's nothing
+# else to do. If there isn't, we pick the first config that was
+# enabled in the orignal config and use that.
+sub parse_config_selects
+{
+    my ($config, $p) = @_;
+
+    my $next_config;
+
+    while ($p =~ /[$valid]/) {
+
+	if ($p =~ /^[^$valid]*([$valid]+)/) {
+	    my $conf = "CONFIG_" . $1;
+
+	    $p =~ s/^[^$valid]*[$valid]+//;
+
+	    # Make sure that this config exists in the current .config file
+	    if (!defined($orig_configs{$conf})) {
+		dprint "$conf not set for $config select\n";
+		next;
+	    }
+
+	    # Check if something other than a module selects this config
+	    if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
+		dprint "$conf (non module) selects config, we are good\n";
+		# we are good with this
+		return;
+	    }
+	    if (defined($configs{$conf})) {
+		dprint "$conf selects $config so we are good\n";
+		# A set config selects this config, we are good
+		return;
+	    }
+	    # Set this config to be selected
+	    if (!defined($next_config)) {
+		$next_config = $conf;
+	    }
+	} else {
+	    die "this should never happen";
+	}
+    }
+
+    # If no possible config selected this, then something happened.
+    if (!defined($next_config)) {
+	print STDERR "WARNING: $config is required, but nothing in the\n";
+	print STDERR "  current config selects it.\n";
+	return;
+    }
+
+    # If we are here, then we found no config that is set and
+    # selects this config. Repeat.
+    $repeat = 1;
+    # Make this config need to be selected
+    $configs{$next_config} = 1;
+    dprint "$next_config selected by select $config\n";
+}
+
+my %process_selects;
+
+# loop through all configs, select their dependencies.
+sub loop_depend {
+    $repeat = 1;
+
+    while ($repeat) {
+	$repeat = 0;
+
+      forloop:
+	foreach my $config (keys %configs) {
+
+	    # If this config is not a module, we do not need to process it
+	    if (defined($orig_configs{$config}) && $orig_configs{$config} ne "m") {
+		next forloop;
+	    }
+
+	    $config =~ s/^CONFIG_//;
+	    $depconfig = $config;
+
+	    if (defined($depends{$config})) {
+		# This config has dependencies. Make sure they are also included
+		parse_config_depends $depends{$config};
+	    }
+
+	    # If the config has no prompt, then we need to check if a config
+	    # that is enabled selected it. Or if we need to enable one.
+	    if (!defined($prompts{$config}) && defined($selects{$config})) {
+		$process_selects{$config} = 1;
+	    }
+	}
+    }
+}
+
+sub loop_select {
+
+    foreach my $config (keys %process_selects) {
+	$config =~ s/^CONFIG_//;
+
+	dprint "Process select $config\n";
+
+	# config has no prompt and must be selected.
+	parse_config_selects $config, $selects{$config};
+    }
+}
+
+while ($repeat) {
+    # Get the first set of configs and their dependencies.
+    loop_depend;
+
+    $repeat = 0;
+
+    # Now we need to see if we have to check selects;
+    loop_select;
+}	    
+
+my %setconfigs;
+
+# Finally, read the .config file and turn off any module enabled that
+# we could not find a reason to keep enabled.
+foreach my $line (@config_file) {
+    $_ = $line;
+
+    if (/CONFIG_IKCONFIG/) {
+	if (/# CONFIG_IKCONFIG is not set/) {
+	    # enable IKCONFIG at least as a module
+	    print "CONFIG_IKCONFIG=m\n";
+	    # don't ask about PROC
+	    print "# CONFIG_IKCONFIG_PROC is not set\n";
+	} else {
+	    print;
+	}
+	next;
+    }
+
+    if (/^(CONFIG.*)=(m|y)/) {
+	if (defined($configs{$1})) {
+	    if ($localyesconfig) {
+	        $setconfigs{$1} = 'y';
+		print "$1=y\n";
+		next;
+	    } else {
+	        $setconfigs{$1} = $2;
+	    }
+	} elsif ($2 eq "m") {
+	    print "# $1 is not set\n";
+	    next;
+	}
+    }
+    print;
+}
+
+# Integrity check, make sure all modules that we want enabled do
+# indeed have their configs set.
+loop:
+foreach my $module (keys(%modules)) {
+    if (defined($objects{$module})) {
+	my @arr = @{$objects{$module}};
+	foreach my $conf (@arr) {
+	    if (defined($setconfigs{$conf})) {
+		next loop;
+	    }
+	}
+	print STDERR "module $module did not have configs";
+	foreach my $conf (@arr) {
+	    print STDERR " " , $conf;
+	}
+	print STDERR "\n";
+    }
+}

+ 483 - 75
extra/config/symbol.c

@@ -7,8 +7,8 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include <regex.h>
 #include <regex.h>
+#include <sys/utsname.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 struct symbol symbol_yes = {
 struct symbol symbol_yes = {
@@ -35,7 +35,7 @@ tristate modules_val;
 
 
 struct expr *sym_env_list;
 struct expr *sym_env_list;
 
 
-void sym_add_default(struct symbol *sym, const char *def)
+static void sym_add_default(struct symbol *sym, const char *def)
 {
 {
 	struct property *prop = prop_alloc(P_DEFAULT, sym);
 	struct property *prop = prop_alloc(P_DEFAULT, sym);
 
 
@@ -45,20 +45,19 @@ void sym_add_default(struct symbol *sym, const char *def)
 void sym_init(void)
 void sym_init(void)
 {
 {
 	struct symbol *sym;
 	struct symbol *sym;
-	char *p;
+	struct utsname uts;
 	static bool inited = false;
 	static bool inited = false;
 
 
 	if (inited)
 	if (inited)
 		return;
 		return;
 	inited = true;
 	inited = true;
 
 
-	p = getenv("VERSION");
-	if (p) {
-		sym = sym_lookup("VERSION", 0);
-		sym->type = S_STRING;
-		sym->flags |= SYMBOL_AUTO;
-		sym_add_default(sym, p);
-	}
+	uname(&uts);
+
+	sym = sym_lookup("UNAME_RELEASE", 0);
+	sym->type = S_STRING;
+	sym->flags |= SYMBOL_AUTO;
+	sym_add_default(sym, uts.release);
 }
 }
 
 
 enum symbol_type sym_get_type(struct symbol *sym)
 enum symbol_type sym_get_type(struct symbol *sym)
@@ -125,7 +124,7 @@ struct property *sym_get_default_prop(struct symbol *sym)
 	return NULL;
 	return NULL;
 }
 }
 
 
-struct property *sym_get_range_prop(struct symbol *sym)
+static struct property *sym_get_range_prop(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
 
 
@@ -137,7 +136,7 @@ struct property *sym_get_range_prop(struct symbol *sym)
 	return NULL;
 	return NULL;
 }
 }
 
 
-static int sym_get_range_val(struct symbol *sym, int base)
+static long sym_get_range_val(struct symbol *sym, int base)
 {
 {
 	sym_calc_value(sym);
 	sym_calc_value(sym);
 	switch (sym->type) {
 	switch (sym->type) {
@@ -156,7 +155,7 @@ static int sym_get_range_val(struct symbol *sym, int base)
 static void sym_validate_range(struct symbol *sym)
 static void sym_validate_range(struct symbol *sym)
 {
 {
 	struct property *prop;
 	struct property *prop;
-	int base, val, val2;
+	long base, val, val2;
 	char str[64];
 	char str[64];
 
 
 	switch (sym->type) {
 	switch (sym->type) {
@@ -180,9 +179,9 @@ static void sym_validate_range(struct symbol *sym)
 			return;
 			return;
 	}
 	}
 	if (sym->type == S_INT)
 	if (sym->type == S_INT)
-		sprintf(str, "%d", val2);
+		sprintf(str, "%ld", val2);
 	else
 	else
-		sprintf(str, "0x%x", val2);
+		sprintf(str, "0x%lx", val2);
 	sym->curr.val = strdup(str);
 	sym->curr.val = strdup(str);
 }
 }
 
 
@@ -205,6 +204,16 @@ static void sym_calc_visibility(struct symbol *sym)
 	}
 	}
 	if (sym_is_choice_value(sym))
 	if (sym_is_choice_value(sym))
 		return;
 		return;
+	/* defaulting to "yes" if no explicit "depends on" are given */
+	tri = yes;
+	if (sym->dir_dep.expr)
+		tri = expr_calc_value(sym->dir_dep.expr);
+	if (tri == mod)
+		tri = yes;
+	if (sym->dir_dep.tri != tri) {
+		sym->dir_dep.tri = tri;
+		sym_set_changed(sym);
+	}
 	tri = no;
 	tri = no;
 	if (sym->rev_dep.expr)
 	if (sym->rev_dep.expr)
 		tri = expr_calc_value(sym->rev_dep.expr);
 		tri = expr_calc_value(sym->rev_dep.expr);
@@ -216,42 +225,68 @@ static void sym_calc_visibility(struct symbol *sym)
 	}
 	}
 }
 }
 
 
-static struct symbol *sym_calc_choice(struct symbol *sym)
+/*
+ * Find the default symbol for a choice.
+ * First try the default values for the choice symbol
+ * Next locate the first visible choice value
+ * Return NULL if none was found
+ */
+struct symbol *sym_choice_default(struct symbol *sym)
 {
 {
 	struct symbol *def_sym;
 	struct symbol *def_sym;
 	struct property *prop;
 	struct property *prop;
 	struct expr *e;
 	struct expr *e;
 
 
-	/* is the user choice visible? */
-	def_sym = sym->def[S_DEF_USER].val;
-	if (def_sym) {
-		sym_calc_visibility(def_sym);
-		if (def_sym->visible != no)
-			return def_sym;
-	}
-
 	/* any of the defaults visible? */
 	/* any of the defaults visible? */
 	for_all_defaults(sym, prop) {
 	for_all_defaults(sym, prop) {
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
 		prop->visible.tri = expr_calc_value(prop->visible.expr);
 		if (prop->visible.tri == no)
 		if (prop->visible.tri == no)
 			continue;
 			continue;
 		def_sym = prop_get_symbol(prop);
 		def_sym = prop_get_symbol(prop);
-		sym_calc_visibility(def_sym);
 		if (def_sym->visible != no)
 		if (def_sym->visible != no)
 			return def_sym;
 			return def_sym;
 	}
 	}
 
 
 	/* just get the first visible value */
 	/* just get the first visible value */
 	prop = sym_get_choice_prop(sym);
 	prop = sym_get_choice_prop(sym);
+	expr_list_for_each_sym(prop->expr, e, def_sym)
+		if (def_sym->visible != no)
+			return def_sym;
+
+	/* failed to locate any defaults */
+	return NULL;
+}
+
+static struct symbol *sym_calc_choice(struct symbol *sym)
+{
+	struct symbol *def_sym;
+	struct property *prop;
+	struct expr *e;
+	int flags;
+
+	/* first calculate all choice values' visibilities */
+	flags = sym->flags;
+	prop = sym_get_choice_prop(sym);
 	expr_list_for_each_sym(prop->expr, e, def_sym) {
 	expr_list_for_each_sym(prop->expr, e, def_sym) {
 		sym_calc_visibility(def_sym);
 		sym_calc_visibility(def_sym);
 		if (def_sym->visible != no)
 		if (def_sym->visible != no)
-			return def_sym;
+			flags &= def_sym->flags;
 	}
 	}
 
 
-	/* no choice? reset tristate value */
-	sym->curr.tri = no;
-	return NULL;
+	sym->flags &= flags | ~SYMBOL_DEF_USER;
+
+	/* is the user choice visible? */
+	def_sym = sym->def[S_DEF_USER].val;
+	if (def_sym && def_sym->visible != no)
+		return def_sym;
+
+	def_sym = sym_choice_default(sym);
+
+	if (def_sym == NULL)
+		/* no choice? reset tristate value */
+		sym->curr.tri = no;
+
+	return def_sym;
 }
 }
 
 
 void sym_calc_value(struct symbol *sym)
 void sym_calc_value(struct symbol *sym)
@@ -265,6 +300,14 @@ void sym_calc_value(struct symbol *sym)
 
 
 	if (sym->flags & SYMBOL_VALID)
 	if (sym->flags & SYMBOL_VALID)
 		return;
 		return;
+
+	if (sym_is_choice_value(sym) &&
+	    sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
+		sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
+		prop = sym_get_choice_prop(sym);
+		sym_calc_value(prop_get_symbol(prop));
+	}
+
 	sym->flags |= SYMBOL_VALID;
 	sym->flags |= SYMBOL_VALID;
 
 
 	oldval = sym->curr;
 	oldval = sym->curr;
@@ -321,6 +364,18 @@ void sym_calc_value(struct symbol *sym)
 				}
 				}
 			}
 			}
 		calc_newval:
 		calc_newval:
+			if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) {
+				struct expr *e;
+				e = expr_simplify_unmet_dep(sym->rev_dep.expr,
+				    sym->dir_dep.expr);
+				fprintf(stderr, "warning: (");
+				expr_fprint(e, stderr);
+				fprintf(stderr, ") selects %s which has unmet direct dependencies (",
+					sym->name);
+				expr_fprint(sym->dir_dep.expr, stderr);
+				fprintf(stderr, ")\n");
+				expr_free(e);
+			}
 			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
 			newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
 		}
 		}
 		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
 		if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN)
@@ -365,18 +420,22 @@ void sym_calc_value(struct symbol *sym)
 
 
 	if (sym_is_choice(sym)) {
 	if (sym_is_choice(sym)) {
 		struct symbol *choice_sym;
 		struct symbol *choice_sym;
-		int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE);
 
 
 		prop = sym_get_choice_prop(sym);
 		prop = sym_get_choice_prop(sym);
 		expr_list_for_each_sym(prop->expr, e, choice_sym) {
 		expr_list_for_each_sym(prop->expr, e, choice_sym) {
-			choice_sym->flags |= flags;
-			if (flags & SYMBOL_CHANGED)
+			if ((sym->flags & SYMBOL_WRITE) &&
+			    choice_sym->visible != no)
+				choice_sym->flags |= SYMBOL_WRITE;
+			if (sym->flags & SYMBOL_CHANGED)
 				sym_set_changed(choice_sym);
 				sym_set_changed(choice_sym);
 		}
 		}
 	}
 	}
 
 
 	if (sym->flags & SYMBOL_AUTO)
 	if (sym->flags & SYMBOL_AUTO)
 		sym->flags &= ~SYMBOL_WRITE;
 		sym->flags &= ~SYMBOL_WRITE;
+
+	if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
+		set_all_choice_values(sym);
 }
 }
 
 
 void sym_clear_all_valid(void)
 void sym_clear_all_valid(void)
@@ -535,7 +594,7 @@ bool sym_string_valid(struct symbol *sym, const char *str)
 bool sym_string_within_range(struct symbol *sym, const char *str)
 bool sym_string_within_range(struct symbol *sym, const char *str)
 {
 {
 	struct property *prop;
 	struct property *prop;
-	int val;
+	long val;
 
 
 	switch (sym->type) {
 	switch (sym->type) {
 	case S_STRING:
 	case S_STRING:
@@ -608,11 +667,11 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
 	size = strlen(newval) + 1;
 	size = strlen(newval) + 1;
 	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 	if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) {
 		size += 2;
 		size += 2;
-		sym->def[S_DEF_USER].val = val = malloc(size);
+		sym->def[S_DEF_USER].val = val = xmalloc(size);
 		*val++ = '0';
 		*val++ = '0';
 		*val++ = 'x';
 		*val++ = 'x';
 	} else if (!oldval || strcmp(oldval, newval))
 	} else if (!oldval || strcmp(oldval, newval))
-		sym->def[S_DEF_USER].val = val = malloc(size);
+		sym->def[S_DEF_USER].val = val = xmalloc(size);
 	else
 	else
 		return true;
 		return true;
 
 
@@ -623,6 +682,80 @@ bool sym_set_string_value(struct symbol *sym, const char *newval)
 	return true;
 	return true;
 }
 }
 
 
+/*
+ * Find the default value associated to a symbol.
+ * For tristate symbol handle the modules=n case
+ * in which case "m" becomes "y".
+ * If the symbol does not have any default then fallback
+ * to the fixed default values.
+ */
+const char *sym_get_string_default(struct symbol *sym)
+{
+	struct property *prop;
+	struct symbol *ds;
+	const char *str;
+	tristate val;
+
+	sym_calc_visibility(sym);
+	sym_calc_value(modules_sym);
+	val = symbol_no.curr.tri;
+	str = symbol_empty.curr.val;
+
+	/* If symbol has a default value look it up */
+	prop = sym_get_default_prop(sym);
+	if (prop != NULL) {
+		switch (sym->type) {
+		case S_BOOLEAN:
+		case S_TRISTATE:
+			/* The visibility may limit the value from yes => mod */
+			val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri);
+			break;
+		default:
+			/*
+			 * The following fails to handle the situation
+			 * where a default value is further limited by
+			 * the valid range.
+			 */
+			ds = prop_get_symbol(prop);
+			if (ds != NULL) {
+				sym_calc_value(ds);
+				str = (const char *)ds->curr.val;
+			}
+		}
+	}
+
+	/* Handle select statements */
+	val = EXPR_OR(val, sym->rev_dep.tri);
+
+	/* transpose mod to yes if modules are not enabled */
+	if (val == mod)
+		if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
+			val = yes;
+
+	/* transpose mod to yes if type is bool */
+	if (sym->type == S_BOOLEAN && val == mod)
+		val = yes;
+
+	switch (sym->type) {
+	case S_BOOLEAN:
+	case S_TRISTATE:
+		switch (val) {
+		case no: return "n";
+		case mod: return "m";
+		case yes: return "y";
+		}
+	case S_INT:
+	case S_HEX:
+		return str;
+	case S_STRING:
+		return str;
+	case S_OTHER:
+	case S_UNKNOWN:
+		break;
+	}
+	return "";
+}
+
 const char *sym_get_string_value(struct symbol *sym)
 const char *sym_get_string_value(struct symbol *sym)
 {
 {
 	tristate val;
 	tristate val;
@@ -635,7 +768,8 @@ const char *sym_get_string_value(struct symbol *sym)
 		case no:
 		case no:
 			return "n";
 			return "n";
 		case mod:
 		case mod:
-			return "m";
+			sym_calc_value(modules_sym);
+			return (modules_sym->curr.tri == no) ? "n" : "m";
 		case yes:
 		case yes:
 			return "y";
 			return "y";
 		}
 		}
@@ -651,12 +785,20 @@ bool sym_is_changable(struct symbol *sym)
 	return sym->visible > sym->rev_dep.tri;
 	return sym->visible > sym->rev_dep.tri;
 }
 }
 
 
+static unsigned strhash(const char *s)
+{
+	/* fnv32 hash */
+	unsigned hash = 2166136261U;
+	for (; *s; s++)
+		hash = (hash ^ *s) * 0x01000193;
+	return hash;
+}
+
 struct symbol *sym_lookup(const char *name, int flags)
 struct symbol *sym_lookup(const char *name, int flags)
 {
 {
 	struct symbol *symbol;
 	struct symbol *symbol;
-	const char *ptr;
 	char *new_name;
 	char *new_name;
-	int hash = 0;
+	int hash;
 
 
 	if (name) {
 	if (name) {
 		if (name[0] && !name[1]) {
 		if (name[0] && !name[1]) {
@@ -666,12 +808,11 @@ struct symbol *sym_lookup(const char *name, int flags)
 			case 'n': return &symbol_no;
 			case 'n': return &symbol_no;
 			}
 			}
 		}
 		}
-		for (ptr = name; *ptr; ptr++)
-			hash += *ptr;
-		hash &= 0xff;
+		hash = strhash(name) % SYMBOL_HASHSIZE;
 
 
 		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 		for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
-			if (!strcmp(symbol->name, name) &&
+			if (symbol->name &&
+			    !strcmp(symbol->name, name) &&
 			    (flags ? symbol->flags & flags
 			    (flags ? symbol->flags & flags
 				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
 				   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
 				return symbol;
 				return symbol;
@@ -679,10 +820,10 @@ struct symbol *sym_lookup(const char *name, int flags)
 		new_name = strdup(name);
 		new_name = strdup(name);
 	} else {
 	} else {
 		new_name = NULL;
 		new_name = NULL;
-		hash = 256;
+		hash = 0;
 	}
 	}
 
 
-	symbol = malloc(sizeof(*symbol));
+	symbol = xmalloc(sizeof(*symbol));
 	memset(symbol, 0, sizeof(*symbol));
 	memset(symbol, 0, sizeof(*symbol));
 	symbol->name = new_name;
 	symbol->name = new_name;
 	symbol->type = S_UNKNOWN;
 	symbol->type = S_UNKNOWN;
@@ -697,7 +838,6 @@ struct symbol *sym_lookup(const char *name, int flags)
 struct symbol *sym_find(const char *name)
 struct symbol *sym_find(const char *name)
 {
 {
 	struct symbol *symbol = NULL;
 	struct symbol *symbol = NULL;
-	const char *ptr;
 	int hash = 0;
 	int hash = 0;
 
 
 	if (!name)
 	if (!name)
@@ -710,12 +850,11 @@ struct symbol *sym_find(const char *name)
 		case 'n': return &symbol_no;
 		case 'n': return &symbol_no;
 		}
 		}
 	}
 	}
-	for (ptr = name; *ptr; ptr++)
-		hash += *ptr;
-	hash &= 0xff;
+	hash = strhash(name) % SYMBOL_HASHSIZE;
 
 
 	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
 	for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
-		if (!strcmp(symbol->name, name) &&
+		if (symbol->name &&
+		    !strcmp(symbol->name, name) &&
 		    !(symbol->flags & SYMBOL_CONST))
 		    !(symbol->flags & SYMBOL_CONST))
 				break;
 				break;
 	}
 	}
@@ -723,42 +862,301 @@ struct symbol *sym_find(const char *name)
 	return symbol;
 	return symbol;
 }
 }
 
 
+/*
+ * Expand symbol's names embedded in the string given in argument. Symbols'
+ * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to
+ * the empty string.
+ */
+const char *sym_expand_string_value(const char *in)
+{
+	const char *src;
+	char *res;
+	size_t reslen;
+
+	reslen = strlen(in) + 1;
+	res = xmalloc(reslen);
+	res[0] = '\0';
+
+	while ((src = strchr(in, '$'))) {
+		char *p, name[SYMBOL_MAXLENGTH];
+		const char *symval = "";
+		struct symbol *sym;
+		size_t newlen;
+
+		strncat(res, in, src - in);
+		src++;
+
+		p = name;
+		while (isalnum(*src) || *src == '_')
+			*p++ = *src++;
+		*p = '\0';
+
+		sym = sym_find(name);
+		if (sym != NULL) {
+			sym_calc_value(sym);
+			symval = sym_get_string_value(sym);
+		}
+
+		newlen = strlen(res) + strlen(symval) + strlen(src) + 1;
+		if (newlen > reslen) {
+			reslen = newlen;
+			res = realloc(res, reslen);
+		}
+
+		strcat(res, symval);
+		in = src;
+	}
+	strcat(res, in);
+
+	return res;
+}
+
+const char *sym_escape_string_value(const char *in)
+{
+	const char *p;
+	size_t reslen;
+	char *res;
+	size_t l;
+
+	reslen = strlen(in) + strlen("\"\"") + 1;
+
+	p = in;
+	for (;;) {
+		l = strcspn(p, "\"\\");
+		p += l;
+
+		if (p[0] == '\0')
+			break;
+
+		reslen++;
+		p++;
+	}
+
+	res = xmalloc(reslen);
+	res[0] = '\0';
+
+	strcat(res, "\"");
+
+	p = in;
+	for (;;) {
+		l = strcspn(p, "\"\\");
+		strncat(res, p, l);
+		p += l;
+
+		if (p[0] == '\0')
+			break;
+
+		strcat(res, "\\");
+		strncat(res, p++, 1);
+	}
+
+	strcat(res, "\"");
+	return res;
+}
+
+struct sym_match {
+	struct symbol	*sym;
+	off_t		so, eo;
+};
+
+/* Compare matched symbols as thus:
+ * - first, symbols that match exactly
+ * - then, alphabetical sort
+ */
+static int sym_rel_comp( const void *sym1, const void *sym2 )
+{
+	struct sym_match *s1 = *(struct sym_match **)sym1;
+	struct sym_match *s2 = *(struct sym_match **)sym2;
+	int l1, l2;
+
+	/* Exact match:
+	 * - if matched length on symbol s1 is the length of that symbol,
+	 *   then this symbol should come first;
+	 * - if matched length on symbol s2 is the length of that symbol,
+	 *   then this symbol should come first.
+	 * Note: since the search can be a regexp, both symbols may match
+	 * exactly; if this is the case, we can't decide which comes first,
+	 * and we fallback to sorting alphabetically.
+	 */
+	l1 = s1->eo - s1->so;
+	l2 = s2->eo - s2->so;
+	if (l1 == strlen(s1->sym->name) && l2 != strlen(s2->sym->name))
+		return -1;
+	if (l1 != strlen(s1->sym->name) && l2 == strlen(s2->sym->name))
+		return 1;
+
+	/* As a fallback, sort symbols alphabetically */
+	return strcmp(s1->sym->name, s2->sym->name);
+}
+
 struct symbol **sym_re_search(const char *pattern)
 struct symbol **sym_re_search(const char *pattern)
 {
 {
 	struct symbol *sym, **sym_arr = NULL;
 	struct symbol *sym, **sym_arr = NULL;
+	struct sym_match **sym_match_arr = NULL;
 	int i, cnt, size;
 	int i, cnt, size;
 	regex_t re;
 	regex_t re;
+	regmatch_t match[1];
 
 
 	cnt = size = 0;
 	cnt = size = 0;
 	/* Skip if empty */
 	/* Skip if empty */
 	if (strlen(pattern) == 0)
 	if (strlen(pattern) == 0)
 		return NULL;
 		return NULL;
-	if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB|REG_ICASE))
+	if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
 		return NULL;
 		return NULL;
 
 
 	for_all_symbols(i, sym) {
 	for_all_symbols(i, sym) {
+		struct sym_match *tmp_sym_match;
 		if (sym->flags & SYMBOL_CONST || !sym->name)
 		if (sym->flags & SYMBOL_CONST || !sym->name)
 			continue;
 			continue;
-		if (regexec(&re, sym->name, 0, NULL, 0))
+		if (regexec(&re, sym->name, 1, match, 0))
 			continue;
 			continue;
 		if (cnt + 1 >= size) {
 		if (cnt + 1 >= size) {
-			void *tmp = sym_arr;
+			void *tmp;
 			size += 16;
 			size += 16;
-			sym_arr = realloc(sym_arr, size * sizeof(struct symbol *));
-			if (!sym_arr) {
-				free(tmp);
-				return NULL;
+			tmp = realloc(sym_match_arr, size * sizeof(struct sym_match *));
+			if (!tmp) {
+				goto sym_re_search_free;
 			}
 			}
+			sym_match_arr = tmp;
 		}
 		}
-		sym_arr[cnt++] = sym;
+		sym_calc_value(sym);
+		tmp_sym_match = (struct sym_match*)malloc(sizeof(struct sym_match));
+		if (!tmp_sym_match)
+			goto sym_re_search_free;
+		tmp_sym_match->sym = sym;
+		/* As regexec return 0, we know we have a match, so
+		 * we can use match[0].rm_[se]o without further checks
+		 */
+		tmp_sym_match->so = match[0].rm_so;
+		tmp_sym_match->eo = match[0].rm_eo;
+		sym_match_arr[cnt++] = tmp_sym_match;
 	}
 	}
-	if (sym_arr)
+	if (sym_match_arr) {
+		qsort(sym_match_arr, cnt, sizeof(struct sym_match*), sym_rel_comp);
+		sym_arr = malloc((cnt+1) * sizeof(struct symbol));
+		if (!sym_arr)
+			goto sym_re_search_free;
+		for (i = 0; i < cnt; i++)
+			sym_arr[i] = sym_match_arr[i]->sym;
 		sym_arr[cnt] = NULL;
 		sym_arr[cnt] = NULL;
+	}
+sym_re_search_free:
+	if (sym_match_arr) {
+		for (i = 0; i < cnt; i++)
+			free(sym_match_arr[i]);
+		free(sym_match_arr);
+	}
 	regfree(&re);
 	regfree(&re);
 
 
 	return sym_arr;
 	return sym_arr;
 }
 }
 
 
+/*
+ * When we check for recursive dependencies we use a stack to save
+ * current state so we can print out relevant info to user.
+ * The entries are located on the call stack so no need to free memory.
+ * Note inser() remove() must always match to properly clear the stack.
+ */
+static struct dep_stack {
+	struct dep_stack *prev, *next;
+	struct symbol *sym;
+	struct property *prop;
+	struct expr *expr;
+} *check_top;
+
+static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
+{
+	memset(stack, 0, sizeof(*stack));
+	if (check_top)
+		check_top->next = stack;
+	stack->prev = check_top;
+	stack->sym = sym;
+	check_top = stack;
+}
+
+static void dep_stack_remove(void)
+{
+	check_top = check_top->prev;
+	if (check_top)
+		check_top->next = NULL;
+}
+
+/*
+ * Called when we have detected a recursive dependency.
+ * check_top point to the top of the stact so we use
+ * the ->prev pointer to locate the bottom of the stack.
+ */
+static void sym_check_print_recursive(struct symbol *last_sym)
+{
+	struct dep_stack *stack;
+	struct symbol *sym, *next_sym;
+	struct menu *menu = NULL;
+	struct property *prop;
+	struct dep_stack cv_stack;
+
+	if (sym_is_choice_value(last_sym)) {
+		dep_stack_insert(&cv_stack, last_sym);
+		last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
+	}
+
+	for (stack = check_top; stack != NULL; stack = stack->prev)
+		if (stack->sym == last_sym)
+			break;
+	if (!stack) {
+		fprintf(stderr, "unexpected recursive dependency error\n");
+		return;
+	}
+
+	for (; stack; stack = stack->next) {
+		sym = stack->sym;
+		next_sym = stack->next ? stack->next->sym : last_sym;
+		prop = stack->prop;
+		if (prop == NULL)
+			prop = stack->sym->prop;
+
+		/* for choice values find the menu entry (used below) */
+		if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
+			for (prop = sym->prop; prop; prop = prop->next) {
+				menu = prop->menu;
+				if (prop->menu)
+					break;
+			}
+		}
+		if (stack->sym == last_sym)
+			fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
+				prop->file->name, prop->lineno);
+		if (stack->expr) {
+			fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				prop_get_type_name(prop->type),
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (stack->prop) {
+			fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice(sym)) {
+			fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else if (sym_is_choice_value(sym)) {
+			fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
+				menu->file->name, menu->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		} else {
+			fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
+				prop->file->name, prop->lineno,
+				sym->name ? sym->name : "<choice>",
+				next_sym->name ? next_sym->name : "<choice>");
+		}
+	}
+
+	if (check_top == &cv_stack)
+		dep_stack_remove();
+}
 
 
 static struct symbol *sym_check_expr_deps(struct expr *e)
 static struct symbol *sym_check_expr_deps(struct expr *e)
 {
 {
@@ -795,24 +1193,33 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
 {
 {
 	struct symbol *sym2;
 	struct symbol *sym2;
 	struct property *prop;
 	struct property *prop;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, sym);
 
 
 	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 	if (sym2)
 	if (sym2)
-		return sym2;
+		goto out;
 
 
 	for (prop = sym->prop; prop; prop = prop->next) {
 	for (prop = sym->prop; prop; prop = prop->next) {
 		if (prop->type == P_CHOICE || prop->type == P_SELECT)
 		if (prop->type == P_CHOICE || prop->type == P_SELECT)
 			continue;
 			continue;
+		stack.prop = prop;
 		sym2 = sym_check_expr_deps(prop->visible.expr);
 		sym2 = sym_check_expr_deps(prop->visible.expr);
 		if (sym2)
 		if (sym2)
 			break;
 			break;
 		if (prop->type != P_DEFAULT || sym_is_choice(sym))
 		if (prop->type != P_DEFAULT || sym_is_choice(sym))
 			continue;
 			continue;
+		stack.expr = prop->expr;
 		sym2 = sym_check_expr_deps(prop->expr);
 		sym2 = sym_check_expr_deps(prop->expr);
 		if (sym2)
 		if (sym2)
 			break;
 			break;
+		stack.expr = NULL;
 	}
 	}
 
 
+out:
+	dep_stack_remove();
+
 	return sym2;
 	return sym2;
 }
 }
 
 
@@ -821,6 +1228,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
 	struct symbol *sym, *sym2;
 	struct symbol *sym, *sym2;
 	struct property *prop;
 	struct property *prop;
 	struct expr *e;
 	struct expr *e;
+	struct dep_stack stack;
+
+	dep_stack_insert(&stack, choice);
 
 
 	prop = sym_get_choice_prop(choice);
 	prop = sym_get_choice_prop(choice);
 	expr_list_for_each_sym(prop->expr, e, sym)
 	expr_list_for_each_sym(prop->expr, e, sym)
@@ -834,10 +1244,8 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
 
 
 	expr_list_for_each_sym(prop->expr, e, sym) {
 	expr_list_for_each_sym(prop->expr, e, sym) {
 		sym2 = sym_check_sym_deps(sym);
 		sym2 = sym_check_sym_deps(sym);
-		if (sym2) {
-			fprintf(stderr, " -> %s", sym->name);
+		if (sym2)
 			break;
 			break;
-		}
 	}
 	}
 out:
 out:
 	expr_list_for_each_sym(prop->expr, e, sym)
 	expr_list_for_each_sym(prop->expr, e, sym)
@@ -847,6 +1255,8 @@ out:
 	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
 	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
 		sym2 = choice;
 		sym2 = choice;
 
 
+	dep_stack_remove();
+
 	return sym2;
 	return sym2;
 }
 }
 
 
@@ -856,18 +1266,20 @@ struct symbol *sym_check_deps(struct symbol *sym)
 	struct property *prop;
 	struct property *prop;
 
 
 	if (sym->flags & SYMBOL_CHECK) {
 	if (sym->flags & SYMBOL_CHECK) {
-		fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
-		        sym->prop->file->name, sym->prop->lineno,
-			sym->name ? sym->name : "<choice>");
+		sym_check_print_recursive(sym);
 		return sym;
 		return sym;
 	}
 	}
 	if (sym->flags & SYMBOL_CHECKED)
 	if (sym->flags & SYMBOL_CHECKED)
 		return NULL;
 		return NULL;
 
 
 	if (sym_is_choice_value(sym)) {
 	if (sym_is_choice_value(sym)) {
+		struct dep_stack stack;
+
 		/* for choice groups start the check with main choice symbol */
 		/* for choice groups start the check with main choice symbol */
+		dep_stack_insert(&stack, sym);
 		prop = sym_get_choice_prop(sym);
 		prop = sym_get_choice_prop(sym);
 		sym2 = sym_check_deps(prop_get_symbol(prop));
 		sym2 = sym_check_deps(prop_get_symbol(prop));
+		dep_stack_remove();
 	} else if (sym_is_choice(sym)) {
 	} else if (sym_is_choice(sym)) {
 		sym2 = sym_check_choice_deps(sym);
 		sym2 = sym_check_choice_deps(sym);
 	} else {
 	} else {
@@ -876,14 +1288,8 @@ struct symbol *sym_check_deps(struct symbol *sym)
 		sym->flags &= ~SYMBOL_CHECK;
 		sym->flags &= ~SYMBOL_CHECK;
 	}
 	}
 
 
-	if (sym2) {
-		fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
-		if (sym2 == sym) {
-			fprintf(stderr, "\n");
-			zconfnerrs++;
-			sym2 = NULL;
-		}
-	}
+	if (sym2 && sym2 == sym)
+		sym2 = NULL;
 
 
 	return sym2;
 	return sym2;
 }
 }
@@ -893,7 +1299,7 @@ struct property *prop_alloc(enum prop_type type, struct symbol *sym)
 	struct property *prop;
 	struct property *prop;
 	struct property **propp;
 	struct property **propp;
 
 
-	prop = malloc(sizeof(*prop));
+	prop = xmalloc(sizeof(*prop));
 	memset(prop, 0, sizeof(*prop));
 	memset(prop, 0, sizeof(*prop));
 	prop->type = type;
 	prop->type = type;
 	prop->sym = sym;
 	prop->sym = sym;
@@ -937,13 +1343,15 @@ const char *prop_get_type_name(enum prop_type type)
 		return "select";
 		return "select";
 	case P_RANGE:
 	case P_RANGE:
 		return "range";
 		return "range";
+	case P_SYMBOL:
+		return "symbol";
 	case P_UNKNOWN:
 	case P_UNKNOWN:
 		break;
 		break;
 	}
 	}
 	return "unknown";
 	return "unknown";
 }
 }
 
 
-void prop_add_env(const char *env)
+static void prop_add_env(const char *env)
 {
 {
 	struct symbol *sym, *sym2;
 	struct symbol *sym, *sym2;
 	struct property *prop;
 	struct property *prop;

+ 58 - 10
extra/config/util.c

@@ -5,6 +5,8 @@
  * Released under the terms of the GNU GPL v2.0.
  * Released under the terms of the GNU GPL v2.0.
  */
  */
 
 
+#include <stdarg.h>
+#include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include "lkc.h"
 #include "lkc.h"
 
 
@@ -12,15 +14,18 @@
 struct file *file_lookup(const char *name)
 struct file *file_lookup(const char *name)
 {
 {
 	struct file *file;
 	struct file *file;
+	const char *file_name = sym_expand_string_value(name);
 
 
 	for (file = file_list; file; file = file->next) {
 	for (file = file_list; file; file = file->next) {
-		if (!strcmp(name, file->name))
+		if (!strcmp(name, file->name)) {
+			free((void *)file_name);
 			return file;
 			return file;
+		}
 	}
 	}
 
 
-	file = malloc(sizeof(*file));
+	file = xmalloc(sizeof(*file));
 	memset(file, 0, sizeof(*file));
 	memset(file, 0, sizeof(*file));
-	file->name = strdup(name);
+	file->name = file_name;
 	file->next = file_list;
 	file->next = file_list;
 	file_list = file;
 	file_list = file;
 	return file;
 	return file;
@@ -32,11 +37,15 @@ int file_write_dep(const char *name)
 	struct symbol *sym, *env_sym;
 	struct symbol *sym, *env_sym;
 	struct expr *e;
 	struct expr *e;
 	struct file *file;
 	struct file *file;
+	char tmpf[PATH_MAX+1];
 	FILE *out;
 	FILE *out;
 
 
 	if (!name)
 	if (!name)
 		name = ".kconfig.d";
 		name = ".kconfig.d";
-	out = fopen("..config.tmp", "w");
+	strcpy(tmpf, name);
+	dir_name(tmpf);
+	strcat(tmpf, "..config.tmp");
+	out = fopen(tmpf, "w");
 	if (!out)
 	if (!out)
 		return 1;
 		return 1;
 	fprintf(out, "deps_config := \\\n");
 	fprintf(out, "deps_config := \\\n");
@@ -46,8 +55,8 @@ int file_write_dep(const char *name)
 		else
 		else
 			fprintf(out, "\t%s\n", file->name);
 			fprintf(out, "\t%s\n", file->name);
 	}
 	}
-	fprintf(out, "\ninclude/config/auto.conf: \\\n"
-		     "\t$(deps_config)\n\n");
+	fprintf(out, "\n%s: \\\n"
+		     "\t$(deps_config)\n\n", conf_get_autoconfig_name());
 
 
 	expr_list_for_each_sym(sym_env_list, e, sym) {
 	expr_list_for_each_sym(sym_env_list, e, sym) {
 		struct property *prop;
 		struct property *prop;
@@ -61,23 +70,24 @@ int file_write_dep(const char *name)
 		if (!value)
 		if (!value)
 			value = "";
 			value = "";
 		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
 		fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value);
-		fprintf(out, "include/config/auto.conf: FORCE\n");
+		fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name());
 		fprintf(out, "endif\n");
 		fprintf(out, "endif\n");
 	}
 	}
 
 
 	fprintf(out, "\n$(deps_config): ;\n");
 	fprintf(out, "\n$(deps_config): ;\n");
 	fclose(out);
 	fclose(out);
-	rename("..config.tmp", name);
+	rename(tmpf, name);
 	return 0;
 	return 0;
 }
 }
 
 
 
 
-/* Allocate initial growable sting */
+/* Allocate initial growable string */
 struct gstr str_new(void)
 struct gstr str_new(void)
 {
 {
 	struct gstr gs;
 	struct gstr gs;
-	gs.s = malloc(sizeof(char) * 64);
+	gs.s = xmalloc(sizeof(char) * 64);
 	gs.len = 64;
 	gs.len = 64;
+	gs.max_width = 0;
 	strcpy(gs.s, "\0");
 	strcpy(gs.s, "\0");
 	return gs;
 	return gs;
 }
 }
@@ -88,6 +98,7 @@ struct gstr str_assign(const char *s)
 	struct gstr gs;
 	struct gstr gs;
 	gs.s = strdup(s);
 	gs.s = strdup(s);
 	gs.len = strlen(s) + 1;
 	gs.len = strlen(s) + 1;
+	gs.max_width = 0;
 	return gs;
 	return gs;
 }
 }
 
 
@@ -131,3 +142,40 @@ const char *str_get(struct gstr *gs)
 	return gs->s;
 	return gs->s;
 }
 }
 
 
+void *xmalloc(size_t size)
+{
+	void *p = malloc(size);
+	if (p)
+		return p;
+	fprintf(stderr, "Out of memory.\n");
+	exit(1);
+}
+
+void *xcalloc(size_t nmemb, size_t size)
+{
+	void *p = calloc(nmemb, size);
+	if (p)
+		return p;
+	fprintf(stderr, "Out of memory.\n");
+	exit(1);
+}
+
+/* basename, dirname - parse pathname components */
+char *dir_name(char *path)
+{
+	char *slash = strrchr(path, '/');
+	int size = 0;
+	if (slash)
+		size = slash - path + 1;
+	path[size] = 0;
+	return path;
+}
+char *base_name(char *path)
+{
+	char *slash = strrchr(path, '/');
+	if (slash)
+		path += slash - path + 1;
+	return path;
+
+}
+

+ 3 - 0
extra/config/zconf.gperf

@@ -9,6 +9,8 @@
 
 
 struct kconf_id;
 struct kconf_id;
 
 
+static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+
 %%
 %%
 mainmenu,	T_MAINMENU,	TF_COMMAND
 mainmenu,	T_MAINMENU,	TF_COMMAND
 menu,		T_MENU,		TF_COMMAND
 menu,		T_MENU,		TF_COMMAND
@@ -36,6 +38,7 @@ hex,		T_TYPE,		TF_COMMAND, S_HEX
 string,		T_TYPE,		TF_COMMAND, S_STRING
 string,		T_TYPE,		TF_COMMAND, S_STRING
 select,		T_SELECT,	TF_COMMAND
 select,		T_SELECT,	TF_COMMAND
 range,		T_RANGE,	TF_COMMAND
 range,		T_RANGE,	TF_COMMAND
+visible,	T_VISIBLE,	TF_COMMAND
 option,		T_OPTION,	TF_COMMAND
 option,		T_OPTION,	TF_COMMAND
 on,		T_ON,		TF_PARAM
 on,		T_ON,		TF_PARAM
 modules,	T_OPT_MODULES,	TF_OPTION
 modules,	T_OPT_MODULES,	TF_OPTION

+ 160 - 111
extra/config/zconf.hash.c_shipped

@@ -1,6 +1,5 @@
-/* ANSI-C code produced by gperf version 3.0.3 */
-/* Command-line: gperf  */
-/* Computed positions: -k'1,3' */
+/* ANSI-C code produced by gperf version 3.0.4 */
+/* Command-line: gperf -t --output-file scripts/kconfig/zconf.hash.c_shipped -a -C -E -g -k '1,3,$' -p -t scripts/kconfig/zconf.gperf  */
 
 
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
 #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
       && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
@@ -29,8 +28,11 @@
 #error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
 #error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
 #endif
 #endif
 
 
+#line 10 "scripts/kconfig/zconf.gperf"
 struct kconf_id;
 struct kconf_id;
-/* maximum key range = 47, duplicates = 0 */
+
+static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len);
+/* maximum key range = 71, duplicates = 0 */
 
 
 #ifdef __GNUC__
 #ifdef __GNUC__
 __inline
 __inline
@@ -42,34 +44,34 @@ inline
 static unsigned int
 static unsigned int
 kconf_id_hash (register const char *str, register unsigned int len)
 kconf_id_hash (register const char *str, register unsigned int len)
 {
 {
-  static unsigned char asso_values[] =
+  static const unsigned char asso_values[] =
     {
     {
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 11,  5,
-       0,  0,  5, 49,  5, 20, 49, 49,  5, 20,
-       5,  0, 30, 49,  0, 15,  0, 10,  0, 49,
-      25, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
-      49, 49, 49, 49, 49, 49
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 25, 25,
+       0,  0,  0,  5,  0,  0, 73, 73,  5,  0,
+      10,  5, 45, 73, 20, 20,  0, 15, 15, 73,
+      20, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      73, 73, 73, 73, 73, 73
     };
     };
   register int hval = len;
   register int hval = len;
 
 
@@ -83,137 +85,183 @@ kconf_id_hash (register const char *str, register unsigned int len)
         hval += asso_values[(unsigned char)str[0]];
         hval += asso_values[(unsigned char)str[0]];
         break;
         break;
     }
     }
-  return hval;
+  return hval + asso_values[(unsigned char)str[len - 1]];
 }
 }
 
 
 struct kconf_id_strings_t
 struct kconf_id_strings_t
   {
   {
-    char kconf_id_strings_str2[sizeof("on")];
-    char kconf_id_strings_str3[sizeof("env")];
+    char kconf_id_strings_str2[sizeof("if")];
+    char kconf_id_strings_str3[sizeof("int")];
     char kconf_id_strings_str5[sizeof("endif")];
     char kconf_id_strings_str5[sizeof("endif")];
-    char kconf_id_strings_str6[sizeof("option")];
-    char kconf_id_strings_str7[sizeof("endmenu")];
-    char kconf_id_strings_str8[sizeof("optional")];
+    char kconf_id_strings_str7[sizeof("default")];
+    char kconf_id_strings_str8[sizeof("tristate")];
     char kconf_id_strings_str9[sizeof("endchoice")];
     char kconf_id_strings_str9[sizeof("endchoice")];
-    char kconf_id_strings_str10[sizeof("range")];
-    char kconf_id_strings_str11[sizeof("choice")];
-    char kconf_id_strings_str12[sizeof("default")];
+    char kconf_id_strings_str12[sizeof("def_tristate")];
     char kconf_id_strings_str13[sizeof("def_bool")];
     char kconf_id_strings_str13[sizeof("def_bool")];
-    char kconf_id_strings_str14[sizeof("help")];
-    char kconf_id_strings_str15[sizeof("bool")];
-    char kconf_id_strings_str16[sizeof("config")];
-    char kconf_id_strings_str17[sizeof("def_tristate")];
-    char kconf_id_strings_str18[sizeof("boolean")];
-    char kconf_id_strings_str19[sizeof("defconfig_list")];
-    char kconf_id_strings_str21[sizeof("string")];
-    char kconf_id_strings_str22[sizeof("if")];
-    char kconf_id_strings_str23[sizeof("int")];
-    char kconf_id_strings_str26[sizeof("select")];
+    char kconf_id_strings_str14[sizeof("defconfig_list")];
+    char kconf_id_strings_str17[sizeof("on")];
+    char kconf_id_strings_str18[sizeof("optional")];
+    char kconf_id_strings_str21[sizeof("option")];
+    char kconf_id_strings_str22[sizeof("endmenu")];
+    char kconf_id_strings_str23[sizeof("mainmenu")];
+    char kconf_id_strings_str25[sizeof("menuconfig")];
     char kconf_id_strings_str27[sizeof("modules")];
     char kconf_id_strings_str27[sizeof("modules")];
-    char kconf_id_strings_str28[sizeof("tristate")];
     char kconf_id_strings_str29[sizeof("menu")];
     char kconf_id_strings_str29[sizeof("menu")];
-    char kconf_id_strings_str31[sizeof("source")];
+    char kconf_id_strings_str31[sizeof("select")];
     char kconf_id_strings_str32[sizeof("comment")];
     char kconf_id_strings_str32[sizeof("comment")];
-    char kconf_id_strings_str33[sizeof("hex")];
-    char kconf_id_strings_str35[sizeof("menuconfig")];
-    char kconf_id_strings_str36[sizeof("prompt")];
-    char kconf_id_strings_str37[sizeof("depends")];
-    char kconf_id_strings_str48[sizeof("mainmenu")];
+    char kconf_id_strings_str33[sizeof("env")];
+    char kconf_id_strings_str35[sizeof("range")];
+    char kconf_id_strings_str36[sizeof("choice")];
+    char kconf_id_strings_str39[sizeof("bool")];
+    char kconf_id_strings_str41[sizeof("source")];
+    char kconf_id_strings_str42[sizeof("visible")];
+    char kconf_id_strings_str43[sizeof("hex")];
+    char kconf_id_strings_str46[sizeof("config")];
+    char kconf_id_strings_str47[sizeof("boolean")];
+    char kconf_id_strings_str51[sizeof("string")];
+    char kconf_id_strings_str54[sizeof("help")];
+    char kconf_id_strings_str56[sizeof("prompt")];
+    char kconf_id_strings_str72[sizeof("depends")];
   };
   };
-static struct kconf_id_strings_t kconf_id_strings_contents =
+static const struct kconf_id_strings_t kconf_id_strings_contents =
   {
   {
-    "on",
-    "env",
+    "if",
+    "int",
     "endif",
     "endif",
+    "default",
+    "tristate",
+    "endchoice",
+    "def_tristate",
+    "def_bool",
+    "defconfig_list",
+    "on",
+    "optional",
     "option",
     "option",
     "endmenu",
     "endmenu",
-    "optional",
-    "endchoice",
+    "mainmenu",
+    "menuconfig",
+    "modules",
+    "menu",
+    "select",
+    "comment",
+    "env",
     "range",
     "range",
     "choice",
     "choice",
-    "default",
-    "def_bool",
-    "help",
     "bool",
     "bool",
+    "source",
+    "visible",
+    "hex",
     "config",
     "config",
-    "def_tristate",
     "boolean",
     "boolean",
-    "defconfig_list",
     "string",
     "string",
-    "if",
-    "int",
-    "select",
-    "modules",
-    "tristate",
-    "menu",
-    "source",
-    "comment",
-    "hex",
-    "menuconfig",
+    "help",
     "prompt",
     "prompt",
-    "depends",
-    "mainmenu"
+    "depends"
   };
   };
 #define kconf_id_strings ((const char *) &kconf_id_strings_contents)
 #define kconf_id_strings ((const char *) &kconf_id_strings_contents)
 #ifdef __GNUC__
 #ifdef __GNUC__
 __inline
 __inline
-#ifdef __GNUC_STDC_INLINE__
+#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
 __attribute__ ((__gnu_inline__))
 __attribute__ ((__gnu_inline__))
 #endif
 #endif
 #endif
 #endif
-struct kconf_id *
+const struct kconf_id *
 kconf_id_lookup (register const char *str, register unsigned int len)
 kconf_id_lookup (register const char *str, register unsigned int len)
 {
 {
   enum
   enum
     {
     {
-      TOTAL_KEYWORDS = 31,
+      TOTAL_KEYWORDS = 32,
       MIN_WORD_LENGTH = 2,
       MIN_WORD_LENGTH = 2,
       MAX_WORD_LENGTH = 14,
       MAX_WORD_LENGTH = 14,
       MIN_HASH_VALUE = 2,
       MIN_HASH_VALUE = 2,
-      MAX_HASH_VALUE = 48
+      MAX_HASH_VALUE = 72
     };
     };
 
 
-  static struct kconf_id wordlist[] =
+  static const struct kconf_id wordlist[] =
     {
     {
       {-1}, {-1},
       {-1}, {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_ON,		TF_PARAM},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_OPT_ENV,	TF_OPTION},
+#line 25 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2,		T_IF,		TF_COMMAND|TF_PARAM},
+#line 36 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3,		T_TYPE,		TF_COMMAND, S_INT},
       {-1},
       {-1},
+#line 26 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5,		T_ENDIF,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6,		T_OPTION,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_ENDMENU,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_OPTIONAL,	TF_COMMAND},
+      {-1},
+#line 29 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+#line 31 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+#line 20 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9,	T_ENDCHOICE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10,		T_RANGE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str11,		T_CHOICE,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_UNKNOWN},
+      {-1}, {-1},
+#line 32 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
+#line 35 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13,	T_DEFAULT,	TF_COMMAND, S_BOOLEAN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,		T_HELP,		TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16,		T_CONFIG,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,	T_DEFAULT,	TF_COMMAND, S_TRISTATE},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
-      {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_TYPE,		TF_COMMAND, S_STRING},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,		T_IF,		TF_COMMAND|TF_PARAM},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,		T_TYPE,		TF_COMMAND, S_INT},
+#line 45 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14,	T_OPT_DEFCONFIG_LIST,TF_OPTION},
+      {-1}, {-1},
+#line 43 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17,		T_ON,		TF_PARAM},
+#line 28 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18,	T_OPTIONAL,	TF_COMMAND},
       {-1}, {-1},
       {-1}, {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26,		T_SELECT,	TF_COMMAND},
+#line 42 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21,		T_OPTION,	TF_COMMAND},
+#line 17 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22,	T_ENDMENU,	TF_COMMAND},
+#line 15 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23,	T_MAINMENU,	TF_COMMAND},
+      {-1},
+#line 23 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25,	T_MENUCONFIG,	TF_COMMAND},
+      {-1},
+#line 44 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,	T_OPT_MODULES,	TF_OPTION},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,	T_TYPE,		TF_COMMAND, S_TRISTATE},
+      {-1},
+#line 16 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,		T_MENU,		TF_COMMAND},
       {-1},
       {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SOURCE,	TF_COMMAND},
+#line 39 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31,		T_SELECT,	TF_COMMAND},
+#line 21 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32,	T_COMMENT,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,		T_TYPE,		TF_COMMAND, S_HEX},
+#line 46 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33,		T_OPT_ENV,	TF_OPTION},
       {-1},
       {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,	T_MENUCONFIG,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_PROMPT,	TF_COMMAND},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37,	T_DEPENDS,	TF_COMMAND},
-      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#line 40 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35,		T_RANGE,	TF_COMMAND},
+#line 19 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36,		T_CHOICE,	TF_COMMAND},
+      {-1}, {-1},
+#line 33 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39,		T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1},
+#line 18 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41,		T_SOURCE,	TF_COMMAND},
+#line 41 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42,	T_VISIBLE,	TF_COMMAND},
+#line 37 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43,		T_TYPE,		TF_COMMAND, S_HEX},
+      {-1}, {-1},
+#line 22 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46,		T_CONFIG,	TF_COMMAND},
+#line 34 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47,	T_TYPE,		TF_COMMAND, S_BOOLEAN},
+      {-1}, {-1}, {-1},
+#line 38 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51,		T_TYPE,		TF_COMMAND, S_STRING},
+      {-1}, {-1},
+#line 24 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54,		T_HELP,		TF_COMMAND},
       {-1},
       {-1},
-      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48,	T_MAINMENU,	TF_COMMAND}
+#line 30 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56,		T_PROMPT,	TF_COMMAND},
+      {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+      {-1}, {-1}, {-1}, {-1}, {-1}, {-1},
+#line 27 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72,	T_DEPENDS,	TF_COMMAND}
     };
     };
 
 
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
@@ -234,4 +282,5 @@ kconf_id_lookup (register const char *str, register unsigned int len)
     }
     }
   return 0;
   return 0;
 }
 }
+#line 47 "scripts/kconfig/zconf.gperf"
 
 

+ 34 - 29
extra/config/zconf.l

@@ -1,5 +1,5 @@
-%option backup nostdinit noyywrap never-interactive full ecs
-%option 8bit backup nodefault perf-report perf-report
+%option nostdinit noyywrap never-interactive full ecs
+%option 8bit nodefault perf-report perf-report
 %option noinput
 %option noinput
 %x COMMAND HELP STRING PARAM
 %x COMMAND HELP STRING PARAM
 %{
 %{
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <string.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 #define START_STRSIZE	16
 #define START_STRSIZE	16
@@ -39,15 +38,15 @@ static int last_ts, first_ts;
 static void zconf_endhelp(void);
 static void zconf_endhelp(void);
 static void zconf_endfile(void);
 static void zconf_endfile(void);
 
 
-void new_string(void)
+static void new_string(void)
 {
 {
-	text = malloc(START_STRSIZE);
+	text = xmalloc(START_STRSIZE);
 	text_asize = START_STRSIZE;
 	text_asize = START_STRSIZE;
 	text_size = 0;
 	text_size = 0;
 	*text = 0;
 	*text = 0;
 }
 }
 
 
-void append_string(const char *str, int size)
+static void append_string(const char *str, int size)
 {
 {
 	int new_size = text_size + size + 1;
 	int new_size = text_size + size + 1;
 	if (new_size > text_asize) {
 	if (new_size > text_asize) {
@@ -61,9 +60,9 @@ void append_string(const char *str, int size)
 	text[text_size] = 0;
 	text[text_size] = 0;
 }
 }
 
 
-void alloc_string(const char *str, int size)
+static void alloc_string(const char *str, int size)
 {
 {
-	text = malloc(size + 1);
+	text = xmalloc(size + 1);
 	memcpy(text, str, size);
 	memcpy(text, str, size);
 	text[size] = 0;
 	text[size] = 0;
 }
 }
@@ -96,7 +95,7 @@ n	[A-Za-z0-9_]
 
 
 <COMMAND>{
 <COMMAND>{
 	{n}+	{
 	{n}+	{
-		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
 		BEGIN(PARAM);
 		BEGIN(PARAM);
 		current_pos.file = current_file;
 		current_pos.file = current_file;
 		current_pos.lineno = current_file->lineno;
 		current_pos.lineno = current_file->lineno;
@@ -132,7 +131,7 @@ n	[A-Za-z0-9_]
 	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	\n	BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	---	/* ignore */
 	---	/* ignore */
 	({n}|[-/.])+	{
 	({n}|[-/.])+	{
-		struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
+		const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
 		if (id && id->flags & TF_PARAM) {
 		if (id && id->flags & TF_PARAM) {
 			zconflval.id = id;
 			zconflval.id = id;
 			return id->token;
 			return id->token;
@@ -289,42 +288,50 @@ void zconf_initscan(const char *name)
 		exit(1);
 		exit(1);
 	}
 	}
 
 
-	current_buf = malloc(sizeof(*current_buf));
+	current_buf = xmalloc(sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 
 
 	current_file = file_lookup(name);
 	current_file = file_lookup(name);
 	current_file->lineno = 1;
 	current_file->lineno = 1;
-	current_file->flags = FILE_BUSY;
 }
 }
 
 
 void zconf_nextfile(const char *name)
 void zconf_nextfile(const char *name)
 {
 {
+	struct file *iter;
 	struct file *file = file_lookup(name);
 	struct file *file = file_lookup(name);
-	struct buffer *buf = malloc(sizeof(*buf));
+	struct buffer *buf = xmalloc(sizeof(*buf));
 	memset(buf, 0, sizeof(*buf));
 	memset(buf, 0, sizeof(*buf));
 
 
 	current_buf->state = YY_CURRENT_BUFFER;
 	current_buf->state = YY_CURRENT_BUFFER;
-	yyin = zconf_fopen(name);
+	yyin = zconf_fopen(file->name);
 	if (!yyin) {
 	if (!yyin) {
-		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
 		exit(1);
 		exit(1);
 	}
 	}
 	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
 	yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
 	buf->parent = current_buf;
 	buf->parent = current_buf;
 	current_buf = buf;
 	current_buf = buf;
 
 
-	if (file->flags & FILE_BUSY) {
-		printf("%s:%d: do not source '%s' from itself\n",
-		       zconf_curname(), zconf_lineno(), name);
-		exit(1);
-	}
-	if (file->flags & FILE_SCANNED) {
-		printf("%s:%d: file '%s' is already sourced from '%s'\n",
-		       zconf_curname(), zconf_lineno(), name,
-		       file->parent->name);
-		exit(1);
+	for (iter = current_file->parent; iter; iter = iter->parent ) {
+		if (!strcmp(current_file->name,iter->name) ) {
+			printf("%s:%d: recursive inclusion detected. "
+			       "Inclusion path:\n  current file : '%s'\n",
+			       zconf_curname(), zconf_lineno(),
+			       zconf_curname());
+			iter = current_file->parent;
+			while (iter && \
+			       strcmp(iter->name,current_file->name)) {
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno-1);
+				iter = iter->parent;
+			}
+			if (iter)
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno+1);
+			exit(1);
+		}
 	}
 	}
-	file->flags |= FILE_BUSY;
 	file->lineno = 1;
 	file->lineno = 1;
 	file->parent = current_file;
 	file->parent = current_file;
 	current_file = file;
 	current_file = file;
@@ -334,8 +341,6 @@ static void zconf_endfile(void)
 {
 {
 	struct buffer *parent;
 	struct buffer *parent;
 
 
-	current_file->flags |= FILE_SCANNED;
-	current_file->flags &= ~FILE_BUSY;
 	current_file = current_file->parent;
 	current_file = current_file->parent;
 
 
 	parent = current_buf->parent;
 	parent = current_buf->parent;
@@ -353,7 +358,7 @@ int zconf_lineno(void)
 	return current_pos.lineno;
 	return current_pos.lineno;
 }
 }
 
 
-char *zconf_curname(void)
+const char *zconf_curname(void)
 {
 {
 	return current_pos.file ? current_pos.file->name : "<none>";
 	return current_pos.file ? current_pos.file->name : "<none>";
 }
 }

+ 37 - 33
extra/config/lex.zconf.c_shipped → extra/config/zconf.lex.c_shipped

@@ -1,5 +1,5 @@
 
 
-#line 3 "scripts/kconfig/lex.zconf.c"
+#line 3 "scripts/kconfig/zconf.lex.c_shipped"
 
 
 #define  YY_INT_ALIGNED short int
 #define  YY_INT_ALIGNED short int
 
 
@@ -52,7 +52,7 @@
 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
 
 
 /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
 /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
+ * if you want the limit (max/min) macros for int types. 
  */
  */
 #ifndef __STDC_LIMIT_MACROS
 #ifndef __STDC_LIMIT_MACROS
 #define __STDC_LIMIT_MACROS 1
 #define __STDC_LIMIT_MACROS 1
@@ -72,6 +72,7 @@ typedef int flex_int32_t;
 typedef unsigned char flex_uint8_t; 
 typedef unsigned char flex_uint8_t; 
 typedef unsigned short int flex_uint16_t;
 typedef unsigned short int flex_uint16_t;
 typedef unsigned int flex_uint32_t;
 typedef unsigned int flex_uint32_t;
+#endif /* ! C99 */
 
 
 /* Limits of integral types. */
 /* Limits of integral types. */
 #ifndef INT8_MIN
 #ifndef INT8_MIN
@@ -102,8 +103,6 @@ typedef unsigned int flex_uint32_t;
 #define UINT32_MAX             (4294967295U)
 #define UINT32_MAX             (4294967295U)
 #endif
 #endif
 
 
-#endif /* ! C99 */
-
 #endif /* ! FLEXINT_H */
 #endif /* ! FLEXINT_H */
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -777,7 +776,6 @@ char *zconftext;
 #include <string.h>
 #include <string.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
 #define START_STRSIZE	16
 #define START_STRSIZE	16
@@ -802,15 +800,15 @@ static int last_ts, first_ts;
 static void zconf_endhelp(void);
 static void zconf_endhelp(void);
 static void zconf_endfile(void);
 static void zconf_endfile(void);
 
 
-void new_string(void)
+static void new_string(void)
 {
 {
-	text = malloc(START_STRSIZE);
+	text = xmalloc(START_STRSIZE);
 	text_asize = START_STRSIZE;
 	text_asize = START_STRSIZE;
 	text_size = 0;
 	text_size = 0;
 	*text = 0;
 	*text = 0;
 }
 }
 
 
-void append_string(const char *str, int size)
+static void append_string(const char *str, int size)
 {
 {
 	int new_size = text_size + size + 1;
 	int new_size = text_size + size + 1;
 	if (new_size > text_asize) {
 	if (new_size > text_asize) {
@@ -824,9 +822,9 @@ void append_string(const char *str, int size)
 	text[text_size] = 0;
 	text[text_size] = 0;
 }
 }
 
 
-void alloc_string(const char *str, int size)
+static void alloc_string(const char *str, int size)
 {
 {
-	text = malloc(size + 1);
+	text = xmalloc(size + 1);
 	memcpy(text, str, size);
 	memcpy(text, str, size);
 	text[size] = 0;
 	text[size] = 0;
 }
 }
@@ -922,7 +920,7 @@ static int input (void );
 /* This used to be an fputs(), but since the string might contain NUL's,
 /* This used to be an fputs(), but since the string might contain NUL's,
  * we now use fwrite().
  * we now use fwrite().
  */
  */
-#define ECHO fwrite( zconftext, zconfleng, 1, zconfout )
+#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
 #endif
 #endif
 
 
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
 /* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
@@ -1087,7 +1085,7 @@ YY_RULE_SETUP
 case 6:
 case 6:
 YY_RULE_SETUP
 YY_RULE_SETUP
 {
 {
-		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
 		BEGIN(PARAM);
 		BEGIN(PARAM);
 		current_pos.file = current_file;
 		current_pos.file = current_file;
 		current_pos.lineno = current_file->lineno;
 		current_pos.lineno = current_file->lineno;
@@ -1162,7 +1160,7 @@ YY_RULE_SETUP
 case 19:
 case 19:
 YY_RULE_SETUP
 YY_RULE_SETUP
 {
 {
-		struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
+		const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
 		if (id && id->flags & TF_PARAM) {
 		if (id && id->flags & TF_PARAM) {
 			zconflval.id = id;
 			zconflval.id = id;
 			return id->token;
 			return id->token;
@@ -1982,7 +1980,7 @@ static void zconfensure_buffer_stack (void)
 								);
 								);
 		if ( ! (yy_buffer_stack) )
 		if ( ! (yy_buffer_stack) )
 			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
 			YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
-
+								  
 		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
 		memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
 				
 				
 		(yy_buffer_stack_max) = num_to_alloc;
 		(yy_buffer_stack_max) = num_to_alloc;
@@ -2345,42 +2343,50 @@ void zconf_initscan(const char *name)
 		exit(1);
 		exit(1);
 	}
 	}
 
 
-	current_buf = malloc(sizeof(*current_buf));
+	current_buf = xmalloc(sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
 
 
 	current_file = file_lookup(name);
 	current_file = file_lookup(name);
 	current_file->lineno = 1;
 	current_file->lineno = 1;
-	current_file->flags = FILE_BUSY;
 }
 }
 
 
 void zconf_nextfile(const char *name)
 void zconf_nextfile(const char *name)
 {
 {
+	struct file *iter;
 	struct file *file = file_lookup(name);
 	struct file *file = file_lookup(name);
-	struct buffer *buf = malloc(sizeof(*buf));
+	struct buffer *buf = xmalloc(sizeof(*buf));
 	memset(buf, 0, sizeof(*buf));
 	memset(buf, 0, sizeof(*buf));
 
 
 	current_buf->state = YY_CURRENT_BUFFER;
 	current_buf->state = YY_CURRENT_BUFFER;
-	zconfin = zconf_fopen(name);
+	zconfin = zconf_fopen(file->name);
 	if (!zconfin) {
 	if (!zconfin) {
-		printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name);
+		printf("%s:%d: can't open file \"%s\"\n",
+		    zconf_curname(), zconf_lineno(), file->name);
 		exit(1);
 		exit(1);
 	}
 	}
 	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
 	zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
 	buf->parent = current_buf;
 	buf->parent = current_buf;
 	current_buf = buf;
 	current_buf = buf;
 
 
-	if (file->flags & FILE_BUSY) {
-		printf("%s:%d: do not source '%s' from itself\n",
-		       zconf_curname(), zconf_lineno(), name);
-		exit(1);
-	}
-	if (file->flags & FILE_SCANNED) {
-		printf("%s:%d: file '%s' is already sourced from '%s'\n",
-		       zconf_curname(), zconf_lineno(), name,
-		       file->parent->name);
-		exit(1);
+	for (iter = current_file->parent; iter; iter = iter->parent ) {
+		if (!strcmp(current_file->name,iter->name) ) {
+			printf("%s:%d: recursive inclusion detected. "
+			       "Inclusion path:\n  current file : '%s'\n",
+			       zconf_curname(), zconf_lineno(),
+			       zconf_curname());
+			iter = current_file->parent;
+			while (iter && \
+			       strcmp(iter->name,current_file->name)) {
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno-1);
+				iter = iter->parent;
+			}
+			if (iter)
+				printf("  included from: '%s:%d'\n",
+				       iter->name, iter->lineno+1);
+			exit(1);
+		}
 	}
 	}
-	file->flags |= FILE_BUSY;
 	file->lineno = 1;
 	file->lineno = 1;
 	file->parent = current_file;
 	file->parent = current_file;
 	current_file = file;
 	current_file = file;
@@ -2390,8 +2396,6 @@ static void zconf_endfile(void)
 {
 {
 	struct buffer *parent;
 	struct buffer *parent;
 
 
-	current_file->flags |= FILE_SCANNED;
-	current_file->flags &= ~FILE_BUSY;
 	current_file = current_file->parent;
 	current_file = current_file->parent;
 
 
 	parent = current_buf->parent;
 	parent = current_buf->parent;
@@ -2409,7 +2413,7 @@ int zconf_lineno(void)
 	return current_pos.lineno;
 	return current_pos.lineno;
 }
 }
 
 
-char *zconf_curname(void)
+const char *zconf_curname(void)
 {
 {
 	return current_pos.file ? current_pos.file->name : "<none>";
 	return current_pos.file ? current_pos.file->name : "<none>";
 }
 }

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


+ 64 - 30
extra/config/zconf.y

@@ -11,11 +11,8 @@
 #include <string.h>
 #include <string.h>
 #include <stdbool.h>
 #include <stdbool.h>
 
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 #include "lkc.h"
 
 
-#include "zconf.hash.c"
-
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
 
 
 #define PRINTD		0x0001
 #define PRINTD		0x0001
@@ -27,18 +24,14 @@ extern int zconflex(void);
 static void zconfprint(const char *err, ...);
 static void zconfprint(const char *err, ...);
 static void zconf_error(const char *err, ...);
 static void zconf_error(const char *err, ...);
 static void zconferror(const char *err);
 static void zconferror(const char *err);
-static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken);
 
 
-struct symbol *symbol_hash[257];
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
 
 
 static struct menu *current_menu, *current_entry;
 static struct menu *current_menu, *current_entry;
 
 
-#define YYDEBUG 0
-#if YYDEBUG
-#define YYERROR_VERBOSE
-#endif
 %}
 %}
-%expect 26
+%expect 30
 
 
 %union
 %union
 {
 {
@@ -47,7 +40,7 @@ static struct menu *current_menu, *current_entry;
 	struct symbol *symbol;
 	struct symbol *symbol;
 	struct expr *expr;
 	struct expr *expr;
 	struct menu *menu;
 	struct menu *menu;
-	struct kconf_id *id;
+	const struct kconf_id *id;
 }
 }
 
 
 %token <id>T_MAINMENU
 %token <id>T_MAINMENU
@@ -70,6 +63,7 @@ static struct menu *current_menu, *current_entry;
 %token <id>T_DEFAULT
 %token <id>T_DEFAULT
 %token <id>T_SELECT
 %token <id>T_SELECT
 %token <id>T_RANGE
 %token <id>T_RANGE
+%token <id>T_VISIBLE
 %token <id>T_OPTION
 %token <id>T_OPTION
 %token <id>T_ON
 %token <id>T_ON
 %token <string> T_WORD
 %token <string> T_WORD
@@ -100,15 +94,21 @@ static struct menu *current_menu, *current_entry;
 		menu_end_menu();
 		menu_end_menu();
 } if_entry menu_entry choice_entry
 } if_entry menu_entry choice_entry
 
 
+%{
+/* Include zconf.hash.c here so it can see the token constants. */
+#include "zconf.hash.c"
+%}
+
 %%
 %%
-input: stmt_list;
+input: nl start | start;
+
+start: mainmenu_stmt stmt_list | stmt_list;
 
 
 stmt_list:
 stmt_list:
 	  /* empty */
 	  /* empty */
 	| stmt_list common_stmt
 	| stmt_list common_stmt
 	| stmt_list choice_stmt
 	| stmt_list choice_stmt
 	| stmt_list menu_stmt
 	| stmt_list menu_stmt
-	| stmt_list T_MAINMENU prompt nl
 	| stmt_list end			{ zconf_error("unexpected end statement"); }
 	| stmt_list end			{ zconf_error("unexpected end statement"); }
 	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
 	| stmt_list T_WORD error T_EOL	{ zconf_error("unknown statement \"%s\"", $2); }
 	| stmt_list option_name error T_EOL
 	| stmt_list option_name error T_EOL
@@ -119,7 +119,7 @@ stmt_list:
 ;
 ;
 
 
 option_name:
 option_name:
-	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT
+	T_DEPENDS | T_PROMPT | T_TYPE | T_SELECT | T_OPTIONAL | T_RANGE | T_DEFAULT | T_VISIBLE
 ;
 ;
 
 
 common_stmt:
 common_stmt:
@@ -224,7 +224,7 @@ symbol_option_list:
 	  /* empty */
 	  /* empty */
 	| symbol_option_list T_WORD symbol_option_arg
 	| symbol_option_list T_WORD symbol_option_arg
 {
 {
-	struct kconf_id *id = kconf_id_lookup($2, strlen($2));
+	const struct kconf_id *id = kconf_id_lookup($2, strlen($2));
 	if (id && id->flags & TF_OPTION)
 	if (id && id->flags & TF_OPTION)
 		menu_add_option(id->token, $3);
 		menu_add_option(id->token, $3);
 	else
 	else
@@ -339,6 +339,13 @@ if_block:
 	| if_block choice_stmt
 	| if_block choice_stmt
 ;
 ;
 
 
+/* mainmenu entry */
+
+mainmenu_stmt: T_MAINMENU prompt nl
+{
+	menu_add_prompt(P_MENU, $2, NULL);
+};
+
 /* menu entry */
 /* menu entry */
 
 
 menu: T_MENU prompt T_EOL
 menu: T_MENU prompt T_EOL
@@ -348,7 +355,7 @@ menu: T_MENU prompt T_EOL
 	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
 };
 };
 
 
-menu_entry: menu depends_list
+menu_entry: menu visibility_list depends_list
 {
 {
 	$$ = menu_add_menu();
 	$$ = menu_add_menu();
 };
 };
@@ -419,6 +426,19 @@ depends: T_DEPENDS T_ON expr T_EOL
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
 };
 };
 
 
+/* visibility option */
+
+visibility_list:
+	  /* empty */
+	| visibility_list visible
+	| visibility_list T_EOL
+;
+
+visible: T_VISIBLE if_expr
+{
+	menu_add_visibility($2);
+};
+
 /* prompt statement */
 /* prompt statement */
 
 
 prompt_stmt_opt:
 prompt_stmt_opt:
@@ -472,16 +492,14 @@ void conf_parse(const char *name)
 	zconf_initscan(name);
 	zconf_initscan(name);
 
 
 	sym_init();
 	sym_init();
-	menu_init();
+	_menu_init();
 	modules_sym = sym_lookup(NULL, 0);
 	modules_sym = sym_lookup(NULL, 0);
 	modules_sym->type = S_BOOLEAN;
 	modules_sym->type = S_BOOLEAN;
 	modules_sym->flags |= SYMBOL_AUTO;
 	modules_sym->flags |= SYMBOL_AUTO;
 	rootmenu.prompt = menu_add_prompt(P_MENU, "uClibc Configuration", NULL);
 	rootmenu.prompt = menu_add_prompt(P_MENU, "uClibc Configuration", NULL);
 
 
-#if YYDEBUG
 	if (getenv("ZCONF_DEBUG"))
 	if (getenv("ZCONF_DEBUG"))
 		zconfdebug = 1;
 		zconfdebug = 1;
-#endif
 	zconfparse();
 	zconfparse();
 	if (zconfnerrs)
 	if (zconfnerrs)
 		exit(1);
 		exit(1);
@@ -491,6 +509,10 @@ void conf_parse(const char *name)
 		prop = prop_alloc(P_DEFAULT, modules_sym);
 		prop = prop_alloc(P_DEFAULT, modules_sym);
 		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
 		prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
 	}
 	}
+
+	rootmenu.prompt->text = _(rootmenu.prompt->text);
+	rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
+
 	menu_finalize(&rootmenu);
 	menu_finalize(&rootmenu);
 	for_all_symbols(i, sym) {
 	for_all_symbols(i, sym) {
 		if (sym_check_deps(sym))
 		if (sym_check_deps(sym))
@@ -501,7 +523,7 @@ void conf_parse(const char *name)
 	sym_set_change_count(1);
 	sym_set_change_count(1);
 }
 }
 
 
-const char *zconf_tokenname(int token)
+static const char *zconf_tokenname(int token)
 {
 {
 	switch (token) {
 	switch (token) {
 	case T_MENU:		return "menu";
 	case T_MENU:		return "menu";
@@ -511,11 +533,12 @@ const char *zconf_tokenname(int token)
 	case T_IF:		return "if";
 	case T_IF:		return "if";
 	case T_ENDIF:		return "endif";
 	case T_ENDIF:		return "endif";
 	case T_DEPENDS:		return "depends";
 	case T_DEPENDS:		return "depends";
+	case T_VISIBLE:		return "visible";
 	}
 	}
 	return "<token>";
 	return "<token>";
 }
 }
 
 
-static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken)
+static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken)
 {
 {
 	if (id->token != endtoken) {
 	if (id->token != endtoken) {
 		zconf_error("unexpected '%s' within %s block",
 		zconf_error("unexpected '%s' within %s block",
@@ -560,12 +583,10 @@ static void zconf_error(const char *err, ...)
 
 
 static void zconferror(const char *err)
 static void zconferror(const char *err)
 {
 {
-#if YYDEBUG
 	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
 	fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err);
-#endif
 }
 }
 
 
-void print_quoted_string(FILE *out, const char *str)
+static void print_quoted_string(FILE *out, const char *str)
 {
 {
 	const char *p;
 	const char *p;
 	int len;
 	int len;
@@ -582,15 +603,15 @@ void print_quoted_string(FILE *out, const char *str)
 	putc('"', out);
 	putc('"', out);
 }
 }
 
 
-void print_symbol(FILE *out, struct menu *menu)
+static void print_symbol(FILE *out, struct menu *menu)
 {
 {
 	struct symbol *sym = menu->sym;
 	struct symbol *sym = menu->sym;
 	struct property *prop;
 	struct property *prop;
 
 
 	if (sym_is_choice(sym))
 	if (sym_is_choice(sym))
-		fprintf(out, "choice\n");
+		fprintf(out, "\nchoice\n");
 	else
 	else
-		fprintf(out, "config %s\n", sym->name);
+		fprintf(out, "\nconfig %s\n", sym->name);
 	switch (sym->type) {
 	switch (sym->type) {
 	case S_BOOLEAN:
 	case S_BOOLEAN:
 		fputs("  boolean\n", out);
 		fputs("  boolean\n", out);
@@ -636,6 +657,21 @@ void print_symbol(FILE *out, struct menu *menu)
 		case P_CHOICE:
 		case P_CHOICE:
 			fputs("  #choice value\n", out);
 			fputs("  #choice value\n", out);
 			break;
 			break;
+		case P_SELECT:
+			fputs( "  select ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_RANGE:
+			fputs( "  range ", out);
+			expr_fprint(prop->expr, out);
+			fputc('\n', out);
+			break;
+		case P_MENU:
+			fputs( "  menu ", out);
+			print_quoted_string(out, prop->text);
+			fputc('\n', out);
+			break;
 		default:
 		default:
 			fprintf(out, "  unknown prop %d!\n", prop->type);
 			fprintf(out, "  unknown prop %d!\n", prop->type);
 			break;
 			break;
@@ -647,7 +683,6 @@ void print_symbol(FILE *out, struct menu *menu)
 			menu->help[len] = 0;
 			menu->help[len] = 0;
 		fprintf(out, "  help\n%s\n", menu->help);
 		fprintf(out, "  help\n%s\n", menu->help);
 	}
 	}
-	fputc('\n', out);
 }
 }
 
 
 void zconfdump(FILE *out)
 void zconfdump(FILE *out)
@@ -680,7 +715,6 @@ void zconfdump(FILE *out)
 				expr_fprint(prop->visible.expr, out);
 				expr_fprint(prop->visible.expr, out);
 				fputc('\n', out);
 				fputc('\n', out);
 			}
 			}
-			fputs("\n", out);
 		}
 		}
 
 
 		if (menu->list)
 		if (menu->list)
@@ -698,7 +732,7 @@ void zconfdump(FILE *out)
 	}
 	}
 }
 }
 
 
-#include "lex.zconf.c"
+#include "zconf.lex.c"
 #include "util.c"
 #include "util.c"
 #include "confdata.c"
 #include "confdata.c"
 #include "expr.c"
 #include "expr.c"

+ 1 - 0
include/.gitignore

@@ -8,6 +8,7 @@
 #
 #
 /bits/
 /bits/
 /config/
 /config/
+/generated/
 
 
 /bfin_fixed_code.h
 /bfin_fixed_code.h
 /bfin_l1layout.h
 /bfin_l1layout.h

+ 3 - 3
test/Makefile

@@ -64,15 +64,15 @@ subdirs_clean: $(patsubst %, _dirclean_%, $(ALL_SUBDIRS))
 
 
 $(patsubst %, _dir_%, $(DIRS)) : dummy
 $(patsubst %, _dir_%, $(DIRS)) : dummy
 	$(Q)$(MAKE) -C $(patsubst _dir_%, %, $@) \
 	$(Q)$(MAKE) -C $(patsubst _dir_%, %, $@) \
-		KCONFIG_CONFIG=$(__ABS_KCONFIG_CONFIG)
+		KCONFIG_CONFIG=$(KCONFIG_CONFIG)
 
 
 $(patsubst %, _dirrun_%, $(DIRS)) : dummy
 $(patsubst %, _dirrun_%, $(DIRS)) : dummy
 	$(Q)$(MAKE) -C $(patsubst _dirrun_%, %, $@) run \
 	$(Q)$(MAKE) -C $(patsubst _dirrun_%, %, $@) run \
-		KCONFIG_CONFIG=$(__ABS_KCONFIG_CONFIG)
+		KCONFIG_CONFIG=$(KCONFIG_CONFIG)
 
 
 $(patsubst %, _dircompile_%, $(DIRS)) : dummy
 $(patsubst %, _dircompile_%, $(DIRS)) : dummy
 	$(Q)$(MAKE) -C $(patsubst _dircompile_%, %, $@) compile \
 	$(Q)$(MAKE) -C $(patsubst _dircompile_%, %, $@) compile \
-		KCONFIG_CONFIG=$(__ABS_KCONFIG_CONFIG)
+		KCONFIG_CONFIG=$(KCONFIG_CONFIG)
 
 
 $(patsubst %, _dirclean_%, $(ALL_SUBDIRS)) : dummy
 $(patsubst %, _dirclean_%, $(ALL_SUBDIRS)) : dummy
 	$(Q)$(MAKE) -C $(patsubst _dirclean_%, %, $@) clean
 	$(Q)$(MAKE) -C $(patsubst _dirclean_%, %, $@) clean

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