Initial Kbuild / Kconfig commit
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 29 May 2013 06:57:52 +0000 (23:57 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 30 May 2013 20:37:20 +0000 (13:37 -0700)
This is just the contents of git://github.com/lacombar/kconfig.git,
which was made back in Aug 2011.  It should be a slimmed down version of
the Kbuild essentials.

The one modification I made was to move Makefile -> Makefil-KB for now.

In case we ever update it, I'll keep my changes in a separate commit.

50 files changed:
Makefile-KB [new file with mode: 0644]
scripts/Kbuild.include [new file with mode: 0644]
scripts/Makefile [new file with mode: 0644]
scripts/Makefile.build [new file with mode: 0644]
scripts/Makefile.clean [new file with mode: 0644]
scripts/Makefile.host [new file with mode: 0644]
scripts/Makefile.lib [new file with mode: 0644]
scripts/basic/Makefile [new file with mode: 0644]
scripts/basic/fixdep.c [new file with mode: 0644]
scripts/kconfig/.gitignore [new file with mode: 0644]
scripts/kconfig/Makefile [new file with mode: 0644]
scripts/kconfig/POTFILES.in [new file with mode: 0644]
scripts/kconfig/check.sh [new file with mode: 0755]
scripts/kconfig/conf.c [new file with mode: 0644]
scripts/kconfig/confdata.c [new file with mode: 0644]
scripts/kconfig/expr.c [new file with mode: 0644]
scripts/kconfig/expr.h [new file with mode: 0644]
scripts/kconfig/gconf.c [new file with mode: 0644]
scripts/kconfig/gconf.glade [new file with mode: 0644]
scripts/kconfig/images.c [new file with mode: 0644]
scripts/kconfig/kconfig_load.c [new file with mode: 0644]
scripts/kconfig/kxgettext.c [new file with mode: 0644]
scripts/kconfig/lex.zconf.c_shipped [new file with mode: 0644]
scripts/kconfig/lkc.h [new file with mode: 0644]
scripts/kconfig/lkc_proto.h [new file with mode: 0644]
scripts/kconfig/lxdialog/.gitignore [new file with mode: 0644]
scripts/kconfig/lxdialog/BIG.FAT.WARNING [new file with mode: 0644]
scripts/kconfig/lxdialog/check-lxdialog.sh [new file with mode: 0644]
scripts/kconfig/lxdialog/checklist.c [new file with mode: 0644]
scripts/kconfig/lxdialog/dialog.h [new file with mode: 0644]
scripts/kconfig/lxdialog/inputbox.c [new file with mode: 0644]
scripts/kconfig/lxdialog/menubox.c [new file with mode: 0644]
scripts/kconfig/lxdialog/textbox.c [new file with mode: 0644]
scripts/kconfig/lxdialog/util.c [new file with mode: 0644]
scripts/kconfig/lxdialog/yesno.c [new file with mode: 0644]
scripts/kconfig/mconf.c [new file with mode: 0644]
scripts/kconfig/menu.c [new file with mode: 0644]
scripts/kconfig/nconf.c [new file with mode: 0644]
scripts/kconfig/nconf.gui.c [new file with mode: 0644]
scripts/kconfig/nconf.h [new file with mode: 0644]
scripts/kconfig/qconf.cc [new file with mode: 0644]
scripts/kconfig/qconf.h [new file with mode: 0644]
scripts/kconfig/streamline_config.pl [new file with mode: 0644]
scripts/kconfig/symbol.c [new file with mode: 0644]
scripts/kconfig/util.c [new file with mode: 0644]
scripts/kconfig/zconf.gperf [new file with mode: 0644]
scripts/kconfig/zconf.hash.c_shipped [new file with mode: 0644]
scripts/kconfig/zconf.l [new file with mode: 0644]
scripts/kconfig/zconf.tab.c_shipped [new file with mode: 0644]
scripts/kconfig/zconf.y [new file with mode: 0644]

diff --git a/Makefile-KB b/Makefile-KB
new file mode 100644 (file)
index 0000000..88f222e
--- /dev/null
@@ -0,0 +1,100 @@
+VERSION = 2
+PATCHLEVEL = 6
+SUBLEVEL = 38
+EXTRAVERSION =
+NAME = Sheep on Meth
+
+# To put more focus on warnings, be less verbose as default
+# Use 'make V=1' to see the full commands
+
+ifeq ("$(origin V)", "command line")
+  KBUILD_VERBOSE = $(V)
+endif
+ifndef KBUILD_VERBOSE
+  KBUILD_VERBOSE = 0
+endif
+
+srctree                := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))
+objtree                := $(CURDIR)
+
+export srctree objtree
+
+CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+         else if [ -x /bin/bash ]; then echo /bin/bash; \
+         else echo sh; fi ; fi)
+
+HOSTCC       = gcc
+HOSTCXX      = g++
+HOSTCFLAGS   = -Wall -Wno-char-subscripts -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer
+HOSTCXXFLAGS = -O2
+
+export CONFIG_SHELL HOSTCC HOSTCXX HOSTCFLAGS HOSTCXXFLAGS
+
+# Beautify output
+# ---------------------------------------------------------------------------
+#
+# Normally, we echo the whole command before executing it. By making
+# that echo $($(quiet)$(cmd)), we now have the possibility to set
+# $(quiet) to choose other forms of output instead, e.g.
+#
+#         quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
+#         cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
+#
+# If $(quiet) is empty, the whole command will be printed.
+# If it is set to "quiet_", only the short version will be printed. 
+# If it is set to "silent_", nothing will be printed at all, since
+# the variable $(silent_cmd_cc_o_c) doesn't exist.
+#
+# A simple variant is to prefix commands with $(Q) - that's useful
+# for commands that shall be hidden in non-verbose mode.
+#
+#      $(Q)ln $@ :<
+#
+# If KBUILD_VERBOSE equals 0 then the above command will be hidden.
+# If KBUILD_VERBOSE equals 1 then the above command is displayed.
+
+ifeq ($(KBUILD_VERBOSE),1)
+  quiet =
+  Q =
+else
+  quiet=quiet_
+  Q = @
+endif
+export quiet Q KBUILD_VERBOSE
+
+# We need some generic definitions (do not try to remake the file).
+include $(srctree)/scripts/Kbuild.include
+
+# Basic helpers built in scripts/
+PHONY += scripts_basic
+scripts_basic:
+       $(Q)$(MAKE) $(build)=scripts/basic
+       $(Q)rm -f .tmp_quiet_recordmcount
+
+config: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=scripts/kconfig $@
+
+%config: scripts_basic FORCE
+       $(Q)$(MAKE) $(build)=scripts/kconfig $@
+
+# mrproper - Delete all generated files, including .config
+#
+mrproper-dirs      := $(addprefix _mrproper_,scripts)
+
+PHONY += $(mrproper-dirs) mrproper
+$(mrproper-dirs):
+       $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@)
+
+mrproper: $(mrproper-dirs)
+
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+PHONY += FORCE
+FORCE:
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable so we can use it in if_changed and friends.
+.PHONY: $(PHONY)
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
new file mode 100644 (file)
index 0000000..ed2773e
--- /dev/null
@@ -0,0 +1,262 @@
+####
+# kbuild: Generic definitions
+
+# Convenient variables
+comma   := ,
+squote  := '
+empty   :=
+space   := $(empty) $(empty)
+
+###
+# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o
+dot-target = $(dir $@).$(notdir $@)
+
+###
+# The temporary file to save gcc -MD generated dependencies must not
+# contain a comma
+depfile = $(subst $(comma),_,$(dot-target).d)
+
+###
+# filename of target with directory and extension stripped
+basetarget = $(basename $(notdir $@))
+
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+
+###
+# Easy method for doing a status message
+       kecho := :
+ quiet_kecho := echo
+silent_kecho := :
+kecho := $($(quiet)kecho)
+
+###
+# filechk is used to check if the content of a generated file is updated.
+# Sample usage:
+# define filechk_sample
+#      echo $KERNELRELEASE
+# endef
+# version.h : Makefile
+#      $(call filechk,sample)
+# The rule defined shall write to stdout the content of the new file.
+# The existing file will be compared with the new one.
+# - If no file exist it is created
+# - If the content differ the new file is used
+# - If they are equal no change, and no timestamp update
+# - stdin is piped in from the first prerequisite ($<) so one has
+#   to specify a valid file as first prerequisite (often the kbuild file)
+define filechk
+       $(Q)set -e;                             \
+       $(kecho) '  CHK     $@';                \
+       mkdir -p $(dir $@);                     \
+       $(filechk_$(1)) < $< > $@.tmp;          \
+       if [ -r $@ ] && cmp -s $@ $@.tmp; then  \
+               rm -f $@.tmp;                   \
+       else                                    \
+               $(kecho) '  UPD     $@';        \
+               mv -f $@.tmp $@;                \
+       fi
+endef
+
+######
+# gcc support functions
+# See documentation in Documentation/kbuild/makefiles.txt
+
+# cc-cross-prefix
+# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-)
+# Return first prefix where a prefix$(CC) is found in PATH.
+# If no $(CC) found in PATH with listed prefixes return nothing
+cc-cross-prefix =  \
+       $(word 1, $(foreach c,$(1),                                   \
+               $(shell set -e;                                       \
+               if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \
+                       echo $(c);                                    \
+               fi)))
+
+# output directory for tests below
+TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
+
+# try-run
+# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
+# Exit code chooses option. "$$TMP" is can be used as temporary file and
+# is automatically cleaned up.
+try-run = $(shell set -e;              \
+       TMP="$(TMPOUT).$$$$.tmp";       \
+       TMPO="$(TMPOUT).$$$$.o";        \
+       if ($(1)) >/dev/null 2>&1;      \
+       then echo "$(2)";               \
+       else echo "$(3)";               \
+       fi;                             \
+       rm -f "$$TMP" "$$TMPO")
+
+# as-option
+# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
+
+as-option = $(call try-run,\
+       $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2))
+
+# as-instr
+# Usage: cflags-y += $(call as-instr,instr,option1,option2)
+
+as-instr = $(call try-run,\
+       /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
+
+# cc-option
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
+
+cc-option = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2))
+
+# cc-option-yn
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call try-run,\
+       $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n)
+
+# cc-option-align
+# Prefix align with either -falign or -malign
+cc-option-align = $(subst -functions=0,,\
+       $(call cc-option,-falign-functions=0,-malign-functions=0))
+
+# cc-version
+# Usage gcc-ver := $(call cc-version)
+cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
+
+# cc-fullversion
+# Usage gcc-ver := $(call cc-fullversion)
+cc-fullversion = $(shell $(CONFIG_SHELL) \
+       $(srctree)/scripts/gcc-version.sh -p $(CC))
+
+# cc-ifversion
+# Usage:  EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
+cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
+
+# cc-ldoption
+# Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both)
+cc-ldoption = $(call try-run,\
+       $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2))
+
+# ld-option
+# Usage: LDFLAGS += $(call ld-option, -X)
+ld-option = $(call try-run,\
+       $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2))
+
+######
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
+# Usage:
+# $(Q)$(MAKE) $(build)=dir
+build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
+
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj=
+# Usage:
+# $(Q)$(MAKE) $(modbuiltin)=dir
+modbuiltin := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.modbuiltin obj
+
+# Prefix -I with $(srctree) if it is not an absolute path.
+# skip if -I has no parameter
+addtree = $(if $(patsubst -I%,%,$(1)), \
+$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1))
+
+# Find all -I options and call addtree
+flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
+
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+       echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+
+# printing commands
+cmd = @$(echo-cmd) $(cmd_$(1))
+
+# Add $(obj)/ for paths that are not absolute
+objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
+
+###
+# if_changed      - execute command if any prerequisite is newer than
+#                   target, or command line has changed
+# if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
+#                   including used config symbols
+# if_changed_rule - as if_changed but execute rule instead
+# See Documentation/kbuild/makefiles.txt for more info
+
+ifneq ($(KBUILD_NOCMDDEP),1)
+# Check if both arguments has same arguments. Result is empty string if equal.
+# User may override this check using make KBUILD_NOCMDDEP=1
+arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+                    $(filter-out $(cmd_$@),   $(cmd_$(1))) )
+endif
+
+# >'< substitution is for echo to work,
+# >$< substitution to preserve $ when reloading .cmd file
+# note: when using inline perl scripts [perl -e '...$$t=1;...']
+# in $(cmd_xxx) double $$ your perl vars
+make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
+
+# Find any prerequisites that is newer than target or that does not exist.
+# PHONY targets skipped in both cases.
+any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+
+# Execute command if command has changed or prerequisite(s) are updated.
+#
+if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
+       @set -e;                                                             \
+       $(echo-cmd) $(cmd_$(1));                                             \
+       echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
+
+# Execute the command and also postprocess generated .d dependencies file.
+if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
+       @set -e;                                                             \
+       $(echo-cmd) $(cmd_$(1));                                             \
+       scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\
+       rm -f $(depfile);                                                    \
+       mv -f $(dot-target).tmp $(dot-target).cmd)
+
+# Usage: $(call if_changed_rule,foo)
+# Will check if $(cmd_foo) or any of the prerequisites changed,
+# and if so will execute $(rule_foo).
+if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
+       @set -e;                                                             \
+       $(rule_$(1)))
+
+###
+# why - tell why a a target got build
+#       enabled by make V=2
+#       Output (listed in the order they are checked):
+#          (1) - due to target is PHONY
+#          (2) - due to target missing
+#          (3) - due to: file1.h file2.h
+#          (4) - due to command line change
+#          (5) - due to missing .cmd file
+#          (6) - due to target not in $(targets)
+# (1) PHONY targets are always build
+# (2) No target, so we better build it
+# (3) Prerequisite is newer than target
+# (4) The command line stored in the file named dir/.target.cmd
+#     differed from actual command line. This happens when compiler
+#     options changes
+# (5) No dir/.target.cmd file (used to store command line)
+# (6) No dir/.target.cmd file and target not listed in $(targets)
+#     This is a good hint that there is a bug in the kbuild file
+ifeq ($(KBUILD_VERBOSE),2)
+why =                                                                        \
+    $(if $(filter $@, $(PHONY)),- due to target is PHONY,                    \
+        $(if $(wildcard $@),                                                 \
+            $(if $(strip $(any-prereq)),- due to: $(any-prereq),             \
+                $(if $(arg-check),                                           \
+                    $(if $(cmd_$@),- due to command line change,             \
+                        $(if $(filter $@, $(targets)),                       \
+                            - due to missing .cmd file,                      \
+                            - due to $(notdir $@) not in $$(targets)         \
+                         )                                                   \
+                     )                                                       \
+                 )                                                           \
+             ),                                                              \
+             - due to target missing                                         \
+         )                                                                   \
+     )
+
+echo-why = $(call escsq, $(strip $(why)))
+endif
diff --git a/scripts/Makefile b/scripts/Makefile
new file mode 100644 (file)
index 0000000..161620f
--- /dev/null
@@ -0,0 +1,2 @@
+# Let clean descend into subdirs
+subdir-        += basic kconfig
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
new file mode 100644 (file)
index 0000000..0b94d2f
--- /dev/null
@@ -0,0 +1,391 @@
+# ==========================================================================
+# Building
+# ==========================================================================
+
+src := $(obj)
+
+PHONY := __build
+__build:
+
+# Init all relevant variables used in kbuild files so
+# 1) they have correct type
+# 2) they do not inherit any value from the environment
+obj-y :=
+obj-m :=
+lib-y :=
+lib-m :=
+always :=
+targets :=
+subdir-y :=
+subdir-m :=
+EXTRA_AFLAGS   :=
+EXTRA_CFLAGS   :=
+EXTRA_CPPFLAGS :=
+EXTRA_LDFLAGS  :=
+asflags-y  :=
+ccflags-y  :=
+cppflags-y :=
+ldflags-y  :=
+
+subdir-asflags-y :=
+subdir-ccflags-y :=
+
+# Read auto.conf if it exists, otherwise ignore
+-include include/config/auto.conf
+
+include scripts/Kbuild.include
+
+# For backward compatibility check that these variables do not change
+save-cflags := $(CFLAGS)
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
+include $(kbuild-file)
+
+# If the save-* variables changed error out
+ifeq ($(KBUILD_NOPEDANTIC),)
+        ifneq ("$(save-cflags)","$(CFLAGS)")
+                $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use EXTRA_CFLAGS)
+        endif
+endif
+include scripts/Makefile.lib
+
+ifdef host-progs
+ifneq ($(hostprogs-y),$(host-progs))
+$(warning kbuild: $(obj)/Makefile - Usage of host-progs is deprecated. Please replace with hostprogs-y!)
+hostprogs-y += $(host-progs)
+endif
+endif
+
+# Do not include host rules unless needed
+ifneq ($(hostprogs-y)$(hostprogs-m),)
+include scripts/Makefile.host
+endif
+
+ifneq ($(KBUILD_SRC),)
+# Create output directory if not already present
+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj))
+
+# Create directories for object files if directory does not exist
+# Needed when obj-y := dir/file.o syntax is used
+_dummy := $(foreach d,$(obj-dirs), $(shell [ -d $(d) ] || mkdir -p $(d)))
+endif
+
+ifndef obj
+$(warning kbuild: Makefile.build is included improperly)
+endif
+
+# ===========================================================================
+
+ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
+lib-target := $(obj)/lib.a
+endif
+
+ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
+builtin-target := $(obj)/built-in.o
+endif
+
+modorder-target := $(obj)/modules.order
+
+# We keep a list of all modules in $(MODVERDIR)
+
+__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
+        $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
+        $(subdir-ym) $(always)
+       @:
+
+# Linus' kernel sanity checking tool
+ifneq ($(KBUILD_CHECKSRC),0)
+  ifeq ($(KBUILD_CHECKSRC),2)
+    quiet_cmd_force_checksrc = CHECK   $<
+          cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
+  else
+      quiet_cmd_checksrc     = CHECK   $<
+            cmd_checksrc     = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ;
+  endif
+endif
+
+# Do section mismatch analysis for each module/built-in.o
+ifdef CONFIG_DEBUG_SECTION_MISMATCH
+  cmd_secanalysis = ; scripts/mod/modpost $@
+endif
+
+# Compile C sources (.c)
+# ---------------------------------------------------------------------------
+
+# Default is built-in, unless we know otherwise
+modkern_cflags = $(if $(part-of-module), $(CFLAGS_MODULE), $(CFLAGS_KERNEL))
+quiet_modtag := $(empty)   $(empty)
+
+$(real-objs-m)        : part-of-module := y
+$(real-objs-m:.o=.i)  : part-of-module := y
+$(real-objs-m:.o=.s)  : part-of-module := y
+$(real-objs-m:.o=.lst): part-of-module := y
+
+$(real-objs-m)        : quiet_modtag := [M]
+$(real-objs-m:.o=.i)  : quiet_modtag := [M]
+$(real-objs-m:.o=.s)  : quiet_modtag := [M]
+$(real-objs-m:.o=.lst): quiet_modtag := [M]
+
+$(obj-m)              : quiet_modtag := [M]
+
+# Default for not multi-part modules
+modname = $(basetarget)
+
+$(multi-objs-m)         : modname = $(modname-multi)
+$(multi-objs-m:.o=.i)   : modname = $(modname-multi)
+$(multi-objs-m:.o=.s)   : modname = $(modname-multi)
+$(multi-objs-m:.o=.lst) : modname = $(modname-multi)
+$(multi-objs-y)         : modname = $(modname-multi)
+$(multi-objs-y:.o=.i)   : modname = $(modname-multi)
+$(multi-objs-y:.o=.s)   : modname = $(modname-multi)
+$(multi-objs-y:.o=.lst) : modname = $(modname-multi)
+
+quiet_cmd_cc_s_c = CC $(quiet_modtag)  $@
+cmd_cc_s_c       = $(CC) $(c_flags) -fverbose-asm -S -o $@ $<
+
+$(obj)/%.s: $(src)/%.c FORCE
+       $(call if_changed_dep,cc_s_c)
+
+quiet_cmd_cc_i_c = CPP $(quiet_modtag) $@
+cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
+
+$(obj)/%.i: $(src)/%.c FORCE
+       $(call if_changed_dep,cc_i_c)
+
+cmd_gensymtypes =                                                           \
+    $(CPP) -D__GENKSYMS__ $(c_flags) $< |                                   \
+    $(GENKSYMS) -T $@ -a $(ARCH)                                            \
+     $(if $(KBUILD_PRESERVE),-p)                                            \
+     $(if $(1),-r $(firstword $(wildcard $(@:.symtypes=.symref) /dev/null)))
+
+quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
+cmd_cc_symtypes_c =                                                         \
+    set -e;                                                                 \
+    $(call cmd_gensymtypes, true) >/dev/null;                               \
+    test -s $@ || rm -f $@
+
+$(obj)/%.symtypes : $(src)/%.c FORCE
+       $(call cmd,cc_symtypes_c)
+
+# C (.c) files
+# The C file is compiled and updated dependency information is generated.
+# (See cmd_cc_o_c + relevant part of rule_cc_o_c)
+
+quiet_cmd_cc_o_c = CC $(quiet_modtag)  $@
+
+ifndef CONFIG_MODVERSIONS
+cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+
+else
+# When module versioning is enabled the following steps are executed:
+# o compile a .tmp_<file>.o from <file>.c
+# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does
+#   not export symbols, we just rename .tmp_<file>.o to <file>.o and
+#   are done.
+# o otherwise, we calculate symbol versions using the good old
+#   genksyms on the preprocessed source and postprocess them in a way
+#   that they are usable as a linker script
+# o generate <file>.o from .tmp_<file>.o using the linker to
+#   replace the unresolved symbols __crc_exported_symbol with
+#   the actual value of the checksum generated by genksyms
+
+cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
+cmd_modversions =                                                      \
+       if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then     \
+               $(call cmd_gensymtypes, $(KBUILD_SYMTYPES))             \
+                   > $(@D)/.tmp_$(@F:.o=.ver);                         \
+                                                                       \
+               $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F)              \
+                       -T $(@D)/.tmp_$(@F:.o=.ver);                    \
+               rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);        \
+       else                                                            \
+               mv -f $(@D)/.tmp_$(@F) $@;                              \
+       fi;
+endif
+
+ifdef CONFIG_FTRACE_MCOUNT_RECORD
+cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
+       "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
+       "$(if $(CONFIG_64BIT),64,32)" \
+       "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
+       "$(if $(part-of-module),1,0)" "$(@)";
+endif
+
+define rule_cc_o_c
+       $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
+       $(call echo-cmd,cc_o_c) $(cmd_cc_o_c);                            \
+       $(cmd_modversions)                                                \
+       $(call echo-cmd,record_mcount)                                    \
+       $(cmd_record_mcount)                                              \
+       scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' >    \
+                                                     $(dot-target).tmp;  \
+       rm -f $(depfile);                                                 \
+       mv -f $(dot-target).tmp $(dot-target).cmd
+endef
+
+# Built-in and composite module parts
+$(obj)/%.o: $(src)/%.c FORCE
+       $(call cmd,force_checksrc)
+       $(call if_changed_rule,cc_o_c)
+
+# Single-part modules are special since we need to mark them in $(MODVERDIR)
+
+$(single-used-m): $(obj)/%.o: $(src)/%.c FORCE
+       $(call cmd,force_checksrc)
+       $(call if_changed_rule,cc_o_c)
+       @{ echo $(@:.o=.ko); echo $@; } > $(MODVERDIR)/$(@F:.o=.mod)
+
+quiet_cmd_cc_lst_c = MKLST   $@
+      cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \
+                    $(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \
+                                    System.map $(OBJDUMP) > $@
+
+$(obj)/%.lst: $(src)/%.c FORCE
+       $(call if_changed_dep,cc_lst_c)
+
+# Compile assembler sources (.S)
+# ---------------------------------------------------------------------------
+
+modkern_aflags := $(AFLAGS_KERNEL)
+
+$(real-objs-m)      : modkern_aflags := $(AFLAGS_MODULE)
+$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
+
+quiet_cmd_as_s_S = CPP $(quiet_modtag) $@
+cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
+
+$(obj)/%.s: $(src)/%.S FORCE
+       $(call if_changed_dep,as_s_S)
+
+quiet_cmd_as_o_S = AS $(quiet_modtag)  $@
+cmd_as_o_S       = $(CC) $(a_flags) -c -o $@ $<
+
+$(obj)/%.o: $(src)/%.S FORCE
+       $(call if_changed_dep,as_o_S)
+
+targets += $(real-objs-y) $(real-objs-m) $(lib-y)
+targets += $(extra-y) $(MAKECMDGOALS) $(always)
+
+# Linker scripts preprocessor (.lds.S -> .lds)
+# ---------------------------------------------------------------------------
+quiet_cmd_cpp_lds_S = LDS     $@
+      cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
+                            -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
+
+$(obj)/%.lds: $(src)/%.lds.S FORCE
+       $(call if_changed_dep,cpp_lds_S)
+
+# Build the compiled-in targets
+# ---------------------------------------------------------------------------
+
+# To build objects in subdirs, we need to descend into the directories
+$(sort $(subdir-obj-y)): $(subdir-ym) ;
+
+#
+# Rule to compile a set of .o files into one .o file
+#
+ifdef builtin-target
+quiet_cmd_link_o_target = LD      $@
+# If the list of objects to link is empty, just create an empty built-in.o
+cmd_link_o_target = $(if $(strip $(obj-y)),\
+                     $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^) \
+                     $(cmd_secanalysis),\
+                     rm -f $@; $(AR) rcs $@)
+
+$(builtin-target): $(obj-y) FORCE
+       $(call if_changed,link_o_target)
+
+targets += $(builtin-target)
+endif # builtin-target
+
+#
+# Rule to create modules.order file
+#
+# Create commands to either record .ko file or cat modules.order from
+# a subdirectory
+modorder-cmds =                                                \
+       $(foreach m, $(modorder),                       \
+               $(if $(filter %/modules.order, $m),     \
+                       cat $m;, echo kernel/$m;))
+
+$(modorder-target): $(subdir-ym) FORCE
+       $(Q)(cat /dev/null; $(modorder-cmds)) > $@
+
+#
+# Rule to compile a set of .o files into one .a file
+#
+ifdef lib-target
+quiet_cmd_link_l_target = AR      $@
+cmd_link_l_target = rm -f $@; $(AR) rcs $@ $(lib-y)
+
+$(lib-target): $(lib-y) FORCE
+       $(call if_changed,link_l_target)
+
+targets += $(lib-target)
+endif
+
+#
+# Rule to link composite objects
+#
+#  Composite objects are specified in kbuild makefile as follows:
+#    <composite-object>-objs := <list of .o files>
+#  or
+#    <composite-object>-y    := <list of .o files>
+link_multi_deps =                     \
+$(filter $(addprefix $(obj)/,         \
+$($(subst $(obj)/,,$(@:.o=-objs)))    \
+$($(subst $(obj)/,,$(@:.o=-y)))), $^)
+quiet_cmd_link_multi-y = LD      $@
+cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis)
+
+quiet_cmd_link_multi-m = LD [M]  $@
+cmd_link_multi-m = $(cmd_link_multi-y)
+
+# We would rather have a list of rules like
+#      foo.o: $(foo-objs)
+# but that's not so easy, so we rather make all composite objects depend
+# on the set of all their parts
+$(multi-used-y) : %.o: $(multi-objs-y) FORCE
+       $(call if_changed,link_multi-y)
+
+$(multi-used-m) : %.o: $(multi-objs-m) FORCE
+       $(call if_changed,link_multi-m)
+       @{ echo $(@:.o=.ko); echo $(link_multi_deps); } > $(MODVERDIR)/$(@F:.o=.mod)
+
+targets += $(multi-used-y) $(multi-used-m)
+
+
+# Descending
+# ---------------------------------------------------------------------------
+
+PHONY += $(subdir-ym)
+$(subdir-ym):
+       $(Q)$(MAKE) $(build)=$@
+
+# Add FORCE to the prequisites of a target to force it to be always rebuilt.
+# ---------------------------------------------------------------------------
+
+PHONY += FORCE
+
+FORCE:
+
+# Read all saved command lines and dependencies for the $(targets) we
+# may be building above, using $(if_changed{,_dep}). As an
+# optimization, we don't need to read them if the target does not
+# exist, we will rebuild anyway in that case.
+
+targets := $(wildcard $(sort $(targets)))
+cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd))
+
+ifneq ($(cmd_files),)
+  include $(cmd_files)
+endif
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean
new file mode 100644 (file)
index 0000000..6f89fbb
--- /dev/null
@@ -0,0 +1,102 @@
+# ==========================================================================
+# Cleaning up
+# ==========================================================================
+
+src := $(obj)
+
+PHONY := __clean
+__clean:
+
+# Shorthand for $(Q)$(MAKE) scripts/Makefile.clean obj=dir
+# Usage:
+# $(Q)$(MAKE) $(clean)=dir
+clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj
+
+# The filename Kbuild has precedence over Makefile
+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
+include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile)
+
+# Figure out what we need to build from the various variables
+# ==========================================================================
+
+__subdir-y     := $(patsubst %/,%,$(filter %/, $(obj-y)))
+subdir-y       += $(__subdir-y)
+__subdir-m     := $(patsubst %/,%,$(filter %/, $(obj-m)))
+subdir-m       += $(__subdir-m)
+__subdir-n     := $(patsubst %/,%,$(filter %/, $(obj-n)))
+subdir-n       += $(__subdir-n)
+__subdir-      := $(patsubst %/,%,$(filter %/, $(obj-)))
+subdir-                += $(__subdir-)
+
+# Subdirectories we need to descend into
+
+subdir-ym      := $(sort $(subdir-y) $(subdir-m))
+subdir-ymn      := $(sort $(subdir-ym) $(subdir-n) $(subdir-))
+
+# Add subdir path
+
+subdir-ymn     := $(addprefix $(obj)/,$(subdir-ymn))
+
+# build a list of files to remove, usually relative to the current
+# directory
+
+__clean-files  := $(extra-y) $(always)                  \
+                  $(targets) $(clean-files)             \
+                  $(host-progs)                         \
+                  $(hostprogs-y) $(hostprogs-m) $(hostprogs-)
+
+# as clean-files is given relative to the current directory, this adds
+# a $(obj) prefix, except for absolute paths
+
+__clean-files   := $(wildcard                                               \
+                   $(addprefix $(obj)/, $(filter-out /%, $(__clean-files))) \
+                  $(filter /%, $(__clean-files)))
+
+# as clean-dirs is given relative to the current directory, this adds
+# a $(obj) prefix, except for absolute paths
+
+__clean-dirs    := $(wildcard                                               \
+                   $(addprefix $(obj)/, $(filter-out /%, $(clean-dirs)))    \
+                  $(filter /%, $(clean-dirs)))
+
+# ==========================================================================
+
+quiet_cmd_clean    = CLEAN   $(obj)
+      cmd_clean    = rm -f $(__clean-files)
+quiet_cmd_cleandir = CLEAN   $(__clean-dirs)
+      cmd_cleandir = rm -rf $(__clean-dirs)
+
+
+__clean: $(subdir-ymn)
+ifneq ($(strip $(__clean-files)),)
+       +$(call cmd,clean)
+endif
+ifneq ($(strip $(__clean-dirs)),)
+       +$(call cmd,cleandir)
+endif
+ifneq ($(strip $(clean-rule)),)
+       +$(clean-rule)
+endif
+       @:
+
+
+# ===========================================================================
+# Generic stuff
+# ===========================================================================
+
+# Descending
+# ---------------------------------------------------------------------------
+
+PHONY += $(subdir-ymn)
+$(subdir-ymn):
+       $(Q)$(MAKE) $(clean)=$@
+
+# If quiet is set, only print short version of command
+
+cmd = @$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))' &&) $(cmd_$(1))
+
+
+# Declare the contents of the .PHONY variable as phony.  We keep that
+# information in a variable se we can use it in if_changed and friends.
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.host b/scripts/Makefile.host
new file mode 100644 (file)
index 0000000..1ac414f
--- /dev/null
@@ -0,0 +1,170 @@
+# ==========================================================================
+# Building binaries on the host system
+# Binaries are used during the compilation of the kernel, for example
+# to preprocess a data file.
+#
+# Both C and C++ are supported, but preferred language is C for such utilities.
+#
+# Sample syntax (see Documentation/kbuild/makefiles.txt for reference)
+# hostprogs-y := bin2hex
+# Will compile bin2hex.c and create an executable named bin2hex
+#
+# hostprogs-y    := lxdialog
+# lxdialog-objs := checklist.o lxdialog.o
+# Will compile lxdialog.c and checklist.c, and then link the executable
+# lxdialog, based on checklist.o and lxdialog.o
+#
+# hostprogs-y      := qconf
+# qconf-cxxobjs   := qconf.o
+# qconf-objs      := menu.o
+# Will compile qconf as a C++ program, and menu as a C program.
+# They are linked as C++ code to the executable qconf
+
+# hostprogs-y := conf
+# conf-objs  := conf.o libkconfig.so
+# libkconfig-objs := expr.o type.o
+# Will create a shared library named libkconfig.so that consists of
+# expr.o and type.o (they are both compiled as C code and the object files
+# are made as position independent code).
+# conf.c is compiled as a C program, and conf.o is linked together with
+# libkconfig.so as the executable conf.
+# Note: Shared libraries consisting of C++ files are not supported
+
+__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m))
+
+# C code
+# Executables compiled from a single .c file
+host-csingle   := $(foreach m,$(__hostprogs),$(if $($(m)-objs),,$(m)))
+
+# C executables linked based on several .o files
+host-cmulti    := $(foreach m,$(__hostprogs),\
+                  $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m))))
+
+# Object (.o) files compiled from .c files
+host-cobjs     := $(sort $(foreach m,$(__hostprogs),$($(m)-objs)))
+
+# C++ code
+# C++ executables compiled from at least on .cc file
+# and zero or more .c files
+host-cxxmulti  := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m)))
+
+# C++ Object (.o) files compiled from .cc files
+host-cxxobjs   := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs)))
+
+# Shared libaries (only .c supported)
+# Shared libraries (.so) - all .so files referenced in "xxx-objs"
+host-cshlib    := $(sort $(filter %.so, $(host-cobjs)))
+# Remove .so files from "xxx-objs"
+host-cobjs     := $(filter-out %.so,$(host-cobjs))
+
+#Object (.o) files used by the shared libaries
+host-cshobjs   := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs))))
+
+# output directory for programs/.o files
+# hostprogs-y := tools/build may have been specified. Retrieve directory
+host-objdirs := $(foreach f,$(__hostprogs), $(if $(dir $(f)),$(dir $(f))))
+# directory of .o files from prog-objs notation
+host-objdirs += $(foreach f,$(host-cmulti),                  \
+                    $(foreach m,$($(f)-objs),                \
+                        $(if $(dir $(m)),$(dir $(m)))))
+# directory of .o files from prog-cxxobjs notation
+host-objdirs += $(foreach f,$(host-cxxmulti),                  \
+                    $(foreach m,$($(f)-cxxobjs),                \
+                        $(if $(dir $(m)),$(dir $(m)))))
+
+host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs))))
+
+
+__hostprogs     := $(addprefix $(obj)/,$(__hostprogs))
+host-csingle   := $(addprefix $(obj)/,$(host-csingle))
+host-cmulti    := $(addprefix $(obj)/,$(host-cmulti))
+host-cobjs     := $(addprefix $(obj)/,$(host-cobjs))
+host-cxxmulti  := $(addprefix $(obj)/,$(host-cxxmulti))
+host-cxxobjs   := $(addprefix $(obj)/,$(host-cxxobjs))
+host-cshlib    := $(addprefix $(obj)/,$(host-cshlib))
+host-cshobjs   := $(addprefix $(obj)/,$(host-cshobjs))
+host-objdirs    := $(addprefix $(obj)/,$(host-objdirs))
+
+obj-dirs += $(host-objdirs)
+
+#####
+# Handle options to gcc. Support building with separate output directory
+
+_hostc_flags   = $(HOSTCFLAGS)   $(HOST_EXTRACFLAGS)   \
+                 $(HOSTCFLAGS_$(basetarget).o)
+_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \
+                 $(HOSTCXXFLAGS_$(basetarget).o)
+
+ifeq ($(KBUILD_SRC),)
+__hostc_flags  = $(_hostc_flags)
+__hostcxx_flags        = $(_hostcxx_flags)
+else
+__hostc_flags  = -I$(obj) $(call flags,_hostc_flags)
+__hostcxx_flags        = -I$(obj) $(call flags,_hostcxx_flags)
+endif
+
+hostc_flags    = -Wp,-MD,$(depfile) $(__hostc_flags)
+hostcxx_flags  = -Wp,-MD,$(depfile) $(__hostcxx_flags)
+
+#####
+# Compile programs on the host
+
+# Create executable from a single .c file
+# host-csingle -> Executable
+quiet_cmd_host-csingle         = HOSTCC  $@
+      cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \
+               $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-csingle): $(obj)/%: $(src)/%.c FORCE
+       $(call if_changed_dep,host-csingle)
+
+# Link an executable based on list of .o files, all plain c
+# host-cmulti -> executable
+quiet_cmd_host-cmulti  = HOSTLD  $@
+      cmd_host-cmulti  = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \
+                         $(addprefix $(obj)/,$($(@F)-objs)) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cmulti): $(obj)/%: $(host-cobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cmulti)
+
+# Create .o file from a single .c file
+# host-cobjs -> .o
+quiet_cmd_host-cobjs   = HOSTCC  $@
+      cmd_host-cobjs   = $(HOSTCC) $(hostc_flags) -c -o $@ $<
+$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE
+       $(call if_changed_dep,host-cobjs)
+
+# Link an executable based on list of .o files, a mixture of .c and .cc
+# host-cxxmulti -> executable
+quiet_cmd_host-cxxmulti        = HOSTLD  $@
+      cmd_host-cxxmulti        = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \
+                         $(foreach o,objs cxxobjs,\
+                         $(addprefix $(obj)/,$($(@F)-$(o)))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cxxmulti): $(obj)/%: $(host-cobjs) $(host-cxxobjs) $(host-cshlib) FORCE
+       $(call if_changed,host-cxxmulti)
+
+# Create .o file from a single .cc (C++) file
+quiet_cmd_host-cxxobjs = HOSTCXX $@
+      cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $<
+$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE
+       $(call if_changed_dep,host-cxxobjs)
+
+# Compile .c file, create position independent .o file
+# host-cshobjs -> .o
+quiet_cmd_host-cshobjs = HOSTCC  -fPIC $@
+      cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $<
+$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE
+       $(call if_changed_dep,host-cshobjs)
+
+# Link a shared library, based on position independent .o files
+# *.o -> .so shared library (host-cshlib)
+quiet_cmd_host-cshlib  = HOSTLLD -shared $@
+      cmd_host-cshlib  = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \
+                         $(addprefix $(obj)/,$($(@F:.so=-objs))) \
+                         $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F))
+$(host-cshlib): $(obj)/%: $(host-cshobjs) FORCE
+       $(call if_changed,host-cshlib)
+
+targets += $(host-csingle)  $(host-cmulti) $(host-cobjs)\
+          $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) 
+
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
new file mode 100644 (file)
index 0000000..f9bdf26
--- /dev/null
@@ -0,0 +1,247 @@
+# Backward compatibility
+asflags-y  += $(EXTRA_AFLAGS)
+ccflags-y  += $(EXTRA_CFLAGS)
+cppflags-y += $(EXTRA_CPPFLAGS)
+ldflags-y  += $(EXTRA_LDFLAGS)
+
+#
+# flags that take effect in sub directories
+export KBUILD_SUBDIR_ASFLAGS := $(KBUILD_SUBDIR_ASFLAGS) $(subdir-asflags-y)
+export KBUILD_SUBDIR_CCFLAGS := $(KBUILD_SUBDIR_CCFLAGS) $(subdir-ccflags-y)
+
+# Figure out what we need to build from the various variables
+# ===========================================================================
+
+# When an object is listed to be built compiled-in and modular,
+# only build the compiled-in version
+
+obj-m := $(filter-out $(obj-y),$(obj-m))
+
+# Libraries are always collected in one lib file.
+# Filter out objects already built-in
+
+lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
+
+
+# Handle objects in subdirs
+# ---------------------------------------------------------------------------
+# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o
+#   and add the directory to the list of dirs to descend into: $(subdir-y)
+# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) 
+#   and add the directory to the list of dirs to descend into: $(subdir-m)
+
+# Determine modorder.
+# Unfortunately, we don't have information about ordering between -y
+# and -m subdirs.  Just put -y's first.
+modorder       := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko))
+
+__subdir-y     := $(patsubst %/,%,$(filter %/, $(obj-y)))
+subdir-y       += $(__subdir-y)
+__subdir-m     := $(patsubst %/,%,$(filter %/, $(obj-m)))
+subdir-m       += $(__subdir-m)
+obj-y          := $(patsubst %/, %/built-in.o, $(obj-y))
+obj-m          := $(filter-out %/, $(obj-m))
+
+# Subdirectories we need to descend into
+
+subdir-ym      := $(sort $(subdir-y) $(subdir-m))
+
+# if $(foo-objs) exists, foo.o is a composite object 
+multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
+multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m))))
+multi-used   := $(multi-used-y) $(multi-used-m)
+single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m)))
+
+# Build list of the parts of our composite objects, our composite
+# objects depend on those (obviously)
+multi-objs-y := $(foreach m, $(multi-used-y), $($(m:.o=-objs)) $($(m:.o=-y)))
+multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y)))
+multi-objs   := $(multi-objs-y) $(multi-objs-m)
+
+# $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to
+# tell kbuild to descend
+subdir-obj-y := $(filter %/built-in.o, $(obj-y))
+
+# $(obj-dirs) is a list of directories that contain object files
+obj-dirs := $(dir $(multi-objs) $(subdir-obj-y))
+
+# Replace multi-part objects by their individual parts, look at local dir only
+real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y)
+real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m)))
+
+# Add subdir path
+
+extra-y                := $(addprefix $(obj)/,$(extra-y))
+always         := $(addprefix $(obj)/,$(always))
+targets                := $(addprefix $(obj)/,$(targets))
+modorder       := $(addprefix $(obj)/,$(modorder))
+obj-y          := $(addprefix $(obj)/,$(obj-y))
+obj-m          := $(addprefix $(obj)/,$(obj-m))
+lib-y          := $(addprefix $(obj)/,$(lib-y))
+subdir-obj-y   := $(addprefix $(obj)/,$(subdir-obj-y))
+real-objs-y    := $(addprefix $(obj)/,$(real-objs-y))
+real-objs-m    := $(addprefix $(obj)/,$(real-objs-m))
+single-used-m  := $(addprefix $(obj)/,$(single-used-m))
+multi-used-y   := $(addprefix $(obj)/,$(multi-used-y))
+multi-used-m   := $(addprefix $(obj)/,$(multi-used-m))
+multi-objs-y   := $(addprefix $(obj)/,$(multi-objs-y))
+multi-objs-m   := $(addprefix $(obj)/,$(multi-objs-m))
+subdir-ym      := $(addprefix $(obj)/,$(subdir-ym))
+obj-dirs       := $(addprefix $(obj)/,$(obj-dirs))
+
+# These flags are needed for modversions and compiling, so we define them here
+# already
+# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will 
+# end up in (or would, if it gets compiled in)
+# Note: It's possible that one object gets potentially linked into more
+#       than one module. In that case KBUILD_MODNAME will be set to foo_bar,
+#       where foo and bar are the name of the modules.
+name-fix = $(subst $(comma),_,$(subst -,_,$1))
+basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
+modname_flags  = $(if $(filter 1,$(words $(modname))),\
+                 -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
+
+#hash values
+ifdef CONFIG_DYNAMIC_DEBUG
+debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
+              -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
+else
+debug_flags =
+endif
+
+orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
+                 $(ccflags-y) $(CFLAGS_$(basetarget).o)
+_c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
+_a_flags       = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \
+                 $(asflags-y) $(AFLAGS_$(basetarget).o)
+_cpp_flags     = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F))
+
+#
+# Enable gcov profiling flags for a file, directory or for all files depending
+# on variables GCOV_PROFILE_obj.o, GCOV_PROFILE and CONFIG_GCOV_PROFILE_ALL
+# (in this order)
+#
+ifeq ($(CONFIG_GCOV_KERNEL),y)
+_c_flags += $(if $(patsubst n%,, \
+               $(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \
+               $(CFLAGS_GCOV))
+endif
+
+ifdef CONFIG_SYMBOL_PREFIX
+_cpp_flags += -DSYMBOL_PREFIX=$(patsubst "%",%,$(CONFIG_SYMBOL_PREFIX))
+endif
+
+
+# If building the kernel in a separate objtree expand all occurrences
+# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/').
+
+ifeq ($(KBUILD_SRC),)
+__c_flags      = $(_c_flags)
+__a_flags      = $(_a_flags)
+__cpp_flags     = $(_cpp_flags)
+else
+
+# -I$(obj) locates generated .h files
+# $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files
+#   and locates generated .h files
+# FIXME: Replace both with specific CFLAGS* statements in the makefiles
+__c_flags      = $(call addtree,-I$(obj)) $(call flags,_c_flags)
+__a_flags      =                          $(call flags,_a_flags)
+__cpp_flags     =                          $(call flags,_cpp_flags)
+endif
+
+c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
+                $(__c_flags) $(modkern_cflags)                           \
+                -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
+                 $(debug_flags)
+
+a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
+                $(__a_flags) $(modkern_aflags)
+
+cpp_flags      = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
+                $(__cpp_flags)
+
+ld_flags       = $(LDFLAGS) $(ldflags-y)
+
+# Finds the multi-part object the current object will be linked into
+modname-multi = $(sort $(foreach m,$(multi-used),\
+               $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=))))
+
+# Shipped files
+# ===========================================================================
+
+quiet_cmd_shipped = SHIPPED $@
+cmd_shipped = cat $< > $@
+
+$(obj)/%:: $(src)/%_shipped
+       $(call cmd,shipped)
+
+# Commands useful for building a boot image
+# ===========================================================================
+# 
+#      Use as following:
+#
+#      target: source(s) FORCE
+#              $(if_changed,ld/objcopy/gzip)
+#
+#      and add target to extra-y so that we know we have to
+#      read in the saved command line
+
+# Linking
+# ---------------------------------------------------------------------------
+
+quiet_cmd_ld = LD      $@
+cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \
+              $(filter-out FORCE,$^) -o $@ 
+
+# Objcopy
+# ---------------------------------------------------------------------------
+
+quiet_cmd_objcopy = OBJCOPY $@
+cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@
+
+# Gzip
+# ---------------------------------------------------------------------------
+
+quiet_cmd_gzip = GZIP    $@
+cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -f -9 > $@) || \
+       (rm -f $@ ; false)
+
+
+# Bzip2
+# ---------------------------------------------------------------------------
+
+# Bzip2 and LZMA do not include size in file... so we have to fake that;
+# append the size as a 32-bit littleendian number as gzip does.
+size_append = printf $(shell                                           \
+dec_size=0;                                                            \
+for F in $1; do                                                                \
+       fsize=$$(stat -c "%s" $$F);                                     \
+       dec_size=$$(expr $$dec_size + $$fsize);                         \
+done;                                                                  \
+printf "%08x\n" $$dec_size |                                           \
+       sed 's/\(..\)/\1 /g' | {                                        \
+               read ch0 ch1 ch2 ch3;                                   \
+               for ch in $$ch3 $$ch2 $$ch1 $$ch0; do                   \
+                       printf '%s%03o' '\\' $$((0x$$ch));              \
+               done;                                                   \
+       }                                                               \
+)
+
+quiet_cmd_bzip2 = BZIP2   $@
+cmd_bzip2 = (cat $(filter-out FORCE,$^) | \
+       bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+       (rm -f $@ ; false)
+
+# Lzma
+# ---------------------------------------------------------------------------
+
+quiet_cmd_lzma = LZMA    $@
+cmd_lzma = (cat $(filter-out FORCE,$^) | \
+       lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+       (rm -f $@ ; false)
+
+quiet_cmd_lzo = LZO    $@
+cmd_lzo = (cat $(filter-out FORCE,$^) | \
+       lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
+       (rm -f $@ ; false)
diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile
new file mode 100644 (file)
index 0000000..4f576cc
--- /dev/null
@@ -0,0 +1,16 @@
+###
+# Makefile.basic lists the most basic programs used during the build process.
+# The programs listed herein are what are needed to do the basic stuff,
+# such as fix file dependencies.
+# This initial step is needed to avoid files to be recompiled
+# when kernel configuration changes (which is what happens when
+# .config is included by main Makefile.
+# ---------------------------------------------------------------------------
+# fixdep:       Used to generate dependency information during build process
+# docproc:      Used in Documentation/DocBook
+
+hostprogs-y    := fixdep
+always         := $(hostprogs-y)
+
+# fixdep is needed to compile other host programs
+$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
new file mode 100644 (file)
index 0000000..ea26b23
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD
+ * for the kernel build
+ * ===========================================================================
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * Introduction:
+ *
+ * gcc produces a very nice and correct list of dependencies which
+ * tells make when to remake a file.
+ *
+ * To use this list as-is however has the drawback that virtually
+ * every file in the kernel includes autoconf.h.
+ *
+ * If the user re-runs make *config, autoconf.h will be
+ * regenerated.  make notices that and will rebuild every file which
+ * includes autoconf.h, i.e. basically all files. This is extremely
+ * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
+ *
+ * So we play the same trick that "mkdep" played before. We replace
+ * the dependency on autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *
+ * kconfig populates a tree in include/config/ with an empty file
+ * for each config symbol and when the configuration is updated
+ * the files representing changed config options are touched
+ * which then let make pick up the changes and the files that use
+ * the config symbols are rebuilt.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+ * so most likely only his driver ;-)
+ *
+ * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
+ *
+ * So to get dependencies right, there are two issues:
+ * o if any of the files the compiler read changed, we need to rebuild
+ * o if the command line given to the compile the file changed, we
+ *   better rebuild as well.
+ *
+ * The former is handled by using the -MD output, the later by saving
+ * the command line used to compile the old object and comparing it
+ * to the one we would now use.
+ *
+ * Again, also this idea is pretty old and has been discussed on
+ * kbuild-devel a long time ago. I don't have a sensibly working
+ * internet connection right now, so I rather don't mention names
+ * without double checking.
+ *
+ * This code here has been based partially based on mkdep.c, which
+ * says the following about its history:
+ *
+ *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ *   This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ *
+ * It is invoked as
+ *
+ *   fixdep <depfile> <target> <cmdline>
+ *
+ * and will read the dependency file <depfile>
+ *
+ * The transformed dependency snipped is written to stdout.
+ *
+ * It first generates a line
+ *
+ *   cmd_<target> = <cmdline>
+ *
+ * and then basically copies the .<target>.d file to stdout, in the
+ * process filtering out the dependency on autoconf.h and adding
+ * dependencies on include/config/my/option.h for every
+ * CONFIG_MY_OPTION encountered in any of the prequisites.
+ *
+ * It will also filter out all the dependencies on *.ver. We need
+ * to make sure that the generated version checksum are globally up
+ * to date before even starting the recursive build, so it's too late
+ * at this point anyway.
+ *
+ * The algorithm to grep for "CONFIG_..." is bit unusual, but should
+ * be fast ;-) We don't even try to really parse the header files, but
+ * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
+ * be picked up as well. It's not a problem with respect to
+ * correctness, since that can only give too many dependencies, thus
+ * we cannot miss a rebuild. Since people tend to not mention totally
+ * unrelated CONFIG_ options all over the place, it's not an
+ * efficiency problem either.
+ *
+ * (Note: it'd be easy to port over the complete mkdep state machine,
+ *  but I don't think the added complexity is worth it)
+ */
+/*
+ * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
+ * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
+ * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
+ * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
+ * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
+ * those files will have correct dependencies.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <arpa/inet.h>
+
+#define INT_CONF ntohl(0x434f4e46)
+#define INT_ONFI ntohl(0x4f4e4649)
+#define INT_NFIG ntohl(0x4e464947)
+#define INT_FIG_ ntohl(0x4649475f)
+
+char *target;
+char *depfile;
+char *cmdline;
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: fixdep <depfile> <target> <cmdline>\n");
+       exit(1);
+}
+
+/*
+ * Print out the commandline prefixed with cmd_<target filename> :=
+ */
+static void print_cmdline(void)
+{
+       printf("cmd_%s := %s\n\n", target, cmdline);
+}
+
+char * str_config  = NULL;
+int    size_config = 0;
+int    len_config  = 0;
+
+/*
+ * Grow the configuration string to a desired length.
+ * Usually the first growth is plenty.
+ */
+static void grow_config(int len)
+{
+       while (len_config + len > size_config) {
+               if (size_config == 0)
+                       size_config = 2048;
+               str_config = realloc(str_config, size_config *= 2);
+               if (str_config == NULL)
+                       { perror("fixdep:malloc"); exit(1); }
+       }
+}
+
+
+
+/*
+ * Lookup a value in the configuration string.
+ */
+static int is_defined_config(const char * name, int len)
+{
+       const char * pconfig;
+       const char * plast = str_config + len_config - len;
+       for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
+               if (pconfig[ -1] == '\n'
+               &&  pconfig[len] == '\n'
+               &&  !memcmp(pconfig, name, len))
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ * Add a new value to the configuration string.
+ */
+static void define_config(const char * name, int len)
+{
+       grow_config(len + 1);
+
+       memcpy(str_config+len_config, name, len);
+       len_config += len;
+       str_config[len_config++] = '\n';
+}
+
+/*
+ * Clear the set of configuration strings.
+ */
+static void clear_config(void)
+{
+       len_config = 0;
+       define_config("", 0);
+}
+
+/*
+ * Record the use of a CONFIG_* word.
+ */
+static void use_config(char *m, int slen)
+{
+       char s[PATH_MAX];
+       char *p;
+
+       if (is_defined_config(m, slen))
+           return;
+
+       define_config(m, slen);
+
+       memcpy(s, m, slen); s[slen] = 0;
+
+       for (p = s; p < s + slen; p++) {
+               if (*p == '_')
+                       *p = '/';
+               else
+                       *p = tolower((int)*p);
+       }
+       printf("    $(wildcard include/config/%s.h) \\\n", s);
+}
+
+static void parse_config_file(char *map, size_t len)
+{
+       int *end = (int *) (map + len);
+       /* start at +1, so that p can never be < map */
+       int *m   = (int *) map + 1;
+       char *p, *q;
+
+       for (; m < end; m++) {
+               if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+               if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+               if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+               if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
+               continue;
+       conf:
+               if (p > map + len - 7)
+                       continue;
+               if (memcmp(p, "CONFIG_", 7))
+                       continue;
+               for (q = p + 7; q < map + len; q++) {
+                       if (!(isalnum(*q) || *q == '_'))
+                               goto found;
+               }
+               continue;
+
+       found:
+               if (!memcmp(q - 7, "_MODULE", 7))
+                       q -= 7;
+               if( (q-p-7) < 0 )
+                       continue;
+               use_config(p+7, q-p-7);
+       }
+}
+
+/* test is s ends in sub */
+static int strrcmp(char *s, char *sub)
+{
+       int slen = strlen(s);
+       int sublen = strlen(sub);
+
+       if (sublen > slen)
+               return 1;
+
+       return memcmp(s + slen - sublen, sub, sublen);
+}
+
+static void do_config_file(char *filename)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "fixdep: ");
+               perror(filename);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("fixdep: mmap");
+               close(fd);
+               return;
+       }
+
+       parse_config_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+}
+
+static void parse_dep_file(void *map, size_t len)
+{
+       char *m = map;
+       char *end = m + len;
+       char *p;
+       char s[PATH_MAX];
+
+       p = strchr(m, ':');
+       if (!p) {
+               fprintf(stderr, "fixdep: parse error\n");
+               exit(1);
+       }
+       memcpy(s, m, p-m); s[p-m] = 0;
+       printf("deps_%s := \\\n", target);
+       m = p+1;
+
+       clear_config();
+
+       while (m < end) {
+               while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+                       m++;
+               p = m;
+               while (p < end && *p != ' ') p++;
+               if (p == end) {
+                       do p--; while (!isalnum(*p));
+                       p++;
+               }
+               memcpy(s, m, p-m); s[p-m] = 0;
+               if (strrcmp(s, "include/generated/autoconf.h") &&
+                   strrcmp(s, "arch/um/include/uml-config.h") &&
+                   strrcmp(s, ".ver")) {
+                       printf("  %s \\\n", s);
+                       do_config_file(s);
+               }
+               m = p + 1;
+       }
+       printf("\n%s: $(deps_%s)\n\n", target, target);
+       printf("$(deps_%s):\n", target);
+}
+
+static void print_deps(void)
+{
+       struct stat st;
+       int fd;
+       void *map;
+
+       fd = open(depfile, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "fixdep: ");
+               perror(depfile);
+               exit(2);
+       }
+       fstat(fd, &st);
+       if (st.st_size == 0) {
+               fprintf(stderr,"fixdep: %s is empty\n",depfile);
+               close(fd);
+               return;
+       }
+       map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if ((long) map == -1) {
+               perror("fixdep: mmap");
+               close(fd);
+               return;
+       }
+
+       parse_dep_file(map, st.st_size);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+}
+
+static void traps(void)
+{
+       static char test[] __attribute__((aligned(sizeof(int)))) = "CONF";
+       int *p = (int *)test;
+
+       if (*p != INT_CONF) {
+               fprintf(stderr, "fixdep: sizeof(int) != 4 or wrong endianess? %#x\n",
+                       *p);
+               exit(2);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       traps();
+
+       if (argc != 4)
+               usage();
+
+       depfile = argv[1];
+       target = argv[2];
+       cmdline = argv[3];
+
+       print_cmdline();
+       print_deps();
+
+       return 0;
+}
diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore
new file mode 100644 (file)
index 0000000..624f650
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# Generated files
+#
+config*
+lex.*.c
+*.tab.c
+*.tab.h
+zconf.hash.c
+*.moc
+lkc_defs.h
+gconf.glade.h
+*.pot
+*.mo
+
+#
+# configuration programs
+#
+conf
+mconf
+nconf
+qconf
+gconf
+kxgettext
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
new file mode 100644 (file)
index 0000000..3657e1a
--- /dev/null
@@ -0,0 +1,203 @@
+# ===========================================================================
+# Kernel configuration targets
+# These targets are used from top-level makefile
+
+PHONY += oldconfig xconfig gconfig menuconfig config
+
+xconfig: $(obj)/qconf
+
+gconfig: $(obj)/gconf
+
+menuconfig: $(obj)/mconf
+
+config: $(obj)/conf
+
+nconfig: $(obj)/nconf
+
+# lxdialog stuff
+check-lxdialog  := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
+
+# 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)
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \
+                    -DLOCALE
+
+# ===========================================================================
+# Shared Makefile for the various kconfig executables:
+# conf:          Used for defconfig, oldconfig and related targets
+# nconf:  Used for the nconfig target.
+#         Utilizes ncurses
+# mconf:  Used for the menuconfig target
+#         Utilizes the lxdialog package
+# qconf:  Used for the xconfig target
+#         Based on QT which needs to be installed to compile it
+# gconf:  Used for the gconfig target
+#         Based on GTK which needs to be installed to compile it
+# object files used by all kconfig flavours
+
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
+conf-objs      := conf.o  zconf.tab.o
+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
+
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),nconfig)
+       hostprogs-y += nconf
+endif
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+       hostprogs-y += mconf
+endif
+
+ifeq ($(MAKECMDGOALS),xconfig)
+       qconf-target := 1
+endif
+ifeq ($(MAKECMDGOALS),gconfig)
+       gconf-target := 1
+endif
+
+
+ifeq ($(qconf-target),1)
+qconf-cxxobjs  := qconf.o
+qconf-objs     := kconfig_load.o zconf.tab.o
+endif
+
+ifeq ($(gconf-target),1)
+gconf-objs     := gconf.o kconfig_load.o zconf.tab.o
+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 nconf
+clean-files     += config.pot linux.pot
+
+# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
+PHONY += $(obj)/dochecklxdialog
+$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog
+$(obj)/dochecklxdialog:
+       $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf)
+
+always := dochecklxdialog
+
+# Add environment specific flags
+HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS))
+
+# generated files seem to need this to find local include files
+HOSTCFLAGS_lex.zconf.o := -I$(src)
+HOSTCFLAGS_zconf.tab.o := -I$(src)
+
+HOSTLOADLIBES_qconf    = $(KC_QT_LIBS) -ldl
+HOSTCXXFLAGS_qconf.o   = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_gconf    = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
+HOSTCFLAGS_gconf.o     = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
+                          -D LKC_DIRECT_LINK
+
+HOSTLOADLIBES_mconf   = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOSTLOADLIBES_nconf    = -lmenu -lpanel -lncurses
+$(obj)/qconf.o: $(obj)/.tmp_qtcheck
+
+ifeq ($(qconf-target),1)
+$(obj)/.tmp_qtcheck: $(src)/Makefile
+-include $(obj)/.tmp_qtcheck
+
+# QT needs some extra effort...
+$(obj)/.tmp_qtcheck:
+       @set -e; echo "  CHECK   qt"; dir=""; pkg=""; \
+       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 "*"; \
+               echo "* Unable to find any QT installation. Please make sure that"; \
+               echo "* the QT4 or QT3 development package is correctly installed and"; \
+               echo "* either qmake can be found or install pkg-config or set"; \
+               echo "* the QTDIR environment 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"; \
+           fi; \
+       else \
+         cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
+         libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
+         binpath="\$$(shell pkg-config QtCore --variable=prefix)"; \
+         moc="$$binpath/bin/moc"; \
+       fi; \
+       echo "KC_QT_CFLAGS=$$cflags" > $@; \
+       echo "KC_QT_LIBS=$$libs" >> $@; \
+       echo "KC_QT_MOC=$$moc" >> $@
+endif
+
+$(obj)/gconf.o: $(obj)/.tmp_gtkcheck
+
+ifeq ($(gconf-target),1)
+-include $(obj)/.tmp_gtkcheck
+
+# GTK needs some extra effort, too...
+$(obj)/.tmp_gtkcheck:
+       @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then               \
+               if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then                  \
+                       touch $@;                                                               \
+               else                                                                    \
+                       echo "*";                                                       \
+                       echo "* GTK+ is present but version >= 2.0.0 is required.";     \
+                       echo "*";                                                       \
+                       false;                                                          \
+               fi                                                                      \
+       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 "*";                                                               \
+               false;                                                                  \
+       fi
+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)/gconf.o: $(obj)/lkc_defs.h
+
+$(obj)/%.moc: $(src)/%.h
+       $(KC_QT_MOC) -i $< -o $@
+
+$(obj)/lkc_defs.h: $(src)/lkc_proto.h
+       sed < $< > $@ 's/P(\([^,]*\),.*/#define \1 (\*\1_p)/'
+
+# Extract gconf menu items for I18N support
+$(obj)/gconf.glade.h: $(obj)/gconf.glade
+       intltool-extract --type=gettext/glade $(obj)/gconf.glade
+
diff --git a/scripts/kconfig/POTFILES.in b/scripts/kconfig/POTFILES.in
new file mode 100644 (file)
index 0000000..9674573
--- /dev/null
@@ -0,0 +1,12 @@
+scripts/kconfig/lxdialog/checklist.c
+scripts/kconfig/lxdialog/inputbox.c
+scripts/kconfig/lxdialog/menubox.c
+scripts/kconfig/lxdialog/textbox.c
+scripts/kconfig/lxdialog/util.c
+scripts/kconfig/lxdialog/yesno.c
+scripts/kconfig/mconf.c
+scripts/kconfig/conf.c
+scripts/kconfig/confdata.c
+scripts/kconfig/gconf.c
+scripts/kconfig/gconf.glade.h
+scripts/kconfig/qconf.cc
diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh
new file mode 100755 (executable)
index 0000000..fa59cbf
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+# Needed for systems without gettext
+$* -xc -o /dev/null - > /dev/null 2>&1 << EOF
+#include <libintl.h>
+int main()
+{
+       gettext("");
+       return 0;
+}
+EOF
+if [ ! "$?" -eq "0"  ]; then
+       echo -DKBUILD_NO_NLS;
+fi
+
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
new file mode 100644 (file)
index 0000000..659326c
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <locale.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf(struct menu *menu);
+static void check_conf(struct menu *menu);
+
+enum input_mode {
+       oldaskconfig,
+       silentoldconfig,
+       oldconfig,
+       allnoconfig,
+       allyesconfig,
+       allmodconfig,
+       alldefconfig,
+       randconfig,
+       defconfig,
+       savedefconfig,
+       listnewconfig,
+       oldnoconfig,
+} input_mode = oldaskconfig;
+
+char *defconfig_file;
+
+static int indent = 1;
+static int valid_stdin = 1;
+static int sync_kconfig;
+static int conf_cnt;
+static char line[128];
+static struct menu *rootEntry;
+
+static void print_help(struct menu *menu)
+{
+       struct gstr help = str_new();
+
+       menu_get_ext_help(menu, &help);
+
+       printf("\n%s\n", str_get(&help));
+       str_free(&help);
+}
+
+static void strip(char *str)
+{
+       char *p = str;
+       int l;
+
+       while ((isspace(*p)))
+               p++;
+       l = strlen(p);
+       if (p != str)
+               memmove(str, p, l + 1);
+       if (!l)
+               return;
+       p = str + l - 1;
+       while ((isspace(*p)))
+               *p-- = 0;
+}
+
+static void check_stdin(void)
+{
+       if (!valid_stdin) {
+               printf(_("aborted!\n\n"));
+               printf(_("Console input/output is redirected. "));
+               printf(_("Run 'make oldconfig' to update configuration.\n\n"));
+               exit(1);
+       }
+}
+
+static int conf_askvalue(struct symbol *sym, const char *def)
+{
+       enum symbol_type type = sym_get_type(sym);
+
+       if (!sym_has_value(sym))
+               printf(_("(NEW) "));
+
+       line[0] = '\n';
+       line[1] = 0;
+
+       if (!sym_is_changable(sym)) {
+               printf("%s\n", def);
+               line[0] = '\n';
+               line[1] = 0;
+               return 0;
+       }
+
+       switch (input_mode) {
+       case oldconfig:
+       case silentoldconfig:
+               if (sym_has_value(sym)) {
+                       printf("%s\n", def);
+                       return 0;
+               }
+               check_stdin();
+       case oldaskconfig:
+               fflush(stdout);
+               xfgets(line, 128, stdin);
+               return 1;
+       default:
+               break;
+       }
+
+       switch (type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               printf("%s\n", def);
+               return 1;
+       default:
+               ;
+       }
+       printf("%s", line);
+       return 1;
+}
+
+static int conf_string(struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       const char *def;
+
+       while (1) {
+               printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+               printf("(%s) ", sym->name);
+               def = sym_get_string_value(sym);
+               if (sym_get_string_value(sym))
+                       printf("[%s] ", def);
+               if (!conf_askvalue(sym, def))
+                       return 0;
+               switch (line[0]) {
+               case '\n':
+                       break;
+               case '?':
+                       /* print help */
+                       if (line[1] == '\n') {
+                               print_help(menu);
+                               def = NULL;
+                               break;
+                       }
+               default:
+                       line[strlen(line)-1] = 0;
+                       def = line;
+               }
+               if (def && sym_set_string_value(sym, def))
+                       return 0;
+       }
+}
+
+static int conf_sym(struct menu *menu)
+{
+       struct symbol *sym = menu->sym;
+       tristate oldval, newval;
+
+       while (1) {
+               printf("%*s%s ", indent - 1, "", _(menu->prompt->text));
+               if (sym->name)
+                       printf("(%s) ", sym->name);
+               putchar('[');
+               oldval = sym_get_tristate_value(sym);
+               switch (oldval) {
+               case no:
+                       putchar('N');
+                       break;
+               case mod:
+                       putchar('M');
+                       break;
+               case yes:
+                       putchar('Y');
+                       break;
+               }
+               if (oldval != no && sym_tristate_within_range(sym, no))
+                       printf("/n");
+               if (oldval != mod && sym_tristate_within_range(sym, mod))
+                       printf("/m");
+               if (oldval != yes && sym_tristate_within_range(sym, yes))
+                       printf("/y");
+               if (menu_has_help(menu))
+                       printf("/?");
+               printf("] ");
+               if (!conf_askvalue(sym, sym_get_string_value(sym)))
+                       return 0;
+               strip(line);
+
+               switch (line[0]) {
+               case 'n':
+               case 'N':
+                       newval = no;
+                       if (!line[1] || !strcmp(&line[1], "o"))
+                               break;
+                       continue;
+               case 'm':
+               case 'M':
+                       newval = mod;
+                       if (!line[1])
+                               break;
+                       continue;
+               case 'y':
+               case 'Y':
+                       newval = yes;
+                       if (!line[1] || !strcmp(&line[1], "es"))
+                               break;
+                       continue;
+               case 0:
+                       newval = oldval;
+                       break;
+               case '?':
+                       goto help;
+               default:
+                       continue;
+               }
+               if (sym_set_tristate_value(sym, newval))
+                       return 0;
+help:
+               print_help(menu);
+       }
+}
+
+static int conf_choice(struct menu *menu)
+{
+       struct symbol *sym, *def_sym;
+       struct menu *child;
+       bool is_new;
+
+       sym = menu->sym;
+       is_new = !sym_has_value(sym);
+       if (sym_is_changable(sym)) {
+               conf_sym(menu);
+               sym_calc_value(sym);
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       return 1;
+               case mod:
+                       return 0;
+               case yes:
+                       break;
+               }
+       } else {
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       return 1;
+               case mod:
+                       printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+                       return 0;
+               case yes:
+                       break;
+               }
+       }
+
+       while (1) {
+               int cnt, def;
+
+               printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu)));
+               def_sym = sym_get_choice_value(sym);
+               cnt = def = 0;
+               line[0] = 0;
+               for (child = menu->list; child; child = child->next) {
+                       if (!menu_is_visible(child))
+                               continue;
+                       if (!child->sym) {
+                               printf("%*c %s\n", indent, '*', _(menu_get_prompt(child)));
+                               continue;
+                       }
+                       cnt++;
+                       if (child->sym == def_sym) {
+                               def = cnt;
+                               printf("%*c", indent, '>');
+                       } else
+                               printf("%*c", indent, ' ');
+                       printf(" %d. %s", cnt, _(menu_get_prompt(child)));
+                       if (child->sym->name)
+                               printf(" (%s)", child->sym->name);
+                       if (!sym_has_value(child->sym))
+                               printf(_(" (NEW)"));
+                       printf("\n");
+               }
+               printf(_("%*schoice"), indent - 1, "");
+               if (cnt == 1) {
+                       printf("[1]: 1\n");
+                       goto conf_childs;
+               }
+               printf("[1-%d", cnt);
+               if (menu_has_help(menu))
+                       printf("?");
+               printf("]: ");
+               switch (input_mode) {
+               case oldconfig:
+               case silentoldconfig:
+                       if (!is_new) {
+                               cnt = def;
+                               printf("%d\n", cnt);
+                               break;
+                       }
+                       check_stdin();
+               case oldaskconfig:
+                       fflush(stdout);
+                       xfgets(line, 128, stdin);
+                       strip(line);
+                       if (line[0] == '?') {
+                               print_help(menu);
+                               continue;
+                       }
+                       if (!line[0])
+                               cnt = def;
+                       else if (isdigit(line[0]))
+                               cnt = atoi(line);
+                       else
+                               continue;
+                       break;
+               default:
+                       break;
+               }
+
+       conf_childs:
+               for (child = menu->list; child; child = child->next) {
+                       if (!child->sym || !menu_is_visible(child))
+                               continue;
+                       if (!--cnt)
+                               break;
+               }
+               if (!child)
+                       continue;
+               if (line[strlen(line) - 1] == '?') {
+                       print_help(child);
+                       continue;
+               }
+               sym_set_choice_value(sym, child->sym);
+               for (child = child->list; child; child = child->next) {
+                       indent += 2;
+                       conf(child);
+                       indent -= 2;
+               }
+               return 1;
+       }
+}
+
+static void conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       prop = menu->prompt;
+       if (prop) {
+               const char *prompt;
+
+               switch (prop->type) {
+               case P_MENU:
+                       if ((input_mode == silentoldconfig ||
+                            input_mode == listnewconfig ||
+                            input_mode == oldnoconfig) &&
+                           rootEntry != menu) {
+                               check_conf(menu);
+                               return;
+                       }
+               case P_COMMENT:
+                       prompt = menu_get_prompt(menu);
+                       if (prompt)
+                               printf("%*c\n%*c %s\n%*c\n",
+                                       indent, '*',
+                                       indent, '*', _(prompt),
+                                       indent, '*');
+               default:
+                       ;
+               }
+       }
+
+       if (!sym)
+               goto conf_childs;
+
+       if (sym_is_choice(sym)) {
+               conf_choice(menu);
+               if (sym->curr.tri != mod)
+                       return;
+               goto conf_childs;
+       }
+
+       switch (sym->type) {
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               conf_string(menu);
+               break;
+       default:
+               conf_sym(menu);
+               break;
+       }
+
+conf_childs:
+       if (sym)
+               indent += 2;
+       for (child = menu->list; child; child = child->next)
+               conf(child);
+       if (sym)
+               indent -= 2;
+}
+
+static void check_conf(struct menu *menu)
+{
+       struct symbol *sym;
+       struct menu *child;
+
+       if (!menu_is_visible(menu))
+               return;
+
+       sym = menu->sym;
+       if (sym && !sym_has_value(sym)) {
+               if (sym_is_changable(sym) ||
+                   (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
+                       if (input_mode == listnewconfig) {
+                               if (sym->name && !sym_is_choice_value(sym)) {
+                                       printf("%s%s\n", CONFIG_, sym->name);
+                               }
+                       } else if (input_mode != oldnoconfig) {
+                               if (!conf_cnt++)
+                                       printf(_("*\n* Restart config...\n*\n"));
+                               rootEntry = menu_get_parent_menu(menu);
+                               conf(rootEntry);
+                       }
+               }
+       }
+
+       for (child = menu->list; child; child = child->next)
+               check_conf(child);
+}
+
+static struct option long_opts[] = {
+       {"oldaskconfig",    no_argument,       NULL, oldaskconfig},
+       {"oldconfig",       no_argument,       NULL, oldconfig},
+       {"silentoldconfig", no_argument,       NULL, silentoldconfig},
+       {"defconfig",       optional_argument, NULL, defconfig},
+       {"savedefconfig",   required_argument, NULL, savedefconfig},
+       {"allnoconfig",     no_argument,       NULL, allnoconfig},
+       {"allyesconfig",    no_argument,       NULL, allyesconfig},
+       {"allmodconfig",    no_argument,       NULL, allmodconfig},
+       {"alldefconfig",    no_argument,       NULL, alldefconfig},
+       {"randconfig",      no_argument,       NULL, randconfig},
+       {"listnewconfig",   no_argument,       NULL, listnewconfig},
+       {"oldnoconfig",     no_argument,       NULL, oldnoconfig},
+       {NULL, 0, NULL, 0}
+};
+
+int main(int ac, char **av)
+{
+       int opt;
+       const char *name;
+       struct stat tmpstat;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+
+       while ((opt = getopt_long(ac, av, "", long_opts, NULL)) != -1) {
+               input_mode = (enum input_mode)opt;
+               switch (opt) {
+               case silentoldconfig:
+                       sync_kconfig = 1;
+                       break;
+               case defconfig:
+               case savedefconfig:
+                       defconfig_file = optarg;
+                       break;
+               case randconfig:
+               {
+                       struct timeval now;
+                       unsigned int seed;
+
+                       /*
+                        * Use microseconds derived seed,
+                        * compensate for systems where it may be zero
+                        */
+                       gettimeofday(&now, NULL);
+
+                       seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1));
+                       srand(seed);
+                       break;
+               }
+               case '?':
+                       fprintf(stderr, _("See README for usage info\n"));
+                       exit(1);
+                       break;
+               }
+       }
+       if (ac == optind) {
+               printf(_("%s: Kconfig file missing\n"), av[0]);
+               exit(1);
+       }
+       name = av[optind];
+       conf_parse(name);
+       //zconfdump(stdout);
+       if (sync_kconfig) {
+               name = conf_get_configname();
+               if (stat(name, &tmpstat)) {
+                       fprintf(stderr, _("***\n"
+                               "*** Configuration file \"%s\" not found!\n"
+                               "***\n"
+                               "*** Please run some configurator (e.g. \"make oldconfig\" or\n"
+                               "*** \"make menuconfig\" or \"make xconfig\").\n"
+                               "***\n"), name);
+                       exit(1);
+               }
+       }
+
+       switch (input_mode) {
+       case defconfig:
+               if (!defconfig_file)
+                       defconfig_file = conf_get_default_confname();
+               if (conf_read(defconfig_file)) {
+                       printf(_("***\n"
+                               "*** Can't find default configuration \"%s\"!\n"
+                               "***\n"), defconfig_file);
+                       exit(1);
+               }
+               break;
+       case savedefconfig:
+       case silentoldconfig:
+       case oldaskconfig:
+       case oldconfig:
+       case listnewconfig:
+       case oldnoconfig:
+               conf_read(NULL);
+               break;
+       case allnoconfig:
+       case allyesconfig:
+       case allmodconfig:
+       case alldefconfig:
+       case randconfig:
+               name = getenv("KCONFIG_ALLCONFIG");
+               if (name && !stat(name, &tmpstat)) {
+                       conf_read_simple(name, S_DEF_USER);
+                       break;
+               }
+               switch (input_mode) {
+               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;
+               }
+               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);
+               break;
+       default:
+               break;
+       }
+
+       if (sync_kconfig) {
+               if (conf_get_changed()) {
+                       name = getenv("KCONFIG_NOSILENTUPDATE");
+                       if (name && *name) {
+                               fprintf(stderr,
+                                       _("\n*** The configuration requires explicit update.\n\n"));
+                               return 1;
+                       }
+               }
+               valid_stdin = isatty(0) && isatty(1) && isatty(2);
+       }
+
+       switch (input_mode) {
+       case allnoconfig:
+               conf_set_all_new_symbols(def_no);
+               break;
+       case allyesconfig:
+               conf_set_all_new_symbols(def_yes);
+               break;
+       case allmodconfig:
+               conf_set_all_new_symbols(def_mod);
+               break;
+       case alldefconfig:
+               conf_set_all_new_symbols(def_default);
+               break;
+       case randconfig:
+               conf_set_all_new_symbols(def_random);
+               break;
+       case defconfig:
+               conf_set_all_new_symbols(def_default);
+               break;
+       case savedefconfig:
+               break;
+       case oldaskconfig:
+               rootEntry = &rootmenu;
+               conf(&rootmenu);
+               input_mode = silentoldconfig;
+               /* fall through */
+       case oldconfig:
+       case listnewconfig:
+       case oldnoconfig:
+       case silentoldconfig:
+               /* Update until a loop caused no more changes */
+               do {
+                       conf_cnt = 0;
+                       check_conf(&rootmenu);
+               } while (conf_cnt &&
+                        (input_mode != listnewconfig &&
+                         input_mode != oldnoconfig));
+               break;
+       }
+
+       if (sync_kconfig) {
+               /* silentoldconfig is used during the build so we shall update autoconf.
+                * All other commands are only used to generate a config.
+                */
+               if (conf_get_changed() && conf_write(NULL)) {
+                       fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+                       exit(1);
+               }
+               if (conf_write_autoconf()) {
+                       fprintf(stderr, _("\n*** Error during update of the configuration.\n\n"));
+                       return 1;
+               }
+       } else if (input_mode == savedefconfig) {
+               if (conf_write_defconfig(defconfig_file)) {
+                       fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"),
+                               defconfig_file);
+                       return 1;
+               }
+       } else if (input_mode != listnewconfig) {
+               if (conf_write(NULL)) {
+                       fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n"));
+                       exit(1);
+               }
+       }
+       return 0;
+}
+/*
+ * Helper function to facilitate fgets() by Jean Sacren.
+ */
+void xfgets(str, size, in)
+       char *str;
+       int size;
+       FILE *in;
+{
+       if (fgets(str, size, in) == NULL)
+               fprintf(stderr, "\nError in reading or end of file.\n");
+}
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
new file mode 100644 (file)
index 0000000..61c35bf
--- /dev/null
@@ -0,0 +1,1053 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static void conf_warning(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+static void conf_message(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+static const char *conf_filename;
+static int conf_lineno, conf_warnings, conf_unsaved;
+
+const char conf_defname[] = "arch/$ARCH/defconfig";
+
+static void conf_warning(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+       conf_warnings++;
+}
+
+static void conf_default_message_callback(const char *fmt, va_list ap)
+{
+       printf("#\n# ");
+       vprintf(fmt, ap);
+       printf("\n#\n");
+}
+
+static void (*conf_message_callback) (const char *fmt, va_list ap) =
+       conf_default_message_callback;
+void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap))
+{
+       conf_message_callback = fn;
+}
+
+static void conf_message(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       if (conf_message_callback)
+               conf_message_callback(fmt, ap);
+}
+
+const char *conf_get_configname(void)
+{
+       char *name = getenv("KCONFIG_CONFIG");
+
+       return name ? name : ".config";
+}
+
+const char *conf_get_autoconfig_name(void)
+{
+       char *name = getenv("KCONFIG_AUTOCONFIG");
+
+       return name ? name : "include/config/auto.conf";
+}
+
+static char *conf_expand_value(const char *in)
+{
+       struct symbol *sym;
+       const char *src;
+       static char res_value[SYMBOL_MAXLENGTH];
+       char *dst, name[SYMBOL_MAXLENGTH];
+
+       res_value[0] = 0;
+       dst = name;
+       while ((src = strchr(in, '$'))) {
+               strncat(res_value, in, src - in);
+               src++;
+               dst = name;
+               while (isalnum(*src) || *src == '_')
+                       *dst++ = *src++;
+               *dst = 0;
+               sym = sym_lookup(name, 0);
+               sym_calc_value(sym);
+               strcat(res_value, sym_get_string_value(sym));
+               in = src;
+       }
+       strcat(res_value, in);
+
+       return res_value;
+}
+
+char *conf_get_default_confname(void)
+{
+       struct stat buf;
+       static char fullname[PATH_MAX+1];
+       char *env, *name;
+
+       name = conf_expand_value(conf_defname);
+       env = getenv(SRCTREE);
+       if (env) {
+               sprintf(fullname, "%s/%s", env, name);
+               if (!stat(fullname, &buf))
+                       return fullname;
+       }
+       return name;
+}
+
+static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
+{
+       char *p2;
+
+       switch (sym->type) {
+       case S_TRISTATE:
+               if (p[0] == 'm') {
+                       sym->def[def].tri = mod;
+                       sym->flags |= def_flags;
+                       break;
+               }
+       case S_BOOLEAN:
+               if (p[0] == 'y') {
+                       sym->def[def].tri = yes;
+                       sym->flags |= def_flags;
+                       break;
+               }
+               if (p[0] == 'n') {
+                       sym->def[def].tri = no;
+                       sym->flags |= def_flags;
+                       break;
+               }
+               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+               break;
+       case S_OTHER:
+               if (*p != '"') {
+                       for (p2 = p; *p2 && !isspace(*p2); p2++)
+                               ;
+                       sym->type = S_STRING;
+                       goto done;
+               }
+       case S_STRING:
+               if (*p++ != '"')
+                       break;
+               for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
+                       if (*p2 == '"') {
+                               *p2 = 0;
+                               break;
+                       }
+                       memmove(p2, p2 + 1, strlen(p2));
+               }
+               if (!p2) {
+                       conf_warning("invalid string found");
+                       return 1;
+               }
+       case S_INT:
+       case S_HEX:
+       done:
+               if (sym_string_valid(sym, p)) {
+                       sym->def[def].val = strdup(p);
+                       sym->flags |= def_flags;
+               } else {
+                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                       return 1;
+               }
+               break;
+       default:
+               ;
+       }
+       return 0;
+}
+
+int conf_read_simple(const char *name, int def)
+{
+       FILE *in = NULL;
+       char line[1024];
+       char *p, *p2;
+       struct symbol *sym;
+       int i, def_flags;
+
+       if (name) {
+               in = zconf_fopen(name);
+       } else {
+               struct property *prop;
+
+               name = conf_get_configname();
+               in = zconf_fopen(name);
+               if (in)
+                       goto load;
+               sym_add_change_count(1);
+               if (!sym_defconfig_list) {
+                       if (modules_sym)
+                               sym_calc_value(modules_sym);
+                       return 1;
+               }
+
+               for_all_defaults(sym_defconfig_list, prop) {
+                       if (expr_calc_value(prop->visible.expr) == no ||
+                           prop->expr->type != E_SYMBOL)
+                               continue;
+                       name = conf_expand_value(prop->expr->left.sym->name);
+                       in = zconf_fopen(name);
+                       if (in) {
+                               conf_message(_("using defaults found in %s"),
+                                        name);
+                               goto load;
+                       }
+               }
+       }
+       if (!in)
+               return 1;
+
+load:
+       conf_filename = name;
+       conf_lineno = 0;
+       conf_warnings = 0;
+       conf_unsaved = 0;
+
+       def_flags = SYMBOL_DEF << def;
+       for_all_symbols(i, sym) {
+               sym->flags |= SYMBOL_CHANGED;
+               sym->flags &= ~(def_flags|SYMBOL_VALID);
+               if (sym_is_choice(sym))
+                       sym->flags |= def_flags;
+               switch (sym->type) {
+               case S_INT:
+               case S_HEX:
+               case S_STRING:
+                       if (sym->def[def].val)
+                               free(sym->def[def].val);
+               default:
+                       sym->def[def].val = NULL;
+                       sym->def[def].tri = no;
+               }
+       }
+
+       while (fgets(line, sizeof(line), in)) {
+               conf_lineno++;
+               sym = NULL;
+               if (line[0] == '#') {
+                       if (memcmp(line + 2, CONFIG_, strlen(CONFIG_)))
+                               continue;
+                       p = strchr(line + 2 + strlen(CONFIG_), ' ');
+                       if (!p)
+                               continue;
+                       *p++ = 0;
+                       if (strncmp(p, "is not set", 10))
+                               continue;
+                       if (def == S_DEF_USER) {
+                               sym = sym_find(line + 2 + strlen(CONFIG_));
+                               if (!sym) {
+                                       sym_add_change_count(1);
+                                       goto setsym;
+                               }
+                       } else {
+                               sym = sym_lookup(line + 2 + strlen(CONFIG_), 0);
+                               if (sym->type == S_UNKNOWN)
+                                       sym->type = S_BOOLEAN;
+                       }
+                       if (sym->flags & def_flags) {
+                               conf_warning("override: reassigning to symbol %s", sym->name);
+                       }
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               sym->def[def].tri = no;
+                               sym->flags |= def_flags;
+                               break;
+                       default:
+                               ;
+                       }
+               } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) {
+                       p = strchr(line + strlen(CONFIG_), '=');
+                       if (!p)
+                               continue;
+                       *p++ = 0;
+                       p2 = strchr(p, '\n');
+                       if (p2) {
+                               *p2-- = 0;
+                               if (*p2 == '\r')
+                                       *p2 = 0;
+                       }
+                       if (def == S_DEF_USER) {
+                               sym = sym_find(line + strlen(CONFIG_));
+                               if (!sym) {
+                                       sym_add_change_count(1);
+                                       goto setsym;
+                               }
+                       } else {
+                               sym = sym_lookup(line + strlen(CONFIG_), 0);
+                               if (sym->type == S_UNKNOWN)
+                                       sym->type = S_OTHER;
+                       }
+                       if (sym->flags & def_flags) {
+                               conf_warning("override: reassigning to symbol %s", sym->name);
+                       }
+                       if (conf_set_sym_val(sym, def, def_flags, p))
+                               continue;
+               } else {
+                       if (line[0] != '\r' && line[0] != '\n')
+                               conf_warning("unexpected data");
+                       continue;
+               }
+setsym:
+               if (sym && sym_is_choice_value(sym)) {
+                       struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
+                       switch (sym->def[def].tri) {
+                       case no:
+                               break;
+                       case mod:
+                               if (cs->def[def].tri == yes) {
+                                       conf_warning("%s creates inconsistent choice state", sym->name);
+                                       cs->flags &= ~def_flags;
+                               }
+                               break;
+                       case yes:
+                               if (cs->def[def].tri != no)
+                                       conf_warning("override: %s changes choice state", sym->name);
+                               cs->def[def].val = sym;
+                               break;
+                       }
+                       cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri);
+               }
+       }
+       fclose(in);
+
+       if (modules_sym)
+               sym_calc_value(modules_sym);
+       return 0;
+}
+
+int conf_read(const char *name)
+{
+       struct symbol *sym, *choice_sym;
+       struct property *prop;
+       struct expr *e;
+       int i, flags;
+
+       sym_set_change_count(0);
+
+       if (conf_read_simple(name, S_DEF_USER))
+               return 1;
+
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO))
+                       goto sym_ok;
+               if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) {
+                       /* check that calculated value agrees with saved value */
+                       switch (sym->type) {
+                       case S_BOOLEAN:
+                       case S_TRISTATE:
+                               if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym))
+                                       break;
+                               if (!sym_is_choice(sym))
+                                       goto sym_ok;
+                       default:
+                               if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val))
+                                       goto sym_ok;
+                               break;
+                       }
+               } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
+                       /* no previous value and not saved */
+                       goto sym_ok;
+               conf_unsaved++;
+               /* maybe print value in verbose mode... */
+       sym_ok:
+               if (!sym_is_choice(sym))
+                       continue;
+               /* The choice symbol only has a set value (and thus is not new)
+                * if all its visible childs have values.
+                */
+               prop = sym_get_choice_prop(sym);
+               flags = sym->flags;
+               expr_list_for_each_sym(prop->expr, e, choice_sym)
+                       if (choice_sym->visible != no)
+                               flags &= choice_sym->flags;
+               sym->flags &= flags | ~SYMBOL_DEF_USER;
+       }
+
+       for_all_symbols(i, sym) {
+               if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
+                       /* Reset values of generates values, so they'll appear
+                        * as new, if they should become visible, but that
+                        * doesn't quite work if the Kconfig and the saved
+                        * configuration disagree.
+                        */
+                       if (sym->visible == no && !conf_unsaved)
+                               sym->flags &= ~SYMBOL_DEF_USER;
+                       switch (sym->type) {
+                       case S_STRING:
+                       case S_INT:
+                       case S_HEX:
+                               /* Reset a string value if it's out of range */
+                               if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+                                       break;
+                               sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+                               conf_unsaved++;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       sym_add_change_count(conf_warnings || conf_unsaved);
+
+       return 0;
+}
+
+/* Write a S_STRING */
+static void conf_write_string(bool headerfile, const char *name,
+                              const char *str, FILE *out)
+{
+       int l;
+       if (headerfile)
+               fprintf(out, "#define %s%s \"", CONFIG_, name);
+       else
+               fprintf(out, "%s%s=\"", CONFIG_, name);
+
+       while (1) {
+               l = strcspn(str, "\"\\");
+               if (l) {
+                       xfwrite(str, l, 1, out);
+                       str += l;
+               }
+               if (!*str)
+                       break;
+               fprintf(out, "\\%c", *str++);
+       }
+       fputs("\"\n", out);
+}
+
+static void conf_write_symbol(struct symbol *sym, FILE *out, bool write_no)
+{
+       const char *str;
+
+       switch (sym->type) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               switch (sym_get_tristate_value(sym)) {
+               case no:
+                       if (write_no)
+                               fprintf(out, "# %s%s is not set\n",
+                                   CONFIG_, sym->name);
+                       break;
+               case mod:
+                       fprintf(out, "%s%s=m\n", CONFIG_, sym->name);
+                       break;
+               case yes:
+                       fprintf(out, "%s%s=y\n", CONFIG_, sym->name);
+                       break;
+               }
+               break;
+       case S_STRING:
+               conf_write_string(false, sym->name, sym_get_string_value(sym), out);
+               break;
+       case S_HEX:
+       case S_INT:
+               str = sym_get_string_value(sym);
+               fprintf(out, "%s%s=%s\n", CONFIG_, sym->name, str);
+               break;
+       case S_OTHER:
+       case S_UNKNOWN:
+               break;
+       }
+}
+
+/*
+ * Write out a minimal config.
+ * All values that has default values are skipped as this is redundant.
+ */
+int conf_write_defconfig(const char *filename)
+{
+       struct symbol *sym;
+       struct menu *menu;
+       FILE *out;
+
+       out = fopen(filename, "w");
+       if (!out)
+               return 1;
+
+       sym_clear_all_valid();
+
+       /* Traverse all menus to find all relevant symbols */
+       menu = rootmenu.list;
+
+       while (menu != NULL)
+       {
+               sym = menu->sym;
+               if (sym == NULL) {
+                       if (!menu_is_visible(menu))
+                               goto next_menu;
+               } else if (!sym_is_choice(sym)) {
+                       sym_calc_value(sym);
+                       if (!(sym->flags & SYMBOL_WRITE))
+                               goto next_menu;
+                       sym->flags &= ~SYMBOL_WRITE;
+                       /* If we cannot change the symbol - skip */
+                       if (!sym_is_changable(sym))
+                               goto next_menu;
+                       /* If symbol equals to default value - skip */
+                       if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0)
+                               goto next_menu;
+
+                       /*
+                        * If symbol is a choice value and equals to the
+                        * default for a choice - skip.
+                        * But only if value is bool and equal to "y" and
+                        * choice is not "optional".
+                        * (If choice is "optional" then all values can be "n")
+                        */
+                       if (sym_is_choice_value(sym)) {
+                               struct symbol *cs;
+                               struct symbol *ds;
+
+                               cs = prop_get_symbol(sym_get_choice_prop(sym));
+                               ds = sym_choice_default(cs);
+                               if (!sym_is_optional(cs) && sym == ds) {
+                                       if ((sym->type == S_BOOLEAN) &&
+                                           sym_get_tristate_value(sym) == yes)
+                                               goto next_menu;
+                               }
+                       }
+                       conf_write_symbol(sym, out, true);
+               }
+next_menu:
+               if (menu->list != NULL) {
+                       menu = menu->list;
+               }
+               else if (menu->next != NULL) {
+                       menu = menu->next;
+               } else {
+                       while ((menu = menu->parent)) {
+                               if (menu->next != NULL) {
+                                       menu = menu->next;
+                                       break;
+                               }
+                       }
+               }
+       }
+       fclose(out);
+       return 0;
+}
+
+int conf_write(const char *name)
+{
+       FILE *out;
+       struct symbol *sym;
+       struct menu *menu;
+       const char *basename;
+       const char *str;
+       char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1];
+       time_t now;
+       int use_timestamp = 1;
+       char *env;
+
+       dirname[0] = 0;
+       if (name && name[0]) {
+               struct stat st;
+               char *slash;
+
+               if (!stat(name, &st) && S_ISDIR(st.st_mode)) {
+                       strcpy(dirname, name);
+                       strcat(dirname, "/");
+                       basename = conf_get_configname();
+               } else if ((slash = strrchr(name, '/'))) {
+                       int size = slash - name + 1;
+                       memcpy(dirname, name, size);
+                       dirname[size] = 0;
+                       if (slash[1])
+                               basename = slash + 1;
+                       else
+                               basename = conf_get_configname();
+               } else
+                       basename = name;
+       } else
+               basename = conf_get_configname();
+
+       sprintf(newname, "%s%s", dirname, basename);
+       env = getenv("KCONFIG_OVERWRITECONFIG");
+       if (!env || !*env) {
+               sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid());
+               out = fopen(tmpname, "w");
+       } else {
+               *tmpname = 0;
+               out = fopen(newname, "w");
+       }
+       if (!out)
+               return 1;
+
+       time(&now);
+       env = getenv("KCONFIG_NOTIMESTAMP");
+       if (env && *env)
+               use_timestamp = 0;
+
+       fprintf(out, _("#\n"
+                      "# Automatically generated make config: don't edit\n"
+                      "# %s\n"
+                      "%s%s"
+                      "#\n"),
+                    rootmenu.prompt->text,
+                    use_timestamp ? "# " : "",
+                    use_timestamp ? ctime(&now) : "");
+
+       if (!conf_get_changed())
+               sym_clear_all_valid();
+
+       menu = rootmenu.list;
+       while (menu) {
+               sym = menu->sym;
+               if (!sym) {
+                       if (!menu_is_visible(menu))
+                               goto next;
+                       str = menu_get_prompt(menu);
+                       fprintf(out, "\n"
+                                    "#\n"
+                                    "# %s\n"
+                                    "#\n", str);
+               } else if (!(sym->flags & SYMBOL_CHOICE)) {
+                       sym_calc_value(sym);
+                       if (!(sym->flags & SYMBOL_WRITE))
+                               goto next;
+                       sym->flags &= ~SYMBOL_WRITE;
+                       /* Write config symbol to file */
+                       conf_write_symbol(sym, out, true);
+               }
+
+next:
+               if (menu->list) {
+                       menu = menu->list;
+                       continue;
+               }
+               if (menu->next)
+                       menu = menu->next;
+               else while ((menu = menu->parent)) {
+                       if (menu->next) {
+                               menu = menu->next;
+                               break;
+                       }
+               }
+       }
+       fclose(out);
+
+       if (*tmpname) {
+               strcat(dirname, basename);
+               strcat(dirname, ".old");
+               rename(newname, dirname);
+               if (rename(tmpname, newname))
+                       return 1;
+       }
+
+       conf_message(_("configuration written to %s"), newname);
+
+       sym_set_change_count(0);
+
+       return 0;
+}
+
+static int conf_split_config(void)
+{
+       const char *name;
+       char path[PATH_MAX+1];
+       char *s, *d, c;
+       struct symbol *sym;
+       struct stat sb;
+       int res, i, fd;
+
+       name = conf_get_autoconfig_name();
+       conf_read_simple(name, S_DEF_AUTO);
+
+       if (chdir("include/config"))
+               return 1;
+
+       res = 0;
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if ((sym->flags & SYMBOL_AUTO) || !sym->name)
+                       continue;
+               if (sym->flags & SYMBOL_WRITE) {
+                       if (sym->flags & SYMBOL_DEF_AUTO) {
+                               /*
+                                * symbol has old and new value,
+                                * so compare them...
+                                */
+                               switch (sym->type) {
+                               case S_BOOLEAN:
+                               case S_TRISTATE:
+                                       if (sym_get_tristate_value(sym) ==
+                                           sym->def[S_DEF_AUTO].tri)
+                                               continue;
+                                       break;
+                               case S_STRING:
+                               case S_HEX:
+                               case S_INT:
+                                       if (!strcmp(sym_get_string_value(sym),
+                                                   sym->def[S_DEF_AUTO].val))
+                                               continue;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       } else {
+                               /*
+                                * If there is no old value, only 'no' (unset)
+                                * is allowed as new value.
+                                */
+                               switch (sym->type) {
+                               case S_BOOLEAN:
+                               case S_TRISTATE:
+                                       if (sym_get_tristate_value(sym) == no)
+                                               continue;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               } else if (!(sym->flags & SYMBOL_DEF_AUTO))
+                       /* There is neither an old nor a new value. */
+                       continue;
+               /* else
+                *      There is an old value, but no new value ('no' (unset)
+                *      isn't saved in auto.conf, so the old value is always
+                *      different from 'no').
+                */
+
+               /* Replace all '_' and append ".h" */
+               s = sym->name;
+               d = path;
+               while ((c = *s++)) {
+                       c = tolower(c);
+                       *d++ = (c == '_') ? '/' : c;
+               }
+               strcpy(d, ".h");
+
+               /* Assume directory path already exists. */
+               fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+               if (fd == -1) {
+                       if (errno != ENOENT) {
+                               res = 1;
+                               break;
+                       }
+                       /*
+                        * Create directory components,
+                        * unless they exist already.
+                        */
+                       d = path;
+                       while ((d = strchr(d, '/'))) {
+                               *d = 0;
+                               if (stat(path, &sb) && mkdir(path, 0755)) {
+                                       res = 1;
+                                       goto out;
+                               }
+                               *d++ = '/';
+                       }
+                       /* Try it again. */
+                       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+                       if (fd == -1) {
+                               res = 1;
+                               break;
+                       }
+               }
+               close(fd);
+       }
+out:
+       if (chdir("../.."))
+               return 1;
+
+       return res;
+}
+
+int conf_write_autoconf(void)
+{
+       struct symbol *sym;
+       const char *str;
+       const char *name;
+       FILE *out, *tristate, *out_h;
+       time_t now;
+       int i;
+
+       sym_clear_all_valid();
+
+       file_write_dep("include/config/auto.conf.cmd");
+
+       if (conf_split_config())
+               return 1;
+
+       out = fopen(".tmpconfig", "w");
+       if (!out)
+               return 1;
+
+       tristate = fopen(".tmpconfig_tristate", "w");
+       if (!tristate) {
+               fclose(out);
+               return 1;
+       }
+
+       out_h = fopen(".tmpconfig.h", "w");
+       if (!out_h) {
+               fclose(out);
+               fclose(tristate);
+               return 1;
+       }
+
+       time(&now);
+       fprintf(out, "#\n"
+                    "# Automatically generated make config: don't edit\n"
+                    "# %s\n"
+                    "# %s"
+                    "#\n",
+                    rootmenu.prompt->text, ctime(&now));
+       fprintf(tristate, "#\n"
+                         "# Automatically generated - do not edit\n"
+                         "\n");
+       fprintf(out_h, "/*\n"
+                      " * Automatically generated C config: don't edit\n"
+                      " * %s\n"
+                      " * %s"
+                      " */\n",
+                      rootmenu.prompt->text, ctime(&now));
+
+       for_all_symbols(i, sym) {
+               sym_calc_value(sym);
+               if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
+                       continue;
+
+               /* write symbol to config file */
+               conf_write_symbol(sym, out, false);
+
+               /* update autoconf and tristate files */
+               switch (sym->type) {
+               case S_BOOLEAN:
+               case S_TRISTATE:
+                       switch (sym_get_tristate_value(sym)) {
+                       case no:
+                               break;
+                       case mod:
+                               fprintf(tristate, "%s%s=M\n",
+                                   CONFIG_, sym->name);
+                               fprintf(out_h, "#define %s%s_MODULE 1\n",
+                                   CONFIG_, sym->name);
+                               break;
+                       case yes:
+                               if (sym->type == S_TRISTATE)
+                                       fprintf(tristate,"%s%s=Y\n",
+                                           CONFIG_, sym->name);
+                               fprintf(out_h, "#define %s%s 1\n",
+                                   CONFIG_, sym->name);
+                               break;
+                       }
+                       break;
+               case S_STRING:
+                       conf_write_string(true, sym->name, sym_get_string_value(sym), out_h);
+                       break;
+               case S_HEX:
+                       str = sym_get_string_value(sym);
+                       if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) {
+                               fprintf(out_h, "#define %s%s 0x%s\n",
+                                   CONFIG_, sym->name, str);
+                               break;
+                       }
+               case S_INT:
+                       str = sym_get_string_value(sym);
+                       fprintf(out_h, "#define %s%s %s\n",
+                           CONFIG_, sym->name, str);
+                       break;
+               default:
+                       break;
+               }
+       }
+       fclose(out);
+       fclose(tristate);
+       fclose(out_h);
+
+       name = getenv("KCONFIG_AUTOHEADER");
+       if (!name)
+               name = "include/generated/autoconf.h";
+       if (rename(".tmpconfig.h", name))
+               return 1;
+       name = getenv("KCONFIG_TRISTATE");
+       if (!name)
+               name = "include/config/tristate.conf";
+       if (rename(".tmpconfig_tristate", name))
+               return 1;
+       name = conf_get_autoconfig_name();
+       /*
+        * This must be the last step, kbuild has a dependency on auto.conf
+        * and this marks the successful completion of the previous steps.
+        */
+       if (rename(".tmpconfig", name))
+               return 1;
+
+       return 0;
+}
+
+static int sym_change_count;
+static void (*conf_changed_callback)(void);
+
+void sym_set_change_count(int count)
+{
+       int _sym_change_count = sym_change_count;
+       sym_change_count = count;
+       if (conf_changed_callback &&
+           (bool)_sym_change_count != (bool)count)
+               conf_changed_callback();
+}
+
+void sym_add_change_count(int count)
+{
+       sym_set_change_count(count + sym_change_count);
+}
+
+bool conf_get_changed(void)
+{
+       return sym_change_count;
+}
+
+void conf_set_changed_callback(void (*fn)(void))
+{
+       conf_changed_callback = fn;
+}
+
+static void randomize_choice_values(struct symbol *csym)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct expr *e;
+       int cnt, def;
+
+       /*
+        * If choice is mod then we may have more items selected
+        * and if no then no-one.
+        * In both cases stop.
+        */
+       if (csym->curr.tri != yes)
+               return;
+
+       prop = sym_get_choice_prop(csym);
+
+       /* count entries in choice block */
+       cnt = 0;
+       expr_list_for_each_sym(prop->expr, e, sym)
+               cnt++;
+
+       /*
+        * find a random value and set it to yes,
+        * set the rest to no so we have only one set
+        */
+       def = (rand() % cnt);
+
+       cnt = 0;
+       expr_list_for_each_sym(prop->expr, e, sym) {
+               if (def == cnt++) {
+                       sym->def[S_DEF_USER].tri = yes;
+                       csym->def[S_DEF_USER].val = sym;
+               }
+               else {
+                       sym->def[S_DEF_USER].tri = no;
+               }
+       }
+       csym->flags |= SYMBOL_DEF_USER;
+       /* clear VALID to get value calculated */
+       csym->flags &= ~(SYMBOL_VALID);
+}
+
+static void set_all_choice_values(struct symbol *csym)
+{
+       struct property *prop;
+       struct symbol *sym;
+       struct expr *e;
+
+       prop = sym_get_choice_prop(csym);
+
+       /*
+        * Set all non-assinged choice values to no
+        */
+       expr_list_for_each_sym(prop->expr, e, sym) {
+               if (!sym_has_value(sym))
+                       sym->def[S_DEF_USER].tri = no;
+       }
+       csym->flags |= SYMBOL_DEF_USER;
+       /* clear VALID to get value calculated */
+       csym->flags &= ~(SYMBOL_VALID);
+}
+
+void conf_set_all_new_symbols(enum conf_def_mode mode)
+{
+       struct symbol *sym, *csym;
+       int i, cnt;
+
+       for_all_symbols(i, sym) {
+               if (sym_has_value(sym))
+                       continue;
+               switch (sym_get_type(sym)) {
+               case S_BOOLEAN:
+               case S_TRISTATE:
+                       switch (mode) {
+                       case def_yes:
+                               sym->def[S_DEF_USER].tri = yes;
+                               break;
+                       case def_mod:
+                               sym->def[S_DEF_USER].tri = mod;
+                               break;
+                       case def_no:
+                               sym->def[S_DEF_USER].tri = no;
+                               break;
+                       case def_random:
+                               cnt = sym_get_type(sym) == S_TRISTATE ? 3 : 2;
+                               sym->def[S_DEF_USER].tri = (tristate)(rand() % cnt);
+                               break;
+                       default:
+                               continue;
+                       }
+                       if (!(sym_is_choice(sym) && mode == def_random))
+                               sym->flags |= SYMBOL_DEF_USER;
+                       break;
+               default:
+                       break;
+               }
+
+       }
+
+       sym_clear_all_valid();
+
+       /*
+        * We have different type of choice blocks.
+        * If curr.tri equals to mod then we can select several
+        * choice symbols in one block.
+        * In this case we do nothing.
+        * If curr.tri equals yes then only one symbol can be
+        * selected in a choice block and we set it to yes,
+        * and the rest to no.
+        */
+       for_all_symbols(i, csym) {
+               if (sym_has_value(csym) || !sym_is_choice(csym))
+                       continue;
+
+               sym_calc_value(csym);
+               if (mode == def_random)
+                       randomize_choice_values(csym);
+               else
+                       set_all_choice_values(csym);
+       }
+}
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
new file mode 100644 (file)
index 0000000..0010034
--- /dev/null
@@ -0,0 +1,1173 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+#define DEBUG_EXPR     0
+
+struct expr *expr_alloc_symbol(struct symbol *sym)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = E_SYMBOL;
+       e->left.sym = sym;
+       return e;
+}
+
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
+{
+       struct expr *e = malloc(sizeof(*e));
+       memset(e, 0, sizeof(*e));
+       e->type = type;
+       e->left.expr = ce;
+       return e;
+}
+
+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));
+       e->type = type;
+       e->left.expr = e1;
+       e->right.expr = e2;
+       return e;
+}
+
+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));
+       e->type = type;
+       e->left.sym = s1;
+       e->right.sym = s2;
+       return e;
+}
+
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2)
+{
+       if (!e1)
+               return e2;
+       return e2 ? expr_alloc_two(E_AND, e1, e2) : e1;
+}
+
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
+{
+       if (!e1)
+               return e2;
+       return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
+}
+
+struct expr *expr_copy(const struct expr *org)
+{
+       struct expr *e;
+
+       if (!org)
+               return NULL;
+
+       e = malloc(sizeof(*org));
+       memcpy(e, org, sizeof(*org));
+       switch (org->type) {
+       case E_SYMBOL:
+               e->left = org->left;
+               break;
+       case E_NOT:
+               e->left.expr = expr_copy(org->left.expr);
+               break;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               e->left.sym = org->left.sym;
+               e->right.sym = org->right.sym;
+               break;
+       case E_AND:
+       case E_OR:
+       case E_LIST:
+               e->left.expr = expr_copy(org->left.expr);
+               e->right.expr = expr_copy(org->right.expr);
+               break;
+       default:
+               printf("can't copy type %d\n", e->type);
+               free(e);
+               e = NULL;
+               break;
+       }
+
+       return e;
+}
+
+void expr_free(struct expr *e)
+{
+       if (!e)
+               return;
+
+       switch (e->type) {
+       case E_SYMBOL:
+               break;
+       case E_NOT:
+               expr_free(e->left.expr);
+               return;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               break;
+       case E_OR:
+       case E_AND:
+               expr_free(e->left.expr);
+               expr_free(e->right.expr);
+               break;
+       default:
+               printf("how to free type %d?\n", e->type);
+               break;
+       }
+       free(e);
+}
+
+static int trans_count;
+
+#define e1 (*ep1)
+#define e2 (*ep2)
+
+static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+       if (e1->type == type) {
+               __expr_eliminate_eq(type, &e1->left.expr, &e2);
+               __expr_eliminate_eq(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               __expr_eliminate_eq(type, &e1, &e2->left.expr);
+               __expr_eliminate_eq(type, &e1, &e2->right.expr);
+               return;
+       }
+       if (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+           e1->left.sym == e2->left.sym &&
+           (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no))
+               return;
+       if (!expr_eq(e1, e2))
+               return;
+       trans_count++;
+       expr_free(e1); expr_free(e2);
+       switch (type) {
+       case E_OR:
+               e1 = expr_alloc_symbol(&symbol_no);
+               e2 = expr_alloc_symbol(&symbol_no);
+               break;
+       case E_AND:
+               e1 = expr_alloc_symbol(&symbol_yes);
+               e2 = expr_alloc_symbol(&symbol_yes);
+               break;
+       default:
+               ;
+       }
+}
+
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
+{
+       if (!e1 || !e2)
+               return;
+       switch (e1->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e1->type, ep1, ep2);
+       default:
+               ;
+       }
+       if (e1->type != e2->type) switch (e2->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e2->type, ep1, ep2);
+       default:
+               ;
+       }
+       e1 = expr_eliminate_yn(e1);
+       e2 = expr_eliminate_yn(e2);
+}
+
+#undef e1
+#undef e2
+
+int expr_eq(struct expr *e1, struct expr *e2)
+{
+       int res, old_count;
+
+       if (e1->type != e2->type)
+               return 0;
+       switch (e1->type) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+               return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym;
+       case E_SYMBOL:
+               return e1->left.sym == e2->left.sym;
+       case E_NOT:
+               return expr_eq(e1->left.expr, e2->left.expr);
+       case E_AND:
+       case E_OR:
+               e1 = expr_copy(e1);
+               e2 = expr_copy(e2);
+               old_count = trans_count;
+               expr_eliminate_eq(&e1, &e2);
+               res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL &&
+                      e1->left.sym == e2->left.sym);
+               expr_free(e1);
+               expr_free(e2);
+               trans_count = old_count;
+               return res;
+       case E_LIST:
+       case E_RANGE:
+       case E_NONE:
+               /* panic */;
+       }
+
+       if (DEBUG_EXPR) {
+               expr_fprint(e1, stdout);
+               printf(" = ");
+               expr_fprint(e2, stdout);
+               printf(" ?\n");
+       }
+
+       return 0;
+}
+
+struct expr *expr_eliminate_yn(struct expr *e)
+{
+       struct expr *tmp;
+
+       if (e) switch (e->type) {
+       case E_AND:
+               e->left.expr = expr_eliminate_yn(e->left.expr);
+               e->right.expr = expr_eliminate_yn(e->right.expr);
+               if (e->left.expr->type == E_SYMBOL) {
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               e->right.expr = NULL;
+                               return e;
+                       } else if (e->left.expr->left.sym == &symbol_yes) {
+                               free(e->left.expr);
+                               tmp = e->right.expr;
+                               *e = *(e->right.expr);
+                               free(tmp);
+                               return e;
+                       }
+               }
+               if (e->right.expr->type == E_SYMBOL) {
+                       if (e->right.expr->left.sym == &symbol_no) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               e->right.expr = NULL;
+                               return e;
+                       } else if (e->right.expr->left.sym == &symbol_yes) {
+                               free(e->right.expr);
+                               tmp = e->left.expr;
+                               *e = *(e->left.expr);
+                               free(tmp);
+                               return e;
+                       }
+               }
+               break;
+       case E_OR:
+               e->left.expr = expr_eliminate_yn(e->left.expr);
+               e->right.expr = expr_eliminate_yn(e->right.expr);
+               if (e->left.expr->type == E_SYMBOL) {
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               free(e->left.expr);
+                               tmp = e->right.expr;
+                               *e = *(e->right.expr);
+                               free(tmp);
+                               return e;
+                       } else if (e->left.expr->left.sym == &symbol_yes) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               e->right.expr = NULL;
+                               return e;
+                       }
+               }
+               if (e->right.expr->type == E_SYMBOL) {
+                       if (e->right.expr->left.sym == &symbol_no) {
+                               free(e->right.expr);
+                               tmp = e->left.expr;
+                               *e = *(e->left.expr);
+                               free(tmp);
+                               return e;
+                       } else if (e->right.expr->left.sym == &symbol_yes) {
+                               expr_free(e->left.expr);
+                               expr_free(e->right.expr);
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               e->right.expr = NULL;
+                               return e;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+/*
+ * bool FOO!=n => FOO
+ */
+struct expr *expr_trans_bool(struct expr *e)
+{
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_AND:
+       case E_OR:
+       case E_NOT:
+               e->left.expr = expr_trans_bool(e->left.expr);
+               e->right.expr = expr_trans_bool(e->right.expr);
+               break;
+       case E_UNEQUAL:
+               // FOO!=n -> FOO
+               if (e->left.sym->type == S_TRISTATE) {
+                       if (e->right.sym == &symbol_no) {
+                               e->type = E_SYMBOL;
+                               e->right.sym = NULL;
+                       }
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+/*
+ * e1 || e2 -> ?
+ */
+static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
+{
+       struct expr *tmp;
+       struct symbol *sym1, *sym2;
+
+       if (expr_eq(e1, e2))
+               return expr_copy(e1);
+       if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+               return NULL;
+       if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+               return NULL;
+       if (e1->type == E_NOT) {
+               tmp = e1->left.expr;
+               if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+                       return NULL;
+               sym1 = tmp->left.sym;
+       } else
+               sym1 = e1->left.sym;
+       if (e2->type == E_NOT) {
+               if (e2->left.expr->type != E_SYMBOL)
+                       return NULL;
+               sym2 = e2->left.expr->left.sym;
+       } else
+               sym2 = e2->left.sym;
+       if (sym1 != sym2)
+               return NULL;
+       if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+               return NULL;
+       if (sym1->type == S_TRISTATE) {
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+                    (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
+                       // (a='y') || (a='m') -> (a!='n')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
+               }
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+                    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
+                       // (a='y') || (a='n') -> (a!='m')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
+               }
+               if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
+                   ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+                    (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
+                       // (a='m') || (a='n') -> (a!='y')
+                       return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
+               }
+       }
+       if (sym1->type == S_BOOLEAN && sym1 == sym2) {
+               if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) ||
+                   (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL))
+                       return expr_alloc_symbol(&symbol_yes);
+       }
+
+       if (DEBUG_EXPR) {
+               printf("optimize (");
+               expr_fprint(e1, stdout);
+               printf(") || (");
+               expr_fprint(e2, stdout);
+               printf(")?\n");
+       }
+       return NULL;
+}
+
+static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
+{
+       struct expr *tmp;
+       struct symbol *sym1, *sym2;
+
+       if (expr_eq(e1, e2))
+               return expr_copy(e1);
+       if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT)
+               return NULL;
+       if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT)
+               return NULL;
+       if (e1->type == E_NOT) {
+               tmp = e1->left.expr;
+               if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL)
+                       return NULL;
+               sym1 = tmp->left.sym;
+       } else
+               sym1 = e1->left.sym;
+       if (e2->type == E_NOT) {
+               if (e2->left.expr->type != E_SYMBOL)
+                       return NULL;
+               sym2 = e2->left.expr->left.sym;
+       } else
+               sym2 = e2->left.sym;
+       if (sym1 != sym2)
+               return NULL;
+       if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE)
+               return NULL;
+
+       if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
+           (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
+               // (a) && (a='y') -> (a='y')
+               return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+       if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
+           (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
+               // (a) && (a!='n') -> (a)
+               return expr_alloc_symbol(sym1);
+
+       if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
+           (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
+               // (a) && (a!='m') -> (a='y')
+               return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+       if (sym1->type == S_TRISTATE) {
+               if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+                       sym2 = e1->right.sym;
+                       if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+                               return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+                                                            : expr_alloc_symbol(&symbol_no);
+               }
+               if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
+                       sym2 = e2->right.sym;
+                       if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
+                               return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
+                                                            : expr_alloc_symbol(&symbol_no);
+               }
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
+                           (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
+                       // (a!='y') && (a!='n') -> (a='m')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
+
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
+                           (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
+                       // (a!='y') && (a!='m') -> (a='n')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
+
+               if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
+                          ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
+                           (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
+                       // (a!='m') && (a!='n') -> (a='m')
+                       return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
+
+               if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
+                   (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) ||
+                   (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) ||
+                   (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes))
+                       return NULL;
+       }
+
+       if (DEBUG_EXPR) {
+               printf("optimize (");
+               expr_fprint(e1, stdout);
+               printf(") && (");
+               expr_fprint(e2, stdout);
+               printf(")?\n");
+       }
+       return NULL;
+}
+
+static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       struct expr *tmp;
+
+       if (e1->type == type) {
+               expr_eliminate_dups1(type, &e1->left.expr, &e2);
+               expr_eliminate_dups1(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_eliminate_dups1(type, &e1, &e2->left.expr);
+               expr_eliminate_dups1(type, &e1, &e2->right.expr);
+               return;
+       }
+       if (e1 == e2)
+               return;
+
+       switch (e1->type) {
+       case E_OR: case E_AND:
+               expr_eliminate_dups1(e1->type, &e1, &e1);
+       default:
+               ;
+       }
+
+       switch (type) {
+       case E_OR:
+               tmp = expr_join_or(e1, e2);
+               if (tmp) {
+                       expr_free(e1); expr_free(e2);
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       e2 = tmp;
+                       trans_count++;
+               }
+               break;
+       case E_AND:
+               tmp = expr_join_and(e1, e2);
+               if (tmp) {
+                       expr_free(e1); expr_free(e2);
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       e2 = tmp;
+                       trans_count++;
+               }
+               break;
+       default:
+               ;
+       }
+#undef e1
+#undef e2
+}
+
+static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       struct expr *tmp, *tmp1, *tmp2;
+
+       if (e1->type == type) {
+               expr_eliminate_dups2(type, &e1->left.expr, &e2);
+               expr_eliminate_dups2(type, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_eliminate_dups2(type, &e1, &e2->left.expr);
+               expr_eliminate_dups2(type, &e1, &e2->right.expr);
+       }
+       if (e1 == e2)
+               return;
+
+       switch (e1->type) {
+       case E_OR:
+               expr_eliminate_dups2(e1->type, &e1, &e1);
+               // (FOO || BAR) && (!FOO && !BAR) -> n
+               tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+               tmp2 = expr_copy(e2);
+               tmp = expr_extract_eq_and(&tmp1, &tmp2);
+               if (expr_is_yes(tmp1)) {
+                       expr_free(e1);
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       trans_count++;
+               }
+               expr_free(tmp2);
+               expr_free(tmp1);
+               expr_free(tmp);
+               break;
+       case E_AND:
+               expr_eliminate_dups2(e1->type, &e1, &e1);
+               // (FOO && BAR) || (!FOO || !BAR) -> y
+               tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
+               tmp2 = expr_copy(e2);
+               tmp = expr_extract_eq_or(&tmp1, &tmp2);
+               if (expr_is_no(tmp1)) {
+                       expr_free(e1);
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       trans_count++;
+               }
+               expr_free(tmp2);
+               expr_free(tmp1);
+               expr_free(tmp);
+               break;
+       default:
+               ;
+       }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_eliminate_dups(struct expr *e)
+{
+       int oldcount;
+       if (!e)
+               return e;
+
+       oldcount = trans_count;
+       while (1) {
+               trans_count = 0;
+               switch (e->type) {
+               case E_OR: case E_AND:
+                       expr_eliminate_dups1(e->type, &e, &e);
+                       expr_eliminate_dups2(e->type, &e, &e);
+               default:
+                       ;
+               }
+               if (!trans_count)
+                       break;
+               e = expr_eliminate_yn(e);
+       }
+       trans_count = oldcount;
+       return e;
+}
+
+struct expr *expr_transform(struct expr *e)
+{
+       struct expr *tmp;
+
+       if (!e)
+               return NULL;
+       switch (e->type) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+       case E_SYMBOL:
+       case E_LIST:
+               break;
+       default:
+               e->left.expr = expr_transform(e->left.expr);
+               e->right.expr = expr_transform(e->right.expr);
+       }
+
+       switch (e->type) {
+       case E_EQUAL:
+               if (e->left.sym->type != S_BOOLEAN)
+                       break;
+               if (e->right.sym == &symbol_no) {
+                       e->type = E_NOT;
+                       e->left.expr = expr_alloc_symbol(e->left.sym);
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_mod) {
+                       printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name);
+                       e->type = E_SYMBOL;
+                       e->left.sym = &symbol_no;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_yes) {
+                       e->type = E_SYMBOL;
+                       e->right.sym = NULL;
+                       break;
+               }
+               break;
+       case E_UNEQUAL:
+               if (e->left.sym->type != S_BOOLEAN)
+                       break;
+               if (e->right.sym == &symbol_no) {
+                       e->type = E_SYMBOL;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_mod) {
+                       printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name);
+                       e->type = E_SYMBOL;
+                       e->left.sym = &symbol_yes;
+                       e->right.sym = NULL;
+                       break;
+               }
+               if (e->right.sym == &symbol_yes) {
+                       e->type = E_NOT;
+                       e->left.expr = expr_alloc_symbol(e->left.sym);
+                       e->right.sym = NULL;
+                       break;
+               }
+               break;
+       case E_NOT:
+               switch (e->left.expr->type) {
+               case E_NOT:
+                       // !!a -> a
+                       tmp = e->left.expr->left.expr;
+                       free(e->left.expr);
+                       free(e);
+                       e = tmp;
+                       e = expr_transform(e);
+                       break;
+               case E_EQUAL:
+               case E_UNEQUAL:
+                       // !a='x' -> a!='x'
+                       tmp = e->left.expr;
+                       free(e);
+                       e = tmp;
+                       e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
+                       break;
+               case E_OR:
+                       // !(a || b) -> !a && !b
+                       tmp = e->left.expr;
+                       e->type = E_AND;
+                       e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+                       tmp->type = E_NOT;
+                       tmp->right.expr = NULL;
+                       e = expr_transform(e);
+                       break;
+               case E_AND:
+                       // !(a && b) -> !a || !b
+                       tmp = e->left.expr;
+                       e->type = E_OR;
+                       e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
+                       tmp->type = E_NOT;
+                       tmp->right.expr = NULL;
+                       e = expr_transform(e);
+                       break;
+               case E_SYMBOL:
+                       if (e->left.expr->left.sym == &symbol_yes) {
+                               // !'y' -> 'n'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_no;
+                               break;
+                       }
+                       if (e->left.expr->left.sym == &symbol_mod) {
+                               // !'m' -> 'm'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_mod;
+                               break;
+                       }
+                       if (e->left.expr->left.sym == &symbol_no) {
+                               // !'n' -> 'y'
+                               tmp = e->left.expr;
+                               free(e);
+                               e = tmp;
+                               e->type = E_SYMBOL;
+                               e->left.sym = &symbol_yes;
+                               break;
+                       }
+                       break;
+               default:
+                       ;
+               }
+               break;
+       default:
+               ;
+       }
+       return e;
+}
+
+int expr_contains_symbol(struct expr *dep, struct symbol *sym)
+{
+       if (!dep)
+               return 0;
+
+       switch (dep->type) {
+       case E_AND:
+       case E_OR:
+               return expr_contains_symbol(dep->left.expr, sym) ||
+                      expr_contains_symbol(dep->right.expr, sym);
+       case E_SYMBOL:
+               return dep->left.sym == sym;
+       case E_EQUAL:
+       case E_UNEQUAL:
+               return dep->left.sym == sym ||
+                      dep->right.sym == sym;
+       case E_NOT:
+               return expr_contains_symbol(dep->left.expr, sym);
+       default:
+               ;
+       }
+       return 0;
+}
+
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
+{
+       if (!dep)
+               return false;
+
+       switch (dep->type) {
+       case E_AND:
+               return expr_depends_symbol(dep->left.expr, sym) ||
+                      expr_depends_symbol(dep->right.expr, sym);
+       case E_SYMBOL:
+               return dep->left.sym == sym;
+       case E_EQUAL:
+               if (dep->left.sym == sym) {
+                       if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod)
+                               return true;
+               }
+               break;
+       case E_UNEQUAL:
+               if (dep->left.sym == sym) {
+                       if (dep->right.sym == &symbol_no)
+                               return true;
+               }
+               break;
+       default:
+               ;
+       }
+       return false;
+}
+
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
+{
+       struct expr *tmp = NULL;
+       expr_extract_eq(E_AND, &tmp, ep1, ep2);
+       if (tmp) {
+               *ep1 = expr_eliminate_yn(*ep1);
+               *ep2 = expr_eliminate_yn(*ep2);
+       }
+       return tmp;
+}
+
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2)
+{
+       struct expr *tmp = NULL;
+       expr_extract_eq(E_OR, &tmp, ep1, ep2);
+       if (tmp) {
+               *ep1 = expr_eliminate_yn(*ep1);
+               *ep2 = expr_eliminate_yn(*ep2);
+       }
+       return tmp;
+}
+
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2)
+{
+#define e1 (*ep1)
+#define e2 (*ep2)
+       if (e1->type == type) {
+               expr_extract_eq(type, ep, &e1->left.expr, &e2);
+               expr_extract_eq(type, ep, &e1->right.expr, &e2);
+               return;
+       }
+       if (e2->type == type) {
+               expr_extract_eq(type, ep, ep1, &e2->left.expr);
+               expr_extract_eq(type, ep, ep1, &e2->right.expr);
+               return;
+       }
+       if (expr_eq(e1, e2)) {
+               *ep = *ep ? expr_alloc_two(type, *ep, e1) : e1;
+               expr_free(e2);
+               if (type == E_AND) {
+                       e1 = expr_alloc_symbol(&symbol_yes);
+                       e2 = expr_alloc_symbol(&symbol_yes);
+               } else if (type == E_OR) {
+                       e1 = expr_alloc_symbol(&symbol_no);
+                       e2 = expr_alloc_symbol(&symbol_no);
+               }
+       }
+#undef e1
+#undef e2
+}
+
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym)
+{
+       struct expr *e1, *e2;
+
+       if (!e) {
+               e = expr_alloc_symbol(sym);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       }
+       switch (e->type) {
+       case E_AND:
+               e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+               e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+               if (sym == &symbol_yes)
+                       e = expr_alloc_two(E_AND, e1, e2);
+               if (sym == &symbol_no)
+                       e = expr_alloc_two(E_OR, e1, e2);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       case E_OR:
+               e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym);
+               e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym);
+               if (sym == &symbol_yes)
+                       e = expr_alloc_two(E_OR, e1, e2);
+               if (sym == &symbol_no)
+                       e = expr_alloc_two(E_AND, e1, e2);
+               if (type == E_UNEQUAL)
+                       e = expr_alloc_one(E_NOT, e);
+               return e;
+       case E_NOT:
+               return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym);
+       case E_UNEQUAL:
+       case E_EQUAL:
+               if (type == E_EQUAL) {
+                       if (sym == &symbol_yes)
+                               return expr_copy(e);
+                       if (sym == &symbol_mod)
+                               return expr_alloc_symbol(&symbol_no);
+                       if (sym == &symbol_no)
+                               return expr_alloc_one(E_NOT, expr_copy(e));
+               } else {
+                       if (sym == &symbol_yes)
+                               return expr_alloc_one(E_NOT, expr_copy(e));
+                       if (sym == &symbol_mod)
+                               return expr_alloc_symbol(&symbol_yes);
+                       if (sym == &symbol_no)
+                               return expr_copy(e);
+               }
+               break;
+       case E_SYMBOL:
+               return expr_alloc_comp(type, e->left.sym, sym);
+       case E_LIST:
+       case E_RANGE:
+       case E_NONE:
+               /* panic */;
+       }
+       return NULL;
+}
+
+tristate expr_calc_value(struct expr *e)
+{
+       tristate val1, val2;
+       const char *str1, *str2;
+
+       if (!e)
+               return yes;
+
+       switch (e->type) {
+       case E_SYMBOL:
+               sym_calc_value(e->left.sym);
+               return e->left.sym->curr.tri;
+       case E_AND:
+               val1 = expr_calc_value(e->left.expr);
+               val2 = expr_calc_value(e->right.expr);
+               return EXPR_AND(val1, val2);
+       case E_OR:
+               val1 = expr_calc_value(e->left.expr);
+               val2 = expr_calc_value(e->right.expr);
+               return EXPR_OR(val1, val2);
+       case E_NOT:
+               val1 = expr_calc_value(e->left.expr);
+               return EXPR_NOT(val1);
+       case E_EQUAL:
+               sym_calc_value(e->left.sym);
+               sym_calc_value(e->right.sym);
+               str1 = sym_get_string_value(e->left.sym);
+               str2 = sym_get_string_value(e->right.sym);
+               return !strcmp(str1, str2) ? yes : no;
+       case E_UNEQUAL:
+               sym_calc_value(e->left.sym);
+               sym_calc_value(e->right.sym);
+               str1 = sym_get_string_value(e->left.sym);
+               str2 = sym_get_string_value(e->right.sym);
+               return !strcmp(str1, str2) ? no : yes;
+       default:
+               printf("expr_calc_value: %d?\n", e->type);
+               return no;
+       }
+}
+
+int expr_compare_type(enum expr_type t1, enum expr_type t2)
+{
+#if 0
+       return 1;
+#else
+       if (t1 == t2)
+               return 0;
+       switch (t1) {
+       case E_EQUAL:
+       case E_UNEQUAL:
+               if (t2 == E_NOT)
+                       return 1;
+       case E_NOT:
+               if (t2 == E_AND)
+                       return 1;
+       case E_AND:
+               if (t2 == E_OR)
+                       return 1;
+       case E_OR:
+               if (t2 == E_LIST)
+                       return 1;
+       case E_LIST:
+               if (t2 == 0)
+                       return 1;
+       default:
+               return -1;
+       }
+       printf("[%dgt%d?]", t1, t2);
+       return 0;
+#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)
+{
+       if (!e) {
+               fn(data, NULL, "y");
+               return;
+       }
+
+       if (expr_compare_type(prevtoken, e->type) > 0)
+               fn(data, NULL, "(");
+       switch (e->type) {
+       case E_SYMBOL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym, e->left.sym->name);
+               else
+                       fn(data, NULL, "<choice>");
+               break;
+       case E_NOT:
+               fn(data, NULL, "!");
+               expr_print(e->left.expr, fn, data, E_NOT);
+               break;
+       case E_EQUAL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym, e->left.sym->name);
+               else
+                       fn(data, NULL, "<choice>");
+               fn(data, NULL, "=");
+               fn(data, e->right.sym, e->right.sym->name);
+               break;
+       case E_UNEQUAL:
+               if (e->left.sym->name)
+                       fn(data, e->left.sym, e->left.sym->name);
+               else
+                       fn(data, NULL, "<choice>");
+               fn(data, NULL, "!=");
+               fn(data, e->right.sym, e->right.sym->name);
+               break;
+       case E_OR:
+               expr_print(e->left.expr, fn, data, E_OR);
+               fn(data, NULL, " || ");
+               expr_print(e->right.expr, fn, data, E_OR);
+               break;
+       case E_AND:
+               expr_print(e->left.expr, fn, data, E_AND);
+               fn(data, NULL, " && ");
+               expr_print(e->right.expr, fn, data, E_AND);
+               break;
+       case E_LIST:
+               fn(data, e->right.sym, e->right.sym->name);
+               if (e->left.expr) {
+                       fn(data, NULL, " ^ ");
+                       expr_print(e->left.expr, fn, data, E_LIST);
+               }
+               break;
+       case E_RANGE:
+               fn(data, NULL, "[");
+               fn(data, e->left.sym, e->left.sym->name);
+               fn(data, NULL, " ");
+               fn(data, e->right.sym, e->right.sym->name);
+               fn(data, NULL, "]");
+               break;
+       default:
+         {
+               char buf[32];
+               sprintf(buf, "<unknown type %d>", e->type);
+               fn(data, NULL, buf);
+               break;
+         }
+       }
+       if (expr_compare_type(prevtoken, e->type) > 0)
+               fn(data, NULL, ")");
+}
+
+static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
+{
+       xfwrite(str, strlen(str), 1, data);
+}
+
+void expr_fprint(struct expr *e, FILE *out)
+{
+       expr_print(e, expr_print_file_helper, out, E_NONE);
+}
+
+static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *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)
+{
+       expr_print(e, expr_print_gstr_helper, gs, E_NONE);
+}
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
new file mode 100644 (file)
index 0000000..3d238db
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+#ifndef EXPR_H
+#define EXPR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+struct file {
+       struct file *next;
+       struct file *parent;
+       const char *name;
+       int lineno;
+       int flags;
+};
+
+#define FILE_BUSY              0x0001
+#define FILE_SCANNED           0x0002
+
+typedef enum tristate {
+       no, mod, yes
+} tristate;
+
+enum expr_type {
+       E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_LIST, E_SYMBOL, E_RANGE
+};
+
+union expr_data {
+       struct expr *expr;
+       struct symbol *sym;
+};
+
+struct expr {
+       enum expr_type type;
+       union expr_data left, right;
+};
+
+#define EXPR_OR(dep1, dep2)    (((dep1)>(dep2))?(dep1):(dep2))
+#define EXPR_AND(dep1, dep2)   (((dep1)<(dep2))?(dep1):(dep2))
+#define EXPR_NOT(dep)          (2-(dep))
+
+#define expr_list_for_each_sym(l, e, s) \
+       for (e = (l); e && (s = e->right.sym); e = e->left.expr)
+
+struct expr_value {
+       struct expr *expr;
+       tristate tri;
+};
+
+struct symbol_value {
+       void *val;
+       tristate tri;
+};
+
+enum symbol_type {
+       S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER
+};
+
+/* enum values are used as index to symbol.def[] */
+enum {
+       S_DEF_USER,             /* main user value */
+       S_DEF_AUTO,             /* values read from auto.conf */
+       S_DEF_DEF3,             /* Reserved for UI usage */
+       S_DEF_DEF4,             /* Reserved for UI usage */
+       S_DEF_COUNT
+};
+
+struct symbol {
+       struct symbol *next;
+       char *name;
+       enum symbol_type type;
+       struct symbol_value curr;
+       struct symbol_value def[S_DEF_COUNT];
+       tristate visible;
+       int flags;
+       struct property *prop;
+       struct expr_value dir_dep;
+       struct expr_value rev_dep;
+};
+
+#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_CHECK      0x0008  /* used during dependency checking */
+#define SYMBOL_CHOICE     0x0010  /* start of a choice block (null name) */
+#define SYMBOL_CHOICEVAL  0x0020  /* used as a value in a choice block */
+#define SYMBOL_VALID      0x0080  /* set when symbol.curr is calculated */
+#define SYMBOL_OPTIONAL   0x0100  /* choice is optional - values can be 'n' */
+#define SYMBOL_WRITE      0x0200  /* ? */
+#define SYMBOL_CHANGED    0x0400  /* ? */
+#define SYMBOL_AUTO       0x1000  /* value from environment variable */
+#define SYMBOL_CHECKED    0x2000  /* used during dependency checking */
+#define SYMBOL_WARNED     0x8000  /* warning has been issued */
+
+/* Set when symbol.def[] is used */
+#define SYMBOL_DEF        0x10000  /* First bit of SYMBOL_DEF */
+#define SYMBOL_DEF_USER   0x10000  /* symbol.def[S_DEF_USER] is valid */
+#define SYMBOL_DEF_AUTO   0x20000  /* symbol.def[S_DEF_AUTO] is valid */
+#define SYMBOL_DEF3       0x40000  /* symbol.def[S_DEF_3] is valid */
+#define SYMBOL_DEF4       0x80000  /* symbol.def[S_DEF_4] is valid */
+
+#define SYMBOL_MAXLENGTH       256
+#define SYMBOL_HASHSIZE                9973
+
+/* A property represent the config options that can be associated
+ * with a config "symbol".
+ * Sample:
+ * config FOO
+ *         default y
+ *         prompt "foo prompt"
+ *         select BAR
+ * config BAZ
+ *         int "BAZ Value"
+ *         range 1..255
+ */
+enum prop_type {
+       P_UNKNOWN,
+       P_PROMPT,   /* prompt "foo prompt" or "BAZ Value" */
+       P_COMMENT,  /* text associated with a comment */
+       P_MENU,     /* prompt associated with a menuconfig option */
+       P_DEFAULT,  /* default y */
+       P_CHOICE,   /* choice value */
+       P_SELECT,   /* select BAR */
+       P_RANGE,    /* range 7..100 (for a symbol) */
+       P_ENV,      /* value from environment variable */
+       P_SYMBOL,   /* where a symbol is defined */
+};
+
+struct property {
+       struct property *next;     /* next property - null if last */
+       struct symbol *sym;        /* the symbol for which the property is associated */
+       enum prop_type type;       /* type of property */
+       const char *text;          /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */
+       struct expr_value visible;
+       struct expr *expr;         /* the optional conditional part of the property */
+       struct menu *menu;         /* the menu the property are associated with
+                                   * valid for: P_SELECT, P_RANGE, P_CHOICE,
+                                   * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */
+       struct file *file;         /* what file was this property defined */
+       int lineno;                /* what lineno was this property defined */
+};
+
+#define for_all_properties(sym, st, tok) \
+       for (st = sym->prop; st; st = st->next) \
+               if (st->type == (tok))
+#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT)
+#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE)
+#define for_all_prompts(sym, st) \
+       for (st = sym->prop; st; st = st->next) \
+               if (st->text)
+
+struct menu {
+       struct menu *next;
+       struct menu *parent;
+       struct menu *list;
+       struct symbol *sym;
+       struct property *prompt;
+       struct expr *visibility;
+       struct expr *dep;
+       unsigned int flags;
+       char *help;
+       struct file *file;
+       int lineno;
+       void *data;
+};
+
+#define MENU_CHANGED           0x0001
+#define MENU_ROOT              0x0002
+
+#ifndef SWIG
+
+extern struct file *file_list;
+extern struct file *current_file;
+struct file *lookup_file(const char *name);
+
+extern struct symbol symbol_yes, symbol_no, symbol_mod;
+extern struct symbol *modules_sym;
+extern struct symbol *sym_defconfig_list;
+extern int cdebug;
+struct expr *expr_alloc_symbol(struct symbol *sym);
+struct expr *expr_alloc_one(enum expr_type type, struct expr *ce);
+struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2);
+struct expr *expr_alloc_and(struct expr *e1, struct expr *e2);
+struct expr *expr_alloc_or(struct expr *e1, struct expr *e2);
+struct expr *expr_copy(const struct expr *org);
+void expr_free(struct expr *e);
+int expr_eq(struct expr *e1, struct expr *e2);
+void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
+tristate expr_calc_value(struct expr *e);
+struct expr *expr_eliminate_yn(struct expr *e);
+struct expr *expr_trans_bool(struct expr *e);
+struct expr *expr_eliminate_dups(struct expr *e);
+struct expr *expr_transform(struct expr *e);
+int expr_contains_symbol(struct expr *dep, struct symbol *sym);
+bool expr_depends_symbol(struct expr *dep, struct symbol *sym);
+struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2);
+struct expr *expr_extract_eq_or(struct expr **ep1, struct expr **ep2);
+void expr_extract_eq(enum expr_type type, struct expr **ep, struct expr **ep1, struct expr **ep2);
+struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym);
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2);
+
+void expr_fprint(struct expr *e, FILE *out);
+struct gstr; /* forward */
+void expr_gstr_print(struct expr *e, struct gstr *gs);
+
+static inline int expr_is_yes(struct expr *e)
+{
+       return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes);
+}
+
+static inline int expr_is_no(struct expr *e)
+{
+       return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EXPR_H */
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
new file mode 100644 (file)
index 0000000..4558961
--- /dev/null
@@ -0,0 +1,1577 @@
+/* Hey EMACS -*- linux-c -*- */
+/*
+ *
+ * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info>
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "lkc.h"
+#include "images.c"
+
+#include <glade/glade.h>
+#include <gtk/gtk.h>
+#include <glib.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+
+//#define DEBUG
+
+enum {
+       SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
+};
+
+enum {
+       OPT_NORMAL, OPT_ALL, OPT_PROMPT
+};
+
+static gint view_mode = FULL_VIEW;
+static gboolean show_name = TRUE;
+static gboolean show_range = TRUE;
+static gboolean show_value = TRUE;
+static gboolean resizeable = FALSE;
+static int opt_mode = OPT_NORMAL;
+
+GtkWidget *main_wnd = NULL;
+GtkWidget *tree1_w = NULL;     // left  frame
+GtkWidget *tree2_w = NULL;     // right frame
+GtkWidget *text_w = NULL;
+GtkWidget *hpaned = NULL;
+GtkWidget *vpaned = NULL;
+GtkWidget *back_btn = NULL;
+GtkWidget *save_btn = NULL;
+GtkWidget *save_menu_item = NULL;
+
+GtkTextTag *tag1, *tag2;
+GdkColor color;
+
+GtkTreeStore *tree1, *tree2, *tree;
+GtkTreeModel *model1, *model2;
+static GtkTreeIter *parents[256];
+static gint indent;
+
+static struct menu *current; // current node for SINGLE view
+static struct menu *browsed; // browsed node for SPLIT view
+
+enum {
+       COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
+       COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
+       COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
+       COL_NUMBER
+};
+
+static void display_list(void);
+static void display_tree(struct menu *menu);
+static void display_tree_part(void);
+static void update_tree(struct menu *src, GtkTreeIter * dst);
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
+static gchar **fill_row(struct menu *menu);
+static void conf_changed(void);
+
+/* Helping/Debugging Functions */
+
+const char *dbg_sym_flags(int val)
+{
+       static char buf[256];
+
+       bzero(buf, 256);
+
+       if (val & SYMBOL_CONST)
+               strcat(buf, "const/");
+       if (val & SYMBOL_CHECK)
+               strcat(buf, "check/");
+       if (val & SYMBOL_CHOICE)
+               strcat(buf, "choice/");
+       if (val & SYMBOL_CHOICEVAL)
+               strcat(buf, "choiceval/");
+       if (val & SYMBOL_VALID)
+               strcat(buf, "valid/");
+       if (val & SYMBOL_OPTIONAL)
+               strcat(buf, "optional/");
+       if (val & SYMBOL_WRITE)
+               strcat(buf, "write/");
+       if (val & SYMBOL_CHANGED)
+               strcat(buf, "changed/");
+       if (val & SYMBOL_AUTO)
+               strcat(buf, "auto/");
+
+       buf[strlen(buf) - 1] = '\0';
+
+       return buf;
+}
+
+void replace_button_icon(GladeXML * xml, GdkDrawable * window,
+                        GtkStyle * style, gchar * btn_name, gchar ** xpm)
+{
+       GdkPixmap *pixmap;
+       GdkBitmap *mask;
+       GtkToolButton *button;
+       GtkWidget *image;
+
+       pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
+                                             &style->bg[GTK_STATE_NORMAL],
+                                             xpm);
+
+       button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
+       image = gtk_image_new_from_pixmap(pixmap, mask);
+       gtk_widget_show(image);
+       gtk_tool_button_set_icon_widget(button, image);
+}
+
+/* Main Window Initialization */
+void init_main_window(const gchar * glade_file)
+{
+       GladeXML *xml;
+       GtkWidget *widget;
+       GtkTextBuffer *txtbuf;
+       GtkStyle *style;
+
+       xml = glade_xml_new(glade_file, "window1", NULL);
+       if (!xml)
+               g_error(_("GUI loading failed !\n"));
+       glade_xml_signal_autoconnect(xml);
+
+       main_wnd = glade_xml_get_widget(xml, "window1");
+       hpaned = glade_xml_get_widget(xml, "hpaned1");
+       vpaned = glade_xml_get_widget(xml, "vpaned1");
+       tree1_w = glade_xml_get_widget(xml, "treeview1");
+       tree2_w = glade_xml_get_widget(xml, "treeview2");
+       text_w = glade_xml_get_widget(xml, "textview3");
+
+       back_btn = glade_xml_get_widget(xml, "button1");
+       gtk_widget_set_sensitive(back_btn, FALSE);
+
+       widget = glade_xml_get_widget(xml, "show_name1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_name);
+
+       widget = glade_xml_get_widget(xml, "show_range1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_range);
+
+       widget = glade_xml_get_widget(xml, "show_data1");
+       gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
+                                      show_value);
+
+       save_btn = glade_xml_get_widget(xml, "button3");
+       save_menu_item = glade_xml_get_widget(xml, "save1");
+       conf_set_changed_callback(conf_changed);
+
+       style = gtk_widget_get_style(main_wnd);
+       widget = glade_xml_get_widget(xml, "toolbar1");
+
+#if 0  /* Use stock Gtk icons instead */
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button1", (gchar **) xpm_back);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button2", (gchar **) xpm_load);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button3", (gchar **) xpm_save);
+#endif
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button4", (gchar **) xpm_single_view);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button5", (gchar **) xpm_split_view);
+       replace_button_icon(xml, main_wnd->window, style,
+                           "button6", (gchar **) xpm_tree_view);
+
+#if 0
+       switch (view_mode) {
+       case SINGLE_VIEW:
+               widget = glade_xml_get_widget(xml, "button4");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       case SPLIT_VIEW:
+               widget = glade_xml_get_widget(xml, "button5");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       case FULL_VIEW:
+               widget = glade_xml_get_widget(xml, "button6");
+               g_signal_emit_by_name(widget, "clicked");
+               break;
+       }
+#endif
+       txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
+                                         "foreground", "red",
+                                         "weight", PANGO_WEIGHT_BOLD,
+                                         NULL);
+       tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
+                                         /*"style", PANGO_STYLE_OBLIQUE, */
+                                         NULL);
+
+       gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
+
+       gtk_widget_show(main_wnd);
+}
+
+void init_tree_model(void)
+{
+       gint i;
+
+       tree = tree2 = gtk_tree_store_new(COL_NUMBER,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_STRING, G_TYPE_STRING,
+                                         G_TYPE_POINTER, GDK_TYPE_COLOR,
+                                         G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                         G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                         G_TYPE_BOOLEAN);
+       model2 = GTK_TREE_MODEL(tree2);
+
+       for (parents[0] = NULL, i = 1; i < 256; i++)
+               parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
+
+       tree1 = gtk_tree_store_new(COL_NUMBER,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_STRING, G_TYPE_STRING,
+                                  G_TYPE_POINTER, GDK_TYPE_COLOR,
+                                  G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
+                                  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                  G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
+                                  G_TYPE_BOOLEAN);
+       model1 = GTK_TREE_MODEL(tree1);
+}
+
+void init_left_tree(void)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *sel;
+       GtkTreeViewColumn *column;
+
+       gtk_tree_view_set_model(view, model1);
+       gtk_tree_view_set_headers_visible(view, TRUE);
+       gtk_tree_view_set_rules_hint(view, FALSE);
+
+       column = gtk_tree_view_column_new();
+       gtk_tree_view_append_column(view, column);
+       gtk_tree_view_column_set_title(column, _("Options"));
+
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "active", COL_BTNACT,
+                                           "inconsistent", COL_BTNINC,
+                                           "visible", COL_BTNVIS,
+                                           "radio", COL_BTNRAD, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "text", COL_OPTION,
+                                           "foreground-gdk",
+                                           COL_COLOR, NULL);
+
+       sel = gtk_tree_view_get_selection(view);
+       gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+       gtk_widget_realize(tree1_w);
+}
+
+static void renderer_edited(GtkCellRendererText * cell,
+                           const gchar * path_string,
+                           const gchar * new_text, gpointer user_data);
+static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
+                            gchar * arg1, gpointer user_data);
+
+void init_right_tree(void)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
+       GtkCellRenderer *renderer;
+       GtkTreeSelection *sel;
+       GtkTreeViewColumn *column;
+       gint i;
+
+       gtk_tree_view_set_model(view, model2);
+       gtk_tree_view_set_headers_visible(view, TRUE);
+       gtk_tree_view_set_rules_hint(view, FALSE);
+
+       column = gtk_tree_view_column_new();
+       gtk_tree_view_append_column(view, column);
+       gtk_tree_view_column_set_title(column, _("Options"));
+
+       renderer = gtk_cell_renderer_pixbuf_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "pixbuf", COL_PIXBUF,
+                                           "visible", COL_PIXVIS, NULL);
+       renderer = gtk_cell_renderer_toggle_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "active", COL_BTNACT,
+                                           "inconsistent", COL_BTNINC,
+                                           "visible", COL_BTNVIS,
+                                           "radio", COL_BTNRAD, NULL);
+       /*g_signal_connect(G_OBJECT(renderer), "toggled",
+          G_CALLBACK(renderer_toggled), NULL); */
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
+                                       renderer, FALSE);
+       gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
+                                           renderer,
+                                           "text", COL_OPTION,
+                                           "foreground-gdk",
+                                           COL_COLOR, NULL);
+
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   _("Name"), renderer,
+                                                   "text", COL_NAME,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "N", renderer,
+                                                   "text", COL_NO,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "M", renderer,
+                                                   "text", COL_MOD,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   "Y", renderer,
+                                                   "text", COL_YES,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       renderer = gtk_cell_renderer_text_new();
+       gtk_tree_view_insert_column_with_attributes(view, -1,
+                                                   _("Value"), renderer,
+                                                   "text", COL_VALUE,
+                                                   "editable",
+                                                   COL_EDIT,
+                                                   "foreground-gdk",
+                                                   COL_COLOR, NULL);
+       g_signal_connect(G_OBJECT(renderer), "edited",
+                        G_CALLBACK(renderer_edited), NULL);
+
+       column = gtk_tree_view_get_column(view, COL_NAME);
+       gtk_tree_view_column_set_visible(column, show_name);
+       column = gtk_tree_view_get_column(view, COL_NO);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_MOD);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_YES);
+       gtk_tree_view_column_set_visible(column, show_range);
+       column = gtk_tree_view_get_column(view, COL_VALUE);
+       gtk_tree_view_column_set_visible(column, show_value);
+
+       if (resizeable) {
+               for (i = 0; i < COL_VALUE; i++) {
+                       column = gtk_tree_view_get_column(view, i);
+                       gtk_tree_view_column_set_resizable(column, TRUE);
+               }
+       }
+
+       sel = gtk_tree_view_get_selection(view);
+       gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
+}
+
+
+/* Utility Functions */
+
+
+static void text_insert_help(struct menu *menu)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       const char *prompt = _(menu_get_prompt(menu));
+       struct gstr help = str_new();
+
+       menu_get_ext_help(menu, &help);
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       gtk_text_buffer_get_bounds(buffer, &start, &end);
+       gtk_text_buffer_delete(buffer, &start, &end);
+       gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
+                                        NULL);
+       str_free(&help);
+}
+
+
+static void text_insert_msg(const char *title, const char *message)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter start, end;
+       const char *msg = message;
+
+       buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
+       gtk_text_buffer_get_bounds(buffer, &start, &end);
+       gtk_text_buffer_delete(buffer, &start, &end);
+       gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
+
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
+                                        NULL);
+       gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
+       gtk_text_buffer_get_end_iter(buffer, &end);
+       gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
+                                        NULL);
+}
+
+
+/* Main Windows Callbacks */
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
+gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
+                                gpointer user_data)
+{
+       GtkWidget *dialog, *label;
+       gint result;
+
+       if (!conf_get_changed())
+               return FALSE;
+
+       dialog = gtk_dialog_new_with_buttons(_("Warning !"),
+                                            GTK_WINDOW(main_wnd),
+                                            (GtkDialogFlags)
+                                            (GTK_DIALOG_MODAL |
+                                             GTK_DIALOG_DESTROY_WITH_PARENT),
+                                            GTK_STOCK_OK,
+                                            GTK_RESPONSE_YES,
+                                            GTK_STOCK_NO,
+                                            GTK_RESPONSE_NO,
+                                            GTK_STOCK_CANCEL,
+                                            GTK_RESPONSE_CANCEL, NULL);
+       gtk_dialog_set_default_response(GTK_DIALOG(dialog),
+                                       GTK_RESPONSE_CANCEL);
+
+       label = gtk_label_new(_("\nSave configuration ?\n"));
+       gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
+       gtk_widget_show(label);
+
+       result = gtk_dialog_run(GTK_DIALOG(dialog));
+       switch (result) {
+       case GTK_RESPONSE_YES:
+               on_save_activate(NULL, NULL);
+               return FALSE;
+       case GTK_RESPONSE_NO:
+               return FALSE;
+       case GTK_RESPONSE_CANCEL:
+       case GTK_RESPONSE_DELETE_EVENT:
+       default:
+               gtk_widget_destroy(dialog);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+
+void on_window1_destroy(GtkObject * object, gpointer user_data)
+{
+       gtk_main_quit();
+}
+
+
+void
+on_window1_size_request(GtkWidget * widget,
+                       GtkRequisition * requisition, gpointer user_data)
+{
+       static gint old_h;
+       gint w, h;
+
+       if (widget->window == NULL)
+               gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+       else
+               gdk_window_get_size(widget->window, &w, &h);
+
+       if (h == old_h)
+               return;
+       old_h = h;
+
+       gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
+}
+
+
+/* Menu & Toolbar Callbacks */
+
+
+static void
+load_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+       const gchar *fn;
+
+       fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+                                            (user_data));
+
+       if (conf_read(fn))
+               text_insert_msg(_("Error"), _("Unable to load configuration !"));
+       else
+               display_tree(&rootmenu);
+}
+
+void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *fs;
+
+       fs = gtk_file_selection_new(_("Load file..."));
+       g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+                        "clicked",
+                        G_CALLBACK(load_filename), (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->ok_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->cancel_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       gtk_widget_show(fs);
+}
+
+
+void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       if (conf_write(NULL))
+               text_insert_msg(_("Error"), _("Unable to save configuration !"));
+}
+
+
+static void
+store_filename(GtkFileSelection * file_selector, gpointer user_data)
+{
+       const gchar *fn;
+
+       fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
+                                            (user_data));
+
+       if (conf_write(fn))
+               text_insert_msg(_("Error"), _("Unable to save configuration !"));
+
+       gtk_widget_destroy(GTK_WIDGET(user_data));
+}
+
+void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *fs;
+
+       fs = gtk_file_selection_new(_("Save file as..."));
+       g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
+                        "clicked",
+                        G_CALLBACK(store_filename), (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->ok_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       g_signal_connect_swapped(GTK_OBJECT
+                                (GTK_FILE_SELECTION(fs)->cancel_button),
+                                "clicked", G_CALLBACK(gtk_widget_destroy),
+                                (gpointer) fs);
+       gtk_widget_show(fs);
+}
+
+
+void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       if (!on_window1_delete_event(NULL, NULL, NULL))
+               gtk_widget_destroy(GTK_WIDGET(main_wnd));
+}
+
+
+void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_name);
+}
+
+
+void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_range);
+
+}
+
+
+void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkTreeViewColumn *col;
+
+       show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
+       col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
+       if (col)
+               gtk_tree_view_column_set_visible(col, show_value);
+}
+
+
+void
+on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+       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);
+       display_tree(&rootmenu);        /* instead of update_tree to speed-up */
+}
+
+
+void
+on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+       opt_mode = OPT_PROMPT;
+       gtk_tree_store_clear(tree2);
+       display_tree(&rootmenu);        /* instead of update_tree to speed-up */
+}
+
+
+void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *intro_text = _(
+           "Welcome to gkc, the GTK+ graphical configuration tool\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"
+           "be compiled as a module.  Clicking on the box will cycle through the three states.\n"
+           "\n"
+           "If you do not see an option (e.g., a device driver) that you\n"
+           "believe should be present, try turning on Show All Options\n"
+           "under the Options menu.\n"
+           "Although there is no cross reference yet to help you figure out\n"
+           "what other options must be enabled to support the option you\n"
+           "are interested in, you can still view the help of a grayed-out\n"
+           "option.\n"
+           "\n"
+           "Toggling Show Debug Info under the Options menu will show \n"
+           "the dependencies, which you can then match by examining other options.");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, intro_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *about_text =
+           _("gkc is copyright (c) 2002 Romain Lievin <roms@lpg.ticalc.org>.\n"
+             "Based on the source code from Roman Zippel.\n");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, about_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
+{
+       GtkWidget *dialog;
+       const gchar *license_text =
+           _("gkc is released under the terms of the GNU GPL v2.\n"
+             "For more information, please see the source code or\n"
+             "visit http://www.fsf.org/licenses/licenses.html\n");
+
+       dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
+                                       GTK_DIALOG_DESTROY_WITH_PARENT,
+                                       GTK_MESSAGE_INFO,
+                                       GTK_BUTTONS_CLOSE, license_text);
+       g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
+                                G_CALLBACK(gtk_widget_destroy),
+                                GTK_OBJECT(dialog));
+       gtk_widget_show_all(dialog);
+}
+
+
+void on_back_clicked(GtkButton * button, gpointer user_data)
+{
+       enum prop_type ptype;
+
+       current = current->parent;
+       ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
+       if (ptype != P_MENU)
+               current = current->parent;
+       display_tree_part();
+
+       if (current == &rootmenu)
+               gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_load_clicked(GtkButton * button, gpointer user_data)
+{
+       on_load1_activate(NULL, user_data);
+}
+
+
+void on_single_clicked(GtkButton * button, gpointer user_data)
+{
+       view_mode = SINGLE_VIEW;
+       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+       gtk_widget_hide(tree1_w);
+       current = &rootmenu;
+       display_tree_part();
+}
+
+
+void on_split_clicked(GtkButton * button, gpointer user_data)
+{
+       gint w, h;
+       view_mode = SPLIT_VIEW;
+       gtk_widget_show(tree1_w);
+       gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
+       gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       display_list();
+
+       /* Disable back btn, like in full mode. */
+       gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_full_clicked(GtkButton * button, gpointer user_data)
+{
+       view_mode = FULL_VIEW;
+       gtk_paned_set_position(GTK_PANED(hpaned), 0);
+       gtk_widget_hide(tree1_w);
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       display_tree(&rootmenu);
+       gtk_widget_set_sensitive(back_btn, FALSE);
+}
+
+
+void on_collapse_clicked(GtkButton * button, gpointer user_data)
+{
+       gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+void on_expand_clicked(GtkButton * button, gpointer user_data)
+{
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+
+/* CTree Callbacks */
+
+/* Change hex/int/string value in the cell */
+static void renderer_edited(GtkCellRendererText * cell,
+                           const gchar * path_string,
+                           const gchar * new_text, gpointer user_data)
+{
+       GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
+       GtkTreeIter iter;
+       const char *old_def, *new_def;
+       struct menu *menu;
+       struct symbol *sym;
+
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return;
+
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+       sym = menu->sym;
+
+       gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
+       new_def = new_text;
+
+       sym_set_string_value(sym, new_def);
+
+       update_tree(&rootmenu, NULL);
+
+       gtk_tree_path_free(path);
+}
+
+/* Change the value of a symbol and update the tree */
+static void change_sym_value(struct menu *menu, gint col)
+{
+       struct symbol *sym = menu->sym;
+       tristate oldval, newval;
+
+       if (!sym)
+               return;
+
+       if (col == COL_NO)
+               newval = no;
+       else if (col == COL_MOD)
+               newval = mod;
+       else if (col == COL_YES)
+               newval = yes;
+       else
+               return;
+
+       switch (sym_get_type(sym)) {
+       case S_BOOLEAN:
+       case S_TRISTATE:
+               oldval = sym_get_tristate_value(sym);
+               if (!sym_tristate_within_range(sym, newval))
+                       newval = yes;
+               sym_set_tristate_value(sym, newval);
+               if (view_mode == FULL_VIEW)
+                       update_tree(&rootmenu, NULL);
+               else if (view_mode == SPLIT_VIEW) {
+                       update_tree(browsed, NULL);
+                       display_list();
+               }
+               else if (view_mode == SINGLE_VIEW)
+                       display_tree_part();    //fixme: keep exp/coll
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+       default:
+               break;
+       }
+}
+
+static void toggle_sym_value(struct menu *menu)
+{
+       if (!menu->sym)
+               return;
+
+       sym_toggle_tristate_value(menu->sym);
+       if (view_mode == FULL_VIEW)
+               update_tree(&rootmenu, NULL);
+       else if (view_mode == SPLIT_VIEW) {
+               update_tree(browsed, NULL);
+               display_list();
+       }
+       else if (view_mode == SINGLE_VIEW)
+               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)
+{
+       gint i;
+
+       for (i = 0; i < COL_NUMBER; i++) {
+               GtkTreeViewColumn *col;
+
+               col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
+               if (col == column)
+                       return i;
+       }
+
+       return -1;
+}
+
+
+/* User click: update choice (full) or goes down (single) */
+gboolean
+on_treeview2_button_press_event(GtkWidget * widget,
+                               GdkEventButton * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+       gint col;
+
+#if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
+       gint tx = (gint) event->x;
+       gint ty = (gint) event->y;
+       gint cx, cy;
+
+       gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+                                     &cy);
+#else
+       gtk_tree_view_get_cursor(view, &path, &column);
+#endif
+       if (path == NULL)
+               return FALSE;
+
+       if (!gtk_tree_model_get_iter(model2, &iter, path))
+               return FALSE;
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+       col = column2index(column);
+       if (event->type == GDK_2BUTTON_PRESS) {
+               enum prop_type ptype;
+               ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+
+               if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
+                       // goes down into menu
+                       current = menu;
+                       display_tree_part();
+                       gtk_widget_set_sensitive(back_btn, TRUE);
+               } else if ((col == COL_OPTION)) {
+                       toggle_sym_value(menu);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               }
+       } else {
+               if (col == COL_VALUE) {
+                       toggle_sym_value(menu);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               } else if (col == COL_NO || col == COL_MOD
+                          || col == COL_YES) {
+                       change_sym_value(menu, col);
+                       gtk_tree_view_expand_row(view, path, TRUE);
+               }
+       }
+
+       return FALSE;
+}
+
+/* Key pressed: update choice */
+gboolean
+on_treeview2_key_press_event(GtkWidget * widget,
+                            GdkEventKey * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+       gint col;
+
+       gtk_tree_view_get_cursor(view, &path, &column);
+       if (path == NULL)
+               return FALSE;
+
+       if (event->keyval == GDK_space) {
+               if (gtk_tree_view_row_expanded(view, path))
+                       gtk_tree_view_collapse_row(view, path);
+               else
+                       gtk_tree_view_expand_row(view, path, FALSE);
+               return TRUE;
+       }
+       if (event->keyval == GDK_KP_Enter) {
+       }
+       if (widget == tree1_w)
+               return FALSE;
+
+       gtk_tree_model_get_iter(model2, &iter, path);
+       gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+
+       if (!strcasecmp(event->string, "n"))
+               col = COL_NO;
+       else if (!strcasecmp(event->string, "m"))
+               col = COL_MOD;
+       else if (!strcasecmp(event->string, "y"))
+               col = COL_YES;
+       else
+               col = -1;
+       change_sym_value(menu, col);
+
+       return FALSE;
+}
+
+
+/* Row selection changed: update help */
+void
+on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
+{
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       struct menu *menu;
+
+       selection = gtk_tree_view_get_selection(treeview);
+       if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
+               gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
+               text_insert_help(menu);
+       }
+}
+
+
+/* User click: display sub-tree in the right frame. */
+gboolean
+on_treeview1_button_press_event(GtkWidget * widget,
+                               GdkEventButton * event, gpointer user_data)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(widget);
+       GtkTreePath *path;
+       GtkTreeViewColumn *column;
+       GtkTreeIter iter;
+       struct menu *menu;
+
+       gint tx = (gint) event->x;
+       gint ty = (gint) event->y;
+       gint cx, cy;
+
+       gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
+                                     &cy);
+       if (path == NULL)
+               return FALSE;
+
+       gtk_tree_model_get_iter(model1, &iter, path);
+       gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
+
+       if (event->type == GDK_2BUTTON_PRESS) {
+               toggle_sym_value(menu);
+               current = menu;
+               display_tree_part();
+       } else {
+               browsed = menu;
+               display_tree_part();
+       }
+
+       gtk_widget_realize(tree2_w);
+       gtk_tree_view_set_cursor(view, path, NULL, FALSE);
+       gtk_widget_grab_focus(tree2_w);
+
+       return FALSE;
+}
+
+
+/* Fill a row of strings */
+static gchar **fill_row(struct menu *menu)
+{
+       static gchar *row[COL_NUMBER];
+       struct symbol *sym = menu->sym;
+       const char *def;
+       int stype;
+       tristate val;
+       enum prop_type ptype;
+       int i;
+
+       for (i = COL_OPTION; i <= COL_COLOR; i++)
+               g_free(row[i]);
+       bzero(row, sizeof(row));
+
+       row[COL_OPTION] =
+           g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
+                           sym && !sym_has_value(sym) ? "(NEW)" : "");
+
+       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");
+       else
+               row[COL_COLOR] = g_strdup("Black");
+
+       ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+       switch (ptype) {
+       case P_MENU:
+               row[COL_PIXBUF] = (gchar *) xpm_menu;
+               if (view_mode == SINGLE_VIEW)
+                       row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       case P_COMMENT:
+               row[COL_PIXBUF] = (gchar *) xpm_void;
+               row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       default:
+               row[COL_PIXBUF] = (gchar *) xpm_void;
+               row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+               break;
+       }
+
+       if (!sym)
+               return row;
+       row[COL_NAME] = g_strdup(sym->name);
+
+       sym_calc_value(sym);
+       sym->flags &= ~SYMBOL_CHANGED;
+
+       if (sym_is_choice(sym)) {       // parse childs for getting final value
+               struct menu *child;
+               struct symbol *def_sym = sym_get_choice_value(sym);
+               struct menu *def_menu = NULL;
+
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+
+               for (child = menu->list; child; child = child->next) {
+                       if (menu_is_visible(child)
+                           && child->sym == def_sym)
+                               def_menu = child;
+               }
+
+               if (def_menu)
+                       row[COL_VALUE] =
+                           g_strdup(_(menu_get_prompt(def_menu)));
+       }
+       if (sym->flags & SYMBOL_CHOICEVAL)
+               row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
+
+       stype = sym_get_type(sym);
+       switch (stype) {
+       case S_BOOLEAN:
+               if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
+                       row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
+               if (sym_is_choice(sym))
+                       break;
+       case S_TRISTATE:
+               val = sym_get_tristate_value(sym);
+               switch (val) {
+               case no:
+                       row[COL_NO] = g_strdup("N");
+                       row[COL_VALUE] = g_strdup("N");
+                       row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
+                       row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+                       break;
+               case mod:
+                       row[COL_MOD] = g_strdup("M");
+                       row[COL_VALUE] = g_strdup("M");
+                       row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
+                       break;
+               case yes:
+                       row[COL_YES] = g_strdup("Y");
+                       row[COL_VALUE] = g_strdup("Y");
+                       row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
+                       row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
+                       break;
+               }
+
+               if (val != no && sym_tristate_within_range(sym, no))
+                       row[COL_NO] = g_strdup("_");
+               if (val != mod && sym_tristate_within_range(sym, mod))
+                       row[COL_MOD] = g_strdup("_");
+               if (val != yes && sym_tristate_within_range(sym, yes))
+                       row[COL_YES] = g_strdup("_");
+               break;
+       case S_INT:
+       case S_HEX:
+       case S_STRING:
+               def = sym_get_string_value(sym);
+               row[COL_VALUE] = g_strdup(def);
+               row[COL_EDIT] = GINT_TO_POINTER(TRUE);
+               row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
+               break;
+       }
+
+       return row;
+}
+
+
+/* Set the node content with a row of strings */
+static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
+{
+       GdkColor color;
+       gboolean success;
+       GdkPixbuf *pix;
+
+       pix = gdk_pixbuf_new_from_xpm_data((const char **)
+                                          row[COL_PIXBUF]);
+
+       gdk_color_parse(row[COL_COLOR], &color);
+       gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
+                                 FALSE, FALSE, &success);
+
+       gtk_tree_store_set(tree, node,
+                          COL_OPTION, row[COL_OPTION],
+                          COL_NAME, row[COL_NAME],
+                          COL_NO, row[COL_NO],
+                          COL_MOD, row[COL_MOD],
+                          COL_YES, row[COL_YES],
+                          COL_VALUE, row[COL_VALUE],
+                          COL_MENU, (gpointer) menu,
+                          COL_COLOR, &color,
+                          COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
+                          COL_PIXBUF, pix,
+                          COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
+                          COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
+                          COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
+                          COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
+                          COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
+                          -1);
+
+       g_object_unref(pix);
+}
+
+
+/* Add a node to the tree */
+static void place_node(struct menu *menu, char **row)
+{
+       GtkTreeIter *parent = parents[indent - 1];
+       GtkTreeIter *node = parents[indent];
+
+       gtk_tree_store_append(tree, node, parent);
+       set_node(node, menu, row);
+}
+
+
+/* Find a node in the GTK+ tree */
+static GtkTreeIter found;
+
+/*
+ * Find a menu in the GtkTree starting at parent.
+ */
+GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
+                                   struct menu *tofind)
+{
+       GtkTreeIter iter;
+       GtkTreeIter *child = &iter;
+       gboolean valid;
+       GtkTreeIter *ret;
+
+       valid = gtk_tree_model_iter_children(model2, child, parent);
+       while (valid) {
+               struct menu *menu;
+
+               gtk_tree_model_get(model2, child, 6, &menu, -1);
+
+               if (menu == tofind) {
+                       memcpy(&found, child, sizeof(GtkTreeIter));
+                       return &found;
+               }
+
+               ret = gtktree_iter_find_node(child, tofind);
+               if (ret)
+                       return ret;
+
+               valid = gtk_tree_model_iter_next(model2, child);
+       }
+
+       return NULL;
+}
+
+
+/*
+ * Update the tree by adding/removing entries
+ * Does not change other nodes
+ */
+static void update_tree(struct menu *src, GtkTreeIter * dst)
+{
+       struct menu *child1;
+       GtkTreeIter iter, tmp;
+       GtkTreeIter *child2 = &iter;
+       gboolean valid;
+       GtkTreeIter *sibling;
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *menu1, *menu2;
+
+       if (src == &rootmenu)
+               indent = 1;
+
+       valid = gtk_tree_model_iter_children(model2, child2, dst);
+       for (child1 = src->list; child1; child1 = child1->next) {
+
+               prop = child1->prompt;
+               sym = child1->sym;
+
+             reparse:
+               menu1 = child1;
+               if (valid)
+                       gtk_tree_model_get(model2, child2, COL_MENU,
+                                          &menu2, -1);
+               else
+                       menu2 = NULL;   // force adding of a first child
+
+#ifdef DEBUG
+               printf("%*c%s | %s\n", indent, ' ',
+                      menu1 ? menu_get_prompt(menu1) : "nil",
+                      menu2 ? menu_get_prompt(menu2) : "nil");
+#endif
+
+               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) {
+                               memcpy(&tmp, child2, sizeof(GtkTreeIter));
+                               valid = gtk_tree_model_iter_next(model2,
+                                                                child2);
+                               gtk_tree_store_remove(tree2, &tmp);
+                               if (!valid)
+                                       return;         /* next parent */
+                               else
+                                       goto reparse;   /* next child */
+                       } else
+                               continue;
+               }
+
+               if (menu1 != menu2) {
+                       if (gtktree_iter_find_node(dst, menu1) == NULL) {       // add node
+                               if (!valid && !menu2)
+                                       sibling = NULL;
+                               else
+                                       sibling = child2;
+                               gtk_tree_store_insert_before(tree2,
+                                                            child2,
+                                                            dst, sibling);
+                               set_node(child2, menu1, fill_row(menu1));
+                               if (menu2 == NULL)
+                                       valid = TRUE;
+                       } else {        // remove node
+                               memcpy(&tmp, child2, sizeof(GtkTreeIter));
+                               valid = gtk_tree_model_iter_next(model2,
+                                                                child2);
+                               gtk_tree_store_remove(tree2, &tmp);
+                               if (!valid)
+                                       return; // next parent
+                               else
+                                       goto reparse;   // next child
+                       }
+               } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
+                       set_node(child2, menu1, fill_row(menu1));
+               }
+
+               indent++;
+               update_tree(child1, child2);
+               indent--;
+
+               valid = gtk_tree_model_iter_next(model2, child2);
+       }
+}
+
+
+/* Display the whole tree (single/split/full view) */
+static void display_tree(struct menu *menu)
+{
+       struct symbol *sym;
+       struct property *prop;
+       struct menu *child;
+       enum prop_type ptype;
+
+       if (menu == &rootmenu) {
+               indent = 1;
+               current = &rootmenu;
+       }
+
+       for (child = menu->list; child; child = child->next) {
+               prop = child->prompt;
+               sym = child->sym;
+               ptype = prop ? prop->type : P_UNKNOWN;
+
+               if (sym)
+                       sym->flags &= ~SYMBOL_CHANGED;
+
+               if ((view_mode == SPLIT_VIEW)
+                   && !(child->flags & MENU_ROOT) && (tree == tree1))
+                       continue;
+
+               if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
+                   && (tree == tree2))
+                       continue;
+
+               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));
+#ifdef DEBUG
+               printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
+               printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
+               printf("%s", prop_get_type_name(ptype));
+               printf(" | ");
+               if (sym) {
+                       printf("%s", sym_type_name(sym->type));
+                       printf(" | ");
+                       printf("%s", dbg_sym_flags(sym->flags));
+                       printf("\n");
+               } else
+                       printf("\n");
+#endif
+               if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
+                   && (tree == tree2))
+                       continue;
+/*
+                if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
+                   || (view_mode == FULL_VIEW)
+                   || (view_mode == SPLIT_VIEW))*/
+               if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
+                   || (view_mode == FULL_VIEW)
+                   || (view_mode == SPLIT_VIEW)) {
+                       indent++;
+                       display_tree(child);
+                       indent--;
+               }
+       }
+}
+
+/* Display a part of the tree starting at current node (single/split view) */
+static void display_tree_part(void)
+{
+       if (tree2)
+               gtk_tree_store_clear(tree2);
+       if (view_mode == SINGLE_VIEW)
+               display_tree(current);
+       else if (view_mode == SPLIT_VIEW)
+               display_tree(browsed);
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
+}
+
+/* Display the list in the left frame (split view) */
+static void display_list(void)
+{
+       if (tree1)
+               gtk_tree_store_clear(tree1);
+
+       tree = tree1;
+       display_tree(&rootmenu);
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
+       tree = tree2;
+}
+
+void fixup_rootmenu(struct menu *menu)
+{
+       struct menu *child;
+       static int menu_cnt = 0;
+
+       menu->flags |= MENU_ROOT;
+       for (child = menu->list; child; child = child->next) {
+               if (child->prompt && child->prompt->type == P_MENU) {
+                       menu_cnt++;
+                       fixup_rootmenu(child);
+                       menu_cnt--;
+               } else if (!menu_cnt)
+                       fixup_rootmenu(child);
+       }
+}
+
+
+/* Main */
+int main(int ac, char *av[])
+{
+       const char *name;
+       char *env;
+       gchar *glade_file;
+
+#ifndef LKC_DIRECT_LINK
+       kconfig_load();
+#endif
+
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       bind_textdomain_codeset(PACKAGE, "UTF-8");
+       textdomain(PACKAGE);
+
+       /* GTK stuffs */
+       gtk_set_locale();
+       gtk_init(&ac, &av);
+       glade_init();
+
+       //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
+       //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
+
+       /* Determine GUI path */
+       env = getenv(SRCTREE);
+       if (env)
+               glade_file = g_strconcat(env, "/scripts/kconfig/gconf.glade", NULL);
+       else if (av[0][0] == '/')
+               glade_file = g_strconcat(av[0], ".glade", NULL);
+       else
+               glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
+
+       /* Conf stuffs */
+       if (ac > 1 && av[1][0] == '-') {
+               switch (av[1][1]) {
+               case 'a':
+                       //showAll = 1;
+                       break;
+               case 'h':
+               case '?':
+                       printf("%s <config>\n", av[0]);
+                       exit(0);
+               }
+               name = av[2];
+       } else
+               name = av[1];
+
+       conf_parse(name);
+       fixup_rootmenu(&rootmenu);
+       conf_read(NULL);
+
+       /* Load the interface and connect signals */
+       init_main_window(glade_file);
+       init_tree_model();
+       init_left_tree();
+       init_right_tree();
+
+       switch (view_mode) {
+       case SINGLE_VIEW:
+               display_tree_part();
+               break;
+       case SPLIT_VIEW:
+               display_list();
+               break;
+       case FULL_VIEW:
+               display_tree(&rootmenu);
+               break;
+       }
+
+       gtk_main();
+
+       return 0;
+}
+
+static void conf_changed(void)
+{
+       bool changed = conf_get_changed();
+       gtk_widget_set_sensitive(save_btn, changed);
+       gtk_widget_set_sensitive(save_menu_item, changed);
+}
diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade
new file mode 100644 (file)
index 0000000..aa483cb
--- /dev/null
@@ -0,0 +1,661 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+
+<glade-interface>
+
+<widget class="GtkWindow" id="window1">
+  <property name="visible">True</property>
+  <property name="title" translatable="yes">Gtk Kernel Configurator</property>
+  <property name="type">GTK_WINDOW_TOPLEVEL</property>
+  <property name="window_position">GTK_WIN_POS_NONE</property>
+  <property name="modal">False</property>
+  <property name="default_width">640</property>
+  <property name="default_height">480</property>
+  <property name="resizable">True</property>
+  <property name="destroy_with_parent">False</property>
+  <property name="decorated">True</property>
+  <property name="skip_taskbar_hint">False</property>
+  <property name="skip_pager_hint">False</property>
+  <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+  <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+  <signal name="destroy" handler="on_window1_destroy" object="window1"/>
+  <signal name="size_request" handler="on_window1_size_request" object="vpaned1" last_modification_time="Fri, 11 Jan 2002 16:17:11 GMT"/>
+  <signal name="delete_event" handler="on_window1_delete_event" object="window1" last_modification_time="Sun, 09 Mar 2003 19:42:46 GMT"/>
+
+  <child>
+    <widget class="GtkVBox" id="vbox1">
+      <property name="visible">True</property>
+      <property name="homogeneous">False</property>
+      <property name="spacing">0</property>
+
+      <child>
+       <widget class="GtkMenuBar" id="menubar1">
+         <property name="visible">True</property>
+
+         <child>
+           <widget class="GtkMenuItem" id="file1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_File</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="file1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="load1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Load a config file</property>
+                     <property name="label" translatable="yes">_Load</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_load1_activate"/>
+                     <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image39">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-open</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Save the config in .config</property>
+                     <property name="label" translatable="yes">_Save</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_save_activate"/>
+                     <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image40">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-save</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="save_as1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Save the config in a file</property>
+                     <property name="label" translatable="yes">Save _as</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_save_as1_activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image41">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-save-as</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separator1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="quit1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_Quit</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_quit1_activate"/>
+                     <accelerator key="Q" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image42">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-quit</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="options1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Options</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="options1_menu">
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_name1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show name</property>
+                     <property name="label" translatable="yes">Show _name</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_name1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_range1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show range (Y/M/N)</property>
+                     <property name="label" translatable="yes">Show _range</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_range1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkCheckMenuItem" id="show_data1">
+                     <property name="visible">True</property>
+                     <property name="tooltip" translatable="yes">Show value of the option</property>
+                     <property name="label" translatable="yes">Show _data</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <signal name="activate" handler="on_show_data1_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkSeparatorMenuItem" id="separator2">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <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="tooltip" translatable="yes">Show all options</property>
+                     <property name="label" translatable="yes">Show all _options</property>
+                     <property name="use_underline">True</property>
+                     <property name="active">False</property>
+                     <property name="group">set_option_mode1</property>
+                     <signal name="activate" handler="on_set_option_mode2_activate"/>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkRadioMenuItem" id="set_option_mode3">
+                     <property name="visible">True</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="active">False</property>
+                     <property name="group">set_option_mode1</property>
+                     <signal name="activate" handler="on_set_option_mode3_activate"/>
+                   </widget>
+                 </child>
+
+               </widget>
+             </child>
+           </widget>
+         </child>
+
+         <child>
+           <widget class="GtkMenuItem" id="help1">
+             <property name="visible">True</property>
+             <property name="label" translatable="yes">_Help</property>
+             <property name="use_underline">True</property>
+
+             <child>
+               <widget class="GtkMenu" id="help1_menu">
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="introduction1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_Introduction</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_introduction1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+                     <accelerator key="I" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image43">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-dialog-question</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="about1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_About</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_about1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+                     <accelerator key="A" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image44">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-properties</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+
+                 <child>
+                   <widget class="GtkImageMenuItem" id="license1">
+                     <property name="visible">True</property>
+                     <property name="label" translatable="yes">_License</property>
+                     <property name="use_underline">True</property>
+                     <signal name="activate" handler="on_license1_activate" last_modification_time="Fri, 15 Nov 2002 20:26:30 GMT"/>
+
+                     <child internal-child="image">
+                       <widget class="GtkImage" id="image45">
+                         <property name="visible">True</property>
+                         <property name="stock">gtk-justify-fill</property>
+                         <property name="icon_size">1</property>
+                         <property name="xalign">0.5</property>
+                         <property name="yalign">0.5</property>
+                         <property name="xpad">0</property>
+                         <property name="ypad">0</property>
+                       </widget>
+                     </child>
+                   </widget>
+                 </child>
+               </widget>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHandleBox" id="handlebox1">
+         <property name="visible">True</property>
+         <property name="shadow_type">GTK_SHADOW_OUT</property>
+         <property name="handle_position">GTK_POS_LEFT</property>
+         <property name="snap_edge">GTK_POS_TOP</property>
+
+         <child>
+           <widget class="GtkToolbar" id="toolbar1">
+             <property name="visible">True</property>
+             <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+             <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+             <property name="tooltips">True</property>
+             <property name="show_arrow">True</property>
+
+             <child>
+               <widget class="GtkToolButton" id="button1">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Goes up of one level (single view)</property>
+                 <property name="label" translatable="yes">Back</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-undo</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_back_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem1">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator1">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button2">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Load a config file</property>
+                 <property name="label" translatable="yes">Load</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-open</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_load_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button3">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Save a config file</property>
+                 <property name="label" translatable="yes">Save</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-save</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_save_activate"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem2">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator2">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button4">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Single view</property>
+                 <property name="label" translatable="yes">Single</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_single_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:39 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button5">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Split view</property>
+                 <property name="label" translatable="yes">Split</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_split_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:45 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button6">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Full view</property>
+                 <property name="label" translatable="yes">Full</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-missing-image</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_full_clicked" last_modification_time="Sun, 12 Jan 2003 14:28:50 GMT"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolItem" id="toolitem3">
+                 <property name="visible">True</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+
+                 <child>
+                   <widget class="GtkVSeparator" id="vseparator3">
+                     <property name="visible">True</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button7">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Collapse the whole tree in the right frame</property>
+                 <property name="label" translatable="yes">Collapse</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-remove</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_collapse_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkToolButton" id="button8">
+                 <property name="visible">True</property>
+                 <property name="tooltip" translatable="yes">Expand the whole tree in the right frame</property>
+                 <property name="label" translatable="yes">Expand</property>
+                 <property name="use_underline">True</property>
+                 <property name="stock_id">gtk-add</property>
+                 <property name="visible_horizontal">True</property>
+                 <property name="visible_vertical">True</property>
+                 <property name="is_important">False</property>
+                 <signal name="clicked" handler="on_expand_clicked"/>
+               </widget>
+               <packing>
+                 <property name="expand">False</property>
+                 <property name="homogeneous">True</property>
+               </packing>
+             </child>
+           </widget>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">False</property>
+         <property name="fill">False</property>
+       </packing>
+      </child>
+
+      <child>
+       <widget class="GtkHPaned" id="hpaned1">
+         <property name="width_request">1</property>
+         <property name="visible">True</property>
+         <property name="can_focus">True</property>
+         <property name="position">0</property>
+
+         <child>
+           <widget class="GtkScrolledWindow" id="scrolledwindow1">
+             <property name="visible">True</property>
+             <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+             <property name="shadow_type">GTK_SHADOW_IN</property>
+             <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+             <child>
+               <widget class="GtkTreeView" id="treeview1">
+                 <property name="visible">True</property>
+                 <property name="can_focus">True</property>
+                 <property name="headers_visible">True</property>
+                 <property name="rules_hint">False</property>
+                 <property name="reorderable">False</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="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"/>
+               </widget>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">False</property>
+           </packing>
+         </child>
+
+         <child>
+           <widget class="GtkVPaned" id="vpaned1">
+             <property name="visible">True</property>
+             <property name="can_focus">True</property>
+             <property name="position">0</property>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow2">
+                 <property name="visible">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTreeView" id="treeview2">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="has_focus">True</property>
+                     <property name="headers_visible">True</property>
+                     <property name="rules_hint">False</property>
+                     <property name="reorderable">False</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="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"/>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="shrink">True</property>
+                 <property name="resize">False</property>
+               </packing>
+             </child>
+
+             <child>
+               <widget class="GtkScrolledWindow" id="scrolledwindow3">
+                 <property name="visible">True</property>
+                 <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+                 <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+                 <property name="shadow_type">GTK_SHADOW_IN</property>
+                 <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+                 <child>
+                   <widget class="GtkTextView" id="textview3">
+                     <property name="visible">True</property>
+                     <property name="can_focus">True</property>
+                     <property name="editable">False</property>
+                     <property name="overwrite">False</property>
+                     <property name="accepts_tab">True</property>
+                     <property name="justification">GTK_JUSTIFY_LEFT</property>
+                     <property name="wrap_mode">GTK_WRAP_WORD</property>
+                     <property name="cursor_visible">True</property>
+                     <property name="pixels_above_lines">0</property>
+                     <property name="pixels_below_lines">0</property>
+                     <property name="pixels_inside_wrap">0</property>
+                     <property name="left_margin">0</property>
+                     <property name="right_margin">0</property>
+                     <property name="indent">0</property>
+                     <property name="text" translatable="yes">Sorry, no help available for this option yet.</property>
+                   </widget>
+                 </child>
+               </widget>
+               <packing>
+                 <property name="shrink">True</property>
+                 <property name="resize">True</property>
+               </packing>
+             </child>
+           </widget>
+           <packing>
+             <property name="shrink">True</property>
+             <property name="resize">True</property>
+           </packing>
+         </child>
+       </widget>
+       <packing>
+         <property name="padding">0</property>
+         <property name="expand">True</property>
+         <property name="fill">True</property>
+       </packing>
+      </child>
+    </widget>
+  </child>
+</widget>
+
+</glade-interface>
diff --git a/scripts/kconfig/images.c b/scripts/kconfig/images.c
new file mode 100644 (file)
index 0000000..d4f84bd
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Released under the terms of the GNU GPL v2.0.
+ */
+
+static const char *xpm_load[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"c c #838100",
+"a c #ffff00",
+"b c #ffffff",
+"......................",
+"......................",
+"......................",
+"............####....#.",
+"...........#....##.##.",
+"..................###.",
+".................####.",
+".####...........#####.",
+"#abab##########.......",
+"#babababababab#.......",
+"#ababababababa#.......",
+"#babababababab#.......",
+"#ababab###############",
+"#babab##cccccccccccc##",
+"#abab##cccccccccccc##.",
+"#bab##cccccccccccc##..",
+"#ab##cccccccccccc##...",
+"#b##cccccccccccc##....",
+"###cccccccccccc##.....",
+"##cccccccccccc##......",
+"###############.......",
+"......................"};
+
+static const char *xpm_save[] = {
+"22 22 5 1",
+". c None",
+"# c #000000",
+"a c #838100",
+"b c #c5c2c5",
+"c c #cdb6d5",
+"......................",
+".####################.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbbbb#bb#.",
+".#aa#bbbbbbbbbcbb####.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbccbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aa#bbbbbbbbbbbb#aa#.",
+".#aaa############aaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaaaaaaaaaaaaaaaaa#.",
+".#aaa#############aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+".#aaa#########bbb#aa#.",
+"..##################..",
+"......................"};
+
+static const char *xpm_back[] = {
+"22 22 3 1",
+". c None",
+"# c #000083",
+"a c #838183",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"...........######a....",
+"..#......##########...",
+"..##...####......##a..",
+"..###.###.........##..",
+"..######..........##..",
+"..#####...........##..",
+"..######..........##..",
+"..#######.........##..",
+"..########.......##a..",
+"...............a###...",
+"...............###....",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................",
+"......................"};
+
+static const char *xpm_tree_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......#...............",
+"......########........",
+"......................",
+"......................"};
+
+static const char *xpm_single_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"..........#...........",
+"......................",
+"......................"};
+
+static const char *xpm_split_view[] = {
+"22 22 2 1",
+". c None",
+"# c #000000",
+"......................",
+"......................",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......#......#........",
+"......................",
+"......................"};
+
+static const char *xpm_symbol_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_mod[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+" .        . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_symbol_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .        . ",
+" .      . . ",
+" .     .. . ",
+" . .  ..  . ",
+" . ....   . ",
+" .  ..    . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_choice_no[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .        . ",
+" .        . ",
+" .        . ",
+" .        . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_choice_yes[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"    ....    ",
+"  ..    ..  ",
+"  .      .  ",
+" .   ..   . ",
+" .  ....  . ",
+" .  ....  . ",
+" .   ..   . ",
+"  .      .  ",
+"  ..    ..  ",
+"    ....    ",
+"            "};
+
+static const char *xpm_menu[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" . ..     . ",
+" . ....   . ",
+" . ...... . ",
+" . ...... . ",
+" . ....   . ",
+" . ..     . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_menu_inv[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .......... ",
+" ..  ...... ",
+" ..    .... ",
+" ..      .. ",
+" ..      .. ",
+" ..    .... ",
+" ..  ...... ",
+" .......... ",
+" .......... ",
+"            "};
+
+static const char *xpm_menuback[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+" .......... ",
+" .        . ",
+" .     .. . ",
+" .   .... . ",
+" . ...... . ",
+" . ...... . ",
+" .   .... . ",
+" .     .. . ",
+" .        . ",
+" .......... ",
+"            "};
+
+static const char *xpm_void[] = {
+"12 12 2 1",
+"  c white",
+". c black",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            ",
+"            "};
diff --git a/scripts/kconfig/kconfig_load.c b/scripts/kconfig/kconfig_load.c
new file mode 100644 (file)
index 0000000..dbdcaad
--- /dev/null
@@ -0,0 +1,35 @@
+#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
+}
diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c
new file mode 100644 (file)
index 0000000..e9d8e79
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2005
+ *
+ * Released under the terms of the GNU GPL v2.0
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+
+static char *escape(const char* text, char *bf, int len)
+{
+       char *bfp = bf;
+       int multiline = strchr(text, '\n') != NULL;
+       int eol = 0;
+       int textlen = strlen(text);
+
+       if ((textlen > 0) && (text[textlen-1] == '\n'))
+               eol = 1;
+
+       *bfp++ = '"';
+       --len;
+
+       if (multiline) {
+               *bfp++ = '"';
+               *bfp++ = '\n';
+               *bfp++ = '"';
+               len -= 3;
+       }
+
+       while (*text != '\0' && len > 1) {
+               if (*text == '"')
+                       *bfp++ = '\\';
+               else if (*text == '\n') {
+                       *bfp++ = '\\';
+                       *bfp++ = 'n';
+                       *bfp++ = '"';
+                       *bfp++ = '\n';
+                       *bfp++ = '"';
+                       len -= 5;
+                       ++text;
+                       goto next;
+               }
+               else if (*text == '\\') {
+                       *bfp++ = '\\';
+                       len--;
+               }
+               *bfp++ = *text++;
+next:
+               --len;
+       }
+
+       if (multiline && eol)
+               bfp -= 3;
+
+       *bfp++ = '"';
+       *bfp = '\0';
+
+       return bf;
+}
+
+struct file_line {
+       struct file_line *next;
+       const char *file;
+       int lineno;
+};
+
+static struct file_line *file_line__new(const char *file, int lineno)
+{
+       struct file_line *self = malloc(sizeof(*self));
+
+       if (self == NULL)
+               goto out;
+
+       self->file   = file;
+       self->lineno = lineno;
+      &n