[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Minios-devel] [UNIKRAFT PATCH v3 01/23] kconfig: Import kconfig from Linux kernel



Hi Sharan,

Thanks for these patch series, this patch looks ok.

-- Felipe

Reviewed-by: Felipe Huici <felipe.huici@xxxxxxxxx>

On 19.09.19, 14:08, "Minios-devel on behalf of Sharan Santhanam" 
<minios-devel-bounces@xxxxxxxxxxxxxxxxxxxx on behalf of 
Sharan.Santhanam@xxxxxxxxx> wrote:

    Importing the kconfig from the Linux kernel
    Kernel Tag: v5.2
    
    Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx>
    ---
     support/kconfig.new/Makefile                       |  208 ++
     support/kconfig.new/conf.c                         |  702 +++++
     support/kconfig.new/confdata.c                     | 1380 ++++++++++
     support/kconfig.new/expr.c                         | 1297 +++++++++
     support/kconfig.new/expr.h                         |  331 +++
     support/kconfig.new/gconf-cfg.sh                   |   30 +
     support/kconfig.new/gconf.c                        | 1516 +++++++++++
     support/kconfig.new/gconf.glade                    |  661 +++++
     support/kconfig.new/images.c                       |  328 +++
     support/kconfig.new/images.h                       |   33 +
     support/kconfig.new/lexer.l                        |  471 ++++
     support/kconfig.new/list.h                         |  132 +
     support/kconfig.new/lkc.h                          |  159 ++
     support/kconfig.new/lkc_proto.h                    |   66 +
     support/kconfig.new/lxdialog/BIG.FAT.WARNING       |    4 +
     support/kconfig.new/lxdialog/checklist.c           |  319 +++
     support/kconfig.new/lxdialog/dialog.h              |  238 ++
     support/kconfig.new/lxdialog/inputbox.c            |  289 ++
     support/kconfig.new/lxdialog/menubox.c             |  424 +++
     support/kconfig.new/lxdialog/textbox.c             |  395 +++
     support/kconfig.new/lxdialog/util.c                |  700 +++++
     support/kconfig.new/lxdialog/yesno.c               |  101 +
     support/kconfig.new/mconf-cfg.sh                   |   47 +
     support/kconfig.new/mconf.c                        | 1039 ++++++++
     support/kconfig.new/menu.c                         |  867 ++++++
     support/kconfig.new/merge_config.sh                |  189 ++
     support/kconfig.new/nconf-cfg.sh                   |   47 +
     support/kconfig.new/nconf.c                        | 1555 +++++++++++
     support/kconfig.new/nconf.gui.c                    |  664 +++++
     support/kconfig.new/nconf.h                        |   92 +
     support/kconfig.new/parser.y                       |  731 +++++
     support/kconfig.new/preprocess.c                   |  573 ++++
     support/kconfig.new/qconf-cfg.sh                   |   32 +
     support/kconfig.new/qconf.cc                       | 1896 +++++++++++++
     support/kconfig.new/qconf.h                        |  331 +++
     support/kconfig.new/streamline_config.pl           |  682 +++++
     support/kconfig.new/symbol.c                       | 1331 +++++++++
     support/kconfig.new/tests/auto_submenu/Kconfig     |   52 +
     support/kconfig.new/tests/auto_submenu/__init__.py |   13 +
     .../kconfig.new/tests/auto_submenu/expected_stdout |   10 +
     support/kconfig.new/tests/choice/Kconfig           |   56 +
     support/kconfig.new/tests/choice/__init__.py       |   41 +
     .../tests/choice/alldef_expected_config            |    5 +
     .../tests/choice/allmod_expected_config            |    9 +
     .../kconfig.new/tests/choice/allno_expected_config |    5 +
     .../tests/choice/allyes_expected_config            |    9 +
     .../tests/choice/oldask0_expected_stdout           |   10 +
     support/kconfig.new/tests/choice/oldask1_config    |    2 +
     .../tests/choice/oldask1_expected_stdout           |   15 +
     .../tests/choice_value_with_m_dep/Kconfig          |   21 +
     .../tests/choice_value_with_m_dep/__init__.py      |   16 +
     .../tests/choice_value_with_m_dep/config           |    2 +
     .../tests/choice_value_with_m_dep/expected_config  |    3 +
     .../tests/choice_value_with_m_dep/expected_stdout  |    4 +
     support/kconfig.new/tests/conftest.py              |  291 ++
     .../kconfig.new/tests/err_recursive_dep/Kconfig    |   63 +
     .../tests/err_recursive_dep/__init__.py            |   10 +
     .../tests/err_recursive_dep/expected_stderr        |   38 +
     .../kconfig.new/tests/err_recursive_inc/Kconfig    |    2 +
     .../tests/err_recursive_inc/Kconfig.inc1           |    5 +
     .../tests/err_recursive_inc/Kconfig.inc2           |    4 +
     .../tests/err_recursive_inc/Kconfig.inc3           |    2 +
     .../tests/err_recursive_inc/__init__.py            |   11 +
     .../tests/err_recursive_inc/expected_stderr        |    6 +
     support/kconfig.new/tests/inter_choice/Kconfig     |   25 +
     support/kconfig.new/tests/inter_choice/__init__.py |   15 +
     support/kconfig.new/tests/inter_choice/defconfig   |    1 +
     .../kconfig.new/tests/inter_choice/expected_config |    4 +
     .../kconfig.new/tests/new_choice_with_dep/Kconfig  |   39 +
     .../tests/new_choice_with_dep/__init__.py          |   15 +
     .../kconfig.new/tests/new_choice_with_dep/config   |    3 +
     .../tests/new_choice_with_dep/expected_stdout      |   10 +
     .../tests/no_write_if_dep_unmet/Kconfig            |   16 +
     .../tests/no_write_if_dep_unmet/__init__.py        |   20 +
     .../kconfig.new/tests/no_write_if_dep_unmet/config |    1 +
     .../tests/no_write_if_dep_unmet/expected_config    |    5 +
     .../tests/preprocess/builtin_func/Kconfig          |   27 +
     .../tests/preprocess/builtin_func/__init__.py      |    9 +
     .../tests/preprocess/builtin_func/expected_stderr  |    5 +
     .../tests/preprocess/builtin_func/expected_stdout  |    1 +
     .../tests/preprocess/circular_expansion/Kconfig    |    5 +
     .../preprocess/circular_expansion/__init__.py      |   11 +
     .../preprocess/circular_expansion/expected_stderr  |    1 +
     .../kconfig.new/tests/preprocess/escape/Kconfig    |   44 +
     .../tests/preprocess/escape/__init__.py            |    8 +
     .../tests/preprocess/escape/expected_stderr        |   10 +
     .../kconfig.new/tests/preprocess/variable/Kconfig  |   53 +
     .../tests/preprocess/variable/__init__.py          |    8 +
     .../tests/preprocess/variable/expected_stderr      |    9 +
     support/kconfig.new/tests/pytest.ini               |    7 +
     .../kconfig.new/tests/rand_nested_choice/Kconfig   |   35 +
     .../tests/rand_nested_choice/__init__.py           |   17 +
     .../tests/rand_nested_choice/expected_stdout0      |    2 +
     .../tests/rand_nested_choice/expected_stdout1      |    4 +
     .../tests/rand_nested_choice/expected_stdout2      |    5 +
     support/kconfig.new/util.c                         |  129 +
     support/kconfig.new/zconf.lex.c                    | 2820 
++++++++++++++++++++
     support/kconfig.new/zconf.tab.c                    | 2504 +++++++++++++++++
     98 files changed, 26433 insertions(+)
     create mode 100644 support/kconfig.new/Makefile
     create mode 100644 support/kconfig.new/conf.c
     create mode 100644 support/kconfig.new/confdata.c
     create mode 100644 support/kconfig.new/expr.c
     create mode 100644 support/kconfig.new/expr.h
     create mode 100755 support/kconfig.new/gconf-cfg.sh
     create mode 100644 support/kconfig.new/gconf.c
     create mode 100644 support/kconfig.new/gconf.glade
     create mode 100644 support/kconfig.new/images.c
     create mode 100644 support/kconfig.new/images.h
     create mode 100644 support/kconfig.new/lexer.l
     create mode 100644 support/kconfig.new/list.h
     create mode 100644 support/kconfig.new/lkc.h
     create mode 100644 support/kconfig.new/lkc_proto.h
     create mode 100644 support/kconfig.new/lxdialog/BIG.FAT.WARNING
     create mode 100644 support/kconfig.new/lxdialog/checklist.c
     create mode 100644 support/kconfig.new/lxdialog/dialog.h
     create mode 100644 support/kconfig.new/lxdialog/inputbox.c
     create mode 100644 support/kconfig.new/lxdialog/menubox.c
     create mode 100644 support/kconfig.new/lxdialog/textbox.c
     create mode 100644 support/kconfig.new/lxdialog/util.c
     create mode 100644 support/kconfig.new/lxdialog/yesno.c
     create mode 100755 support/kconfig.new/mconf-cfg.sh
     create mode 100644 support/kconfig.new/mconf.c
     create mode 100644 support/kconfig.new/menu.c
     create mode 100755 support/kconfig.new/merge_config.sh
     create mode 100755 support/kconfig.new/nconf-cfg.sh
     create mode 100644 support/kconfig.new/nconf.c
     create mode 100644 support/kconfig.new/nconf.gui.c
     create mode 100644 support/kconfig.new/nconf.h
     create mode 100644 support/kconfig.new/parser.y
     create mode 100644 support/kconfig.new/preprocess.c
     create mode 100755 support/kconfig.new/qconf-cfg.sh
     create mode 100644 support/kconfig.new/qconf.cc
     create mode 100644 support/kconfig.new/qconf.h
     create mode 100755 support/kconfig.new/streamline_config.pl
     create mode 100644 support/kconfig.new/symbol.c
     create mode 100644 support/kconfig.new/tests/auto_submenu/Kconfig
     create mode 100644 support/kconfig.new/tests/auto_submenu/__init__.py
     create mode 100644 support/kconfig.new/tests/auto_submenu/expected_stdout
     create mode 100644 support/kconfig.new/tests/choice/Kconfig
     create mode 100644 support/kconfig.new/tests/choice/__init__.py
     create mode 100644 support/kconfig.new/tests/choice/alldef_expected_config
     create mode 100644 support/kconfig.new/tests/choice/allmod_expected_config
     create mode 100644 support/kconfig.new/tests/choice/allno_expected_config
     create mode 100644 support/kconfig.new/tests/choice/allyes_expected_config
     create mode 100644 support/kconfig.new/tests/choice/oldask0_expected_stdout
     create mode 100644 support/kconfig.new/tests/choice/oldask1_config
     create mode 100644 support/kconfig.new/tests/choice/oldask1_expected_stdout
     create mode 100644 
support/kconfig.new/tests/choice_value_with_m_dep/Kconfig
     create mode 100644 
support/kconfig.new/tests/choice_value_with_m_dep/__init__.py
     create mode 100644 support/kconfig.new/tests/choice_value_with_m_dep/config
     create mode 100644 
support/kconfig.new/tests/choice_value_with_m_dep/expected_config
     create mode 100644 
support/kconfig.new/tests/choice_value_with_m_dep/expected_stdout
     create mode 100644 support/kconfig.new/tests/conftest.py
     create mode 100644 support/kconfig.new/tests/err_recursive_dep/Kconfig
     create mode 100644 support/kconfig.new/tests/err_recursive_dep/__init__.py
     create mode 100644 
support/kconfig.new/tests/err_recursive_dep/expected_stderr
     create mode 100644 support/kconfig.new/tests/err_recursive_inc/Kconfig
     create mode 100644 support/kconfig.new/tests/err_recursive_inc/Kconfig.inc1
     create mode 100644 support/kconfig.new/tests/err_recursive_inc/Kconfig.inc2
     create mode 100644 support/kconfig.new/tests/err_recursive_inc/Kconfig.inc3
     create mode 100644 support/kconfig.new/tests/err_recursive_inc/__init__.py
     create mode 100644 
support/kconfig.new/tests/err_recursive_inc/expected_stderr
     create mode 100644 support/kconfig.new/tests/inter_choice/Kconfig
     create mode 100644 support/kconfig.new/tests/inter_choice/__init__.py
     create mode 100644 support/kconfig.new/tests/inter_choice/defconfig
     create mode 100644 support/kconfig.new/tests/inter_choice/expected_config
     create mode 100644 support/kconfig.new/tests/new_choice_with_dep/Kconfig
     create mode 100644 
support/kconfig.new/tests/new_choice_with_dep/__init__.py
     create mode 100644 support/kconfig.new/tests/new_choice_with_dep/config
     create mode 100644 
support/kconfig.new/tests/new_choice_with_dep/expected_stdout
     create mode 100644 support/kconfig.new/tests/no_write_if_dep_unmet/Kconfig
     create mode 100644 
support/kconfig.new/tests/no_write_if_dep_unmet/__init__.py
     create mode 100644 support/kconfig.new/tests/no_write_if_dep_unmet/config
     create mode 100644 
support/kconfig.new/tests/no_write_if_dep_unmet/expected_config
     create mode 100644 
support/kconfig.new/tests/preprocess/builtin_func/Kconfig
     create mode 100644 
support/kconfig.new/tests/preprocess/builtin_func/__init__.py
     create mode 100644 
support/kconfig.new/tests/preprocess/builtin_func/expected_stderr
     create mode 100644 
support/kconfig.new/tests/preprocess/builtin_func/expected_stdout
     create mode 100644 
support/kconfig.new/tests/preprocess/circular_expansion/Kconfig
     create mode 100644 
support/kconfig.new/tests/preprocess/circular_expansion/__init__.py
     create mode 100644 
support/kconfig.new/tests/preprocess/circular_expansion/expected_stderr
     create mode 100644 support/kconfig.new/tests/preprocess/escape/Kconfig
     create mode 100644 support/kconfig.new/tests/preprocess/escape/__init__.py
     create mode 100644 
support/kconfig.new/tests/preprocess/escape/expected_stderr
     create mode 100644 support/kconfig.new/tests/preprocess/variable/Kconfig
     create mode 100644 
support/kconfig.new/tests/preprocess/variable/__init__.py
     create mode 100644 
support/kconfig.new/tests/preprocess/variable/expected_stderr
     create mode 100644 support/kconfig.new/tests/pytest.ini
     create mode 100644 support/kconfig.new/tests/rand_nested_choice/Kconfig
     create mode 100644 support/kconfig.new/tests/rand_nested_choice/__init__.py
     create mode 100644 
support/kconfig.new/tests/rand_nested_choice/expected_stdout0
     create mode 100644 
support/kconfig.new/tests/rand_nested_choice/expected_stdout1
     create mode 100644 
support/kconfig.new/tests/rand_nested_choice/expected_stdout2
     create mode 100644 support/kconfig.new/util.c
     create mode 100644 support/kconfig.new/zconf.lex.c
     create mode 100644 support/kconfig.new/zconf.tab.c
    
    diff --git a/support/kconfig.new/Makefile b/support/kconfig.new/Makefile
    new file mode 100644
    index 0000000..3f327e2
    --- /dev/null
    +++ b/support/kconfig.new/Makefile
    @@ -0,0 +1,208 @@
    +# SPDX-License-Identifier: GPL-2.0
    +# 
===========================================================================
    +# Kernel configuration targets
    +# These targets are used from top-level makefile
    +
    +PHONY += xconfig gconfig menuconfig config localmodconfig localyesconfig \
    +   build_menuconfig build_nconfig build_gconfig build_xconfig
    +
    +ifdef KBUILD_KCONFIG
    +Kconfig := $(KBUILD_KCONFIG)
    +else
    +Kconfig := Kconfig
    +endif
    +
    +ifeq ($(quiet),silent_)
    +silent := -s
    +endif
    +
    +# We need this, in case the user has it in its environment
    +unexport CONFIG_
    +
    +xconfig: $(obj)/qconf
    +   $< $(silent) $(Kconfig)
    +
    +gconfig: $(obj)/gconf
    +   $< $(silent) $(Kconfig)
    +
    +menuconfig: $(obj)/mconf
    +   $< $(silent) $(Kconfig)
    +
    +config: $(obj)/conf
    +   $< $(silent) --oldaskconfig $(Kconfig)
    +
    +nconfig: $(obj)/nconf
    +   $< $(silent) $(Kconfig)
    +
    +build_menuconfig: $(obj)/mconf
    +
    +build_nconfig: $(obj)/nconf
    +
    +build_gconfig: $(obj)/gconf
    +
    +build_xconfig: $(obj)/qconf
    +
    +localyesconfig localmodconfig: $(obj)/conf
    +   $(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) 
$(Kconfig) > .tmp.config
    +   $(Q)if [ -f .config ]; then                                     \
    +                   cmp -s .tmp.config .config ||                   \
    +                   (mv -f .config .config.old.1;                   \
    +                    mv -f .tmp.config .config;                     \
    +                    $< $(silent) --oldconfig $(Kconfig);           \
    +                    mv -f .config.old.1 .config.old)               \
    +   else                                                            \
    +                   mv -f .tmp.config .config;                      \
    +                   $< $(silent) --oldconfig $(Kconfig);            \
    +   fi
    +   $(Q)rm -f .tmp.config
    +
    +# These targets map 1:1 to the commandline options of 'conf'
    +#
    +# Note:
    +#  syncconfig has become an internal implementation detail and is now
    +#  deprecated for external use
    +simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \
    +   alldefconfig randconfig listnewconfig olddefconfig syncconfig
    +PHONY += $(simple-targets)
    +
    +$(simple-targets): $(obj)/conf
    +   $< $(silent) --$@ $(Kconfig)
    +
    +PHONY += savedefconfig defconfig
    +
    +savedefconfig: $(obj)/conf
    +   $< $(silent) --$@=defconfig $(Kconfig)
    +
    +defconfig: $(obj)/conf
    +ifeq ($(KBUILD_DEFCONFIG),)
    +   $< $(silent) --defconfig $(Kconfig)
    +else ifneq ($(wildcard 
$(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),)
    +   @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'"
    +   $(Q)$< $(silent) 
--defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig)
    +else
    +   @$(kecho) "*** Default configuration is based on target 
'$(KBUILD_DEFCONFIG)'"
    +   $(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG)
    +endif
    +
    +%_defconfig: $(obj)/conf
    +   $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
    +
    +configfiles=$(wildcard $(srctree)/kernel/configs/$@ 
$(srctree)/arch/$(SRCARCH)/configs/$@)
    +
    +%.config: $(obj)/conf
    +   $(if $(call configfiles),, $(error No configuration exists for this 
target on this architecture))
    +   $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m 
.config $(configfiles)
    +   +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig
    +
    +PHONY += kvmconfig
    +kvmconfig: kvm_guest.config
    +   @:
    +
    +PHONY += xenconfig
    +xenconfig: xen.config
    +   @:
    +
    +PHONY += tinyconfig
    +tinyconfig:
    +   $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config
    +
    +# CHECK: -o cache_dir=<path> working?
    +PHONY += testconfig
    +testconfig: $(obj)/conf
    +   $(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \
    +   -o cache_dir=$(abspath $(obj)/tests/.cache) \
    +   $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no)
    +clean-dirs += tests/.cache
    +
    +# Help text used by make help
    +help:
    +   @echo  '  config          - Update current config utilising a 
line-oriented program'
    +   @echo  '  nconfig         - Update current config utilising a ncurses 
menu based program'
    +   @echo  '  menuconfig      - Update current config utilising a menu 
based program'
    +   @echo  '  xconfig         - Update current config utilising a Qt based 
front-end'
    +   @echo  '  gconfig         - Update current config utilising a GTK+ 
based front-end'
    +   @echo  '  oldconfig       - Update current config utilising a provided 
.config as base'
    +   @echo  '  localmodconfig  - Update current config disabling modules not 
loaded'
    +   @echo  '  localyesconfig  - Update current config converting local mods 
to core'
    +   @echo  '  defconfig       - New config with default from ARCH supplied 
defconfig'
    +   @echo  '  savedefconfig   - Save current config as ./defconfig (minimal 
config)'
    +   @echo  '  allnoconfig     - New config where all options are answered 
with no'
    +   @echo  '  allyesconfig    - New config where all options are accepted 
with yes'
    +   @echo  '  allmodconfig    - New config selecting modules when possible'
    +   @echo  '  alldefconfig    - New config with all symbols set to default'
    +   @echo  '  randconfig      - New config with random answer to all 
options'
    +   @echo  '  listnewconfig   - List new options'
    +   @echo  '  olddefconfig    - Same as oldconfig but sets new symbols to 
their'
    +   @echo  '                    default value without prompting'
    +   @echo  '  kvmconfig       - Enable additional options for kvm guest 
kernel support'
    +   @echo  '  xenconfig       - Enable additional options for xen dom0 and 
guest kernel support'
    +   @echo  '  tinyconfig      - Configure the tiniest possible kernel'
    +   @echo  '  testconfig      - Run Kconfig unit tests (requires python3 
and pytest)'
    +
    +# 
===========================================================================
    +# object files used by all kconfig flavours
    +common-objs        := confdata.o expr.o lexer.lex.o parser.tab.o 
preprocess.o \
    +              symbol.o
    +
    +$(obj)/lexer.lex.o: $(obj)/parser.tab.h
    +HOSTCFLAGS_lexer.lex.o     := -I $(srctree)/$(src)
    +HOSTCFLAGS_parser.tab.o    := -I $(srctree)/$(src)
    +
    +# conf: Used for defconfig, oldconfig and related targets
    +hostprogs-y        += conf
    +conf-objs  := conf.o $(common-objs)
    +
    +# nconf: Used for the nconfig target based on ncurses
    +hostprogs-y        += nconf
    +nconf-objs := nconf.o nconf.gui.o $(common-objs)
    +
    +HOSTLDLIBS_nconf   = $(shell . $(obj)/nconf-cfg && echo $$libs)
    +HOSTCFLAGS_nconf.o = $(shell . $(obj)/nconf-cfg && echo $$cflags)
    +HOSTCFLAGS_nconf.gui.o     = $(shell . $(obj)/nconf-cfg && echo $$cflags)
    +
    +$(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/nconf-cfg
    +
    +# mconf: Used for the menuconfig target based on lxdialog
    +hostprogs-y        += mconf
    +lxdialog   := checklist.o inputbox.o menubox.o textbox.o util.o yesno.o
    +mconf-objs := mconf.o $(addprefix lxdialog/, $(lxdialog)) $(common-objs)
    +
    +HOSTLDLIBS_mconf = $(shell . $(obj)/mconf-cfg && echo $$libs)
    +$(foreach f, mconf.o $(lxdialog), \
    +  $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/mconf-cfg && echo $$$$cflags)))
    +
    +$(obj)/mconf.o: $(obj)/mconf-cfg
    +$(addprefix $(obj)/lxdialog/, $(lxdialog)): $(obj)/mconf-cfg
    +
    +# qconf: Used for the xconfig target based on Qt
    +hostprogs-y        += qconf
    +qconf-cxxobjs      := qconf.o
    +qconf-objs := images.o $(common-objs)
    +
    +HOSTLDLIBS_qconf   = $(shell . $(obj)/qconf-cfg && echo $$libs)
    +HOSTCXXFLAGS_qconf.o       = $(shell . $(obj)/qconf-cfg && echo $$cflags)
    +
    +$(obj)/qconf.o: $(obj)/qconf-cfg $(obj)/qconf.moc
    +
    +quiet_cmd_moc = MOC     $@
    +      cmd_moc = $(shell . $(obj)/qconf-cfg && echo $$moc) -i $< -o $@
    +
    +$(obj)/%.moc: $(src)/%.h $(obj)/qconf-cfg
    +   $(call cmd,moc)
    +
    +# gconf: Used for the gconfig target based on GTK+
    +hostprogs-y        += gconf
    +gconf-objs := gconf.o images.o $(common-objs)
    +
    +HOSTLDLIBS_gconf    = $(shell . $(obj)/gconf-cfg && echo $$libs)
    +HOSTCFLAGS_gconf.o  = $(shell . $(obj)/gconf-cfg && echo $$cflags)
    +
    +$(obj)/gconf.o: $(obj)/gconf-cfg
    +
    +# check if necessary packages are available, and configure build flags
    +filechk_conf_cfg = $(CONFIG_SHELL) $<
    +
    +$(obj)/%conf-cfg: $(src)/%conf-cfg.sh FORCE
    +   $(call filechk,conf_cfg)
    +
    +clean-files += *conf-cfg
    diff --git a/support/kconfig.new/conf.c b/support/kconfig.new/conf.c
    new file mode 100644
    index 0000000..ef3678c
    --- /dev/null
    +++ b/support/kconfig.new/conf.c
    @@ -0,0 +1,702 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include <ctype.h>
    +#include <limits.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>
    +#include <errno.h>
    +
    +#include "lkc.h"
    +
    +static void conf(struct menu *menu);
    +static void check_conf(struct menu *menu);
    +
    +enum input_mode {
    +   oldaskconfig,
    +   syncconfig,
    +   oldconfig,
    +   allnoconfig,
    +   allyesconfig,
    +   allmodconfig,
    +   alldefconfig,
    +   randconfig,
    +   defconfig,
    +   savedefconfig,
    +   listnewconfig,
    +   olddefconfig,
    +};
    +static enum input_mode input_mode = oldaskconfig;
    +
    +static int indent = 1;
    +static int tty_stdio;
    +static int sync_kconfig;
    +static int conf_cnt;
    +static char line[PATH_MAX];
    +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;
    +}
    +
    +/* Helper function to facilitate fgets() by Jean Sacren. */
    +static void xfgets(char *str, int size, FILE *in)
    +{
    +   if (!fgets(str, size, in))
    +           fprintf(stderr, "\nError in reading or end of file.\n");
    +
    +   if (!tty_stdio)
    +           printf("%s", str);
    +}
    +
    +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 syncconfig:
    +           if (sym_has_value(sym)) {
    +                   printf("%s\n", def);
    +                   return 0;
    +           }
    +           /* fall through */
    +   case oldaskconfig:
    +           fflush(stdout);
    +           xfgets(line, sizeof(line), 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;
    +                   }
    +                   /* fall through */
    +           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");
    +           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);
    +           switch (input_mode) {
    +           case oldconfig:
    +           case syncconfig:
    +                   if (!is_new) {
    +                           cnt = def;
    +                           printf("%d\n", cnt);
    +                           break;
    +                   }
    +                   /* fall through */
    +           case oldaskconfig:
    +                   fflush(stdout);
    +                   xfgets(line, sizeof(line), 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[0] && 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:
    +                   /*
    +                    * Except in oldaskconfig mode, we show only menus that
    +                    * contain new symbols.
    +                    */
    +                   if (input_mode != oldaskconfig && rootEntry != menu) {
    +                           check_conf(menu);
    +                           return;
    +                   }
    +                   /* fall through */
    +           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) {
    +                                   const char *str;
    +
    +                                   if (sym->type == S_STRING) {
    +                                           str = sym_get_string_value(sym);
    +                                           str = 
sym_escape_string_value(str);
    +                                           printf("%s%s=%s\n", CONFIG_, 
sym->name, str);
    +                                           free((void *)str);
    +                                   } else {
    +                                           str = sym_get_string_value(sym);
    +                                           printf("%s%s=%s\n", CONFIG_, 
sym->name, str);
    +                                   }
    +                           }
    +                   } else {
    +                           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},
    +   {"syncconfig",      no_argument,       NULL, syncconfig},
    +   {"defconfig",       optional_argument, NULL, defconfig},
    +   {"savedefconfig",   required_argument, NULL, savedefconfig},
    +   {"allnoconfig",     no_argument,       NULL, allnoconfig},
    +   {"allyesconfig",    no_argument,       NULL, allyesconfig},
    +   {"allmodconfig",    no_argument,       NULL, allmodconfig},
    +   {"alldefconfig",    no_argument,       NULL, alldefconfig},
    +   {"randconfig",      no_argument,       NULL, randconfig},
    +   {"listnewconfig",   no_argument,       NULL, listnewconfig},
    +   {"olddefconfig",    no_argument,       NULL, olddefconfig},
    +   {NULL, 0, NULL, 0}
    +};
    +
    +static void conf_usage(const char *progname)
    +{
    +
    +   printf("Usage: %s [-s] [option] <kconfig-file>\n", progname);
    +   printf("[option] is _one_ of the following:\n");
    +   printf("  --listnewconfig         List new options\n");
    +   printf("  --oldaskconfig          Start a new configuration using a 
line-oriented program\n");
    +   printf("  --oldconfig             Update a configuration using a 
provided .config as base\n");
    +   printf("  --syncconfig            Similar to oldconfig but generates 
configuration in\n"
    +          "                          include/{generated/,config/}\n");
    +   printf("  --olddefconfig          Same as oldconfig but sets new 
symbols to their default value\n");
    +   printf("  --defconfig <file>      New config with default defined in 
<file>\n");
    +   printf("  --savedefconfig <file>  Save the minimal current 
configuration to <file>\n");
    +   printf("  --allnoconfig           New config where all options are 
answered with no\n");
    +   printf("  --allyesconfig          New config where all options are 
answered with yes\n");
    +   printf("  --allmodconfig          New config where all options are 
answered with mod\n");
    +   printf("  --alldefconfig          New config with all symbols set to 
default\n");
    +   printf("  --randconfig            New config with random answer to all 
options\n");
    +}
    +
    +int main(int ac, char **av)
    +{
    +   const char *progname = av[0];
    +   int opt;
    +   const char *name, *defconfig_file = NULL /* gcc uninit */;
    +   int no_conf_write = 0;
    +
    +   tty_stdio = isatty(0) && isatty(1);
    +
    +   while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) {
    +           if (opt == 's') {
    +                   conf_set_message_callback(NULL);
    +                   continue;
    +           }
    +           input_mode = (enum input_mode)opt;
    +           switch (opt) {
    +           case syncconfig:
    +                   /*
    +                    * syncconfig is invoked during the build stage.
    +                    * Suppress distracting "configuration written to ..."
    +                    */
    +                   conf_set_message_callback(NULL);
    +                   sync_kconfig = 1;
    +                   break;
    +           case defconfig:
    +           case savedefconfig:
    +                   defconfig_file = optarg;
    +                   break;
    +           case randconfig:
    +           {
    +                   struct timeval now;
    +                   unsigned int seed;
    +                   char *seed_env;
    +
    +                   /*
    +                    * 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));
    +
    +                   seed_env = getenv("KCONFIG_SEED");
    +                   if( seed_env && *seed_env ) {
    +                           char *endp;
    +                           int tmp = (int)strtol(seed_env, &endp, 0);
    +                           if (*endp == '\0') {
    +                                   seed = tmp;
    +                           }
    +                   }
    +                   fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed );
    +                   srand(seed);
    +                   break;
    +           }
    +           case oldaskconfig:
    +           case oldconfig:
    +           case allnoconfig:
    +           case allyesconfig:
    +           case allmodconfig:
    +           case alldefconfig:
    +           case listnewconfig:
    +           case olddefconfig:
    +                   break;
    +           case '?':
    +                   conf_usage(progname);
    +                   exit(1);
    +                   break;
    +           }
    +   }
    +   if (ac == optind) {
    +           fprintf(stderr, "%s: Kconfig file missing\n", av[0]);
    +           conf_usage(progname);
    +           exit(1);
    +   }
    +   name = av[optind];
    +   conf_parse(name);
    +   //zconfdump(stdout);
    +
    +   switch (input_mode) {
    +   case defconfig:
    +           if (!defconfig_file)
    +                   defconfig_file = conf_get_default_confname();
    +           if (conf_read(defconfig_file)) {
    +                   fprintf(stderr,
    +                           "***\n"
    +                             "*** Can't find default configuration 
\"%s\"!\n"
    +                             "***\n",
    +                           defconfig_file);
    +                   exit(1);
    +           }
    +           break;
    +   case savedefconfig:
    +   case syncconfig:
    +   case oldaskconfig:
    +   case oldconfig:
    +   case listnewconfig:
    +   case olddefconfig:
    +           conf_read(NULL);
    +           break;
    +   case allnoconfig:
    +   case allyesconfig:
    +   case allmodconfig:
    +   case alldefconfig:
    +   case randconfig:
    +           name = getenv("KCONFIG_ALLCONFIG");
    +           if (!name)
    +                   break;
    +           if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) {
    +                   if (conf_read_simple(name, S_DEF_USER)) {
    +                           fprintf(stderr,
    +                                   "*** Can't read seed configuration 
\"%s\"!\n",
    +                                   name);
    +                           exit(1);
    +                   }
    +                   break;
    +           }
    +           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 (conf_read_simple(name, S_DEF_USER) &&
    +               conf_read_simple("all.config", S_DEF_USER)) {
    +                   fprintf(stderr,
    +                           "*** KCONFIG_ALLCONFIG set, but no \"%s\" or 
\"all.config\" file found\n",
    +                           name);
    +                   exit(1);
    +           }
    +           break;
    +   default:
    +           break;
    +   }
    +
    +   if (sync_kconfig) {
    +           name = getenv("KCONFIG_NOSILENTUPDATE");
    +           if (name && *name) {
    +                   if (conf_get_changed()) {
    +                           fprintf(stderr,
    +                                   "\n*** The configuration requires 
explicit update.\n\n");
    +                           return 1;
    +                   }
    +                   no_conf_write = 1;
    +           }
    +   }
    +
    +   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:
    +           /* Really nothing to do in this loop */
    +           while (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 = oldconfig;
    +           /* fall through */
    +   case oldconfig:
    +   case listnewconfig:
    +   case syncconfig:
    +           /* Update until a loop caused no more changes */
    +           do {
    +                   conf_cnt = 0;
    +                   check_conf(&rootmenu);
    +           } while (conf_cnt);
    +           break;
    +   case olddefconfig:
    +   default:
    +           break;
    +   }
    +
    +   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 (!no_conf_write && conf_write(NULL)) {
    +                   fprintf(stderr, "\n*** Error during writing of the 
configuration.\n\n");
    +                   exit(1);
    +           }
    +
    +           /*
    +            * Create auto.conf if it does not exist.
    +            * This prevents GNU Make 4.1 or older from emitting
    +            * "include/config/auto.conf: No such file or directory"
    +            * in the top-level Makefile
    +            *
    +            * syncconfig always creates or updates auto.conf because it is
    +            * used during the build.
    +            */
    +           if (conf_write_autoconf(sync_kconfig) && sync_kconfig) {
    +                   fprintf(stderr,
    +                           "\n*** Error during sync of the 
configuration.\n\n");
    +                   return 1;
    +           }
    +   }
    +   return 0;
    +}
    diff --git a/support/kconfig.new/confdata.c b/support/kconfig.new/confdata.c
    new file mode 100644
    index 0000000..6006154
    --- /dev/null
    +++ b/support/kconfig.new/confdata.c
    @@ -0,0 +1,1380 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include <sys/mman.h>
    +#include <sys/stat.h>
    +#include <ctype.h>
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <limits.h>
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <time.h>
    +#include <unistd.h>
    +
    +#include "lkc.h"
    +
    +/* return true if 'path' exists, false otherwise */
    +static bool is_present(const char *path)
    +{
    +   struct stat st;
    +
    +   return !stat(path, &st);
    +}
    +
    +/* return true if 'path' exists and it is a directory, false otherwise */
    +static bool is_dir(const char *path)
    +{
    +   struct stat st;
    +
    +   if (stat(path, &st))
    +           return 0;
    +
    +   return S_ISDIR(st.st_mode);
    +}
    +
    +/* return true if the given two files are the same, false otherwise */
    +static bool is_same(const char *file1, const char *file2)
    +{
    +   int fd1, fd2;
    +   struct stat st1, st2;
    +   void *map1, *map2;
    +   bool ret = false;
    +
    +   fd1 = open(file1, O_RDONLY);
    +   if (fd1 < 0)
    +           return ret;
    +
    +   fd2 = open(file2, O_RDONLY);
    +   if (fd2 < 0)
    +           goto close1;
    +
    +   ret = fstat(fd1, &st1);
    +   if (ret)
    +           goto close2;
    +   ret = fstat(fd2, &st2);
    +   if (ret)
    +           goto close2;
    +
    +   if (st1.st_size != st2.st_size)
    +           goto close2;
    +
    +   map1 = mmap(NULL, st1.st_size, PROT_READ, MAP_PRIVATE, fd1, 0);
    +   if (map1 == MAP_FAILED)
    +           goto close2;
    +
    +   map2 = mmap(NULL, st2.st_size, PROT_READ, MAP_PRIVATE, fd2, 0);
    +   if (map2 == MAP_FAILED)
    +           goto close2;
    +
    +   if (bcmp(map1, map2, st1.st_size))
    +           goto close2;
    +
    +   ret = true;
    +close2:
    +   close(fd2);
    +close1:
    +   close(fd1);
    +
    +   return ret;
    +}
    +
    +/*
    + * Create the parent directory of the given path.
    + *
    + * For example, if 'include/config/auto.conf' is given, create 
'include/config'.
    + */
    +static int make_parent_dir(const char *path)
    +{
    +   char tmp[PATH_MAX + 1];
    +   char *p;
    +
    +   strncpy(tmp, path, sizeof(tmp));
    +   tmp[sizeof(tmp) - 1] = 0;
    +
    +   /* Remove the base name. Just return if nothing is left */
    +   p = strrchr(tmp, '/');
    +   if (!p)
    +           return 0;
    +   *(p + 1) = 0;
    +
    +   /* Just in case it is an absolute path */
    +   p = tmp;
    +   while (*p == '/')
    +           p++;
    +
    +   while ((p = strchr(p, '/'))) {
    +           *p = 0;
    +
    +           /* skip if the directory exists */
    +           if (!is_dir(tmp) && mkdir(tmp, 0755))
    +                   return -1;
    +
    +           *p = '/';
    +           while (*p == '/')
    +                   p++;
    +   }
    +
    +   return 0;
    +}
    +
    +static char depfile_path[PATH_MAX];
    +static size_t depfile_prefix_len;
    +
    +/* touch depfile for symbol 'name' */
    +static int conf_touch_dep(const char *name)
    +{
    +   int fd, ret;
    +   const char *s;
    +   char *d, c;
    +
    +   /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */
    +   if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path))
    +           return -1;
    +
    +   d = depfile_path + depfile_prefix_len;
    +   s = name;
    +
    +   while ((c = *s++))
    +           *d++ = (c == '_') ? '/' : tolower(c);
    +   strcpy(d, ".h");
    +
    +   /* Assume directory path already exists. */
    +   fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    +   if (fd == -1) {
    +           if (errno != ENOENT)
    +                   return -1;
    +
    +           ret = make_parent_dir(depfile_path);
    +           if (ret)
    +                   return ret;
    +
    +           /* Try it again. */
    +           fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    +           if (fd == -1)
    +                   return -1;
    +   }
    +   close(fd);
    +
    +   return 0;
    +}
    +
    +struct conf_printer {
    +   void (*print_symbol)(FILE *, struct symbol *, const char *, void *);
    +   void (*print_comment)(FILE *, const char *, void *);
    +};
    +
    +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;
    +
    +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 *s)
    +{
    +   printf("#\n# ");
    +   printf("%s", s);
    +   printf("\n#\n");
    +}
    +
    +static void (*conf_message_callback)(const char *s) =
    +   conf_default_message_callback;
    +void conf_set_message_callback(void (*fn)(const char *s))
    +{
    +   conf_message_callback = fn;
    +}
    +
    +static void conf_message(const char *fmt, ...)
    +{
    +   va_list ap;
    +   char buf[4096];
    +
    +   if (!conf_message_callback)
    +           return;
    +
    +   va_start(ap, fmt);
    +
    +   vsnprintf(buf, sizeof(buf), fmt, ap);
    +   conf_message_callback(buf);
    +   va_end(ap);
    +}
    +
    +const char *conf_get_configname(void)
    +{
    +   char *name = getenv("KCONFIG_CONFIG");
    +
    +   return name ? name : ".config";
    +}
    +
    +static const char *conf_get_autoconfig_name(void)
    +{
    +   char *name = getenv("KCONFIG_AUTOCONFIG");
    +
    +   return name ? name : "include/config/auto.conf";
    +}
    +
    +char *conf_get_default_confname(void)
    +{
    +   static char fullname[PATH_MAX+1];
    +   char *env, *name;
    +
    +   name = expand_string(conf_defname);
    +   env = getenv(SRCTREE);
    +   if (env) {
    +           snprintf(fullname, sizeof(fullname), "%s/%s", env, name);
    +           if (is_present(fullname))
    +                   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;
    +           }
    +           /* fall through */
    +   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;
    +           }
    +           if (def != S_DEF_AUTO)
    +                   conf_warning("symbol value '%s' invalid for %s",
    +                                p, sym->name);
    +           return 1;
    +   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) {
    +                   if (def != S_DEF_AUTO)
    +                           conf_warning("invalid string found");
    +                   return 1;
    +           }
    +           /* fall through */
    +   case S_INT:
    +   case S_HEX:
    +           if (sym_string_valid(sym, p)) {
    +                   sym->def[def].val = xstrdup(p);
    +                   sym->flags |= def_flags;
    +           } else {
    +                   if (def != S_DEF_AUTO)
    +                           conf_warning("symbol value '%s' invalid for %s",
    +                                        p, sym->name);
    +                   return 1;
    +           }
    +           break;
    +   default:
    +           ;
    +   }
    +   return 0;
    +}
    +
    +#define LINE_GROWTH 16
    +static int add_byte(int c, char **lineptr, size_t slen, size_t *n)
    +{
    +   char *nline;
    +   size_t new_size = slen + 1;
    +   if (new_size > *n) {
    +           new_size += LINE_GROWTH - 1;
    +           new_size *= 2;
    +           nline = xrealloc(*lineptr, new_size);
    +           if (!nline)
    +                   return -1;
    +
    +           *lineptr = nline;
    +           *n = new_size;
    +   }
    +
    +   (*lineptr)[slen] = c;
    +
    +   return 0;
    +}
    +
    +static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream)
    +{
    +   char *line = *lineptr;
    +   size_t slen = 0;
    +
    +   for (;;) {
    +           int c = getc(stream);
    +
    +           switch (c) {
    +           case '\n':
    +                   if (add_byte(c, &line, slen, n) < 0)
    +                           goto e_out;
    +                   slen++;
    +                   /* fall through */
    +           case EOF:
    +                   if (add_byte('\0', &line, slen, n) < 0)
    +                           goto e_out;
    +                   *lineptr = line;
    +                   if (slen == 0)
    +                           return -1;
    +                   return slen;
    +           default:
    +                   if (add_byte(c, &line, slen, n) < 0)
    +                           goto e_out;
    +                   slen++;
    +           }
    +   }
    +
    +e_out:
    +   line[slen-1] = '\0';
    +   *lineptr = line;
    +   return -1;
    +}
    +
    +int conf_read_simple(const char *name, int def)
    +{
    +   FILE *in = NULL;
    +   char   *line = NULL;
    +   size_t  line_asize = 0;
    +   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)
    +                   return 1;
    +
    +           for_all_defaults(sym_defconfig_list, prop) {
    +                   if (expr_calc_value(prop->visible.expr) == no ||
    +                       prop->expr->type != E_SYMBOL)
    +                           continue;
    +                   sym_calc_value(prop->expr->left.sym);
    +                   name = sym_get_string_value(prop->expr->left.sym);
    +                   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;
    +
    +   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);
    +                   /* fall through */
    +           default:
    +                   sym->def[def].val = NULL;
    +                   sym->def[def].tri = no;
    +           }
    +   }
    +
    +   while (compat_getline(&line, &line_asize, in) != -1) {
    +           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);
    +                                   continue;
    +                           }
    +                   } 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;
    +                   }
    +
    +                   sym = sym_find(line + strlen(CONFIG_));
    +                   if (!sym) {
    +                           if (def == S_DEF_AUTO)
    +                                   /*
    +                                    * Reading from include/config/auto.conf
    +                                    * If CONFIG_FOO previously existed in
    +                                    * auto.conf but it is missing now,
    +                                    * include/config/foo.h must be touched.
    +                                    */
    +                                   conf_touch_dep(line + strlen(CONFIG_));
    +                           else
    +                                   sym_add_change_count(1);
    +                           continue;
    +                   }
    +
    +                   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: %.*s",
    +                                        (int)strcspn(line, "\r\n"), line);
    +
    +                   continue;
    +           }
    +
    +           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);
    +           }
    +   }
    +   free(line);
    +   fclose(in);
    +   return 0;
    +}
    +
    +int conf_read(const char *name)
    +{
    +   struct symbol *sym;
    +   int conf_unsaved = 0;
    +   int i;
    +
    +   sym_set_change_count(0);
    +
    +   if (conf_read_simple(name, S_DEF_USER)) {
    +           sym_calc_value(modules_sym);
    +           return 1;
    +   }
    +
    +   sym_calc_value(modules_sym);
    +
    +   for_all_symbols(i, sym) {
    +           sym_calc_value(sym);
    +           if (sym_is_choice(sym) || (sym->flags & SYMBOL_NO_WRITE))
    +                   continue;
    +           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))
    +                                   continue;
    +                           /* fall through */
    +                   default:
    +                           if (!strcmp(sym->curr.val, 
sym->def[S_DEF_USER].val))
    +                                   continue;
    +                           break;
    +                   }
    +           } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE))
    +                   /* no previous value and not saved */
    +                   continue;
    +           conf_unsaved++;
    +           /* maybe print value in verbose mode... */
    +   }
    +
    +   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;
    +}
    +
    +/*
    + * Kconfig configuration printer
    + *
    + * This printer is used when generating the resulting configuration after
    + * kconfig invocation and `defconfig' files. Unset symbol might be omitted 
by
    + * passing a non-NULL argument to the printer.
    + *
    + */
    +static void
    +kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void 
*arg)
    +{
    +
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           if (*value == 'n') {
    +                   bool skip_unset = (arg != NULL);
    +
    +                   if (!skip_unset)
    +                           fprintf(fp, "# %s%s is not set\n",
    +                               CONFIG_, sym->name);
    +                   return;
    +           }
    +           break;
    +   default:
    +           break;
    +   }
    +
    +   fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value);
    +}
    +
    +static void
    +kconfig_print_comment(FILE *fp, const char *value, void *arg)
    +{
    +   const char *p = value;
    +   size_t l;
    +
    +   for (;;) {
    +           l = strcspn(p, "\n");
    +           fprintf(fp, "#");
    +           if (l) {
    +                   fprintf(fp, " ");
    +                   xfwrite(p, l, 1, fp);
    +                   p += l;
    +           }
    +           fprintf(fp, "\n");
    +           if (*p++ == '\0')
    +                   break;
    +   }
    +}
    +
    +static struct conf_printer kconfig_printer_cb =
    +{
    +   .print_symbol = kconfig_print_symbol,
    +   .print_comment = kconfig_print_comment,
    +};
    +
    +/*
    + * Header printer
    + *
    + * This printer is used when generating the `include/generated/autoconf.h' 
file.
    + */
    +static void
    +header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void 
*arg)
    +{
    +
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE: {
    +           const char *suffix = "";
    +
    +           switch (*value) {
    +           case 'n':
    +                   break;
    +           case 'm':
    +                   suffix = "_MODULE";
    +                   /* fall through */
    +           default:
    +                   fprintf(fp, "#define %s%s%s 1\n",
    +                       CONFIG_, sym->name, suffix);
    +           }
    +           break;
    +   }
    +   case S_HEX: {
    +           const char *prefix = "";
    +
    +           if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
    +                   prefix = "0x";
    +           fprintf(fp, "#define %s%s %s%s\n",
    +               CONFIG_, sym->name, prefix, value);
    +           break;
    +   }
    +   case S_STRING:
    +   case S_INT:
    +           fprintf(fp, "#define %s%s %s\n",
    +               CONFIG_, sym->name, value);
    +           break;
    +   default:
    +           break;
    +   }
    +
    +}
    +
    +static void
    +header_print_comment(FILE *fp, const char *value, void *arg)
    +{
    +   const char *p = value;
    +   size_t l;
    +
    +   fprintf(fp, "/*\n");
    +   for (;;) {
    +           l = strcspn(p, "\n");
    +           fprintf(fp, " *");
    +           if (l) {
    +                   fprintf(fp, " ");
    +                   xfwrite(p, l, 1, fp);
    +                   p += l;
    +           }
    +           fprintf(fp, "\n");
    +           if (*p++ == '\0')
    +                   break;
    +   }
    +   fprintf(fp, " */\n");
    +}
    +
    +static struct conf_printer header_printer_cb =
    +{
    +   .print_symbol = header_print_symbol,
    +   .print_comment = header_print_comment,
    +};
    +
    +/*
    + * Tristate printer
    + *
    + * This printer is used when generating the `include/config/tristate.conf' 
file.
    + */
    +static void
    +tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, 
void *arg)
    +{
    +
    +   if (sym->type == S_TRISTATE && *value != 'n')
    +           fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, 
(char)toupper(*value));
    +}
    +
    +static struct conf_printer tristate_printer_cb =
    +{
    +   .print_symbol = tristate_print_symbol,
    +   .print_comment = kconfig_print_comment,
    +};
    +
    +static void conf_write_symbol(FILE *fp, struct symbol *sym,
    +                         struct conf_printer *printer, void *printer_arg)
    +{
    +   const char *str;
    +
    +   switch (sym->type) {
    +   case S_UNKNOWN:
    +           break;
    +   case S_STRING:
    +           str = sym_get_string_value(sym);
    +           str = sym_escape_string_value(str);
    +           printer->print_symbol(fp, sym, str, printer_arg);
    +           free((void *)str);
    +           break;
    +   default:
    +           str = sym_get_string_value(sym);
    +           printer->print_symbol(fp, sym, str, printer_arg);
    +   }
    +}
    +
    +static void
    +conf_write_heading(FILE *fp, struct conf_printer *printer, void 
*printer_arg)
    +{
    +   char buf[256];
    +
    +   snprintf(buf, sizeof(buf),
    +       "\n"
    +       "Automatically generated file; DO NOT EDIT.\n"
    +       "%s\n",
    +       rootmenu.prompt->text);
    +
    +   printer->print_comment(fp, buf, printer_arg);
    +}
    +
    +/*
    + * 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(out, sym, &kconfig_printer_cb, NULL);
    +           }
    +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 *str;
    +   char tmpname[PATH_MAX + 1], oldname[PATH_MAX + 1];
    +   char *env;
    +   bool need_newline = false;
    +
    +   if (!name)
    +           name = conf_get_configname();
    +
    +   if (!*name) {
    +           fprintf(stderr, "config name is empty\n");
    +           return -1;
    +   }
    +
    +   if (is_dir(name)) {
    +           fprintf(stderr, "%s: Is a directory\n", name);
    +           return -1;
    +   }
    +
    +   if (make_parent_dir(name))
    +           return -1;
    +
    +   env = getenv("KCONFIG_OVERWRITECONFIG");
    +   if (env && *env) {
    +           *tmpname = 0;
    +           out = fopen(name, "w");
    +   } else {
    +           snprintf(tmpname, sizeof(tmpname), "%s.%d.tmp",
    +                    name, (int)getpid());
    +           out = fopen(tmpname, "w");
    +   }
    +   if (!out)
    +           return 1;
    +
    +   conf_write_heading(out, &kconfig_printer_cb, NULL);
    +
    +   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);
    +                   need_newline = false;
    +           } else if (!(sym->flags & SYMBOL_CHOICE)) {
    +                   sym_calc_value(sym);
    +                   if (!(sym->flags & SYMBOL_WRITE))
    +                           goto next;
    +                   if (need_newline) {
    +                           fprintf(out, "\n");
    +                           need_newline = false;
    +                   }
    +                   sym->flags &= ~SYMBOL_WRITE;
    +                   conf_write_symbol(out, sym, &kconfig_printer_cb, NULL);
    +           }
    +
    +next:
    +           if (menu->list) {
    +                   menu = menu->list;
    +                   continue;
    +           }
    +           if (menu->next)
    +                   menu = menu->next;
    +           else while ((menu = menu->parent)) {
    +                   if (!menu->sym && menu_is_visible(menu) &&
    +                       menu != &rootmenu) {
    +                           str = menu_get_prompt(menu);
    +                           fprintf(out, "# end of %s\n", str);
    +                           need_newline = true;
    +                   }
    +                   if (menu->next) {
    +                           menu = menu->next;
    +                           break;
    +                   }
    +           }
    +   }
    +   fclose(out);
    +
    +   if (*tmpname) {
    +           if (is_same(name, tmpname)) {
    +                   conf_message("No change to %s", name);
    +                   unlink(tmpname);
    +                   sym_set_change_count(0);
    +                   return 0;
    +           }
    +
    +           snprintf(oldname, sizeof(oldname), "%s.old", name);
    +           rename(name, oldname);
    +           if (rename(tmpname, name))
    +                   return 1;
    +   }
    +
    +   conf_message("configuration written to %s", name);
    +
    +   sym_set_change_count(0);
    +
    +   return 0;
    +}
    +
    +/* write a dependency file as used by kbuild to track dependencies */
    +static int conf_write_dep(const char *name)
    +{
    +   struct file *file;
    +   FILE *out;
    +
    +   out = fopen("..config.tmp", "w");
    +   if (!out)
    +           return 1;
    +   fprintf(out, "deps_config := \\\n");
    +   for (file = file_list; file; file = file->next) {
    +           if (file->next)
    +                   fprintf(out, "\t%s \\\n", file->name);
    +           else
    +                   fprintf(out, "\t%s\n", file->name);
    +   }
    +   fprintf(out, "\n%s: \\\n"
    +                "\t$(deps_config)\n\n", conf_get_autoconfig_name());
    +
    +   env_write_dep(out, conf_get_autoconfig_name());
    +
    +   fprintf(out, "\n$(deps_config): ;\n");
    +   fclose(out);
    +
    +   if (make_parent_dir(name))
    +           return 1;
    +   rename("..config.tmp", name);
    +   return 0;
    +}
    +
    +static int conf_touch_deps(void)
    +{
    +   const char *name;
    +   struct symbol *sym;
    +   int res, i;
    +
    +   strcpy(depfile_path, "include/config/");
    +   depfile_prefix_len = strlen(depfile_path);
    +
    +   name = conf_get_autoconfig_name();
    +   conf_read_simple(name, S_DEF_AUTO);
    +   sym_calc_value(modules_sym);
    +
    +   for_all_symbols(i, sym) {
    +           sym_calc_value(sym);
    +           if ((sym->flags & SYMBOL_NO_WRITE) || !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').
    +            */
    +
    +           res = conf_touch_dep(sym->name);
    +           if (res)
    +                   return res;
    +   }
    +
    +   return 0;
    +}
    +
    +int conf_write_autoconf(int overwrite)
    +{
    +   struct symbol *sym;
    +   const char *name;
    +   const char *autoconf_name = conf_get_autoconfig_name();
    +   FILE *out, *tristate, *out_h;
    +   int i;
    +
    +   if (!overwrite && is_present(autoconf_name))
    +           return 0;
    +
    +   sym_clear_all_valid();
    +
    +   conf_write_dep("include/config/auto.conf.cmd");
    +
    +   if (conf_touch_deps())
    +           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;
    +   }
    +
    +   conf_write_heading(out, &kconfig_printer_cb, NULL);
    +
    +   conf_write_heading(tristate, &tristate_printer_cb, NULL);
    +
    +   conf_write_heading(out_h, &header_printer_cb, NULL);
    +
    +   for_all_symbols(i, sym) {
    +           sym_calc_value(sym);
    +           if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
    +                   continue;
    +
    +           /* write symbol to auto.conf, tristate and header files */
    +           conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1);
    +
    +           conf_write_symbol(tristate, sym, &tristate_printer_cb, (void 
*)1);
    +
    +           conf_write_symbol(out_h, sym, &header_printer_cb, NULL);
    +   }
    +   fclose(out);
    +   fclose(tristate);
    +   fclose(out_h);
    +
    +   name = getenv("KCONFIG_AUTOHEADER");
    +   if (!name)
    +           name = "include/generated/autoconf.h";
    +   if (make_parent_dir(name))
    +           return 1;
    +   if (rename(".tmpconfig.h", name))
    +           return 1;
    +
    +   name = getenv("KCONFIG_TRISTATE");
    +   if (!name)
    +           name = "include/config/tristate.conf";
    +   if (make_parent_dir(name))
    +           return 1;
    +   if (rename(".tmpconfig_tristate", name))
    +           return 1;
    +
    +   if (make_parent_dir(autoconf_name))
    +           return 1;
    +   /*
    +    * 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", autoconf_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 bool 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 false;
    +
    +   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;
    +           }
    +           sym->flags |= SYMBOL_DEF_USER;
    +           /* clear VALID to get value calculated */
    +           sym->flags &= ~SYMBOL_VALID;
    +   }
    +   csym->flags |= SYMBOL_DEF_USER;
    +   /* clear VALID to get value calculated */
    +   csym->flags &= ~(SYMBOL_VALID);
    +
    +   return true;
    +}
    +
    +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 | SYMBOL_NEED_SET_CHOICE_VALUES);
    +}
    +
    +bool conf_set_all_new_symbols(enum conf_def_mode mode)
    +{
    +   struct symbol *sym, *csym;
    +   int i, cnt, pby, pty, ptm;      /* pby: probability of bool     = y
    +                                    * pty: probability of tristate = y
    +                                    * ptm: probability of tristate = m
    +                                    */
    +
    +   pby = 50; pty = ptm = 33; /* can't go as the default in switch-case
    +                              * below, otherwise gcc whines about
    +                              * -Wmaybe-uninitialized */
    +   if (mode == def_random) {
    +           int n, p[3];
    +           char *env = getenv("KCONFIG_PROBABILITY");
    +           n = 0;
    +           while( env && *env ) {
    +                   char *endp;
    +                   int tmp = strtol( env, &endp, 10 );
    +                   if( tmp >= 0 && tmp <= 100 ) {
    +                           p[n++] = tmp;
    +                   } else {
    +                           errno = ERANGE;
    +                           perror( "KCONFIG_PROBABILITY" );
    +                           exit( 1 );
    +                   }
    +                   env = (*endp == ':') ? endp+1 : endp;
    +                   if( n >=3 ) {
    +                           break;
    +                   }
    +           }
    +           switch( n ) {
    +           case 1:
    +                   pby = p[0]; ptm = pby/2; pty = pby-ptm;
    +                   break;
    +           case 2:
    +                   pty = p[0]; ptm = p[1]; pby = pty + ptm;
    +                   break;
    +           case 3:
    +                   pby = p[0]; pty = p[1]; ptm = p[2];
    +                   break;
    +           }
    +
    +           if( pty+ptm > 100 ) {
    +                   errno = ERANGE;
    +                   perror( "KCONFIG_PROBABILITY" );
    +                   exit( 1 );
    +           }
    +   }
    +   bool has_changed = false;
    +
    +   for_all_symbols(i, sym) {
    +           if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID))
    +                   continue;
    +           switch (sym_get_type(sym)) {
    +           case S_BOOLEAN:
    +           case S_TRISTATE:
    +                   has_changed = true;
    +                   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:
    +                           if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
    +                                   sym->def[S_DEF_USER].tri = yes;
    +                           else
    +                                   sym->def[S_DEF_USER].tri = no;
    +                           break;
    +                   case def_random:
    +                           sym->def[S_DEF_USER].tri = no;
    +                           cnt = rand() % 100;
    +                           if (sym->type == S_TRISTATE) {
    +                                   if (cnt < pty)
    +                                           sym->def[S_DEF_USER].tri = yes;
    +                                   else if (cnt < (pty+ptm))
    +                                           sym->def[S_DEF_USER].tri = mod;
    +                           } else if (cnt < pby)
    +                                   sym->def[S_DEF_USER].tri = yes;
    +                           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.
    +    */
    +   if (mode != def_random) {
    +           for_all_symbols(i, csym) {
    +                   if ((sym_is_choice(csym) && !sym_has_value(csym)) ||
    +                       sym_is_choice_value(csym))
    +                           csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES;
    +           }
    +   }
    +
    +   for_all_symbols(i, csym) {
    +           if (sym_has_value(csym) || !sym_is_choice(csym))
    +                   continue;
    +
    +           sym_calc_value(csym);
    +           if (mode == def_random)
    +                   has_changed = randomize_choice_values(csym);
    +           else {
    +                   set_all_choice_values(csym);
    +                   has_changed = true;
    +           }
    +   }
    +
    +   return has_changed;
    +}
    diff --git a/support/kconfig.new/expr.c b/support/kconfig.new/expr.c
    new file mode 100644
    index 0000000..77ffff3
    --- /dev/null
    +++ b/support/kconfig.new/expr.c
    @@ -0,0 +1,1297 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include <ctype.h>
    +#include <errno.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "lkc.h"
    +
    +#define DEBUG_EXPR 0
    +
    +static int expr_eq(struct expr *e1, struct expr *e2);
    +static struct expr *expr_eliminate_yn(struct expr *e);
    +
    +struct expr *expr_alloc_symbol(struct symbol *sym)
    +{
    +   struct expr *e = xcalloc(1, 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 = xcalloc(1, 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 = xcalloc(1, 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 = xcalloc(1, 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 = xmalloc(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_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   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:
    +           fprintf(stderr, "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);
    +           break;
    +   case E_EQUAL:
    +   case E_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   case E_UNEQUAL:
    +           break;
    +   case E_OR:
    +   case E_AND:
    +           expr_free(e->left.expr);
    +           expr_free(e->right.expr);
    +           break;
    +   default:
    +           fprintf(stderr, "how to free type %d?\n", e->type);
    +           break;
    +   }
    +   free(e);
    +}
    +
    +static int trans_count;
    +
    +#define e1 (*ep1)
    +#define e2 (*ep2)
    +
    +/*
    + * expr_eliminate_eq() helper.
    + *
    + * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that 
does
    + * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
    + * against all other leaves. Two equal leaves are both replaced with 
either 'y'
    + * or 'n' as appropriate for 'type', to be eliminated later.
    + */
    +static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, 
struct expr **ep2)
    +{
    +   /* Recurse down to leaves */
    +
    +   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;
    +   }
    +
    +   /* e1 and e2 are leaves. Compare them. */
    +
    +   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;
    +
    +   /* e1 and e2 are equal leaves. Prepare them for elimination. */
    +
    +   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:
    +           ;
    +   }
    +}
    +
    +/*
    + * Rewrites the expressions 'ep1' and 'ep2' to remove operands common to 
both.
    + * Example reductions:
    + *
    + * ep1: A && B           ->  ep1: y
    + * ep2: A && B && C      ->  ep2: C
    + *
    + * ep1: A || B           ->  ep1: n
    + * ep2: A || B || C      ->  ep2: C
    + *
    + * ep1: A && (B && FOO)  ->  ep1: FOO
    + * ep2: (BAR && B) && A  ->  ep2: BAR
    + *
    + * ep1: A && (B || C)    ->  ep1: y
    + * ep2: (C || B) && A    ->  ep2: y
    + *
    + * Comparisons are done between all operands at the same "level" of && or 
||.
    + * For example, in the expression 'e1 && (e2 || e3) && (e4 || e5)', the
    + * following operands will be compared:
    + *
    + * - 'e1', 'e2 || e3', and 'e4 || e5', against each other
    + * - e2 against e3
    + * - e4 against e5
    + *
    + * Parentheses are irrelevant within a single level. 'e1 && (e2 && e3)' and
    + * '(e1 && e2) && e3' are both a single level.
    + *
    + * See __expr_eliminate_eq() as well.
    + */
    +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
    +
    +/*
    + * Returns true if 'e1' and 'e2' are equal, after minor simplification. Two
    + * &&/|| expressions are considered equal if every operand in one 
expression
    + * equals some operand in the other (operands do not need to appear in the 
same
    + * order), recursively.
    + */
    +static 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_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   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;
    +}
    +
    +/*
    + * Recursively performs the following simplifications in-place (as well as 
the
    + * corresponding simplifications with swapped operands):
    + *
    + * expr && n  ->  n
    + * expr && y  ->  expr
    + * expr || n  ->  expr
    + * expr || y  ->  y
    + *
    + * Returns the optimized expression.
    + */
    +static 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;
    +}
    +
    +/*
    + * expr_eliminate_dups() helper.
    + *
    + * Walks the two expression trees given in 'ep1' and 'ep2'. Any node that 
does
    + * not have type 'type' (E_OR/E_AND) is considered a leaf, and is compared
    + * against all other leaves to look for simplifications.
    + */
    +static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, 
struct expr **ep2)
    +{
    +#define e1 (*ep1)
    +#define e2 (*ep2)
    +   struct expr *tmp;
    +
    +   /* Recurse down to leaves */
    +
    +   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;
    +   }
    +
    +   /* e1 and e2 are leaves. Compare and process them. */
    +
    +   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
    +}
    +
    +/*
    + * Rewrites 'e' in-place to remove ("join") duplicate and other redundant
    + * operands.
    + *
    + * Example simplifications:
    + *
    + * A || B || A    ->  A || B
    + * A && B && A=y  ->  A=y && B
    + *
    + * Returns the deduplicated expression.
    + */
    +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);
    +           default:
    +                   ;
    +           }
    +           if (!trans_count)
    +                   /* No simplifications done in this pass. We're done */
    +                   break;
    +           e = expr_eliminate_yn(e);
    +   }
    +   trans_count = oldcount;
    +   return e;
    +}
    +
    +/*
    + * Performs various simplifications involving logical operators and
    + * comparisons.
    + *
    + * Allocates and returns a new expression.
    + */
    +struct expr *expr_transform(struct expr *e)
    +{
    +   struct expr *tmp;
    +
    +   if (!e)
    +           return NULL;
    +   switch (e->type) {
    +   case E_EQUAL:
    +   case E_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   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_LEQ:
    +           case E_GEQ:
    +                   // !a<='x' -> a>'x'
    +                   tmp = e->left.expr;
    +                   free(e);
    +                   e = tmp;
    +                   e->type = e->type == E_LEQ ? E_GTH : E_LTH;
    +                   break;
    +           case E_LTH:
    +           case E_GTH:
    +                   // !a<'x' -> a>='x'
    +                   tmp = e->left.expr;
    +                   free(e);
    +                   e = tmp;
    +                   e->type = e->type == E_LTH ? E_GEQ : E_LEQ;
    +                   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_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   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;
    +}
    +
    +/*
    + * Inserts explicit comparisons of type 'type' to symbol 'sym' into the
    + * expression 'e'.
    + *
    + * Examples transformations for type == E_UNEQUAL, sym == &symbol_no:
    + *
    + * A              ->  A!=n
    + * !A             ->  A=n
    + * A && B         ->  !(A=n || B=n)
    + * A || B         ->  !(A=n && B=n)
    + * A && (B || C)  ->  !(A=n || (B=n && C=n))
    + *
    + * Allocates and returns a new expression.
    + */
    +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_LTH:
    +   case E_LEQ:
    +   case E_GTH:
    +   case E_GEQ:
    +   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;
    +}
    +
    +enum string_value_kind {
    +   k_string,
    +   k_signed,
    +   k_unsigned,
    +};
    +
    +union string_value {
    +   unsigned long long u;
    +   signed long long s;
    +};
    +
    +static enum string_value_kind expr_parse_string(const char *str,
    +                                           enum symbol_type type,
    +                                           union string_value *val)
    +{
    +   char *tail;
    +   enum string_value_kind kind;
    +
    +   errno = 0;
    +   switch (type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           val->s = !strcmp(str, "n") ? 0 :
    +                    !strcmp(str, "m") ? 1 :
    +                    !strcmp(str, "y") ? 2 : -1;
    +           return k_signed;
    +   case S_INT:
    +           val->s = strtoll(str, &tail, 10);
    +           kind = k_signed;
    +           break;
    +   case S_HEX:
    +           val->u = strtoull(str, &tail, 16);
    +           kind = k_unsigned;
    +           break;
    +   default:
    +           val->s = strtoll(str, &tail, 0);
    +           kind = k_signed;
    +           break;
    +   }
    +   return !errno && !*tail && tail > str && isxdigit(tail[-1])
    +          ? kind : k_string;
    +}
    +
    +tristate expr_calc_value(struct expr *e)
    +{
    +   tristate val1, val2;
    +   const char *str1, *str2;
    +   enum string_value_kind k1 = k_string, k2 = k_string;
    +   union string_value lval = {}, rval = {};
    +   int res;
    +
    +   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:
    +   case E_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   case E_UNEQUAL:
    +           break;
    +   default:
    +           printf("expr_calc_value: %d?\n", e->type);
    +           return no;
    +   }
    +
    +   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);
    +
    +   if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) {
    +           k1 = expr_parse_string(str1, e->left.sym->type, &lval);
    +           k2 = expr_parse_string(str2, e->right.sym->type, &rval);
    +   }
    +
    +   if (k1 == k_string || k2 == k_string)
    +           res = strcmp(str1, str2);
    +   else if (k1 == k_unsigned || k2 == k_unsigned)
    +           res = (lval.u > rval.u) - (lval.u < rval.u);
    +   else /* if (k1 == k_signed && k2 == k_signed) */
    +           res = (lval.s > rval.s) - (lval.s < rval.s);
    +
    +   switch(e->type) {
    +   case E_EQUAL:
    +           return res ? no : yes;
    +   case E_GEQ:
    +           return res >= 0 ? yes : no;
    +   case E_GTH:
    +           return res > 0 ? yes : no;
    +   case E_LEQ:
    +           return res <= 0 ? yes : no;
    +   case E_LTH:
    +           return res < 0 ? yes : no;
    +   case E_UNEQUAL:
    +           return res ? yes : no;
    +   default:
    +           printf("expr_calc_value: relation %d?\n", e->type);
    +           return no;
    +   }
    +}
    +
    +static int expr_compare_type(enum expr_type t1, enum expr_type t2)
    +{
    +   if (t1 == t2)
    +           return 0;
    +   switch (t1) {
    +   case E_LEQ:
    +   case E_LTH:
    +   case E_GEQ:
    +   case E_GTH:
    +           if (t2 == E_EQUAL || t2 == E_UNEQUAL)
    +                   return 1;
    +   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;
    +}
    +
    +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_LEQ:
    +   case E_LTH:
    +           if (e->left.sym->name)
    +                   fn(data, e->left.sym, e->left.sym->name);
    +           else
    +                   fn(data, NULL, "<choice>");
    +           fn(data, NULL, e->type == E_LEQ ? "<=" : "<");
    +           fn(data, e->right.sym, e->right.sym->name);
    +           break;
    +   case E_GEQ:
    +   case E_GTH:
    +           if (e->left.sym->name)
    +                   fn(data, e->left.sym, e->left.sym->name);
    +           else
    +                   fn(data, NULL, "<choice>");
    +           fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
    +           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);
    +}
    +
    +/*
    + * Transform the top level "||" tokens into newlines and prepend each
    + * line with a minus. This makes expressions much easier to read.
    + * Suitable for reverse dependency expressions.
    + */
    +static void expr_print_revdep(struct expr *e,
    +                         void (*fn)(void *, struct symbol *, const char *),
    +                         void *data, tristate pr_type, const char **title)
    +{
    +   if (e->type == E_OR) {
    +           expr_print_revdep(e->left.expr, fn, data, pr_type, title);
    +           expr_print_revdep(e->right.expr, fn, data, pr_type, title);
    +   } else if (expr_calc_value(e) == pr_type) {
    +           if (*title) {
    +                   fn(data, NULL, *title);
    +                   *title = NULL;
    +           }
    +
    +           fn(data, NULL, "  - ");
    +           expr_print(e, fn, data, E_NONE);
    +           fn(data, NULL, "\n");
    +   }
    +}
    +
    +void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
    +                       tristate pr_type, const char *title)
    +{
    +   expr_print_revdep(e, expr_print_gstr_helper, gs, pr_type, &title);
    +}
    diff --git a/support/kconfig.new/expr.h b/support/kconfig.new/expr.h
    new file mode 100644
    index 0000000..8dde65b
    --- /dev/null
    +++ b/support/kconfig.new/expr.h
    @@ -0,0 +1,331 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#ifndef EXPR_H
    +#define EXPR_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include <assert.h>
    +#include <stdio.h>
    +#include "list.h"
    +#ifndef __cplusplus
    +#include <stdbool.h>
    +#endif
    +
    +struct file {
    +   struct file *next;
    +   struct file *parent;
    +   const char *name;
    +   int lineno;
    +};
    +
    +typedef enum tristate {
    +   no, mod, yes
    +} tristate;
    +
    +enum expr_type {
    +   E_NONE, E_OR, E_AND, E_NOT,
    +   E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ,
    +   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
    +};
    +
    +/* 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
    +};
    +
    +/*
    + * Represents a configuration symbol.
    + *
    + * Choices are represented as a special kind of symbol and have the
    + * SYMBOL_CHOICE bit set in 'flags'.
    + */
    +struct symbol {
    +   /* The next symbol in the same bucket in the symbol hash table */
    +   struct symbol *next;
    +
    +   /* The name of the symbol, e.g. "FOO" for 'config FOO' */
    +   char *name;
    +
    +   /* S_BOOLEAN, S_TRISTATE, ... */
    +   enum symbol_type type;
    +
    +   /*
    +    * The calculated value of the symbol. The SYMBOL_VALID bit is set in
    +    * 'flags' when this is up to date. Note that this value might differ
    +    * from the user value set in e.g. a .config file, due to visibility.
    +    */
    +   struct symbol_value curr;
    +
    +   /*
    +    * Values for the symbol provided from outside. def[S_DEF_USER] holds
    +    * the .config value.
    +    */
    +   struct symbol_value def[S_DEF_COUNT];
    +
    +   /*
    +    * An upper bound on the tristate value the user can set for the symbol
    +    * if it is a boolean or tristate. Calculated from prompt dependencies,
    +    * which also inherit dependencies from enclosing menus, choices, and
    +    * ifs. If 'n', the user value will be ignored.
    +    *
    +    * Symbols lacking prompts always have visibility 'n'.
    +    */
    +   tristate visible;
    +
    +   /* SYMBOL_* flags */
    +   int flags;
    +
    +   /* List of properties. See prop_type. */
    +   struct property *prop;
    +
    +   /* Dependencies from enclosing menus, choices, and ifs */
    +   struct expr_value dir_dep;
    +
    +   /* Reverse dependencies through being selected by other symbols */
    +   struct expr_value rev_dep;
    +
    +   /*
    +    * "Weak" reverse dependencies through being implied by other symbols
    +    */
    +   struct expr_value implied;
    +};
    +
    +#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for 
(sym = symbol_hash[i]; sym; sym = sym->next)
    +
    +#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  /* write symbol to file (KCONFIG_CONFIG) 
*/
    +#define SYMBOL_CHANGED    0x0400  /* ? */
    +#define SYMBOL_NO_WRITE   0x1000  /* Symbol for internal use only; it will 
not be written */
    +#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 */
    +
    +/* choice values need to be set before calculating this symbol value */
    +#define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000
    +
    +/* Set symbol to y if allnoconfig; used for symbols that hide others */
    +#define SYMBOL_ALLNOCONFIG_Y 0x200000
    +
    +#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
    + *
    + * Please, also check parser.y:print_symbol() when modifying the
    + * list of property types!
    + */
    +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 menu or menuconfig symbol */
    +   P_DEFAULT,  /* default y */
    +   P_CHOICE,   /* choice value */
    +   P_SELECT,   /* select BAR */
    +   P_IMPLY,    /* imply BAR */
    +   P_RANGE,    /* range 7..100 (for a symbol) */
    +   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)
    +
    +/*
    + * Represents a node in the menu tree, as seen in e.g. menuconfig (though 
used
    + * for all front ends). Each symbol, menu, etc. defined in the Kconfig 
files
    + * gets a node. A symbol defined in multiple locations gets one node at 
each
    + * location.
    + */
    +struct menu {
    +   /* The next menu node at the same level */
    +   struct menu *next;
    +
    +   /* The parent menu node, corresponding to e.g. a menu or choice */
    +   struct menu *parent;
    +
    +   /* The first child menu node, for e.g. menus and choices */
    +   struct menu *list;
    +
    +   /*
    +    * The symbol associated with the menu node. Choices are implemented as
    +    * a special kind of symbol. NULL for menus, comments, and ifs.
    +    */
    +   struct symbol *sym;
    +
    +   /*
    +    * The prompt associated with the node. This holds the prompt for a
    +    * symbol as well as the text for a menu or comment, along with the
    +    * type (P_PROMPT, P_MENU, etc.)
    +    */
    +   struct property *prompt;
    +
    +   /*
    +    * 'visible if' dependencies. If more than one is given, they will be
    +    * ANDed together.
    +    */
    +   struct expr *visibility;
    +
    +   /*
    +    * Ordinary dependencies from e.g. 'depends on' and 'if', ANDed
    +    * together
    +    */
    +   struct expr *dep;
    +
    +   /* MENU_* flags */
    +   unsigned int flags;
    +
    +   /* Any help text associated with the node */
    +   char *help;
    +
    +   /* The location where the menu node appears in the Kconfig files */
    +   struct file *file;
    +   int lineno;
    +
    +   /* For use by front ends that need to store auxiliary data */
    +   void *data;
    +};
    +
    +/*
    + * Set on a menu node when the corresponding symbol changes state in some 
way.
    + * Can be checked by front ends.
    + */
    +#define MENU_CHANGED               0x0001
    +
    +#define MENU_ROOT          0x0002
    +
    +struct jump_key {
    +   struct list_head entries;
    +   size_t offset;
    +   struct menu *target;
    +   int index;
    +};
    +
    +#define JUMP_NB                    9
    +
    +extern struct file *file_list;
    +extern struct file *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);
    +void expr_eliminate_eq(struct expr **ep1, struct expr **ep2);
    +tristate expr_calc_value(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_trans_compare(struct expr *e, enum expr_type type, 
struct symbol *sym);
    +
    +void expr_fprint(struct expr *e, FILE *out);
    +struct gstr; /* forward */
    +void expr_gstr_print(struct expr *e, struct gstr *gs);
    +void expr_gstr_print_revdep(struct expr *e, struct gstr *gs,
    +                       tristate pr_type, const char *title);
    +
    +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);
    +}
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif /* EXPR_H */
    diff --git a/support/kconfig.new/gconf-cfg.sh 
b/support/kconfig.new/gconf-cfg.sh
    new file mode 100755
    index 0000000..480ecd8
    --- /dev/null
    +++ b/support/kconfig.new/gconf-cfg.sh
    @@ -0,0 +1,30 @@
    +#!/bin/sh
    +# SPDX-License-Identifier: GPL-2.0
    +
    +PKG="gtk+-2.0 gmodule-2.0 libglade-2.0"
    +
    +if [ -z "$(command -v pkg-config)" ]; then
    +   echo >&2 "*"
    +   echo >&2 "* 'make gconfig' requires 'pkg-config'. Please install it."
    +   echo >&2 "*"
    +   exit 1
    +fi
    +
    +if ! pkg-config --exists $PKG; then
    +   echo >&2 "*"
    +   echo >&2 "* Unable to find the GTK+ installation. Please make sure that"
    +   echo >&2 "* the GTK+ 2.0 development package is correctly installed."
    +   echo >&2 "* You need $PKG"
    +   echo >&2 "*"
    +   exit 1
    +fi
    +
    +if ! pkg-config --atleast-version=2.0.0 gtk+-2.0; then
    +   echo >&2 "*"
    +   echo >&2 "* GTK+ is present but version >= 2.0.0 is required."
    +   echo >&2 "*"
    +   exit 1
    +fi
    +
    +echo cflags=\"$(pkg-config --cflags $PKG)\"
    +echo libs=\"$(pkg-config --libs $PKG)\"
    diff --git a/support/kconfig.new/gconf.c b/support/kconfig.new/gconf.c
    new file mode 100644
    index 0000000..e36b342
    --- /dev/null
    +++ b/support/kconfig.new/gconf.c
    @@ -0,0 +1,1516 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002-2003 Romain Lievin <roms@xxxxxxxxx>
    + */
    +
    +#ifdef HAVE_CONFIG_H
    +#  include <config.h>
    +#endif
    +
    +#include <stdlib.h>
    +#include "lkc.h"
    +#include "images.h"
    +
    +#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>
    +
    +//#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 */
    +#ifdef DEBUG
    +static 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_NO_WRITE)
    +           strcat(buf, "no_write/");
    +
    +   buf[strlen(buf) - 1] = '\0';
    +
    +   return buf;
    +}
    +#endif
    +
    +static 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 */
    +static 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");
    +
    +   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);
    +
    +   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);
    +}
    +
    +static 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);
    +}
    +
    +static 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, TRUE);
    +
    +   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 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, TRUE);
    +
    +   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);
    +   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 !");
    +   conf_write_autoconf(0);
    +}
    +
    +
    +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, "%s", 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@xxxxxxxxxxxxxx>.\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, "%s", 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, "%s", 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_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_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 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:
    +           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 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;
    +           /* fall through */
    +   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.
    + */
    +static 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 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) {
    +
    +           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))*/
    +
    +           /* Change paned position if the view is not in 'split mode' */
    +           if (view_mode == SINGLE_VIEW || view_mode == FULL_VIEW) {
    +                   gtk_paned_set_position(GTK_PANED(hpaned), 0);
    +           }
    +
    +           if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
    +               || (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;
    +}
    +
    +static 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;
    +
    +   /* 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 's':
    +                   conf_set_message_callback(NULL);
    +                   break;
    +           case 'h':
    +           case '?':
    +                   printf("%s [-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/support/kconfig.new/gconf.glade 
b/support/kconfig.new/gconf.glade
    new file mode 100644
    index 0000000..aa483cb
    --- /dev/null
    +++ b/support/kconfig.new/gconf.glade
    @@ -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/support/kconfig.new/images.c b/support/kconfig.new/images.c
    new file mode 100644
    index 0000000..b4fa0e4
    --- /dev/null
    +++ b/support/kconfig.new/images.c
    @@ -0,0 +1,328 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include "images.h"
    +
    +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##......",
    +"###############.......",
    +"......................"};
    +
    +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#.",
    +"..##################..",
    +"......................"};
    +
    +const char *xpm_back[] = {
    +"22 22 3 1",
    +". c None",
    +"# c #000083",
    +"a c #838183",
    +"......................",
    +"......................",
    +"......................",
    +"......................",
    +"......................",
    +"...........######a....",
    +"..#......##########...",
    +"..##...####......##a..",
    +"..###.###.........##..",
    +"..######..........##..",
    +"..#####...........##..",
    +"..######..........##..",
    +"..#######.........##..",
    +"..########.......##a..",
    +"...............a###...",
    +"...............###....",
    +"......................",
    +"......................",
    +"......................",
    +"......................",
    +"......................",
    +"......................"};
    +
    +const char *xpm_tree_view[] = {
    +"22 22 2 1",
    +". c None",
    +"# c #000000",
    +"......................",
    +"......................",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......########........",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......########........",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......#...............",
    +"......########........",
    +"......................",
    +"......................"};
    +
    +const char *xpm_single_view[] = {
    +"22 22 2 1",
    +". c None",
    +"# c #000000",
    +"......................",
    +"......................",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"..........#...........",
    +"......................",
    +"......................"};
    +
    +const char *xpm_split_view[] = {
    +"22 22 2 1",
    +". c None",
    +"# c #000000",
    +"......................",
    +"......................",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......#......#........",
    +"......................",
    +"......................"};
    +
    +const char *xpm_symbol_no[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +" .......... ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .......... ",
    +"            "};
    +
    +const char *xpm_symbol_mod[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +" .......... ",
    +" .        . ",
    +" .        . ",
    +" .   ..   . ",
    +" .  ....  . ",
    +" .  ....  . ",
    +" .   ..   . ",
    +" .        . ",
    +" .        . ",
    +" .......... ",
    +"            "};
    +
    +const char *xpm_symbol_yes[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +" .......... ",
    +" .        . ",
    +" .        . ",
    +" .      . . ",
    +" .     .. . ",
    +" . .  ..  . ",
    +" . ....   . ",
    +" .  ..    . ",
    +" .        . ",
    +" .......... ",
    +"            "};
    +
    +const char *xpm_choice_no[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +"    ....    ",
    +"  ..    ..  ",
    +"  .      .  ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +" .        . ",
    +"  .      .  ",
    +"  ..    ..  ",
    +"    ....    ",
    +"            "};
    +
    +const char *xpm_choice_yes[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +"    ....    ",
    +"  ..    ..  ",
    +"  .      .  ",
    +" .   ..   . ",
    +" .  ....  . ",
    +" .  ....  . ",
    +" .   ..   . ",
    +"  .      .  ",
    +"  ..    ..  ",
    +"    ....    ",
    +"            "};
    +
    +const char *xpm_menu[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +" .......... ",
    +" .        . ",
    +" . ..     . ",
    +" . ....   . ",
    +" . ...... . ",
    +" . ...... . ",
    +" . ....   . ",
    +" . ..     . ",
    +" .        . ",
    +" .......... ",
    +"            "};
    +
    +const char *xpm_menu_inv[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +" .......... ",
    +" .......... ",
    +" ..  ...... ",
    +" ..    .... ",
    +" ..      .. ",
    +" ..      .. ",
    +" ..    .... ",
    +" ..  ...... ",
    +" .......... ",
    +" .......... ",
    +"            "};
    +
    +const char *xpm_menuback[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +" .......... ",
    +" .        . ",
    +" .     .. . ",
    +" .   .... . ",
    +" . ...... . ",
    +" . ...... . ",
    +" .   .... . ",
    +" .     .. . ",
    +" .        . ",
    +" .......... ",
    +"            "};
    +
    +const char *xpm_void[] = {
    +"12 12 2 1",
    +"  c white",
    +". c black",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            ",
    +"            "};
    diff --git a/support/kconfig.new/images.h b/support/kconfig.new/images.h
    new file mode 100644
    index 0000000..d8ff614
    --- /dev/null
    +++ b/support/kconfig.new/images.h
    @@ -0,0 +1,33 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#ifndef IMAGES_H
    +#define IMAGES_H
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +extern const char *xpm_load[];
    +extern const char *xpm_save[];
    +extern const char *xpm_back[];
    +extern const char *xpm_tree_view[];
    +extern const char *xpm_single_view[];
    +extern const char *xpm_split_view[];
    +extern const char *xpm_symbol_no[];
    +extern const char *xpm_symbol_mod[];
    +extern const char *xpm_symbol_yes[];
    +extern const char *xpm_choice_no[];
    +extern const char *xpm_choice_yes[];
    +extern const char *xpm_menu[];
    +extern const char *xpm_menu_inv[];
    +extern const char *xpm_menuback[];
    +extern const char *xpm_void[];
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif /* IMAGES_H */
    diff --git a/support/kconfig.new/lexer.l b/support/kconfig.new/lexer.l
    new file mode 100644
    index 0000000..6354c90
    --- /dev/null
    +++ b/support/kconfig.new/lexer.l
    @@ -0,0 +1,471 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +%option nostdinit noyywrap never-interactive full ecs
    +%option 8bit nodefault yylineno
    +%x ASSIGN_VAL HELP STRING
    +%{
    +
    +#include <assert.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "lkc.h"
    +#include "parser.tab.h"
    +
    +#define YY_DECL            static int yylex1(void)
    +
    +#define START_STRSIZE      16
    +
    +static struct {
    +   struct file *file;
    +   int lineno;
    +} current_pos;
    +
    +static int prev_prev_token = T_EOL;
    +static int prev_token = T_EOL;
    +static char *text;
    +static int text_size, text_asize;
    +
    +struct buffer {
    +   struct buffer *parent;
    +   YY_BUFFER_STATE state;
    +};
    +
    +struct buffer *current_buf;
    +
    +static int last_ts, first_ts;
    +
    +static char *expand_token(const char *in, size_t n);
    +static void append_expanded_string(const char *in);
    +static void zconf_endhelp(void);
    +static void zconf_endfile(void);
    +
    +static void new_string(void)
    +{
    +   text = xmalloc(START_STRSIZE);
    +   text_asize = START_STRSIZE;
    +   text_size = 0;
    +   *text = 0;
    +}
    +
    +static void append_string(const char *str, int size)
    +{
    +   int new_size = text_size + size + 1;
    +   if (new_size > text_asize) {
    +           new_size += START_STRSIZE - 1;
    +           new_size &= -START_STRSIZE;
    +           text = xrealloc(text, new_size);
    +           text_asize = new_size;
    +   }
    +   memcpy(text + text_size, str, size);
    +   text_size += size;
    +   text[text_size] = 0;
    +}
    +
    +static void alloc_string(const char *str, int size)
    +{
    +   text = xmalloc(size + 1);
    +   memcpy(text, str, size);
    +   text[size] = 0;
    +}
    +
    +static void warn_ignored_character(char chr)
    +{
    +   fprintf(stderr,
    +           "%s:%d:warning: ignoring unsupported character '%c'\n",
    +           current_file->name, yylineno, chr);
    +}
    +%}
    +
    +n  [A-Za-z0-9_-]
    +
    +%%
    +   int str = 0;
    +   int ts, i;
    +
    +#.*                        /* ignore comment */
    +[ \t]*                     /* whitespaces */
    +\\\n                       /* escaped new line */
    +\n                 return T_EOL;
    +"allnoconfig_y"            return T_ALLNOCONFIG_Y;
    +"bool"                     return T_BOOL;
    +"choice"           return T_CHOICE;
    +"comment"          return T_COMMENT;
    +"config"           return T_CONFIG;
    +"def_bool"         return T_DEF_BOOL;
    +"def_tristate"             return T_DEF_TRISTATE;
    +"default"          return T_DEFAULT;
    +"defconfig_list"   return T_DEFCONFIG_LIST;
    +"depends"          return T_DEPENDS;
    +"endchoice"                return T_ENDCHOICE;
    +"endif"                    return T_ENDIF;
    +"endmenu"          return T_ENDMENU;
    +"help"|"---help---"        return T_HELP;
    +"hex"                      return T_HEX;
    +"if"                       return T_IF;
    +"imply"                    return T_IMPLY;
    +"int"                      return T_INT;
    +"mainmenu"         return T_MAINMENU;
    +"menu"                     return T_MENU;
    +"menuconfig"               return T_MENUCONFIG;
    +"modules"          return T_MODULES;
    +"on"                       return T_ON;
    +"option"           return T_OPTION;
    +"optional"         return T_OPTIONAL;
    +"prompt"           return T_PROMPT;
    +"range"                    return T_RANGE;
    +"select"           return T_SELECT;
    +"source"           return T_SOURCE;
    +"string"           return T_STRING;
    +"tristate"         return T_TRISTATE;
    +"visible"          return T_VISIBLE;
    +"||"                       return T_OR;
    +"&&"                       return T_AND;
    +"="                        return T_EQUAL;
    +"!="                       return T_UNEQUAL;
    +"<"                        return T_LESS;
    +"<="                       return T_LESS_EQUAL;
    +">"                        return T_GREATER;
    +">="                       return T_GREATER_EQUAL;
    +"!"                        return T_NOT;
    +"("                        return T_OPEN_PAREN;
    +")"                        return T_CLOSE_PAREN;
    +":="                       return T_COLON_EQUAL;
    +"+="                       return T_PLUS_EQUAL;
    +\"|\'                      {
    +                           str = yytext[0];
    +                           new_string();
    +                           BEGIN(STRING);
    +                   }
    +{n}+                       {
    +                           alloc_string(yytext, yyleng);
    +                           yylval.string = text;
    +                           return T_WORD;
    +                   }
    +({n}|$)+           {
    +                           /* this token includes at least one '$' */
    +                           yylval.string = expand_token(yytext, yyleng);
    +                           if (strlen(yylval.string))
    +                                   return T_WORD;
    +                           free(yylval.string);
    +                   }
    +.                  warn_ignored_character(*yytext);
    +
    +<ASSIGN_VAL>{
    +   [^[:blank:]\n]+.*       {
    +           alloc_string(yytext, yyleng);
    +           yylval.string = text;
    +           return T_ASSIGN_VAL;
    +   }
    +   \n      { BEGIN(INITIAL); return T_EOL; }
    +   .
    +}
    +
    +<STRING>{
    +   "$".*   append_expanded_string(yytext);
    +   [^$'"\\\n]+     {
    +           append_string(yytext, yyleng);
    +   }
    +   \\.?    {
    +           append_string(yytext + 1, yyleng - 1);
    +   }
    +   \'|\"   {
    +           if (str == yytext[0]) {
    +                   BEGIN(INITIAL);
    +                   yylval.string = text;
    +                   return T_WORD_QUOTE;
    +           } else
    +                   append_string(yytext, 1);
    +   }
    +   \n      {
    +           fprintf(stderr,
    +                   "%s:%d:warning: multi-line strings not supported\n",
    +                   zconf_curname(), zconf_lineno());
    +           unput('\n');
    +           BEGIN(INITIAL);
    +           yylval.string = text;
    +           return T_WORD_QUOTE;
    +   }
    +   <<EOF>> {
    +           BEGIN(INITIAL);
    +           yylval.string = text;
    +           return T_WORD_QUOTE;
    +   }
    +}
    +
    +<HELP>{
    +   [ \t]+  {
    +           ts = 0;
    +           for (i = 0; i < yyleng; i++) {
    +                   if (yytext[i] == '\t')
    +                           ts = (ts & ~7) + 8;
    +                   else
    +                           ts++;
    +           }
    +           last_ts = ts;
    +           if (first_ts) {
    +                   if (ts < first_ts) {
    +                           zconf_endhelp();
    +                           return T_HELPTEXT;
    +                   }
    +                   ts -= first_ts;
    +                   while (ts > 8) {
    +                           append_string("        ", 8);
    +                           ts -= 8;
    +                   }
    +                   append_string("        ", ts);
    +           }
    +   }
    +   [ \t]*\n/[^ \t\n] {
    +           zconf_endhelp();
    +           return T_HELPTEXT;
    +   }
    +   [ \t]*\n        {
    +           append_string("\n", 1);
    +   }
    +   [^ \t\n].* {
    +           while (yyleng) {
    +                   if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != 
'\t'))
    +                           break;
    +                   yyleng--;
    +           }
    +           append_string(yytext, yyleng);
    +           if (!first_ts)
    +                   first_ts = last_ts;
    +   }
    +   <<EOF>> {
    +           zconf_endhelp();
    +           return T_HELPTEXT;
    +   }
    +}
    +
    +<<EOF>>    {
    +   BEGIN(INITIAL);
    +
    +   if (prev_token != T_EOL && prev_token != T_HELPTEXT)
    +           fprintf(stderr, "%s:%d:warning: no new line at end of file\n",
    +                   current_file->name, yylineno);
    +
    +   if (current_file) {
    +           zconf_endfile();
    +           return T_EOL;
    +   }
    +   fclose(yyin);
    +   yyterminate();
    +}
    +
    +%%
    +
    +/* second stage lexer */
    +int yylex(void)
    +{
    +   int token;
    +
    +repeat:
    +   token = yylex1();
    +
    +   if (prev_token == T_EOL || prev_token == T_HELPTEXT) {
    +           if (token == T_EOL) {
    +                   /* Do not pass unneeded T_EOL to the parser. */
    +                   goto repeat;
    +           } else {
    +                   /*
    +                    * For the parser, update file/lineno at the first token
    +                    * of each statement. Generally, \n is a statement
    +                    * terminator in Kconfig, but it is not always true
    +                    * because \n could be escaped by a backslash.
    +                    */
    +                   current_pos.file = current_file;
    +                   current_pos.lineno = yylineno;
    +           }
    +   }
    +
    +   if (prev_prev_token == T_EOL && prev_token == T_WORD &&
    +       (token == T_EQUAL || token == T_COLON_EQUAL || token == 
T_PLUS_EQUAL))
    +           BEGIN(ASSIGN_VAL);
    +
    +   prev_prev_token = prev_token;
    +   prev_token = token;
    +
    +   return token;
    +}
    +
    +static char *expand_token(const char *in, size_t n)
    +{
    +   char *out;
    +   int c;
    +   char c2;
    +   const char *rest, *end;
    +
    +   new_string();
    +   append_string(in, n);
    +
    +   /* get the whole line because we do not know the end of token. */
    +   while ((c = input()) != EOF) {
    +           if (c == '\n') {
    +                   unput(c);
    +                   break;
    +           }
    +           c2 = c;
    +           append_string(&c2, 1);
    +   }
    +
    +   rest = text;
    +   out = expand_one_token(&rest);
    +
    +   /* push back unused characters to the input stream */
    +   end = rest + strlen(rest);
    +   while (end > rest)
    +           unput(*--end);
    +
    +   free(text);
    +
    +   return out;
    +}
    +
    +static void append_expanded_string(const char *str)
    +{
    +   const char *end;
    +   char *res;
    +
    +   str++;
    +
    +   res = expand_dollar(&str);
    +
    +   /* push back unused characters to the input stream */
    +   end = str + strlen(str);
    +   while (end > str)
    +           unput(*--end);
    +
    +   append_string(res, strlen(res));
    +
    +   free(res);
    +}
    +
    +void zconf_starthelp(void)
    +{
    +   new_string();
    +   last_ts = first_ts = 0;
    +   BEGIN(HELP);
    +}
    +
    +static void zconf_endhelp(void)
    +{
    +   yylval.string = text;
    +   BEGIN(INITIAL);
    +}
    +
    +
    +/*
    + * Try to open specified file with following names:
    + * ./name
    + * $(srctree)/name
    + * The latter is used when srctree is separate from objtree
    + * when compiling the kernel.
    + * Return NULL if file is not found.
    + */
    +FILE *zconf_fopen(const char *name)
    +{
    +   char *env, fullname[PATH_MAX+1];
    +   FILE *f;
    +
    +   f = fopen(name, "r");
    +   if (!f && name != NULL && name[0] != '/') {
    +           env = getenv(SRCTREE);
    +           if (env) {
    +                   snprintf(fullname, sizeof(fullname),
    +                            "%s/%s", env, name);
    +                   f = fopen(fullname, "r");
    +           }
    +   }
    +   return f;
    +}
    +
    +void zconf_initscan(const char *name)
    +{
    +   yyin = zconf_fopen(name);
    +   if (!yyin) {
    +           fprintf(stderr, "can't find file %s\n", name);
    +           exit(1);
    +   }
    +
    +   current_buf = xmalloc(sizeof(*current_buf));
    +   memset(current_buf, 0, sizeof(*current_buf));
    +
    +   current_file = file_lookup(name);
    +   yylineno = 1;
    +}
    +
    +void zconf_nextfile(const char *name)
    +{
    +   struct file *iter;
    +   struct file *file = file_lookup(name);
    +   struct buffer *buf = xmalloc(sizeof(*buf));
    +   memset(buf, 0, sizeof(*buf));
    +
    +   current_buf->state = YY_CURRENT_BUFFER;
    +   yyin = zconf_fopen(file->name);
    +   if (!yyin) {
    +           fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
    +                   zconf_curname(), zconf_lineno(), file->name);
    +           exit(1);
    +   }
    +   yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
    +   buf->parent = current_buf;
    +   current_buf = buf;
    +
    +   current_file->lineno = yylineno;
    +   file->parent = current_file;
    +
    +   for (iter = current_file; iter; iter = iter->parent) {
    +           if (!strcmp(iter->name, file->name)) {
    +                   fprintf(stderr,
    +                           "Recursive inclusion detected.\n"
    +                           "Inclusion path:\n"
    +                           "  current file : %s\n", file->name);
    +                   iter = file;
    +                   do {
    +                           iter = iter->parent;
    +                           fprintf(stderr, "  included from: %s:%d\n",
    +                                   iter->name, iter->lineno - 1);
    +                   } while (strcmp(iter->name, file->name));
    +                   exit(1);
    +           }
    +   }
    +
    +   yylineno = 1;
    +   current_file = file;
    +}
    +
    +static void zconf_endfile(void)
    +{
    +   struct buffer *parent;
    +
    +   current_file = current_file->parent;
    +   if (current_file)
    +           yylineno = current_file->lineno;
    +
    +   parent = current_buf->parent;
    +   if (parent) {
    +           fclose(yyin);
    +           yy_delete_buffer(YY_CURRENT_BUFFER);
    +           yy_switch_to_buffer(parent->state);
    +   }
    +   free(current_buf);
    +   current_buf = parent;
    +}
    +
    +int zconf_lineno(void)
    +{
    +   return current_pos.lineno;
    +}
    +
    +const char *zconf_curname(void)
    +{
    +   return current_pos.file ? current_pos.file->name : "<none>";
    +}
    diff --git a/support/kconfig.new/list.h b/support/kconfig.new/list.h
    new file mode 100644
    index 0000000..45cb237
    --- /dev/null
    +++ b/support/kconfig.new/list.h
    @@ -0,0 +1,132 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +#ifndef LIST_H
    +#define LIST_H
    +
    +/*
    + * Copied from include/linux/...
    + */
    +
    +#undef offsetof
    +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    +
    +/**
    + * container_of - cast a member of a structure out to the containing 
structure
    + * @ptr:        the pointer to the member.
    + * @type:       the type of the container struct this is embedded in.
    + * @member:     the name of the member within the struct.
    + *
    + */
    +#define container_of(ptr, type, member) ({                      \
    +   const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    +   (type *)( (char *)__mptr - offsetof(type,member) );})
    +
    +
    +struct list_head {
    +   struct list_head *next, *prev;
    +};
    +
    +
    +#define LIST_HEAD_INIT(name) { &(name), &(name) }
    +
    +#define LIST_HEAD(name) \
    +   struct list_head name = LIST_HEAD_INIT(name)
    +
    +/**
    + * list_entry - get the struct for this entry
    + * @ptr:   the &struct list_head pointer.
    + * @type:  the type of the struct this is embedded in.
    + * @member:        the name of the list_head within the struct.
    + */
    +#define list_entry(ptr, type, member) \
    +   container_of(ptr, type, member)
    +
    +/**
    + * list_for_each_entry     -       iterate over list of given type
    + * @pos:   the type * to use as a loop cursor.
    + * @head:  the head for your list.
    + * @member:        the name of the list_head within the struct.
    + */
    +#define list_for_each_entry(pos, head, member)                             
\
    +   for (pos = list_entry((head)->next, typeof(*pos), member);      \
    +        &pos->member != (head);    \
    +        pos = list_entry(pos->member.next, typeof(*pos), member))
    +
    +/**
    + * list_for_each_entry_safe - iterate over list of given type safe against 
removal of list entry
    + * @pos:   the type * to use as a loop cursor.
    + * @n:             another type * to use as temporary storage
    + * @head:  the head for your list.
    + * @member:        the name of the list_head within the struct.
    + */
    +#define list_for_each_entry_safe(pos, n, head, member)                     
\
    +   for (pos = list_entry((head)->next, typeof(*pos), member),      \
    +           n = list_entry(pos->member.next, typeof(*pos), member); \
    +        &pos->member != (head);                                    \
    +        pos = n, n = list_entry(n->member.next, typeof(*n), member))
    +
    +/**
    + * list_empty - tests whether a list is empty
    + * @head: the list to test.
    + */
    +static inline int list_empty(const struct list_head *head)
    +{
    +   return head->next == head;
    +}
    +
    +/*
    + * Insert a new entry between two known consecutive entries.
    + *
    + * This is only for internal list manipulation where we know
    + * the prev/next entries already!
    + */
    +static inline void __list_add(struct list_head *_new,
    +                         struct list_head *prev,
    +                         struct list_head *next)
    +{
    +   next->prev = _new;
    +   _new->next = next;
    +   _new->prev = prev;
    +   prev->next = _new;
    +}
    +
    +/**
    + * list_add_tail - add a new entry
    + * @new: new entry to be added
    + * @head: list head to add it before
    + *
    + * Insert a new entry before the specified head.
    + * This is useful for implementing queues.
    + */
    +static inline void list_add_tail(struct list_head *_new, struct list_head 
*head)
    +{
    +   __list_add(_new, head->prev, head);
    +}
    +
    +/*
    + * Delete a list entry by making the prev/next entries
    + * point to each other.
    + *
    + * This is only for internal list manipulation where we know
    + * the prev/next entries already!
    + */
    +static inline void __list_del(struct list_head *prev, struct list_head 
*next)
    +{
    +   next->prev = prev;
    +   prev->next = next;
    +}
    +
    +#define LIST_POISON1  ((void *) 0x00100100)
    +#define LIST_POISON2  ((void *) 0x00200200)
    +/**
    + * list_del - deletes entry from list.
    + * @entry: the element to delete from the list.
    + * Note: list_empty() on entry does not return true after this, the entry 
is
    + * in an undefined state.
    + */
    +static inline void list_del(struct list_head *entry)
    +{
    +   __list_del(entry->prev, entry->next);
    +   entry->next = (struct list_head*)LIST_POISON1;
    +   entry->prev = (struct list_head*)LIST_POISON2;
    +}
    +#endif
    diff --git a/support/kconfig.new/lkc.h b/support/kconfig.new/lkc.h
    new file mode 100644
    index 0000000..cbc7658
    --- /dev/null
    +++ b/support/kconfig.new/lkc.h
    @@ -0,0 +1,159 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#ifndef LKC_H
    +#define LKC_H
    +
    +#include "expr.h"
    +
    +#ifdef __cplusplus
    +extern "C" {
    +#endif
    +
    +#include "lkc_proto.h"
    +
    +#define SRCTREE "srctree"
    +
    +#ifndef PACKAGE
    +#define PACKAGE "linux"
    +#endif
    +
    +#ifndef CONFIG_
    +#define CONFIG_ "CONFIG_"
    +#endif
    +static inline const char *CONFIG_prefix(void)
    +{
    +   return getenv( "CONFIG_" ) ?: CONFIG_;
    +}
    +#undef CONFIG_
    +#define CONFIG_ CONFIG_prefix()
    +
    +enum conf_def_mode {
    +   def_default,
    +   def_yes,
    +   def_mod,
    +   def_no,
    +   def_random
    +};
    +
    +extern int yylineno;
    +void zconfdump(FILE *out);
    +void zconf_starthelp(void);
    +FILE *zconf_fopen(const char *name);
    +void zconf_initscan(const char *name);
    +void zconf_nextfile(const char *name);
    +int zconf_lineno(void);
    +const char *zconf_curname(void);
    +
    +/* confdata.c */
    +const char *conf_get_configname(void);
    +char *conf_get_default_confname(void);
    +void sym_set_change_count(int count);
    +void sym_add_change_count(int count);
    +bool conf_set_all_new_symbols(enum conf_def_mode mode);
    +void set_all_choice_values(struct symbol *csym);
    +
    +/* confdata.c and expr.c */
    +static inline void xfwrite(const void *str, size_t len, size_t count, FILE 
*out)
    +{
    +   assert(len != 0);
    +
    +   if (fwrite(str, len, count, out) != count)
    +           fprintf(stderr, "Error in writing or end of file.\n");
    +}
    +
    +/* menu.c */
    +void _menu_init(void);
    +void menu_warn(struct menu *menu, const char *fmt, ...);
    +struct menu *menu_add_menu(void);
    +void menu_end_menu(void);
    +void menu_add_entry(struct symbol *sym);
    +void menu_add_dep(struct expr *dep);
    +void menu_add_visibility(struct expr *dep);
    +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct 
expr *dep);
    +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr 
*dep);
    +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr 
*dep);
    +void menu_add_option_modules(void);
    +void menu_add_option_defconfig_list(void);
    +void menu_add_option_allnoconfig_y(void);
    +void menu_finalize(struct menu *parent);
    +void menu_set_type(int type);
    +
    +/* util.c */
    +struct file *file_lookup(const char *name);
    +void *xmalloc(size_t size);
    +void *xcalloc(size_t nmemb, size_t size);
    +void *xrealloc(void *p, size_t size);
    +char *xstrdup(const char *s);
    +char *xstrndup(const char *s, size_t n);
    +
    +/* lexer.l */
    +int yylex(void);
    +
    +struct gstr {
    +   size_t len;
    +   char  *s;
    +   /*
    +   * when max_width is not zero long lines in string s (if any) get
    +   * wrapped not to exceed the max_width value
    +   */
    +   int max_width;
    +};
    +struct gstr str_new(void);
    +void str_free(struct gstr *gs);
    +void str_append(struct gstr *gs, const char *s);
    +void str_printf(struct gstr *gs, const char *fmt, ...);
    +const char *str_get(struct gstr *gs);
    +
    +/* symbol.c */
    +void sym_clear_all_valid(void);
    +struct symbol *sym_choice_default(struct symbol *sym);
    +struct property *sym_get_range_prop(struct symbol *sym);
    +const char *sym_get_string_default(struct symbol *sym);
    +struct symbol *sym_check_deps(struct symbol *sym);
    +struct property *prop_alloc(enum prop_type type, struct symbol *sym);
    +struct symbol *prop_get_symbol(struct property *prop);
    +
    +static inline tristate sym_get_tristate_value(struct symbol *sym)
    +{
    +   return sym->curr.tri;
    +}
    +
    +
    +static inline struct symbol *sym_get_choice_value(struct symbol *sym)
    +{
    +   return (struct symbol *)sym->curr.val;
    +}
    +
    +static inline bool sym_set_choice_value(struct symbol *ch, struct symbol 
*chval)
    +{
    +   return sym_set_tristate_value(chval, yes);
    +}
    +
    +static inline bool sym_is_choice(struct symbol *sym)
    +{
    +   return sym->flags & SYMBOL_CHOICE ? true : false;
    +}
    +
    +static inline bool sym_is_choice_value(struct symbol *sym)
    +{
    +   return sym->flags & SYMBOL_CHOICEVAL ? true : false;
    +}
    +
    +static inline bool sym_is_optional(struct symbol *sym)
    +{
    +   return sym->flags & SYMBOL_OPTIONAL ? true : false;
    +}
    +
    +static inline bool sym_has_value(struct symbol *sym)
    +{
    +   return sym->flags & SYMBOL_DEF_USER ? true : false;
    +}
    +
    +#ifdef __cplusplus
    +}
    +#endif
    +
    +#endif /* LKC_H */
    diff --git a/support/kconfig.new/lkc_proto.h 
b/support/kconfig.new/lkc_proto.h
    new file mode 100644
    index 0000000..86c2675
    --- /dev/null
    +++ b/support/kconfig.new/lkc_proto.h
    @@ -0,0 +1,66 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +#include <stdarg.h>
    +
    +/* confdata.c */
    +void conf_parse(const char *name);
    +int conf_read(const char *name);
    +int conf_read_simple(const char *name, int);
    +int conf_write_defconfig(const char *name);
    +int conf_write(const char *name);
    +int conf_write_autoconf(int overwrite);
    +bool conf_get_changed(void);
    +void conf_set_changed_callback(void (*fn)(void));
    +void conf_set_message_callback(void (*fn)(const char *s));
    +
    +/* menu.c */
    +extern struct menu rootmenu;
    +
    +bool menu_is_empty(struct menu *menu);
    +bool menu_is_visible(struct menu *menu);
    +bool menu_has_prompt(struct menu *menu);
    +const char * menu_get_prompt(struct menu *menu);
    +struct menu * menu_get_root_menu(struct menu *menu);
    +struct menu * menu_get_parent_menu(struct menu *menu);
    +bool menu_has_help(struct menu *menu);
    +const char * menu_get_help(struct menu *menu);
    +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head 
*head);
    +void menu_get_ext_help(struct menu *menu, struct gstr *help);
    +
    +/* symbol.c */
    +extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
    +
    +struct symbol * sym_lookup(const char *name, int flags);
    +struct symbol * sym_find(const char *name);
    +const char * sym_escape_string_value(const char *in);
    +struct symbol ** sym_re_search(const char *pattern);
    +const char * sym_type_name(enum symbol_type type);
    +void sym_calc_value(struct symbol *sym);
    +enum symbol_type sym_get_type(struct symbol *sym);
    +bool sym_tristate_within_range(struct symbol *sym,tristate tri);
    +bool sym_set_tristate_value(struct symbol *sym,tristate tri);
    +tristate sym_toggle_tristate_value(struct symbol *sym);
    +bool sym_string_valid(struct symbol *sym, const char *newval);
    +bool sym_string_within_range(struct symbol *sym, const char *str);
    +bool sym_set_string_value(struct symbol *sym, const char *newval);
    +bool sym_is_changable(struct symbol *sym);
    +struct property * sym_get_choice_prop(struct symbol *sym);
    +const char * sym_get_string_value(struct symbol *sym);
    +
    +const char * prop_get_type_name(enum prop_type type);
    +
    +/* preprocess.c */
    +enum variable_flavor {
    +   VAR_SIMPLE,
    +   VAR_RECURSIVE,
    +   VAR_APPEND,
    +};
    +void env_write_dep(FILE *f, const char *auto_conf_name);
    +void variable_add(const char *name, const char *value,
    +             enum variable_flavor flavor);
    +void variable_all_del(void);
    +char *expand_string(const char *in);
    +char *expand_dollar(const char **str);
    +char *expand_one_token(const char **str);
    +
    +/* expr.c */
    +void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const 
char *), void *data, int prevtoken);
    diff --git a/support/kconfig.new/lxdialog/BIG.FAT.WARNING 
b/support/kconfig.new/lxdialog/BIG.FAT.WARNING
    new file mode 100644
    index 0000000..7cb5a7e
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/BIG.FAT.WARNING
    @@ -0,0 +1,4 @@
    +This is NOT the official version of dialog.  This version has been
    +significantly modified from the original.  It is for use by the Linux
    +kernel configuration script.  Please do not bother Savio Lam with
    +questions about this program.
    diff --git a/support/kconfig.new/lxdialog/checklist.c 
b/support/kconfig.new/lxdialog/checklist.c
    new file mode 100644
    index 0000000..fd161cf
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/checklist.c
    @@ -0,0 +1,319 @@
    +// SPDX-License-Identifier: GPL-2.0+
    +/*
    + *  checklist.c -- implements the checklist box
    + *
    + *  ORIGINAL AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + *     Stuart Herbert - S.Herbert@xxxxxxxxxxxxxxx: radiolist extension
    + *     Alessandro Rubini - rubini@xxxxxxxxxxxxxxx: merged the two
    + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@xxxxxxx)
    + */
    +
    +#include "dialog.h"
    +
    +static int list_width, check_x, item_x;
    +
    +/*
    + * Print list item
    + */
    +static void print_item(WINDOW * win, int choice, int selected)
    +{
    +   int i;
    +   char *list_item = malloc(list_width + 1);
    +
    +   strncpy(list_item, item_str(), list_width - item_x);
    +   list_item[list_width - item_x] = '\0';
    +
    +   /* Clear 'residue' of last item */
    +   wattrset(win, dlg.menubox.atr);
    +   wmove(win, choice, 0);
    +   for (i = 0; i < list_width; i++)
    +           waddch(win, ' ');
    +
    +   wmove(win, choice, check_x);
    +   wattrset(win, selected ? dlg.check_selected.atr
    +            : dlg.check.atr);
    +   if (!item_is_tag(':'))
    +           wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
    +
    +   wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
    +   mvwaddch(win, choice, item_x, list_item[0]);
    +   wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
    +   waddstr(win, list_item + 1);
    +   if (selected) {
    +           wmove(win, choice, check_x + 1);
    +           wrefresh(win);
    +   }
    +   free(list_item);
    +}
    +
    +/*
    + * Print the scroll indicators.
    + */
    +static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
    +        int y, int x, int height)
    +{
    +   wmove(win, y, x);
    +
    +   if (scroll > 0) {
    +           wattrset(win, dlg.uarrow.atr);
    +           waddch(win, ACS_UARROW);
    +           waddstr(win, "(-)");
    +   } else {
    +           wattrset(win, dlg.menubox.atr);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +   }
    +
    +   y = y + height + 1;
    +   wmove(win, y, x);
    +
    +   if ((height < item_no) && (scroll + choice < item_no - 1)) {
    +           wattrset(win, dlg.darrow.atr);
    +           waddch(win, ACS_DARROW);
    +           waddstr(win, "(+)");
    +   } else {
    +           wattrset(win, dlg.menubox_border.atr);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +   }
    +}
    +
    +/*
    + *  Display the termination buttons
    + */
    +static void print_buttons(WINDOW * dialog, int height, int width, int 
selected)
    +{
    +   int x = width / 2 - 11;
    +   int y = height - 2;
    +
    +   print_button(dialog, "Select", y, x, selected == 0);
    +   print_button(dialog, " Help ", y, x + 14, selected == 1);
    +
    +   wmove(dialog, y, x + 1 + 14 * selected);
    +   wrefresh(dialog);
    +}
    +
    +/*
    + * Display a dialog box with a list of options that can be turned on or off
    + * in the style of radiolist (only one option turned on at a time).
    + */
    +int dialog_checklist(const char *title, const char *prompt, int height,
    +                int width, int list_height)
    +{
    +   int i, x, y, box_x, box_y;
    +   int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
    +   WINDOW *dialog, *list;
    +
    +   /* which item to highlight */
    +   item_foreach() {
    +           if (item_is_tag('X'))
    +                   choice = item_n();
    +           if (item_is_selected()) {
    +                   choice = item_n();
    +                   break;
    +           }
    +   }
    +
    +do_resize:
    +   if (getmaxy(stdscr) < (height + CHECKLIST_HEIGTH_MIN))
    +           return -ERRDISPLAYTOOSMALL;
    +   if (getmaxx(stdscr) < (width + CHECKLIST_WIDTH_MIN))
    +           return -ERRDISPLAYTOOSMALL;
    +
    +   max_choice = MIN(list_height, item_count());
    +
    +   /* center dialog box on screen */
    +   x = (getmaxx(stdscr) - width) / 2;
    +   y = (getmaxy(stdscr) - height) / 2;
    +
    +   draw_shadow(stdscr, y, x, height, width);
    +
    +   dialog = newwin(height, width, y, x);
    +   keypad(dialog, TRUE);
    +
    +   draw_box(dialog, 0, 0, height, width,
    +            dlg.dialog.atr, dlg.border.atr);
    +   wattrset(dialog, dlg.border.atr);
    +   mvwaddch(dialog, height - 3, 0, ACS_LTEE);
    +   for (i = 0; i < width - 2; i++)
    +           waddch(dialog, ACS_HLINE);
    +   wattrset(dialog, dlg.dialog.atr);
    +   waddch(dialog, ACS_RTEE);
    +
    +   print_title(dialog, title, width);
    +
    +   wattrset(dialog, dlg.dialog.atr);
    +   print_autowrap(dialog, prompt, width - 2, 1, 3);
    +
    +   list_width = width - 6;
    +   box_y = height - list_height - 5;
    +   box_x = (width - list_width) / 2 - 1;
    +
    +   /* create new window for the list */
    +   list = subwin(dialog, list_height, list_width, y + box_y + 1,
    +                 x + box_x + 1);
    +
    +   keypad(list, TRUE);
    +
    +   /* draw a box around the list items */
    +   draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
    +            dlg.menubox_border.atr, dlg.menubox.atr);
    +
    +   /* Find length of longest item in order to center checklist */
    +   check_x = 0;
    +   item_foreach()
    +           check_x = MAX(check_x, strlen(item_str()) + 4);
    +   check_x = MIN(check_x, list_width);
    +
    +   check_x = (list_width - check_x) / 2;
    +   item_x = check_x + 4;
    +
    +   if (choice >= list_height) {
    +           scroll = choice - list_height + 1;
    +           choice -= scroll;
    +   }
    +
    +   /* Print the list */
    +   for (i = 0; i < max_choice; i++) {
    +           item_set(scroll + i);
    +           print_item(list, i, i == choice);
    +   }
    +
    +   print_arrows(dialog, choice, item_count(), scroll,
    +                box_y, box_x + check_x + 5, list_height);
    +
    +   print_buttons(dialog, height, width, 0);
    +
    +   wnoutrefresh(dialog);
    +   wnoutrefresh(list);
    +   doupdate();
    +
    +   while (key != KEY_ESC) {
    +           key = wgetch(dialog);
    +
    +           for (i = 0; i < max_choice; i++) {
    +                   item_set(i + scroll);
    +                   if (toupper(key) == toupper(item_str()[0]))
    +                           break;
    +           }
    +
    +           if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
    +               key == '+' || key == '-') {
    +                   if (key == KEY_UP || key == '-') {
    +                           if (!choice) {
    +                                   if (!scroll)
    +                                           continue;
    +                                   /* Scroll list down */
    +                                   if (list_height > 1) {
    +                                           /* De-highlight current first 
item */
    +                                           item_set(scroll);
    +                                           print_item(list, 0, FALSE);
    +                                           scrollok(list, TRUE);
    +                                           wscrl(list, -1);
    +                                           scrollok(list, FALSE);
    +                                   }
    +                                   scroll--;
    +                                   item_set(scroll);
    +                                   print_item(list, 0, TRUE);
    +                                   print_arrows(dialog, choice, 
item_count(),
    +                                                scroll, box_y, box_x + 
check_x + 5, list_height);
    +
    +                                   wnoutrefresh(dialog);
    +                                   wrefresh(list);
    +
    +                                   continue;       /* wait for another key 
press */
    +                           } else
    +                                   i = choice - 1;
    +                   } else if (key == KEY_DOWN || key == '+') {
    +                           if (choice == max_choice - 1) {
    +                                   if (scroll + choice >= item_count() - 1)
    +                                           continue;
    +                                   /* Scroll list up */
    +                                   if (list_height > 1) {
    +                                           /* De-highlight current last 
item before scrolling up */
    +                                           item_set(scroll + max_choice - 
1);
    +                                           print_item(list,
    +                                                       max_choice - 1,
    +                                                       FALSE);
    +                                           scrollok(list, TRUE);
    +                                           wscrl(list, 1);
    +                                           scrollok(list, FALSE);
    +                                   }
    +                                   scroll++;
    +                                   item_set(scroll + max_choice - 1);
    +                                   print_item(list, max_choice - 1, TRUE);
    +
    +                                   print_arrows(dialog, choice, 
item_count(),
    +                                                scroll, box_y, box_x + 
check_x + 5, list_height);
    +
    +                                   wnoutrefresh(dialog);
    +                                   wrefresh(list);
    +
    +                                   continue;       /* wait for another key 
press */
    +                           } else
    +                                   i = choice + 1;
    +                   }
    +                   if (i != choice) {
    +                           /* De-highlight current item */
    +                           item_set(scroll + choice);
    +                           print_item(list, choice, FALSE);
    +                           /* Highlight new item */
    +                           choice = i;
    +                           item_set(scroll + choice);
    +                           print_item(list, choice, TRUE);
    +                           wnoutrefresh(dialog);
    +                           wrefresh(list);
    +                   }
    +                   continue;       /* wait for another key press */
    +           }
    +           switch (key) {
    +           case 'H':
    +           case 'h':
    +           case '?':
    +                   button = 1;
    +                   /* fall-through */
    +           case 'S':
    +           case 's':
    +           case ' ':
    +           case '\n':
    +                   item_foreach()
    +                           item_set_selected(0);
    +                   item_set(scroll + choice);
    +                   item_set_selected(1);
    +                   delwin(list);
    +                   delwin(dialog);
    +                   return button;
    +           case TAB:
    +           case KEY_LEFT:
    +           case KEY_RIGHT:
    +                   button = ((key == KEY_LEFT ? --button : ++button) < 0)
    +                       ? 1 : (button > 1 ? 0 : button);
    +
    +                   print_buttons(dialog, height, width, button);
    +                   wrefresh(dialog);
    +                   break;
    +           case 'X':
    +           case 'x':
    +                   key = KEY_ESC;
    +                   break;
    +           case KEY_ESC:
    +                   key = on_key_esc(dialog);
    +                   break;
    +           case KEY_RESIZE:
    +                   delwin(list);
    +                   delwin(dialog);
    +                   on_key_resize();
    +                   goto do_resize;
    +           }
    +
    +           /* Now, update everything... */
    +           doupdate();
    +   }
    +   delwin(list);
    +   delwin(dialog);
    +   return key;             /* ESC pressed */
    +}
    diff --git a/support/kconfig.new/lxdialog/dialog.h 
b/support/kconfig.new/lxdialog/dialog.h
    new file mode 100644
    index 0000000..68b565e
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/dialog.h
    @@ -0,0 +1,238 @@
    +/* SPDX-License-Identifier: GPL-2.0+ */
    +/*
    + *  dialog.h -- common declarations for all dialog modules
    + *
    + *  AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + */
    +
    +#include <sys/types.h>
    +#include <fcntl.h>
    +#include <unistd.h>
    +#include <ctype.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <stdbool.h>
    +
    +#ifdef __sun__
    +#define CURS_MACROS
    +#endif
    +#include <ncurses.h>
    +
    +/*
    + * Colors in ncurses 1.9.9e do not work properly since foreground and
    + * background colors are OR'd rather than separately masked.  This version
    + * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
    + * with standard curses.  The simplest fix (to make this work with standard
    + * curses) uses the wbkgdset() function, not used in the original hack.
    + * Turn it off if we're building with 1.9.9e, since it just confuses 
things.
    + */
    +#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && 
!defined(GCC_PRINTFLIKE)
    +#define OLD_NCURSES 1
    +#undef  wbkgdset
    +#define wbkgdset(w,p)              /*nothing */
    +#else
    +#define OLD_NCURSES 0
    +#endif
    +
    +#define TR(params) _tracef params
    +
    +#define KEY_ESC 27
    +#define TAB 9
    +#define MAX_LEN 2048
    +#define BUF_SIZE (10*1024)
    +#define MIN(x,y) (x < y ? x : y)
    +#define MAX(x,y) (x > y ? x : y)
    +
    +#ifndef ACS_ULCORNER
    +#define ACS_ULCORNER '+'
    +#endif
    +#ifndef ACS_LLCORNER
    +#define ACS_LLCORNER '+'
    +#endif
    +#ifndef ACS_URCORNER
    +#define ACS_URCORNER '+'
    +#endif
    +#ifndef ACS_LRCORNER
    +#define ACS_LRCORNER '+'
    +#endif
    +#ifndef ACS_HLINE
    +#define ACS_HLINE '-'
    +#endif
    +#ifndef ACS_VLINE
    +#define ACS_VLINE '|'
    +#endif
    +#ifndef ACS_LTEE
    +#define ACS_LTEE '+'
    +#endif
    +#ifndef ACS_RTEE
    +#define ACS_RTEE '+'
    +#endif
    +#ifndef ACS_UARROW
    +#define ACS_UARROW '^'
    +#endif
    +#ifndef ACS_DARROW
    +#define ACS_DARROW 'v'
    +#endif
    +
    +/* error return codes */
    +#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
    +
    +/*
    + *   Color definitions
    + */
    +struct dialog_color {
    +   chtype atr;     /* Color attribute */
    +   int fg;         /* foreground */
    +   int bg;         /* background */
    +   int hl;         /* highlight this item */
    +};
    +
    +struct subtitle_list {
    +   struct subtitle_list *next;
    +   const char *text;
    +};
    +
    +struct dialog_info {
    +   const char *backtitle;
    +   struct subtitle_list *subtitles;
    +   struct dialog_color screen;
    +   struct dialog_color shadow;
    +   struct dialog_color dialog;
    +   struct dialog_color title;
    +   struct dialog_color border;
    +   struct dialog_color button_active;
    +   struct dialog_color button_inactive;
    +   struct dialog_color button_key_active;
    +   struct dialog_color button_key_inactive;
    +   struct dialog_color button_label_active;
    +   struct dialog_color button_label_inactive;
    +   struct dialog_color inputbox;
    +   struct dialog_color inputbox_border;
    +   struct dialog_color searchbox;
    +   struct dialog_color searchbox_title;
    +   struct dialog_color searchbox_border;
    +   struct dialog_color position_indicator;
    +   struct dialog_color menubox;
    +   struct dialog_color menubox_border;
    +   struct dialog_color item;
    +   struct dialog_color item_selected;
    +   struct dialog_color tag;
    +   struct dialog_color tag_selected;
    +   struct dialog_color tag_key;
    +   struct dialog_color tag_key_selected;
    +   struct dialog_color check;
    +   struct dialog_color check_selected;
    +   struct dialog_color uarrow;
    +   struct dialog_color darrow;
    +};
    +
    +/*
    + * Global variables
    + */
    +extern struct dialog_info dlg;
    +extern char dialog_input_result[];
    +extern int saved_x, saved_y;               /* Needed in signal handler in 
mconf.c */
    +
    +/*
    + * Function prototypes
    + */
    +
    +/* item list as used by checklist and menubox */
    +void item_reset(void);
    +void item_make(const char *fmt, ...);
    +void item_add_str(const char *fmt, ...);
    +void item_set_tag(char tag);
    +void item_set_data(void *p);
    +void item_set_selected(int val);
    +int item_activate_selected(void);
    +void *item_data(void);
    +char item_tag(void);
    +
    +/* item list manipulation for lxdialog use */
    +#define MAXITEMSTR 200
    +struct dialog_item {
    +   char str[MAXITEMSTR];   /* prompt displayed */
    +   char tag;
    +   void *data;     /* pointer to menu item - used by menubox+checklist */
    +   int selected;   /* Set to 1 by dialog_*() function if selected. */
    +};
    +
    +/* list of lialog_items */
    +struct dialog_list {
    +   struct dialog_item node;
    +   struct dialog_list *next;
    +};
    +
    +extern struct dialog_list *item_cur;
    +extern struct dialog_list item_nil;
    +extern struct dialog_list *item_head;
    +
    +int item_count(void);
    +void item_set(int n);
    +int item_n(void);
    +const char *item_str(void);
    +int item_is_selected(void);
    +int item_is_tag(char tag);
    +#define item_foreach() \
    +   for (item_cur = item_head ? item_head: item_cur; \
    +        item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
    +
    +/* generic key handlers */
    +int on_key_esc(WINDOW *win);
    +int on_key_resize(void);
    +
    +/* minimum (re)size values */
    +#define CHECKLIST_HEIGTH_MIN 6     /* For dialog_checklist() */
    +#define CHECKLIST_WIDTH_MIN 6
    +#define INPUTBOX_HEIGTH_MIN 2      /* For dialog_inputbox() */
    +#define INPUTBOX_WIDTH_MIN 2
    +#define MENUBOX_HEIGTH_MIN 15      /* For dialog_menu() */
    +#define MENUBOX_WIDTH_MIN 65
    +#define TEXTBOX_HEIGTH_MIN 8       /* For dialog_textbox() */
    +#define TEXTBOX_WIDTH_MIN 8
    +#define YESNO_HEIGTH_MIN 4 /* For dialog_yesno() */
    +#define YESNO_WIDTH_MIN 4
    +#define WINDOW_HEIGTH_MIN 19       /* For init_dialog() */
    +#define WINDOW_WIDTH_MIN 80
    +
    +int init_dialog(const char *backtitle);
    +void set_dialog_backtitle(const char *backtitle);
    +void set_dialog_subtitles(struct subtitle_list *subtitles);
    +void end_dialog(int x, int y);
    +void attr_clear(WINDOW * win, int height, int width, chtype attr);
    +void dialog_clear(void);
    +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, 
int x);
    +void print_button(WINDOW * win, const char *label, int y, int x, int 
selected);
    +void print_title(WINDOW *dialog, const char *title, int width);
    +void draw_box(WINDOW * win, int y, int x, int height, int width, chtype 
box,
    +         chtype border);
    +void draw_shadow(WINDOW * win, int y, int x, int height, int width);
    +
    +int first_alpha(const char *string, const char *exempt);
    +int dialog_yesno(const char *title, const char *prompt, int height, int 
width);
    +int dialog_msgbox(const char *title, const char *prompt, int height,
    +             int width, int pause);
    +
    +
    +typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
    +                          *_data);
    +int dialog_textbox(const char *title, char *tbuf, int initial_height,
    +              int initial_width, int *keys, int *_vscroll, int *_hscroll,
    +              update_text_fn update_text, void *data);
    +int dialog_menu(const char *title, const char *prompt,
    +           const void *selected, int *s_scroll);
    +int dialog_checklist(const char *title, const char *prompt, int height,
    +                int width, int list_height);
    +int dialog_inputbox(const char *title, const char *prompt, int height,
    +               int width, const char *init);
    +
    +/*
    + * This is the base for fictitious keys, which activate
    + * the buttons.
    + *
    + * Mouse-generated keys are the following:
    + *   -- the first 32 are used as numbers, in addition to '0'-'9'
    + *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
    + *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
    + */
    +#define M_EVENT (KEY_MAX+1)
    diff --git a/support/kconfig.new/lxdialog/inputbox.c 
b/support/kconfig.new/lxdialog/inputbox.c
    new file mode 100644
    index 0000000..1dcfb28
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/inputbox.c
    @@ -0,0 +1,289 @@
    +// SPDX-License-Identifier: GPL-2.0+
    +/*
    + *  inputbox.c -- implements the input box
    + *
    + *  ORIGINAL AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@xxxxxxx)
    + */
    +
    +#include "dialog.h"
    +
    +char dialog_input_result[MAX_LEN + 1];
    +
    +/*
    + *  Print the termination buttons
    + */
    +static void print_buttons(WINDOW * dialog, int height, int width, int 
selected)
    +{
    +   int x = width / 2 - 11;
    +   int y = height - 2;
    +
    +   print_button(dialog, "  Ok  ", y, x, selected == 0);
    +   print_button(dialog, " Help ", y, x + 14, selected == 1);
    +
    +   wmove(dialog, y, x + 1 + 14 * selected);
    +   wrefresh(dialog);
    +}
    +
    +/*
    + * Display a dialog box for inputing a string
    + */
    +int dialog_inputbox(const char *title, const char *prompt, int height, int 
width,
    +               const char *init)
    +{
    +   int i, x, y, box_y, box_x, box_width;
    +   int input_x = 0, key = 0, button = -1;
    +   int show_x, len, pos;
    +   char *instr = dialog_input_result;
    +   WINDOW *dialog;
    +
    +   if (!init)
    +           instr[0] = '\0';
    +   else
    +           strcpy(instr, init);
    +
    +do_resize:
    +   if (getmaxy(stdscr) <= (height - INPUTBOX_HEIGTH_MIN))
    +           return -ERRDISPLAYTOOSMALL;
    +   if (getmaxx(stdscr) <= (width - INPUTBOX_WIDTH_MIN))
    +           return -ERRDISPLAYTOOSMALL;
    +
    +   /* center dialog box on screen */
    +   x = (getmaxx(stdscr) - width) / 2;
    +   y = (getmaxy(stdscr) - height) / 2;
    +
    +   draw_shadow(stdscr, y, x, height, width);
    +
    +   dialog = newwin(height, width, y, x);
    +   keypad(dialog, TRUE);
    +
    +   draw_box(dialog, 0, 0, height, width,
    +            dlg.dialog.atr, dlg.border.atr);
    +   wattrset(dialog, dlg.border.atr);
    +   mvwaddch(dialog, height - 3, 0, ACS_LTEE);
    +   for (i = 0; i < width - 2; i++)
    +           waddch(dialog, ACS_HLINE);
    +   wattrset(dialog, dlg.dialog.atr);
    +   waddch(dialog, ACS_RTEE);
    +
    +   print_title(dialog, title, width);
    +
    +   wattrset(dialog, dlg.dialog.atr);
    +   print_autowrap(dialog, prompt, width - 2, 1, 3);
    +
    +   /* Draw the input field box */
    +   box_width = width - 6;
    +   getyx(dialog, y, x);
    +   box_y = y + 2;
    +   box_x = (width - box_width) / 2;
    +   draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
    +            dlg.dialog.atr, dlg.border.atr);
    +
    +   print_buttons(dialog, height, width, 0);
    +
    +   /* Set up the initial value */
    +   wmove(dialog, box_y, box_x);
    +   wattrset(dialog, dlg.inputbox.atr);
    +
    +   len = strlen(instr);
    +   pos = len;
    +
    +   if (len >= box_width) {
    +           show_x = len - box_width + 1;
    +           input_x = box_width - 1;
    +           for (i = 0; i < box_width - 1; i++)
    +                   waddch(dialog, instr[show_x + i]);
    +   } else {
    +           show_x = 0;
    +           input_x = len;
    +           waddstr(dialog, instr);
    +   }
    +
    +   wmove(dialog, box_y, box_x + input_x);
    +
    +   wrefresh(dialog);
    +
    +   while (key != KEY_ESC) {
    +           key = wgetch(dialog);
    +
    +           if (button == -1) {     /* Input box selected */
    +                   switch (key) {
    +                   case TAB:
    +                   case KEY_UP:
    +                   case KEY_DOWN:
    +                           break;
    +                   case KEY_BACKSPACE:
    +                   case 8:   /* ^H */
    +                   case 127: /* ^? */
    +                           if (pos) {
    +                                   wattrset(dialog, dlg.inputbox.atr);
    +                                   if (input_x == 0) {
    +                                           show_x--;
    +                                   } else
    +                                           input_x--;
    +
    +                                   if (pos < len) {
    +                                           for (i = pos - 1; i < len; i++) 
{
    +                                                   instr[i] = instr[i+1];
    +                                           }
    +                                   }
    +
    +                                   pos--;
    +                                   len--;
    +                                   instr[len] = '\0';
    +                                   wmove(dialog, box_y, box_x);
    +                                   for (i = 0; i < box_width; i++) {
    +                                           if (!instr[show_x + i]) {
    +                                                   waddch(dialog, ' ');
    +                                                   break;
    +                                           }
    +                                           waddch(dialog, instr[show_x + 
i]);
    +                                   }
    +                                   wmove(dialog, box_y, input_x + box_x);
    +                                   wrefresh(dialog);
    +                           }
    +                           continue;
    +                   case KEY_LEFT:
    +                           if (pos > 0) {
    +                                   if (input_x > 0) {
    +                                           wmove(dialog, box_y, --input_x 
+ box_x);
    +                                   } else if (input_x == 0) {
    +                                           show_x--;
    +                                           wmove(dialog, box_y, box_x);
    +                                           for (i = 0; i < box_width; i++) 
{
    +                                                   if (!instr[show_x + i]) 
{
    +                                                           waddch(dialog, 
' ');
    +                                                           break;
    +                                                   }
    +                                                   waddch(dialog, 
instr[show_x + i]);
    +                                           }
    +                                           wmove(dialog, box_y, box_x);
    +                                   }
    +                                   pos--;
    +                           }
    +                           continue;
    +                   case KEY_RIGHT:
    +                           if (pos < len) {
    +                                   if (input_x < box_width - 1) {
    +                                           wmove(dialog, box_y, ++input_x 
+ box_x);
    +                                   } else if (input_x == box_width - 1) {
    +                                           show_x++;
    +                                           wmove(dialog, box_y, box_x);
    +                                           for (i = 0; i < box_width; i++) 
{
    +                                                   if (!instr[show_x + i]) 
{
    +                                                           waddch(dialog, 
' ');
    +                                                           break;
    +                                                   }
    +                                                   waddch(dialog, 
instr[show_x + i]);
    +                                           }
    +                                           wmove(dialog, box_y, input_x + 
box_x);
    +                                   }
    +                                   pos++;
    +                           }
    +                           continue;
    +                   default:
    +                           if (key < 0x100 && isprint(key)) {
    +                                   if (len < MAX_LEN) {
    +                                           wattrset(dialog, 
dlg.inputbox.atr);
    +                                           if (pos < len) {
    +                                                   for (i = len; i > pos; 
i--)
    +                                                           instr[i] = 
instr[i-1];
    +                                                   instr[pos] = key;
    +                                           } else {
    +                                                   instr[len] = key;
    +                                           }
    +                                           pos++;
    +                                           len++;
    +                                           instr[len] = '\0';
    +
    +                                           if (input_x == box_width - 1) {
    +                                                   show_x++;
    +                                           } else {
    +                                                   input_x++;
    +                                           }
    +
    +                                           wmove(dialog, box_y, box_x);
    +                                           for (i = 0; i < box_width; i++) 
{
    +                                                   if (!instr[show_x + i]) 
{
    +                                                           waddch(dialog, 
' ');
    +                                                           break;
    +                                                   }
    +                                                   waddch(dialog, 
instr[show_x + i]);
    +                                           }
    +                                           wmove(dialog, box_y, input_x + 
box_x);
    +                                           wrefresh(dialog);
    +                                   } else
    +                                           flash();        /* Alarm user 
about overflow */
    +                                   continue;
    +                           }
    +                   }
    +           }
    +           switch (key) {
    +           case 'O':
    +           case 'o':
    +                   delwin(dialog);
    +                   return 0;
    +           case 'H':
    +           case 'h':
    +                   delwin(dialog);
    +                   return 1;
    +           case KEY_UP:
    +           case KEY_LEFT:
    +                   switch (button) {
    +                   case -1:
    +                           button = 1;     /* Indicates "Help" button is 
selected */
    +                           print_buttons(dialog, height, width, 1);
    +                           break;
    +                   case 0:
    +                           button = -1;    /* Indicates input box is 
selected */
    +                           print_buttons(dialog, height, width, 0);
    +                           wmove(dialog, box_y, box_x + input_x);
    +                           wrefresh(dialog);
    +                           break;
    +                   case 1:
    +                           button = 0;     /* Indicates "OK" button is 
selected */
    +                           print_buttons(dialog, height, width, 0);
    +                           break;
    +                   }
    +                   break;
    +           case TAB:
    +           case KEY_DOWN:
    +           case KEY_RIGHT:
    +                   switch (button) {
    +                   case -1:
    +                           button = 0;     /* Indicates "OK" button is 
selected */
    +                           print_buttons(dialog, height, width, 0);
    +                           break;
    +                   case 0:
    +                           button = 1;     /* Indicates "Help" button is 
selected */
    +                           print_buttons(dialog, height, width, 1);
    +                           break;
    +                   case 1:
    +                           button = -1;    /* Indicates input box is 
selected */
    +                           print_buttons(dialog, height, width, 0);
    +                           wmove(dialog, box_y, box_x + input_x);
    +                           wrefresh(dialog);
    +                           break;
    +                   }
    +                   break;
    +           case ' ':
    +           case '\n':
    +                   delwin(dialog);
    +                   return (button == -1 ? 0 : button);
    +           case 'X':
    +           case 'x':
    +                   key = KEY_ESC;
    +                   break;
    +           case KEY_ESC:
    +                   key = on_key_esc(dialog);
    +                   break;
    +           case KEY_RESIZE:
    +                   delwin(dialog);
    +                   on_key_resize();
    +                   goto do_resize;
    +           }
    +   }
    +
    +   delwin(dialog);
    +   return KEY_ESC;         /* ESC pressed */
    +}
    diff --git a/support/kconfig.new/lxdialog/menubox.c 
b/support/kconfig.new/lxdialog/menubox.c
    new file mode 100644
    index 0000000..58c2f8a
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/menubox.c
    @@ -0,0 +1,424 @@
    +// SPDX-License-Identifier: GPL-2.0+
    +/*
    + *  menubox.c -- implements the menu box
    + *
    + *  ORIGINAL AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@xxxxxxx)
    + */
    +
    +/*
    + *  Changes by Clifford Wolf (god@xxxxxxxxxxx)
    + *
    + *  [ 1998-06-13 ]
    + *
    + *    *)  A bugfix for the Page-Down problem
    + *
    + *    *)  Formerly when I used Page Down and Page Up, the cursor would be 
set
    + *        to the first position in the menu box.  Now lxdialog is a bit
    + *        smarter and works more like other menu systems (just have a look 
at
    + *        it).
    + *
    + *    *)  Formerly if I selected something my scrolling would be broken 
because
    + *        lxdialog is re-invoked by the Menuconfig shell script, can't
    + *        remember the last scrolling position, and just sets it so that 
the
    + *        cursor is at the bottom of the box.  Now it writes the temporary 
file
    + *        lxdialog.scrltmp which contains this information. The file is
    + *        deleted by lxdialog if the user leaves a submenu or enters a new
    + *        one, but it would be nice if Menuconfig could make another "rm 
-f"
    + *        just to be sure.  Just try it out - you will recognise a 
difference!
    + *
    + *  [ 1998-06-14 ]
    + *
    + *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" 
files
    + *        and menus change their size on the fly.
    + *
    + *    *)  If for some reason the last scrolling position is not saved by
    + *        lxdialog, it sets the scrolling so that the selected item is in 
the
    + *        middle of the menu box, not at the bottom.
    + *
    + * 02 January 1999, Michael Elizabeth Chastain (mec@xxxxxxxxx)
    + * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
    + * This fixes a bug in Menuconfig where using ' ' to descend into menus
    + * would leave mis-synchronized lxdialog.scrltmp files lying around,
    + * fscanf would read in 'scroll', and eventually that value would get used.
    + */
    +
    +#include "dialog.h"
    +
    +static int menu_width, item_x;
    +
    +/*
    + * Print menu item
    + */
    +static void do_print_item(WINDOW * win, const char *item, int line_y,
    +                     int selected, int hotkey)
    +{
    +   int j;
    +   char *menu_item = malloc(menu_width + 1);
    +
    +   strncpy(menu_item, item, menu_width - item_x);
    +   menu_item[menu_width - item_x] = '\0';
    +   j = first_alpha(menu_item, "YyNnMmHh");
    +
    +   /* Clear 'residue' of last item */
    +   wattrset(win, dlg.menubox.atr);
    +   wmove(win, line_y, 0);
    +#if OLD_NCURSES
    +   {
    +           int i;
    +           for (i = 0; i < menu_width; i++)
    +                   waddch(win, ' ');
    +   }
    +#else
    +   wclrtoeol(win);
    +#endif
    +   wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
    +   mvwaddstr(win, line_y, item_x, menu_item);
    +   if (hotkey) {
    +           wattrset(win, selected ? dlg.tag_key_selected.atr
    +                    : dlg.tag_key.atr);
    +           mvwaddch(win, line_y, item_x + j, menu_item[j]);
    +   }
    +   if (selected) {
    +           wmove(win, line_y, item_x + 1);
    +   }
    +   free(menu_item);
    +   wrefresh(win);
    +}
    +
    +#define print_item(index, choice, selected)                                
\
    +do {                                                                       
\
    +   item_set(index);                                                \
    +   do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
    +} while (0)
    +
    +/*
    + * Print the scroll indicators.
    + */
    +static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int 
x,
    +                    int height)
    +{
    +   int cur_y, cur_x;
    +
    +   getyx(win, cur_y, cur_x);
    +
    +   wmove(win, y, x);
    +
    +   if (scroll > 0) {
    +           wattrset(win, dlg.uarrow.atr);
    +           waddch(win, ACS_UARROW);
    +           waddstr(win, "(-)");
    +   } else {
    +           wattrset(win, dlg.menubox.atr);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +   }
    +
    +   y = y + height + 1;
    +   wmove(win, y, x);
    +   wrefresh(win);
    +
    +   if ((height < item_no) && (scroll + height < item_no)) {
    +           wattrset(win, dlg.darrow.atr);
    +           waddch(win, ACS_DARROW);
    +           waddstr(win, "(+)");
    +   } else {
    +           wattrset(win, dlg.menubox_border.atr);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +           waddch(win, ACS_HLINE);
    +   }
    +
    +   wmove(win, cur_y, cur_x);
    +   wrefresh(win);
    +}
    +
    +/*
    + * Display the termination buttons.
    + */
    +static void print_buttons(WINDOW * win, int height, int width, int 
selected)
    +{
    +   int x = width / 2 - 28;
    +   int y = height - 2;
    +
    +   print_button(win, "Select", y, x, selected == 0);
    +   print_button(win, " Exit ", y, x + 12, selected == 1);
    +   print_button(win, " Help ", y, x + 24, selected == 2);
    +   print_button(win, " Save ", y, x + 36, selected == 3);
    +   print_button(win, " Load ", y, x + 48, selected == 4);
    +
    +   wmove(win, y, x + 1 + 12 * selected);
    +   wrefresh(win);
    +}
    +
    +/* scroll up n lines (n may be negative) */
    +static void do_scroll(WINDOW *win, int *scroll, int n)
    +{
    +   /* Scroll menu up */
    +   scrollok(win, TRUE);
    +   wscrl(win, n);
    +   scrollok(win, FALSE);
    +   *scroll = *scroll + n;
    +   wrefresh(win);
    +}
    +
    +/*
    + * Display a menu for choosing among a number of options
    + */
    +int dialog_menu(const char *title, const char *prompt,
    +           const void *selected, int *s_scroll)
    +{
    +   int i, j, x, y, box_x, box_y;
    +   int height, width, menu_height;
    +   int key = 0, button = 0, scroll = 0, choice = 0;
    +   int first_item =  0, max_choice;
    +   WINDOW *dialog, *menu;
    +
    +do_resize:
    +   height = getmaxy(stdscr);
    +   width = getmaxx(stdscr);
    +   if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
    +           return -ERRDISPLAYTOOSMALL;
    +
    +   height -= 4;
    +   width  -= 5;
    +   menu_height = height - 10;
    +
    +   max_choice = MIN(menu_height, item_count());
    +
    +   /* center dialog box on screen */
    +   x = (getmaxx(stdscr) - width) / 2;
    +   y = (getmaxy(stdscr) - height) / 2;
    +
    +   draw_shadow(stdscr, y, x, height, width);
    +
    +   dialog = newwin(height, width, y, x);
    +   keypad(dialog, TRUE);
    +
    +   draw_box(dialog, 0, 0, height, width,
    +            dlg.dialog.atr, dlg.border.atr);
    +   wattrset(dialog, dlg.border.atr);
    +   mvwaddch(dialog, height - 3, 0, ACS_LTEE);
    +   for (i = 0; i < width - 2; i++)
    +           waddch(dialog, ACS_HLINE);
    +   wattrset(dialog, dlg.dialog.atr);
    +   wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
    +   waddch(dialog, ACS_RTEE);
    +
    +   print_title(dialog, title, width);
    +
    +   wattrset(dialog, dlg.dialog.atr);
    +   print_autowrap(dialog, prompt, width - 2, 1, 3);
    +
    +   menu_width = width - 6;
    +   box_y = height - menu_height - 5;
    +   box_x = (width - menu_width) / 2 - 1;
    +
    +   /* create new window for the menu */
    +   menu = subwin(dialog, menu_height, menu_width,
    +                 y + box_y + 1, x + box_x + 1);
    +   keypad(menu, TRUE);
    +
    +   /* draw a box around the menu items */
    +   draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
    +            dlg.menubox_border.atr, dlg.menubox.atr);
    +
    +   if (menu_width >= 80)
    +           item_x = (menu_width - 70) / 2;
    +   else
    +           item_x = 4;
    +
    +   /* Set choice to default item */
    +   item_foreach()
    +           if (selected && (selected == item_data()))
    +                   choice = item_n();
    +   /* get the saved scroll info */
    +   scroll = *s_scroll;
    +   if ((scroll <= choice) && (scroll + max_choice > choice) &&
    +      (scroll >= 0) && (scroll + max_choice <= item_count())) {
    +           first_item = scroll;
    +           choice = choice - scroll;
    +   } else {
    +           scroll = 0;
    +   }
    +   if ((choice >= max_choice)) {
    +           if (choice >= item_count() - max_choice / 2)
    +                   scroll = first_item = item_count() - max_choice;
    +           else
    +                   scroll = first_item = choice - max_choice / 2;
    +           choice = choice - scroll;
    +   }
    +
    +   /* Print the menu */
    +   for (i = 0; i < max_choice; i++) {
    +           print_item(first_item + i, i, i == choice);
    +   }
    +
    +   wnoutrefresh(menu);
    +
    +   print_arrows(dialog, item_count(), scroll,
    +                box_y, box_x + item_x + 1, menu_height);
    +
    +   print_buttons(dialog, height, width, 0);
    +   wmove(menu, choice, item_x + 1);
    +   wrefresh(menu);
    +
    +   while (key != KEY_ESC) {
    +           key = wgetch(menu);
    +
    +           if (key < 256 && isalpha(key))
    +                   key = tolower(key);
    +
    +           if (strchr("ynmh", key))
    +                   i = max_choice;
    +           else {
    +                   for (i = choice + 1; i < max_choice; i++) {
    +                           item_set(scroll + i);
    +                           j = first_alpha(item_str(), "YyNnMmHh");
    +                           if (key == tolower(item_str()[j]))
    +                                   break;
    +                   }
    +                   if (i == max_choice)
    +                           for (i = 0; i < max_choice; i++) {
    +                                   item_set(scroll + i);
    +                                   j = first_alpha(item_str(), "YyNnMmHh");
    +                                   if (key == tolower(item_str()[j]))
    +                                           break;
    +                           }
    +           }
    +
    +           if (item_count() != 0 &&
    +               (i < max_choice ||
    +                key == KEY_UP || key == KEY_DOWN ||
    +                key == '-' || key == '+' ||
    +                key == KEY_PPAGE || key == KEY_NPAGE)) {
    +                   /* Remove highligt of current item */
    +                   print_item(scroll + choice, choice, FALSE);
    +
    +                   if (key == KEY_UP || key == '-') {
    +                           if (choice < 2 && scroll) {
    +                                   /* Scroll menu down */
    +                                   do_scroll(menu, &scroll, -1);
    +
    +                                   print_item(scroll, 0, FALSE);
    +                           } else
    +                                   choice = MAX(choice - 1, 0);
    +
    +                   } else if (key == KEY_DOWN || key == '+') {
    +                           print_item(scroll+choice, choice, FALSE);
    +
    +                           if ((choice > max_choice - 3) &&
    +                               (scroll + max_choice < item_count())) {
    +                                   /* Scroll menu up */
    +                                   do_scroll(menu, &scroll, 1);
    +
    +                                   print_item(scroll+max_choice - 1,
    +                                              max_choice - 1, FALSE);
    +                           } else
    +                                   choice = MIN(choice + 1, max_choice - 
1);
    +
    +                   } else if (key == KEY_PPAGE) {
    +                           scrollok(menu, TRUE);
    +                           for (i = 0; (i < max_choice); i++) {
    +                                   if (scroll > 0) {
    +                                           do_scroll(menu, &scroll, -1);
    +                                           print_item(scroll, 0, FALSE);
    +                                   } else {
    +                                           if (choice > 0)
    +                                                   choice--;
    +                                   }
    +                           }
    +
    +                   } else if (key == KEY_NPAGE) {
    +                           for (i = 0; (i < max_choice); i++) {
    +                                   if (scroll + max_choice < item_count()) 
{
    +                                           do_scroll(menu, &scroll, 1);
    +                                           print_item(scroll+max_choice-1,
    +                                                      max_choice - 1, 
FALSE);
    +                                   } else {
    +                                           if (choice + 1 < max_choice)
    +                                                   choice++;
    +                                   }
    +                           }
    +                   } else
    +                           choice = i;
    +
    +                   print_item(scroll + choice, choice, TRUE);
    +
    +                   print_arrows(dialog, item_count(), scroll,
    +                                box_y, box_x + item_x + 1, menu_height);
    +
    +                   wnoutrefresh(dialog);
    +                   wrefresh(menu);
    +
    +                   continue;       /* wait for another key press */
    +           }
    +
    +           switch (key) {
    +           case KEY_LEFT:
    +           case TAB:
    +           case KEY_RIGHT:
    +                   button = ((key == KEY_LEFT ? --button : ++button) < 0)
    +                       ? 4 : (button > 4 ? 0 : button);
    +
    +                   print_buttons(dialog, height, width, button);
    +                   wrefresh(menu);
    +                   break;
    +           case ' ':
    +           case 's':
    +           case 'y':
    +           case 'n':
    +           case 'm':
    +           case '/':
    +           case 'h':
    +           case '?':
    +           case 'z':
    +           case '\n':
    +                   /* save scroll info */
    +                   *s_scroll = scroll;
    +                   delwin(menu);
    +                   delwin(dialog);
    +                   item_set(scroll + choice);
    +                   item_set_selected(1);
    +                   switch (key) {
    +                   case 'h':
    +                   case '?':
    +                           return 2;
    +                   case 's':
    +                   case 'y':
    +                           return 5;
    +                   case 'n':
    +                           return 6;
    +                   case 'm':
    +                           return 7;
    +                   case ' ':
    +                           return 8;
    +                   case '/':
    +                           return 9;
    +                   case 'z':
    +                           return 10;
    +                   case '\n':
    +                           return button;
    +                   }
    +                   return 0;
    +           case 'e':
    +           case 'x':
    +                   key = KEY_ESC;
    +                   break;
    +           case KEY_ESC:
    +                   key = on_key_esc(menu);
    +                   break;
    +           case KEY_RESIZE:
    +                   on_key_resize();
    +                   delwin(menu);
    +                   delwin(dialog);
    +                   goto do_resize;
    +           }
    +   }
    +   delwin(menu);
    +   delwin(dialog);
    +   return key;             /* ESC pressed */
    +}
    diff --git a/support/kconfig.new/lxdialog/textbox.c 
b/support/kconfig.new/lxdialog/textbox.c
    new file mode 100644
    index 0000000..4e339b1
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/textbox.c
    @@ -0,0 +1,395 @@
    +// SPDX-License-Identifier: GPL-2.0+
    +/*
    + *  textbox.c -- implements the text box
    + *
    + *  ORIGINAL AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@xxxxxxx)
    + */
    +
    +#include "dialog.h"
    +
    +static void back_lines(int n);
    +static void print_page(WINDOW *win, int height, int width, update_text_fn
    +                  update_text, void *data);
    +static void print_line(WINDOW *win, int row, int width);
    +static char *get_line(void);
    +static void print_position(WINDOW * win);
    +
    +static int hscroll;
    +static int begin_reached, end_reached, page_length;
    +static char *buf;
    +static char *page;
    +
    +/*
    + * refresh window content
    + */
    +static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int 
boxw,
    +                        int cur_y, int cur_x, update_text_fn update_text,
    +                        void *data)
    +{
    +   print_page(box, boxh, boxw, update_text, data);
    +   print_position(dialog);
    +   wmove(dialog, cur_y, cur_x);    /* Restore cursor position */
    +   wrefresh(dialog);
    +}
    +
    +
    +/*
    + * Display text from a file in a dialog box.
    + *
    + * keys is a null-terminated array
    + * update_text() may not add or remove any '\n' or '\0' in tbuf
    + */
    +int dialog_textbox(const char *title, char *tbuf, int initial_height,
    +              int initial_width, int *keys, int *_vscroll, int *_hscroll,
    +              update_text_fn update_text, void *data)
    +{
    +   int i, x, y, cur_x, cur_y, key = 0;
    +   int height, width, boxh, boxw;
    +   WINDOW *dialog, *box;
    +   bool done = false;
    +
    +   begin_reached = 1;
    +   end_reached = 0;
    +   page_length = 0;
    +   hscroll = 0;
    +   buf = tbuf;
    +   page = buf;     /* page is pointer to start of page to be displayed */
    +
    +   if (_vscroll && *_vscroll) {
    +           begin_reached = 0;
    +
    +           for (i = 0; i < *_vscroll; i++)
    +                   get_line();
    +   }
    +   if (_hscroll)
    +           hscroll = *_hscroll;
    +
    +do_resize:
    +   getmaxyx(stdscr, height, width);
    +   if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
    +           return -ERRDISPLAYTOOSMALL;
    +   if (initial_height != 0)
    +           height = initial_height;
    +   else
    +           if (height > 4)
    +                   height -= 4;
    +           else
    +                   height = 0;
    +   if (initial_width != 0)
    +           width = initial_width;
    +   else
    +           if (width > 5)
    +                   width -= 5;
    +           else
    +                   width = 0;
    +
    +   /* center dialog box on screen */
    +   x = (getmaxx(stdscr) - width) / 2;
    +   y = (getmaxy(stdscr) - height) / 2;
    +
    +   draw_shadow(stdscr, y, x, height, width);
    +
    +   dialog = newwin(height, width, y, x);
    +   keypad(dialog, TRUE);
    +
    +   /* Create window for box region, used for scrolling text */
    +   boxh = height - 4;
    +   boxw = width - 2;
    +   box = subwin(dialog, boxh, boxw, y + 1, x + 1);
    +   wattrset(box, dlg.dialog.atr);
    +   wbkgdset(box, dlg.dialog.atr & A_COLOR);
    +
    +   keypad(box, TRUE);
    +
    +   /* register the new window, along with its borders */
    +   draw_box(dialog, 0, 0, height, width,
    +            dlg.dialog.atr, dlg.border.atr);
    +
    +   wattrset(dialog, dlg.border.atr);
    +   mvwaddch(dialog, height - 3, 0, ACS_LTEE);
    +   for (i = 0; i < width - 2; i++)
    +           waddch(dialog, ACS_HLINE);
    +   wattrset(dialog, dlg.dialog.atr);
    +   wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
    +   waddch(dialog, ACS_RTEE);
    +
    +   print_title(dialog, title, width);
    +
    +   print_button(dialog, " Exit ", height - 2, width / 2 - 4, TRUE);
    +   wnoutrefresh(dialog);
    +   getyx(dialog, cur_y, cur_x);    /* Save cursor position */
    +
    +   /* Print first page of text */
    +   attr_clear(box, boxh, boxw, dlg.dialog.atr);
    +   refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
    +                    data);
    +
    +   while (!done) {
    +           key = wgetch(dialog);
    +           switch (key) {
    +           case 'E':       /* Exit */
    +           case 'e':
    +           case 'X':
    +           case 'x':
    +           case 'q':
    +           case '\n':
    +                   done = true;
    +                   break;
    +           case 'g':       /* First page */
    +           case KEY_HOME:
    +                   if (!begin_reached) {
    +                           begin_reached = 1;
    +                           page = buf;
    +                           refresh_text_box(dialog, box, boxh, boxw,
    +                                            cur_y, cur_x, update_text,
    +                                            data);
    +                   }
    +                   break;
    +           case 'G':       /* Last page */
    +           case KEY_END:
    +
    +                   end_reached = 1;
    +                   /* point to last char in buf */
    +                   page = buf + strlen(buf);
    +                   back_lines(boxh);
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case 'K':       /* Previous line */
    +           case 'k':
    +           case KEY_UP:
    +                   if (begin_reached)
    +                           break;
    +
    +                   back_lines(page_length + 1);
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case 'B':       /* Previous page */
    +           case 'b':
    +           case 'u':
    +           case KEY_PPAGE:
    +                   if (begin_reached)
    +                           break;
    +                   back_lines(page_length + boxh);
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case 'J':       /* Next line */
    +           case 'j':
    +           case KEY_DOWN:
    +                   if (end_reached)
    +                           break;
    +
    +                   back_lines(page_length - 1);
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case KEY_NPAGE: /* Next page */
    +           case ' ':
    +           case 'd':
    +                   if (end_reached)
    +                           break;
    +
    +                   begin_reached = 0;
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case '0':       /* Beginning of line */
    +           case 'H':       /* Scroll left */
    +           case 'h':
    +           case KEY_LEFT:
    +                   if (hscroll <= 0)
    +                           break;
    +
    +                   if (key == '0')
    +                           hscroll = 0;
    +                   else
    +                           hscroll--;
    +                   /* Reprint current page to scroll horizontally */
    +                   back_lines(page_length);
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case 'L':       /* Scroll right */
    +           case 'l':
    +           case KEY_RIGHT:
    +                   if (hscroll >= MAX_LEN)
    +                           break;
    +                   hscroll++;
    +                   /* Reprint current page to scroll horizontally */
    +                   back_lines(page_length);
    +                   refresh_text_box(dialog, box, boxh, boxw, cur_y,
    +                                    cur_x, update_text, data);
    +                   break;
    +           case KEY_ESC:
    +                   if (on_key_esc(dialog) == KEY_ESC)
    +                           done = true;
    +                   break;
    +           case KEY_RESIZE:
    +                   back_lines(height);
    +                   delwin(box);
    +                   delwin(dialog);
    +                   on_key_resize();
    +                   goto do_resize;
    +           default:
    +                   for (i = 0; keys[i]; i++) {
    +                           if (key == keys[i]) {
    +                                   done = true;
    +                                   break;
    +                           }
    +                   }
    +           }
    +   }
    +   delwin(box);
    +   delwin(dialog);
    +   if (_vscroll) {
    +           const char *s;
    +
    +           s = buf;
    +           *_vscroll = 0;
    +           back_lines(page_length);
    +           while (s < page && (s = strchr(s, '\n'))) {
    +                   (*_vscroll)++;
    +                   s++;
    +           }
    +   }
    +   if (_hscroll)
    +           *_hscroll = hscroll;
    +   return key;
    +}
    +
    +/*
    + * Go back 'n' lines in text. Called by dialog_textbox().
    + * 'page' will be updated to point to the desired line in 'buf'.
    + */
    +static void back_lines(int n)
    +{
    +   int i;
    +
    +   begin_reached = 0;
    +   /* Go back 'n' lines */
    +   for (i = 0; i < n; i++) {
    +           if (*page == '\0') {
    +                   if (end_reached) {
    +                           end_reached = 0;
    +                           continue;
    +                   }
    +           }
    +           if (page == buf) {
    +                   begin_reached = 1;
    +                   return;
    +           }
    +           page--;
    +           do {
    +                   if (page == buf) {
    +                           begin_reached = 1;
    +                           return;
    +                   }
    +                   page--;
    +           } while (*page != '\n');
    +           page++;
    +   }
    +}
    +
    +/*
    + * Print a new page of text.
    + */
    +static void print_page(WINDOW *win, int height, int width, update_text_fn
    +                  update_text, void *data)
    +{
    +   int i, passed_end = 0;
    +
    +   if (update_text) {
    +           char *end;
    +
    +           for (i = 0; i < height; i++)
    +                   get_line();
    +           end = page;
    +           back_lines(height);
    +           update_text(buf, page - buf, end - buf, data);
    +   }
    +
    +   page_length = 0;
    +   for (i = 0; i < height; i++) {
    +           print_line(win, i, width);
    +           if (!passed_end)
    +                   page_length++;
    +           if (end_reached && !passed_end)
    +                   passed_end = 1;
    +   }
    +   wnoutrefresh(win);
    +}
    +
    +/*
    + * Print a new line of text.
    + */
    +static void print_line(WINDOW * win, int row, int width)
    +{
    +   char *line;
    +
    +   line = get_line();
    +   line += MIN(strlen(line), hscroll);     /* Scroll horizontally */
    +   wmove(win, row, 0);     /* move cursor to correct line */
    +   waddch(win, ' ');
    +   waddnstr(win, line, MIN(strlen(line), width - 2));
    +
    +   /* Clear 'residue' of previous line */
    +#if OLD_NCURSES
    +   {
    +           int x = getcurx(win);
    +           int i;
    +           for (i = 0; i < width - x; i++)
    +                   waddch(win, ' ');
    +   }
    +#else
    +   wclrtoeol(win);
    +#endif
    +}
    +
    +/*
    + * Return current line of text. Called by dialog_textbox() and 
print_line().
    + * 'page' should point to start of current line before calling, and will be
    + * updated to point to start of next line.
    + */
    +static char *get_line(void)
    +{
    +   int i = 0;
    +   static char line[MAX_LEN + 1];
    +
    +   end_reached = 0;
    +   while (*page != '\n') {
    +           if (*page == '\0') {
    +                   end_reached = 1;
    +                   break;
    +           } else if (i < MAX_LEN)
    +                   line[i++] = *(page++);
    +           else {
    +                   /* Truncate lines longer than MAX_LEN characters */
    +                   if (i == MAX_LEN)
    +                           line[i++] = '\0';
    +                   page++;
    +           }
    +   }
    +   if (i <= MAX_LEN)
    +           line[i] = '\0';
    +   if (!end_reached)
    +           page++;         /* move past '\n' */
    +
    +   return line;
    +}
    +
    +/*
    + * Print current position
    + */
    +static void print_position(WINDOW * win)
    +{
    +   int percent;
    +
    +   wattrset(win, dlg.position_indicator.atr);
    +   wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
    +   percent = (page - buf) * 100 / strlen(buf);
    +   wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
    +   wprintw(win, "(%3d%%)", percent);
    +}
    diff --git a/support/kconfig.new/lxdialog/util.c 
b/support/kconfig.new/lxdialog/util.c
    new file mode 100644
    index 0000000..1b490d4
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/util.c
    @@ -0,0 +1,700 @@
    +// SPDX-License-Identifier: GPL-2.0+
    +/*
    + *  util.c
    + *
    + *  ORIGINAL AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@xxxxxxx)
    + */
    +
    +#include <stdarg.h>
    +
    +#include "dialog.h"
    +
    +/* Needed in signal handler in mconf.c */
    +int saved_x, saved_y;
    +
    +struct dialog_info dlg;
    +
    +static void set_mono_theme(void)
    +{
    +   dlg.screen.atr = A_NORMAL;
    +   dlg.shadow.atr = A_NORMAL;
    +   dlg.dialog.atr = A_NORMAL;
    +   dlg.title.atr = A_BOLD;
    +   dlg.border.atr = A_NORMAL;
    +   dlg.button_active.atr = A_REVERSE;
    +   dlg.button_inactive.atr = A_DIM;
    +   dlg.button_key_active.atr = A_REVERSE;
    +   dlg.button_key_inactive.atr = A_BOLD;
    +   dlg.button_label_active.atr = A_REVERSE;
    +   dlg.button_label_inactive.atr = A_NORMAL;
    +   dlg.inputbox.atr = A_NORMAL;
    +   dlg.inputbox_border.atr = A_NORMAL;
    +   dlg.searchbox.atr = A_NORMAL;
    +   dlg.searchbox_title.atr = A_BOLD;
    +   dlg.searchbox_border.atr = A_NORMAL;
    +   dlg.position_indicator.atr = A_BOLD;
    +   dlg.menubox.atr = A_NORMAL;
    +   dlg.menubox_border.atr = A_NORMAL;
    +   dlg.item.atr = A_NORMAL;
    +   dlg.item_selected.atr = A_REVERSE;
    +   dlg.tag.atr = A_BOLD;
    +   dlg.tag_selected.atr = A_REVERSE;
    +   dlg.tag_key.atr = A_BOLD;
    +   dlg.tag_key_selected.atr = A_REVERSE;
    +   dlg.check.atr = A_BOLD;
    +   dlg.check_selected.atr = A_REVERSE;
    +   dlg.uarrow.atr = A_BOLD;
    +   dlg.darrow.atr = A_BOLD;
    +}
    +
    +#define DLG_COLOR(dialog, f, b, h) \
    +do {                               \
    +   dlg.dialog.fg = (f);       \
    +   dlg.dialog.bg = (b);       \
    +   dlg.dialog.hl = (h);       \
    +} while (0)
    +
    +static void set_classic_theme(void)
    +{
    +   DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
    +   DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
    +   DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
    +   DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
    +   DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
    +   DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
    +   DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
    +   DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
    +   DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
    +   DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
    +   DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
    +   DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
    +   DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
    +   DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
    +   DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
    +   DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
    +   DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
    +   DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
    +   DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
    +   DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
    +   DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
    +   DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
    +}
    +
    +static void set_blackbg_theme(void)
    +{
    +   DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
    +   DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
    +   DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
    +   DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
    +   DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
    +
    +   DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
    +   DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
    +   DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
    +   DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
    +   DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
    +   DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
    +
    +   DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
    +   DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
    +
    +   DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
    +   DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
    +   DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
    +
    +   DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
    +
    +   DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
    +   DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
    +
    +   DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
    +   DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
    +
    +   DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
    +   DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
    +   DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
    +   DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
    +
    +   DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
    +   DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
    +
    +   DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
    +   DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
    +}
    +
    +static void set_bluetitle_theme(void)
    +{
    +   set_classic_theme();
    +   DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
    +   DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
    +   DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
    +   DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
    +   DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
    +   DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
    +   DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
    +
    +}
    +
    +/*
    + * Select color theme
    + */
    +static int set_theme(const char *theme)
    +{
    +   int use_color = 1;
    +   if (!theme)
    +           set_bluetitle_theme();
    +   else if (strcmp(theme, "classic") == 0)
    +           set_classic_theme();
    +   else if (strcmp(theme, "bluetitle") == 0)
    +           set_bluetitle_theme();
    +   else if (strcmp(theme, "blackbg") == 0)
    +           set_blackbg_theme();
    +   else if (strcmp(theme, "mono") == 0)
    +           use_color = 0;
    +
    +   return use_color;
    +}
    +
    +static void init_one_color(struct dialog_color *color)
    +{
    +   static int pair = 0;
    +
    +   pair++;
    +   init_pair(pair, color->fg, color->bg);
    +   if (color->hl)
    +           color->atr = A_BOLD | COLOR_PAIR(pair);
    +   else
    +           color->atr = COLOR_PAIR(pair);
    +}
    +
    +static void init_dialog_colors(void)
    +{
    +   init_one_color(&dlg.screen);
    +   init_one_color(&dlg.shadow);
    +   init_one_color(&dlg.dialog);
    +   init_one_color(&dlg.title);
    +   init_one_color(&dlg.border);
    +   init_one_color(&dlg.button_active);
    +   init_one_color(&dlg.button_inactive);
    +   init_one_color(&dlg.button_key_active);
    +   init_one_color(&dlg.button_key_inactive);
    +   init_one_color(&dlg.button_label_active);
    +   init_one_color(&dlg.button_label_inactive);
    +   init_one_color(&dlg.inputbox);
    +   init_one_color(&dlg.inputbox_border);
    +   init_one_color(&dlg.searchbox);
    +   init_one_color(&dlg.searchbox_title);
    +   init_one_color(&dlg.searchbox_border);
    +   init_one_color(&dlg.position_indicator);
    +   init_one_color(&dlg.menubox);
    +   init_one_color(&dlg.menubox_border);
    +   init_one_color(&dlg.item);
    +   init_one_color(&dlg.item_selected);
    +   init_one_color(&dlg.tag);
    +   init_one_color(&dlg.tag_selected);
    +   init_one_color(&dlg.tag_key);
    +   init_one_color(&dlg.tag_key_selected);
    +   init_one_color(&dlg.check);
    +   init_one_color(&dlg.check_selected);
    +   init_one_color(&dlg.uarrow);
    +   init_one_color(&dlg.darrow);
    +}
    +
    +/*
    + * Setup for color display
    + */
    +static void color_setup(const char *theme)
    +{
    +   int use_color;
    +
    +   use_color = set_theme(theme);
    +   if (use_color && has_colors()) {
    +           start_color();
    +           init_dialog_colors();
    +   } else
    +           set_mono_theme();
    +}
    +
    +/*
    + * Set window to attribute 'attr'
    + */
    +void attr_clear(WINDOW * win, int height, int width, chtype attr)
    +{
    +   int i, j;
    +
    +   wattrset(win, attr);
    +   for (i = 0; i < height; i++) {
    +           wmove(win, i, 0);
    +           for (j = 0; j < width; j++)
    +                   waddch(win, ' ');
    +   }
    +   touchwin(win);
    +}
    +
    +void dialog_clear(void)
    +{
    +   int lines, columns;
    +
    +   lines = getmaxy(stdscr);
    +   columns = getmaxx(stdscr);
    +
    +   attr_clear(stdscr, lines, columns, dlg.screen.atr);
    +   /* Display background title if it exists ... - SLH */
    +   if (dlg.backtitle != NULL) {
    +           int i, len = 0, skip = 0;
    +           struct subtitle_list *pos;
    +
    +           wattrset(stdscr, dlg.screen.atr);
    +           mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
    +
    +           for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
    +                   /* 3 is for the arrow and spaces */
    +                   len += strlen(pos->text) + 3;
    +           }
    +
    +           wmove(stdscr, 1, 1);
    +           if (len > columns - 2) {
    +                   const char *ellipsis = "[...] ";
    +                   waddstr(stdscr, ellipsis);
    +                   skip = len - (columns - 2 - strlen(ellipsis));
    +           }
    +
    +           for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
    +                   if (skip == 0)
    +                           waddch(stdscr, ACS_RARROW);
    +                   else
    +                           skip--;
    +
    +                   if (skip == 0)
    +                           waddch(stdscr, ' ');
    +                   else
    +                           skip--;
    +
    +                   if (skip < strlen(pos->text)) {
    +                           waddstr(stdscr, pos->text + skip);
    +                           skip = 0;
    +                   } else
    +                           skip -= strlen(pos->text);
    +
    +                   if (skip == 0)
    +                           waddch(stdscr, ' ');
    +                   else
    +                           skip--;
    +           }
    +
    +           for (i = len + 1; i < columns - 1; i++)
    +                   waddch(stdscr, ACS_HLINE);
    +   }
    +   wnoutrefresh(stdscr);
    +}
    +
    +/*
    + * Do some initialization for dialog
    + */
    +int init_dialog(const char *backtitle)
    +{
    +   int height, width;
    +
    +   initscr();              /* Init curses */
    +
    +   /* Get current cursor position for signal handler in mconf.c */
    +   getyx(stdscr, saved_y, saved_x);
    +
    +   getmaxyx(stdscr, height, width);
    +   if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
    +           endwin();
    +           return -ERRDISPLAYTOOSMALL;
    +   }
    +
    +   dlg.backtitle = backtitle;
    +   color_setup(getenv("MENUCONFIG_COLOR"));
    +
    +   keypad(stdscr, TRUE);
    +   cbreak();
    +   noecho();
    +   dialog_clear();
    +
    +   return 0;
    +}
    +
    +void set_dialog_backtitle(const char *backtitle)
    +{
    +   dlg.backtitle = backtitle;
    +}
    +
    +void set_dialog_subtitles(struct subtitle_list *subtitles)
    +{
    +   dlg.subtitles = subtitles;
    +}
    +
    +/*
    + * End using dialog functions.
    + */
    +void end_dialog(int x, int y)
    +{
    +   /* move cursor back to original position */
    +   move(y, x);
    +   refresh();
    +   endwin();
    +}
    +
    +/* Print the title of the dialog. Center the title and truncate
    + * tile if wider than dialog (- 2 chars).
    + **/
    +void print_title(WINDOW *dialog, const char *title, int width)
    +{
    +   if (title) {
    +           int tlen = MIN(width - 2, strlen(title));
    +           wattrset(dialog, dlg.title.atr);
    +           mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
    +           mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
    +           waddch(dialog, ' ');
    +   }
    +}
    +
    +/*
    + * Print a string of text in a window, automatically wrap around to the
    + * next line if the string is too long to fit on one line. Newline
    + * characters '\n' are propperly processed.  We start on a new line
    + * if there is no room for at least 4 nonblanks following a double-space.
    + */
    +void print_autowrap(WINDOW * win, const char *prompt, int width, int y, 
int x)
    +{
    +   int newl, cur_x, cur_y;
    +   int prompt_len, room, wlen;
    +   char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
    +
    +   strcpy(tempstr, prompt);
    +
    +   prompt_len = strlen(tempstr);
    +
    +   if (prompt_len <= width - x * 2) {      /* If prompt is short */
    +           wmove(win, y, (width - prompt_len) / 2);
    +           waddstr(win, tempstr);
    +   } else {
    +           cur_x = x;
    +           cur_y = y;
    +           newl = 1;
    +           word = tempstr;
    +           while (word && *word) {
    +                   sp = strpbrk(word, "\n ");
    +                   if (sp && *sp == '\n')
    +                           newline_separator = sp;
    +
    +                   if (sp)
    +                           *sp++ = 0;
    +
    +                   /* Wrap to next line if either the word does not fit,
    +                      or it is the first word of a new sentence, and it is
    +                      short, and the next word does not fit. */
    +                   room = width - cur_x;
    +                   wlen = strlen(word);
    +                   if (wlen > room ||
    +                       (newl && wlen < 4 && sp
    +                        && wlen + 1 + strlen(sp) > room
    +                        && (!(sp2 = strpbrk(sp, "\n "))
    +                            || wlen + 1 + (sp2 - sp) > room))) {
    +                           cur_y++;
    +                           cur_x = x;
    +                   }
    +                   wmove(win, cur_y, cur_x);
    +                   waddstr(win, word);
    +                   getyx(win, cur_y, cur_x);
    +
    +                   /* Move to the next line if the word separator was a 
newline */
    +                   if (newline_separator) {
    +                           cur_y++;
    +                           cur_x = x;
    +                           newline_separator = 0;
    +                   } else
    +                           cur_x++;
    +
    +                   if (sp && *sp == ' ') {
    +                           cur_x++;        /* double space */
    +                           while (*++sp == ' ') ;
    +                           newl = 1;
    +                   } else
    +                           newl = 0;
    +                   word = sp;
    +           }
    +   }
    +}
    +
    +/*
    + * Print a button
    + */
    +void print_button(WINDOW * win, const char *label, int y, int x, int 
selected)
    +{
    +   int i, temp;
    +
    +   wmove(win, y, x);
    +   wattrset(win, selected ? dlg.button_active.atr
    +            : dlg.button_inactive.atr);
    +   waddstr(win, "<");
    +   temp = strspn(label, " ");
    +   label += temp;
    +   wattrset(win, selected ? dlg.button_label_active.atr
    +            : dlg.button_label_inactive.atr);
    +   for (i = 0; i < temp; i++)
    +           waddch(win, ' ');
    +   wattrset(win, selected ? dlg.button_key_active.atr
    +            : dlg.button_key_inactive.atr);
    +   waddch(win, label[0]);
    +   wattrset(win, selected ? dlg.button_label_active.atr
    +            : dlg.button_label_inactive.atr);
    +   waddstr(win, (char *)label + 1);
    +   wattrset(win, selected ? dlg.button_active.atr
    +            : dlg.button_inactive.atr);
    +   waddstr(win, ">");
    +   wmove(win, y, x + temp + 1);
    +}
    +
    +/*
    + * Draw a rectangular box with line drawing characters
    + */
    +void
    +draw_box(WINDOW * win, int y, int x, int height, int width,
    +    chtype box, chtype border)
    +{
    +   int i, j;
    +
    +   wattrset(win, 0);
    +   for (i = 0; i < height; i++) {
    +           wmove(win, y + i, x);
    +           for (j = 0; j < width; j++)
    +                   if (!i && !j)
    +                           waddch(win, border | ACS_ULCORNER);
    +                   else if (i == height - 1 && !j)
    +                           waddch(win, border | ACS_LLCORNER);
    +                   else if (!i && j == width - 1)
    +                           waddch(win, box | ACS_URCORNER);
    +                   else if (i == height - 1 && j == width - 1)
    +                           waddch(win, box | ACS_LRCORNER);
    +                   else if (!i)
    +                           waddch(win, border | ACS_HLINE);
    +                   else if (i == height - 1)
    +                           waddch(win, box | ACS_HLINE);
    +                   else if (!j)
    +                           waddch(win, border | ACS_VLINE);
    +                   else if (j == width - 1)
    +                           waddch(win, box | ACS_VLINE);
    +                   else
    +                           waddch(win, box | ' ');
    +   }
    +}
    +
    +/*
    + * Draw shadows along the right and bottom edge to give a more 3D look
    + * to the boxes
    + */
    +void draw_shadow(WINDOW * win, int y, int x, int height, int width)
    +{
    +   int i;
    +
    +   if (has_colors()) {     /* Whether terminal supports color? */
    +           wattrset(win, dlg.shadow.atr);
    +           wmove(win, y + height, x + 2);
    +           for (i = 0; i < width; i++)
    +                   waddch(win, winch(win) & A_CHARTEXT);
    +           for (i = y + 1; i < y + height + 1; i++) {
    +                   wmove(win, i, x + width);
    +                   waddch(win, winch(win) & A_CHARTEXT);
    +                   waddch(win, winch(win) & A_CHARTEXT);
    +           }
    +           wnoutrefresh(win);
    +   }
    +}
    +
    +/*
    + *  Return the position of the first alphabetic character in a string.
    + */
    +int first_alpha(const char *string, const char *exempt)
    +{
    +   int i, in_paren = 0, c;
    +
    +   for (i = 0; i < strlen(string); i++) {
    +           c = tolower(string[i]);
    +
    +           if (strchr("<[(", c))
    +                   ++in_paren;
    +           if (strchr(">])", c) && in_paren > 0)
    +                   --in_paren;
    +
    +           if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
    +                   return i;
    +   }
    +
    +   return 0;
    +}
    +
    +/*
    + * ncurses uses ESC to detect escaped char sequences. This resutl in
    + * a small timeout before ESC is actually delivered to the application.
    + * lxdialog suggest <ESC> <ESC> which is correctly translated to two
    + * times esc. But then we need to ignore the second esc to avoid stepping
    + * out one menu too much. Filter away all escaped key sequences since
    + * keypad(FALSE) turn off ncurses support for escape sequences - and thats
    + * needed to make notimeout() do as expected.
    + */
    +int on_key_esc(WINDOW *win)
    +{
    +   int key;
    +   int key2;
    +   int key3;
    +
    +   nodelay(win, TRUE);
    +   keypad(win, FALSE);
    +   key = wgetch(win);
    +   key2 = wgetch(win);
    +   do {
    +           key3 = wgetch(win);
    +   } while (key3 != ERR);
    +   nodelay(win, FALSE);
    +   keypad(win, TRUE);
    +   if (key == KEY_ESC && key2 == ERR)
    +           return KEY_ESC;
    +   else if (key != ERR && key != KEY_ESC && key2 == ERR)
    +           ungetch(key);
    +
    +   return -1;
    +}
    +
    +/* redraw screen in new size */
    +int on_key_resize(void)
    +{
    +   dialog_clear();
    +   return KEY_RESIZE;
    +}
    +
    +struct dialog_list *item_cur;
    +struct dialog_list item_nil;
    +struct dialog_list *item_head;
    +
    +void item_reset(void)
    +{
    +   struct dialog_list *p, *next;
    +
    +   for (p = item_head; p; p = next) {
    +           next = p->next;
    +           free(p);
    +   }
    +   item_head = NULL;
    +   item_cur = &item_nil;
    +}
    +
    +void item_make(const char *fmt, ...)
    +{
    +   va_list ap;
    +   struct dialog_list *p = malloc(sizeof(*p));
    +
    +   if (item_head)
    +           item_cur->next = p;
    +   else
    +           item_head = p;
    +   item_cur = p;
    +   memset(p, 0, sizeof(*p));
    +
    +   va_start(ap, fmt);
    +   vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
    +   va_end(ap);
    +}
    +
    +void item_add_str(const char *fmt, ...)
    +{
    +   va_list ap;
    +   size_t avail;
    +
    +   avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
    +
    +   va_start(ap, fmt);
    +   vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
    +             avail, fmt, ap);
    +   item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
    +   va_end(ap);
    +}
    +
    +void item_set_tag(char tag)
    +{
    +   item_cur->node.tag = tag;
    +}
    +void item_set_data(void *ptr)
    +{
    +   item_cur->node.data = ptr;
    +}
    +
    +void item_set_selected(int val)
    +{
    +   item_cur->node.selected = val;
    +}
    +
    +int item_activate_selected(void)
    +{
    +   item_foreach()
    +           if (item_is_selected())
    +                   return 1;
    +   return 0;
    +}
    +
    +void *item_data(void)
    +{
    +   return item_cur->node.data;
    +}
    +
    +char item_tag(void)
    +{
    +   return item_cur->node.tag;
    +}
    +
    +int item_count(void)
    +{
    +   int n = 0;
    +   struct dialog_list *p;
    +
    +   for (p = item_head; p; p = p->next)
    +           n++;
    +   return n;
    +}
    +
    +void item_set(int n)
    +{
    +   int i = 0;
    +   item_foreach()
    +           if (i++ == n)
    +                   return;
    +}
    +
    +int item_n(void)
    +{
    +   int n = 0;
    +   struct dialog_list *p;
    +
    +   for (p = item_head; p; p = p->next) {
    +           if (p == item_cur)
    +                   return n;
    +           n++;
    +   }
    +   return 0;
    +}
    +
    +const char *item_str(void)
    +{
    +   return item_cur->node.str;
    +}
    +
    +int item_is_selected(void)
    +{
    +   return (item_cur->node.selected != 0);
    +}
    +
    +int item_is_tag(char tag)
    +{
    +   return (item_cur->node.tag == tag);
    +}
    diff --git a/support/kconfig.new/lxdialog/yesno.c 
b/support/kconfig.new/lxdialog/yesno.c
    new file mode 100644
    index 0000000..bcaac9b
    --- /dev/null
    +++ b/support/kconfig.new/lxdialog/yesno.c
    @@ -0,0 +1,101 @@
    +// SPDX-License-Identifier: GPL-2.0+
    +/*
    + *  yesno.c -- implements the yes/no box
    + *
    + *  ORIGINAL AUTHOR: Savio Lam (lam836@xxxxxxxxxx)
    + *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@xxxxxxx)
    + */
    +
    +#include "dialog.h"
    +
    +/*
    + * Display termination buttons
    + */
    +static void print_buttons(WINDOW * dialog, int height, int width, int 
selected)
    +{
    +   int x = width / 2 - 10;
    +   int y = height - 2;
    +
    +   print_button(dialog, " Yes ", y, x, selected == 0);
    +   print_button(dialog, "  No  ", y, x + 13, selected == 1);
    +
    +   wmove(dialog, y, x + 1 + 13 * selected);
    +   wrefresh(dialog);
    +}
    +
    +/*
    + * Display a dialog box with two buttons - Yes and No
    + */
    +int dialog_yesno(const char *title, const char *prompt, int height, int 
width)
    +{
    +   int i, x, y, key = 0, button = 0;
    +   WINDOW *dialog;
    +
    +do_resize:
    +   if (getmaxy(stdscr) < (height + YESNO_HEIGTH_MIN))
    +           return -ERRDISPLAYTOOSMALL;
    +   if (getmaxx(stdscr) < (width + YESNO_WIDTH_MIN))
    +           return -ERRDISPLAYTOOSMALL;
    +
    +   /* center dialog box on screen */
    +   x = (getmaxx(stdscr) - width) / 2;
    +   y = (getmaxy(stdscr) - height) / 2;
    +
    +   draw_shadow(stdscr, y, x, height, width);
    +
    +   dialog = newwin(height, width, y, x);
    +   keypad(dialog, TRUE);
    +
    +   draw_box(dialog, 0, 0, height, width,
    +            dlg.dialog.atr, dlg.border.atr);
    +   wattrset(dialog, dlg.border.atr);
    +   mvwaddch(dialog, height - 3, 0, ACS_LTEE);
    +   for (i = 0; i < width - 2; i++)
    +           waddch(dialog, ACS_HLINE);
    +   wattrset(dialog, dlg.dialog.atr);
    +   waddch(dialog, ACS_RTEE);
    +
    +   print_title(dialog, title, width);
    +
    +   wattrset(dialog, dlg.dialog.atr);
    +   print_autowrap(dialog, prompt, width - 2, 1, 3);
    +
    +   print_buttons(dialog, height, width, 0);
    +
    +   while (key != KEY_ESC) {
    +           key = wgetch(dialog);
    +           switch (key) {
    +           case 'Y':
    +           case 'y':
    +                   delwin(dialog);
    +                   return 0;
    +           case 'N':
    +           case 'n':
    +                   delwin(dialog);
    +                   return 1;
    +
    +           case TAB:
    +           case KEY_LEFT:
    +           case KEY_RIGHT:
    +                   button = ((key == KEY_LEFT ? --button : ++button) < 0) 
? 1 : (button > 1 ? 0 : button);
    +
    +                   print_buttons(dialog, height, width, button);
    +                   wrefresh(dialog);
    +                   break;
    +           case ' ':
    +           case '\n':
    +                   delwin(dialog);
    +                   return button;
    +           case KEY_ESC:
    +                   key = on_key_esc(dialog);
    +                   break;
    +           case KEY_RESIZE:
    +                   delwin(dialog);
    +                   on_key_resize();
    +                   goto do_resize;
    +           }
    +   }
    +
    +   delwin(dialog);
    +   return key;             /* ESC pressed */
    +}
    diff --git a/support/kconfig.new/mconf-cfg.sh 
b/support/kconfig.new/mconf-cfg.sh
    new file mode 100755
    index 0000000..c812872
    --- /dev/null
    +++ b/support/kconfig.new/mconf-cfg.sh
    @@ -0,0 +1,47 @@
    +#!/bin/sh
    +# SPDX-License-Identifier: GPL-2.0
    +
    +PKG="ncursesw"
    +PKG2="ncurses"
    +
    +if [ -n "$(command -v pkg-config)" ]; then
    +   if pkg-config --exists $PKG; then
    +           echo cflags=\"$(pkg-config --cflags $PKG)\"
    +           echo libs=\"$(pkg-config --libs $PKG)\"
    +           exit 0
    +   fi
    +
    +   if pkg-config --exists $PKG2; then
    +           echo cflags=\"$(pkg-config --cflags $PKG2)\"
    +           echo libs=\"$(pkg-config --libs $PKG2)\"
    +           exit 0
    +   fi
    +fi
    +
    +# Check the default paths in case pkg-config is not installed.
    +# (Even if it is installed, some distributions such as openSUSE cannot
    +# find ncurses by pkg-config.)
    +if [ -f /usr/include/ncursesw/ncurses.h ]; then
    +   echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\"
    +   echo libs=\"-lncursesw\"
    +   exit 0
    +fi
    +
    +if [ -f /usr/include/ncurses/ncurses.h ]; then
    +   echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\"
    +   echo libs=\"-lncurses\"
    +   exit 0
    +fi
    +
    +if [ -f /usr/include/ncurses.h ]; then
    +   echo cflags=\"-D_GNU_SOURCE\"
    +   echo libs=\"-lncurses\"
    +   exit 0
    +fi
    +
    +echo >&2 "*"
    +echo >&2 "* Unable to find the ncurses package."
    +echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
    +echo >&2 "* depending on your distribution)."
    +echo >&2 "*"
    +exit 1
    diff --git a/support/kconfig.new/mconf.c b/support/kconfig.new/mconf.c
    new file mode 100644
    index 0000000..694091f
    --- /dev/null
    +++ b/support/kconfig.new/mconf.c
    @@ -0,0 +1,1039 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + *
    + * Introduced single menu mode (show all sub-menus in one large tree).
    + * 2002-11-06 Petr Baudis <pasky@xxxxxx>
    + *
    + * i18n, 2005, Arnaldo Carvalho de Melo <acme@xxxxxxxxxxxxxxxx>
    + */
    +
    +#include <ctype.h>
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <limits.h>
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <signal.h>
    +#include <unistd.h>
    +
    +#include "lkc.h"
    +#include "lxdialog/dialog.h"
    +
    +static const char mconf_readme[] =
    +"Overview\n"
    +"--------\n"
    +"This interface lets you select features and parameters for the build.\n"
    +"Features can either be built-in, modularized, or ignored. Parameters\n"
    +"must be entered in as decimal or hexadecimal numbers or text.\n"
    +"\n"
    +"Menu items beginning with following braces represent features that\n"
    +"  [ ] can be built in or removed\n"
    +"  < > can be built in, modularized or removed\n"
    +"  { } can be built in or modularized (selected by other feature)\n"
    +"  - - are selected by other feature,\n"
    +"while *, M or whitespace inside braces means to build in, build as\n"
    +"a module or to exclude the feature respectively.\n"
    +"\n"
    +"To change any of these features, highlight it with the cursor\n"
    +"keys and press <Y> to build it in, <M> to make it a module or\n"
    +"<N> to remove it.  You may also press the <Space Bar> to cycle\n"
    +"through the available options (i.e. Y->N->M->Y).\n"
    +"\n"
    +"Some additional keyboard hints:\n"
    +"\n"
    +"Menus\n"
    +"----------\n"
    +"o  Use the Up/Down arrow keys (cursor keys) to highlight the item you\n"
    +"   wish to change or the submenu you wish to select and press <Enter>.\n"
    +"   Submenus are designated by \"--->\", empty ones by \"----\".\n"
    +"\n"
    +"   Shortcut: Press the option's highlighted letter (hotkey).\n"
    +"             Pressing a hotkey more than once will sequence\n"
    +"             through all visible items which use that hotkey.\n"
    +"\n"
    +"   You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
    +"   unseen options into view.\n"
    +"\n"
    +"o  To exit a menu use the cursor keys to highlight the <Exit> button\n"
    +"   and press <ENTER>.\n"
    +"\n"
    +"   Shortcut: Press <ESC><ESC> or <E> or <X> if there is no hotkey\n"
    +"             using those letters.  You may press a single <ESC>, but\n"
    +"             there is a delayed response which you may find annoying.\n"
    +"\n"
    +"   Also, the <TAB> and cursor keys will cycle between <Select>,\n"
    +"   <Exit>, <Help>, <Save>, and <Load>.\n"
    +"\n"
    +"o  To get help with an item, use the cursor keys to highlight <Help>\n"
    +"   and press <ENTER>.\n"
    +"\n"
    +"   Shortcut: Press <H> or <?>.\n"
    +"\n"
    +"o  To toggle the display of hidden options, press <Z>.\n"
    +"\n"
    +"\n"
    +"Radiolists  (Choice lists)\n"
    +"-----------\n"
    +"o  Use the cursor keys to select the option you wish to set and press\n"
    +"   <S> or the <SPACE BAR>.\n"
    +"\n"
    +"   Shortcut: Press the first letter of the option you wish to set then\n"
    +"             press <S> or <SPACE BAR>.\n"
    +"\n"
    +"o  To see available help for the item, use the cursor keys to highlight\n"
    +"   <Help> and Press <ENTER>.\n"
    +"\n"
    +"   Shortcut: Press <H> or <?>.\n"
    +"\n"
    +"   Also, the <TAB> and cursor keys will cycle between <Select> and\n"
    +"   <Help>\n"
    +"\n"
    +"\n"
    +"Data Entry\n"
    +"-----------\n"
    +"o  Enter the requested information and press <ENTER>\n"
    +"   If you are entering hexadecimal values, it is not necessary to\n"
    +"   add the '0x' prefix to the entry.\n"
    +"\n"
    +"o  For help, use the <TAB> or cursor keys to highlight the help option\n"
    +"   and press <ENTER>.  You can try <TAB><H> as well.\n"
    +"\n"
    +"\n"
    +"Text Box    (Help Window)\n"
    +"--------\n"
    +"o  Use the cursor keys to scroll up/down/left/right.  The VI editor\n"
    +"   keys h,j,k,l function here as do <u>, <d>, <SPACE BAR> and <B> for\n"
    +"   those who are familiar with less and lynx.\n"
    +"\n"
    +"o  Press <E>, <X>, <q>, <Enter> or <Esc><Esc> to exit.\n"
    +"\n"
    +"\n"
    +"Alternate Configuration Files\n"
    +"-----------------------------\n"
    +"Menuconfig supports the use of alternate configuration files for\n"
    +"those who, for various reasons, find it necessary to switch\n"
    +"between different configurations.\n"
    +"\n"
    +"The <Save> button will let you save the current configuration to\n"
    +"a file of your choosing.  Use the <Load> button to load a previously\n"
    +"saved alternate configuration.\n"
    +"\n"
    +"Even if you don't use alternate configuration files, but you find\n"
    +"during a Menuconfig session that you have completely messed up your\n"
    +"settings, you may use the <Load> button to restore your previously\n"
    +"saved settings from \".config\" without restarting Menuconfig.\n"
    +"\n"
    +"Other information\n"
    +"-----------------\n"
    +"If you use Menuconfig in an XTERM window, make sure you have your\n"
    +"$TERM variable set to point to an xterm definition which supports\n"
    +"color.  Otherwise, Menuconfig will look rather bad.  Menuconfig will\n"
    +"not display correctly in an RXVT window because rxvt displays only one\n"
    +"intensity of color, bright.\n"
    +"\n"
    +"Menuconfig will display larger menus on screens or xterms which are\n"
    +"set to display more than the standard 25 row by 80 column geometry.\n"
    +"In order for this to work, the \"stty size\" command must be able to\n"
    +"display the screen's current row and column geometry.  I STRONGLY\n"
    +"RECOMMEND that you make sure you do NOT have the shell variables\n"
    +"LINES and COLUMNS exported into your environment.  Some distributions\n"
    +"export those variables via /etc/profile.  Some ncurses programs can\n"
    +"become confused when those variables (LINES & COLUMNS) don't reflect\n"
    +"the true screen size.\n"
    +"\n"
    +"Optional personality available\n"
    +"------------------------------\n"
    +"If you prefer to have all of the options listed in a single menu,\n"
    +"rather than the default multimenu hierarchy, run the menuconfig with\n"
    +"MENUCONFIG_MODE environment variable set to single_menu. Example:\n"
    +"\n"
    +"make MENUCONFIG_MODE=single_menu menuconfig\n"
    +"\n"
    +"<Enter> will then unroll the appropriate category, or enfold it if it\n"
    +"is already unrolled.\n"
    +"\n"
    +"Note that this mode can eventually be a little more CPU expensive\n"
    +"(especially with a larger number of unrolled categories) than the\n"
    +"default mode.\n"
    +"\n"
    +"Different color themes available\n"
    +"--------------------------------\n"
    +"It is possible to select different color themes using the variable\n"
    +"MENUCONFIG_COLOR. To select a theme use:\n"
    +"\n"
    +"make MENUCONFIG_COLOR=<theme> menuconfig\n"
    +"\n"
    +"Available themes are\n"
    +" mono       => selects colors suitable for monochrome displays\n"
    +" blackbg    => selects a color scheme with black background\n"
    +" classic    => theme with blue background. The classic look\n"
    +" bluetitle  => an LCD friendly version of classic. (default)\n"
    +"\n",
    +menu_instructions[] =
    +   "Arrow keys navigate the menu.  "
    +   "<Enter> selects submenus ---> (or empty submenus ----).  "
    +   "Highlighted letters are hotkeys.  "
    +   "Pressing <Y> includes, <N> excludes, <M> modularizes features.  "
    +   "Press <Esc><Esc> to exit, <?> for Help, </> for Search.  "
    +   "Legend: [*] built-in  [ ] excluded  <M> module  < > module capable",
    +radiolist_instructions[] =
    +   "Use the arrow keys to navigate this window or "
    +   "press the hotkey of the item you wish to select "
    +   "followed by the <SPACE BAR>. "
    +   "Press <?> for additional information about this option.",
    +inputbox_instructions_int[] =
    +   "Please enter a decimal value. "
    +   "Fractions will not be accepted.  "
    +   "Use the <TAB> key to move from the input field to the buttons below 
it.",
    +inputbox_instructions_hex[] =
    +   "Please enter a hexadecimal value. "
    +   "Use the <TAB> key to move from the input field to the buttons below 
it.",
    +inputbox_instructions_string[] =
    +   "Please enter a string value. "
    +   "Use the <TAB> key to move from the input field to the buttons below 
it.",
    +setmod_text[] =
    +   "This feature depends on another which has been configured as a 
module.\n"
    +   "As a result, this feature will be built as a module.",
    +load_config_text[] =
    +   "Enter the name of the configuration file you wish to load.  "
    +   "Accept the name shown to restore the configuration you "
    +   "last retrieved.  Leave blank to abort.",
    +load_config_help[] =
    +   "\n"
    +   "For various reasons, one may wish to keep several different\n"
    +   "configurations available on a single machine.\n"
    +   "\n"
    +   "If you have saved a previous configuration in a file other than the\n"
    +   "default one, entering its name here will allow you to modify that\n"
    +   "configuration.\n"
    +   "\n"
    +   "If you are uncertain, then you have probably never used alternate\n"
    +   "configuration files. You should therefore leave this blank to 
abort.\n",
    +save_config_text[] =
    +   "Enter a filename to which this configuration should be saved "
    +   "as an alternate.  Leave blank to abort.",
    +save_config_help[] =
    +   "\n"
    +   "For various reasons, one may wish to keep different configurations\n"
    +   "available on a single machine.\n"
    +   "\n"
    +   "Entering a file name here will allow you to later retrieve, modify\n"
    +   "and use the current configuration as an alternate to whatever\n"
    +   "configuration options you have selected at that time.\n"
    +   "\n"
    +   "If you are uncertain what all this means then you should probably\n"
    +   "leave this blank.\n",
    +search_help[] =
    +   "\n"
    +   "Search for symbols and display their relations.\n"
    +   "Regular expressions are allowed.\n"
    +   "Example: search for \"^FOO\"\n"
    +   "Result:\n"
    +   "-----------------------------------------------------------------\n"
    +   "Symbol: FOO [=m]\n"
    +   "Type  : tristate\n"
    +   "Prompt: Foo bus is used to drive the bar HW\n"
    +   "  Location:\n"
    +   "    -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
    +   "      -> PCI support (PCI [=y])\n"
    +   "(1)     -> PCI access mode (<choice> [=y])\n"
    +   "  Defined at drivers/pci/Kconfig:47\n"
    +   "  Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
    +   "  Selects: LIBCRC32\n"
    +   "  Selected by: BAR [=n]\n"
    +   "-----------------------------------------------------------------\n"
    +   "o The line 'Type:' shows the type of the configuration option for\n"
    +   "  this symbol (bool, tristate, string, ...)\n"
    +   "o The line 'Prompt:' shows the text used in the menu structure for\n"
    +   "  this symbol\n"
    +   "o The 'Defined at' line tells at what file / line number the symbol\n"
    +   "  is defined\n"
    +   "o The 'Depends on:' line tells what symbols need to be defined for\n"
    +   "  this symbol to be visible in the menu (selectable)\n"
    +   "o The 'Location:' lines tells where in the menu structure this 
symbol\n"
    +   "  is located\n"
    +   "    A location followed by a [=y] indicates that this is a\n"
    +   "    selectable menu item - and the current value is displayed inside\n"
    +   "    brackets.\n"
    +   "    Press the key in the (#) prefix to jump directly to that\n"
    +   "    location. You will be returned to the current search results\n"
    +   "    after exiting this new menu.\n"
    +   "o The 'Selects:' line tells what symbols will be automatically\n"
    +   "  selected if this symbol is selected (y or m)\n"
    +   "o The 'Selected by' line tells what symbol has selected this symbol\n"
    +   "\n"
    +   "Only relevant lines are shown.\n"
    +   "\n\n"
    +   "Search examples:\n"
    +   "Examples: USB  => find all symbols containing USB\n"
    +   "          ^USB => find all symbols starting with USB\n"
    +   "          USB$ => find all symbols ending with USB\n"
    +   "\n";
    +
    +static int indent;
    +static struct menu *current_menu;
    +static int child_count;
    +static int single_menu_mode;
    +static int show_all_options;
    +static int save_and_exit;
    +static int silent;
    +
    +static void conf(struct menu *menu, struct menu *active_menu);
    +static void conf_choice(struct menu *menu);
    +static void conf_string(struct menu *menu);
    +static void conf_load(void);
    +static void conf_save(void);
    +static int show_textbox_ext(const char *title, char *text, int r, int c,
    +                       int *keys, int *vscroll, int *hscroll,
    +                       update_text_fn update_text, void *data);
    +static void show_textbox(const char *title, const char *text, int r, int 
c);
    +static void show_helptext(const char *title, const char *text);
    +static void show_help(struct menu *menu);
    +
    +static char filename[PATH_MAX+1];
    +static void set_config_filename(const char *config_filename)
    +{
    +   static char menu_backtitle[PATH_MAX+128];
    +   int size;
    +
    +   size = snprintf(menu_backtitle, sizeof(menu_backtitle),
    +                   "%s - %s", config_filename, rootmenu.prompt->text);
    +   if (size >= sizeof(menu_backtitle))
    +           menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
    +   set_dialog_backtitle(menu_backtitle);
    +
    +   size = snprintf(filename, sizeof(filename), "%s", config_filename);
    +   if (size >= sizeof(filename))
    +           filename[sizeof(filename)-1] = '\0';
    +}
    +
    +struct subtitle_part {
    +   struct list_head entries;
    +   const char *text;
    +};
    +static LIST_HEAD(trail);
    +
    +static struct subtitle_list *subtitles;
    +static void set_subtitle(void)
    +{
    +   struct subtitle_part *sp;
    +   struct subtitle_list *pos, *tmp;
    +
    +   for (pos = subtitles; pos != NULL; pos = tmp) {
    +           tmp = pos->next;
    +           free(pos);
    +   }
    +
    +   subtitles = NULL;
    +   list_for_each_entry(sp, &trail, entries) {
    +           if (sp->text) {
    +                   if (pos) {
    +                           pos->next = xcalloc(1, sizeof(*pos));
    +                           pos = pos->next;
    +                   } else {
    +                           subtitles = pos = xcalloc(1, sizeof(*pos));
    +                   }
    +                   pos->text = sp->text;
    +           }
    +   }
    +
    +   set_dialog_subtitles(subtitles);
    +}
    +
    +static void reset_subtitle(void)
    +{
    +   struct subtitle_list *pos, *tmp;
    +
    +   for (pos = subtitles; pos != NULL; pos = tmp) {
    +           tmp = pos->next;
    +           free(pos);
    +   }
    +   subtitles = NULL;
    +   set_dialog_subtitles(subtitles);
    +}
    +
    +struct search_data {
    +   struct list_head *head;
    +   struct menu **targets;
    +   int *keys;
    +};
    +
    +static void update_text(char *buf, size_t start, size_t end, void *_data)
    +{
    +   struct search_data *data = _data;
    +   struct jump_key *pos;
    +   int k = 0;
    +
    +   list_for_each_entry(pos, data->head, entries) {
    +           if (pos->offset >= start && pos->offset < end) {
    +                   char header[4];
    +
    +                   if (k < JUMP_NB) {
    +                           int key = '0' + (pos->index % JUMP_NB) + 1;
    +
    +                           sprintf(header, "(%c)", key);
    +                           data->keys[k] = key;
    +                           data->targets[k] = pos->target;
    +                           k++;
    +                   } else {
    +                           sprintf(header, "   ");
    +                   }
    +
    +                   memcpy(buf + pos->offset, header, sizeof(header) - 1);
    +           }
    +   }
    +   data->keys[k] = 0;
    +}
    +
    +static void search_conf(void)
    +{
    +   struct symbol **sym_arr;
    +   struct gstr res;
    +   struct gstr title;
    +   char *dialog_input;
    +   int dres, vscroll = 0, hscroll = 0;
    +   bool again;
    +   struct gstr sttext;
    +   struct subtitle_part stpart;
    +
    +   title = str_new();
    +   str_printf( &title, "Enter (sub)string or regexp to search for "
    +                         "(with or without \"%s\")", CONFIG_);
    +
    +again:
    +   dialog_clear();
    +   dres = dialog_inputbox("Search Configuration Parameter",
    +                         str_get(&title),
    +                         10, 75, "");
    +   switch (dres) {
    +   case 0:
    +           break;
    +   case 1:
    +           show_helptext("Search Configuration", search_help);
    +           goto again;
    +   default:
    +           str_free(&title);
    +           return;
    +   }
    +
    +   /* strip the prefix if necessary */
    +   dialog_input = dialog_input_result;
    +   if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
    +           dialog_input += strlen(CONFIG_);
    +
    +   sttext = str_new();
    +   str_printf(&sttext, "Search (%s)", dialog_input_result);
    +   stpart.text = str_get(&sttext);
    +   list_add_tail(&stpart.entries, &trail);
    +
    +   sym_arr = sym_re_search(dialog_input);
    +   do {
    +           LIST_HEAD(head);
    +           struct menu *targets[JUMP_NB];
    +           int keys[JUMP_NB + 1], i;
    +           struct search_data data = {
    +                   .head = &head,
    +                   .targets = targets,
    +                   .keys = keys,
    +           };
    +           struct jump_key *pos, *tmp;
    +
    +           res = get_relations_str(sym_arr, &head);
    +           set_subtitle();
    +           dres = show_textbox_ext("Search Results", (char *)
    +                                   str_get(&res), 0, 0, keys, &vscroll,
    +                                   &hscroll, &update_text, (void *)
    +                                   &data);
    +           again = false;
    +           for (i = 0; i < JUMP_NB && keys[i]; i++)
    +                   if (dres == keys[i]) {
    +                           conf(targets[i]->parent, targets[i]);
    +                           again = true;
    +                   }
    +           str_free(&res);
    +           list_for_each_entry_safe(pos, tmp, &head, entries)
    +                   free(pos);
    +   } while (again);
    +   free(sym_arr);
    +   str_free(&title);
    +   list_del(trail.prev);
    +   str_free(&sttext);
    +}
    +
    +static void build_conf(struct menu *menu)
    +{
    +   struct symbol *sym;
    +   struct property *prop;
    +   struct menu *child;
    +   int type, tmp, doint = 2;
    +   tristate val;
    +   char ch;
    +   bool visible;
    +
    +   /*
    +    * note: menu_is_visible() has side effect that it will
    +    * recalc the value of the symbol.
    +    */
    +   visible = menu_is_visible(menu);
    +   if (show_all_options && !menu_has_prompt(menu))
    +           return;
    +   else if (!show_all_options && !visible)
    +           return;
    +
    +   sym = menu->sym;
    +   prop = menu->prompt;
    +   if (!sym) {
    +           if (prop && menu != current_menu) {
    +                   const char *prompt = menu_get_prompt(menu);
    +                   switch (prop->type) {
    +                   case P_MENU:
    +                           child_count++;
    +                           if (single_menu_mode) {
    +                                   item_make("%s%*c%s",
    +                                             menu->data ? "-->" : "++>",
    +                                             indent + 1, ' ', prompt);
    +                           } else
    +                                   item_make("   %*c%s  %s",
    +                                             indent + 1, ' ', prompt,
    +                                             menu_is_empty(menu) ? "----" 
: "--->");
    +                           item_set_tag('m');
    +                           item_set_data(menu);
    +                           if (single_menu_mode && menu->data)
    +                                   goto conf_childs;
    +                           return;
    +                   case P_COMMENT:
    +                           if (prompt) {
    +                                   child_count++;
    +                                   item_make("   %*c*** %s ***", indent + 
1, ' ', prompt);
    +                                   item_set_tag(':');
    +                                   item_set_data(menu);
    +                           }
    +                           break;
    +                   default:
    +                           if (prompt) {
    +                                   child_count++;
    +                                   item_make("---%*c%s", indent + 1, ' ', 
prompt);
    +                                   item_set_tag(':');
    +                                   item_set_data(menu);
    +                           }
    +                   }
    +           } else
    +                   doint = 0;
    +           goto conf_childs;
    +   }
    +
    +   type = sym_get_type(sym);
    +   if (sym_is_choice(sym)) {
    +           struct symbol *def_sym = sym_get_choice_value(sym);
    +           struct menu *def_menu = NULL;
    +
    +           child_count++;
    +           for (child = menu->list; child; child = child->next) {
    +                   if (menu_is_visible(child) && child->sym == def_sym)
    +                           def_menu = child;
    +           }
    +
    +           val = sym_get_tristate_value(sym);
    +           if (sym_is_changable(sym)) {
    +                   switch (type) {
    +                   case S_BOOLEAN:
    +                           item_make("[%c]", val == no ? ' ' : '*');
    +                           break;
    +                   case S_TRISTATE:
    +                           switch (val) {
    +                           case yes: ch = '*'; break;
    +                           case mod: ch = 'M'; break;
    +                           default:  ch = ' '; break;
    +                           }
    +                           item_make("<%c>", ch);
    +                           break;
    +                   }
    +                   item_set_tag('t');
    +                   item_set_data(menu);
    +           } else {
    +                   item_make("   ");
    +                   item_set_tag(def_menu ? 't' : ':');
    +                   item_set_data(menu);
    +           }
    +
    +           item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
    +           if (val == yes) {
    +                   if (def_menu) {
    +                           item_add_str(" (%s)", 
menu_get_prompt(def_menu));
    +                           item_add_str("  --->");
    +                           if (def_menu->list) {
    +                                   indent += 2;
    +                                   build_conf(def_menu);
    +                                   indent -= 2;
    +                           }
    +                   }
    +                   return;
    +           }
    +   } else {
    +           if (menu == current_menu) {
    +                   item_make("---%*c%s", indent + 1, ' ', 
menu_get_prompt(menu));
    +                   item_set_tag(':');
    +                   item_set_data(menu);
    +                   goto conf_childs;
    +           }
    +           child_count++;
    +           val = sym_get_tristate_value(sym);
    +           if (sym_is_choice_value(sym) && val == yes) {
    +                   item_make("   ");
    +                   item_set_tag(':');
    +                   item_set_data(menu);
    +           } else {
    +                   switch (type) {
    +                   case S_BOOLEAN:
    +                           if (sym_is_changable(sym))
    +                                   item_make("[%c]", val == no ? ' ' : 
'*');
    +                           else
    +                                   item_make("-%c-", val == no ? ' ' : 
'*');
    +                           item_set_tag('t');
    +                           item_set_data(menu);
    +                           break;
    +                   case S_TRISTATE:
    +                           switch (val) {
    +                           case yes: ch = '*'; break;
    +                           case mod: ch = 'M'; break;
    +                           default:  ch = ' '; break;
    +                           }
    +                           if (sym_is_changable(sym)) {
    +                                   if (sym->rev_dep.tri == mod)
    +                                           item_make("{%c}", ch);
    +                                   else
    +                                           item_make("<%c>", ch);
    +                           } else
    +                                   item_make("-%c-", ch);
    +                           item_set_tag('t');
    +                           item_set_data(menu);
    +                           break;
    +                   default:
    +                           tmp = 2 + strlen(sym_get_string_value(sym)); /* 
() = 2 */
    +                           item_make("(%s)", sym_get_string_value(sym));
    +                           tmp = indent - tmp + 4;
    +                           if (tmp < 0)
    +                                   tmp = 0;
    +                           item_add_str("%*c%s%s", tmp, ' ', 
menu_get_prompt(menu),
    +                                        (sym_has_value(sym) || 
!sym_is_changable(sym)) ?
    +                                        "" : " (NEW)");
    +                           item_set_tag('s');
    +                           item_set_data(menu);
    +                           goto conf_childs;
    +                   }
    +           }
    +           item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
    +                     (sym_has_value(sym) || !sym_is_changable(sym)) ?
    +                     "" : " (NEW)");
    +           if (menu->prompt->type == P_MENU) {
    +                   item_add_str("  %s", menu_is_empty(menu) ? "----" : 
"--->");
    +                   return;
    +           }
    +   }
    +
    +conf_childs:
    +   indent += doint;
    +   for (child = menu->list; child; child = child->next)
    +           build_conf(child);
    +   indent -= doint;
    +}
    +
    +static void conf(struct menu *menu, struct menu *active_menu)
    +{
    +   struct menu *submenu;
    +   const char *prompt = menu_get_prompt(menu);
    +   struct subtitle_part stpart;
    +   struct symbol *sym;
    +   int res;
    +   int s_scroll = 0;
    +
    +   if (menu != &rootmenu)
    +           stpart.text = menu_get_prompt(menu);
    +   else
    +           stpart.text = NULL;
    +   list_add_tail(&stpart.entries, &trail);
    +
    +   while (1) {
    +           item_reset();
    +           current_menu = menu;
    +           build_conf(menu);
    +           if (!child_count)
    +                   break;
    +           set_subtitle();
    +           dialog_clear();
    +           res = dialog_menu(prompt ? prompt : "Main Menu",
    +                             menu_instructions,
    +                             active_menu, &s_scroll);
    +           if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
    +                   break;
    +           if (item_count() != 0) {
    +                   if (!item_activate_selected())
    +                           continue;
    +                   if (!item_tag())
    +                           continue;
    +           }
    +           submenu = item_data();
    +           active_menu = item_data();
    +           if (submenu)
    +                   sym = submenu->sym;
    +           else
    +                   sym = NULL;
    +
    +           switch (res) {
    +           case 0:
    +                   switch (item_tag()) {
    +                   case 'm':
    +                           if (single_menu_mode)
    +                                   submenu->data = (void *) (long) 
!submenu->data;
    +                           else
    +                                   conf(submenu, NULL);
    +                           break;
    +                   case 't':
    +                           if (sym_is_choice(sym) && 
sym_get_tristate_value(sym) == yes)
    +                                   conf_choice(submenu);
    +                           else if (submenu->prompt->type == P_MENU)
    +                                   conf(submenu, NULL);
    +                           break;
    +                   case 's':
    +                           conf_string(submenu);
    +                           break;
    +                   }
    +                   break;
    +           case 2:
    +                   if (sym)
    +                           show_help(submenu);
    +                   else {
    +                           reset_subtitle();
    +                           show_helptext("README", mconf_readme);
    +                   }
    +                   break;
    +           case 3:
    +                   reset_subtitle();
    +                   conf_save();
    +                   break;
    +           case 4:
    +                   reset_subtitle();
    +                   conf_load();
    +                   break;
    +           case 5:
    +                   if (item_is_tag('t')) {
    +                           if (sym_set_tristate_value(sym, yes))
    +                                   break;
    +                           if (sym_set_tristate_value(sym, mod))
    +                                   show_textbox(NULL, setmod_text, 6, 74);
    +                   }
    +                   break;
    +           case 6:
    +                   if (item_is_tag('t'))
    +                           sym_set_tristate_value(sym, no);
    +                   break;
    +           case 7:
    +                   if (item_is_tag('t'))
    +                           sym_set_tristate_value(sym, mod);
    +                   break;
    +           case 8:
    +                   if (item_is_tag('t'))
    +                           sym_toggle_tristate_value(sym);
    +                   else if (item_is_tag('m'))
    +                           conf(submenu, NULL);
    +                   break;
    +           case 9:
    +                   search_conf();
    +                   break;
    +           case 10:
    +                   show_all_options = !show_all_options;
    +                   break;
    +           }
    +   }
    +
    +   list_del(trail.prev);
    +}
    +
    +static int show_textbox_ext(const char *title, char *text, int r, int c, 
int
    +                       *keys, int *vscroll, int *hscroll, update_text_fn
    +                       update_text, void *data)
    +{
    +   dialog_clear();
    +   return dialog_textbox(title, text, r, c, keys, vscroll, hscroll,
    +                         update_text, data);
    +}
    +
    +static void show_textbox(const char *title, const char *text, int r, int c)
    +{
    +   show_textbox_ext(title, (char *) text, r, c, (int []) {0}, NULL, NULL,
    +                    NULL, NULL);
    +}
    +
    +static void show_helptext(const char *title, const char *text)
    +{
    +   show_textbox(title, text, 0, 0);
    +}
    +
    +static void conf_message_callback(const char *s)
    +{
    +   if (save_and_exit) {
    +           if (!silent)
    +                   printf("%s", s);
    +   } else {
    +           show_textbox(NULL, s, 6, 60);
    +   }
    +}
    +
    +static void show_help(struct menu *menu)
    +{
    +   struct gstr help = str_new();
    +
    +   help.max_width = getmaxx(stdscr) - 10;
    +   menu_get_ext_help(menu, &help);
    +
    +   show_helptext(menu_get_prompt(menu), str_get(&help));
    +   str_free(&help);
    +}
    +
    +static void conf_choice(struct menu *menu)
    +{
    +   const char *prompt = menu_get_prompt(menu);
    +   struct menu *child;
    +   struct symbol *active;
    +
    +   active = sym_get_choice_value(menu->sym);
    +   while (1) {
    +           int res;
    +           int selected;
    +           item_reset();
    +
    +           current_menu = menu;
    +           for (child = menu->list; child; child = child->next) {
    +                   if (!menu_is_visible(child))
    +                           continue;
    +                   if (child->sym)
    +                           item_make("%s", menu_get_prompt(child));
    +                   else {
    +                           item_make("*** %s ***", menu_get_prompt(child));
    +                           item_set_tag(':');
    +                   }
    +                   item_set_data(child);
    +                   if (child->sym == active)
    +                           item_set_selected(1);
    +                   if (child->sym == sym_get_choice_value(menu->sym))
    +                           item_set_tag('X');
    +           }
    +           dialog_clear();
    +           res = dialog_checklist(prompt ? prompt : "Main Menu",
    +                                   radiolist_instructions,
    +                                   MENUBOX_HEIGTH_MIN,
    +                                   MENUBOX_WIDTH_MIN,
    +                                   CHECKLIST_HEIGTH_MIN);
    +           selected = item_activate_selected();
    +           switch (res) {
    +           case 0:
    +                   if (selected) {
    +                           child = item_data();
    +                           if (!child->sym)
    +                                   break;
    +
    +                           sym_set_tristate_value(child->sym, yes);
    +                   }
    +                   return;
    +           case 1:
    +                   if (selected) {
    +                           child = item_data();
    +                           show_help(child);
    +                           active = child->sym;
    +                   } else
    +                           show_help(menu);
    +                   break;
    +           case KEY_ESC:
    +                   return;
    +           case -ERRDISPLAYTOOSMALL:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void conf_string(struct menu *menu)
    +{
    +   const char *prompt = menu_get_prompt(menu);
    +
    +   while (1) {
    +           int res;
    +           const char *heading;
    +
    +           switch (sym_get_type(menu->sym)) {
    +           case S_INT:
    +                   heading = inputbox_instructions_int;
    +                   break;
    +           case S_HEX:
    +                   heading = inputbox_instructions_hex;
    +                   break;
    +           case S_STRING:
    +                   heading = inputbox_instructions_string;
    +                   break;
    +           default:
    +                   heading = "Internal mconf error!";
    +           }
    +           dialog_clear();
    +           res = dialog_inputbox(prompt ? prompt : "Main Menu",
    +                                 heading, 10, 75,
    +                                 sym_get_string_value(menu->sym));
    +           switch (res) {
    +           case 0:
    +                   if (sym_set_string_value(menu->sym, 
dialog_input_result))
    +                           return;
    +                   show_textbox(NULL, "You have made an invalid entry.", 
5, 43);
    +                   break;
    +           case 1:
    +                   show_help(menu);
    +                   break;
    +           case KEY_ESC:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void conf_load(void)
    +{
    +
    +   while (1) {
    +           int res;
    +           dialog_clear();
    +           res = dialog_inputbox(NULL, load_config_text,
    +                                 11, 55, filename);
    +           switch(res) {
    +           case 0:
    +                   if (!dialog_input_result[0])
    +                           return;
    +                   if (!conf_read(dialog_input_result)) {
    +                           set_config_filename(dialog_input_result);
    +                           sym_set_change_count(1);
    +                           return;
    +                   }
    +                   show_textbox(NULL, "File does not exist!", 5, 38);
    +                   break;
    +           case 1:
    +                   show_helptext("Load Alternate Configuration", 
load_config_help);
    +                   break;
    +           case KEY_ESC:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void conf_save(void)
    +{
    +   while (1) {
    +           int res;
    +           dialog_clear();
    +           res = dialog_inputbox(NULL, save_config_text,
    +                                 11, 55, filename);
    +           switch(res) {
    +           case 0:
    +                   if (!dialog_input_result[0])
    +                           return;
    +                   if (!conf_write(dialog_input_result)) {
    +                           set_config_filename(dialog_input_result);
    +                           return;
    +                   }
    +                   show_textbox(NULL, "Can't create file!", 5, 60);
    +                   break;
    +           case 1:
    +                   show_helptext("Save Alternate Configuration", 
save_config_help);
    +                   break;
    +           case KEY_ESC:
    +                   return;
    +           }
    +   }
    +}
    +
    +static int handle_exit(void)
    +{
    +   int res;
    +
    +   save_and_exit = 1;
    +   reset_subtitle();
    +   dialog_clear();
    +   if (conf_get_changed())
    +           res = dialog_yesno(NULL,
    +                              "Do you wish to save your new 
configuration?\n"
    +                                "(Press <ESC><ESC> to continue kernel 
configuration.)",
    +                              6, 60);
    +   else
    +           res = -1;
    +
    +   end_dialog(saved_x, saved_y);
    +
    +   switch (res) {
    +   case 0:
    +           if (conf_write(filename)) {
    +                   fprintf(stderr, "\n\n"
    +                                     "Error while writing of the 
configuration.\n"
    +                                     "Your configuration changes were NOT 
saved."
    +                                     "\n\n");
    +                   return 1;
    +           }
    +           conf_write_autoconf(0);
    +           /* fall through */
    +   case -1:
    +           if (!silent)
    +                   printf("\n\n"
    +                            "*** End of the configuration.\n"
    +                            "*** Execute 'make' to start the build or try 
'make help'."
    +                            "\n\n");
    +           res = 0;
    +           break;
    +   default:
    +           if (!silent)
    +                   fprintf(stderr, "\n\n"
    +                                     "Your configuration changes were NOT 
saved."
    +                                     "\n\n");
    +           if (res != KEY_ESC)
    +                   res = 0;
    +   }
    +
    +   return res;
    +}
    +
    +static void sig_handler(int signo)
    +{
    +   exit(handle_exit());
    +}
    +
    +int main(int ac, char **av)
    +{
    +   char *mode;
    +   int res;
    +
    +   signal(SIGINT, sig_handler);
    +
    +   if (ac > 1 && strcmp(av[1], "-s") == 0) {
    +           silent = 1;
    +           /* Silence conf_read() until the real callback is set up */
    +           conf_set_message_callback(NULL);
    +           av++;
    +   }
    +   conf_parse(av[1]);
    +   conf_read(NULL);
    +
    +   mode = getenv("MENUCONFIG_MODE");
    +   if (mode) {
    +           if (!strcasecmp(mode, "single_menu"))
    +                   single_menu_mode = 1;
    +   }
    +
    +   if (init_dialog(NULL)) {
    +           fprintf(stderr, "Your display is too small to run 
Menuconfig!\n");
    +           fprintf(stderr, "It must be at least 19 lines by 80 
columns.\n");
    +           return 1;
    +   }
    +
    +   set_config_filename(conf_get_configname());
    +   conf_set_message_callback(conf_message_callback);
    +   do {
    +           conf(&rootmenu, NULL);
    +           res = handle_exit();
    +   } while (res == KEY_ESC);
    +
    +   return res;
    +}
    diff --git a/support/kconfig.new/menu.c b/support/kconfig.new/menu.c
    new file mode 100644
    index 0000000..d9d1646
    --- /dev/null
    +++ b/support/kconfig.new/menu.c
    @@ -0,0 +1,867 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include <ctype.h>
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "lkc.h"
    +
    +static const char nohelp_text[] = "There is no help available for this 
option.";
    +
    +struct menu rootmenu;
    +static struct menu **last_entry_ptr;
    +
    +struct file *file_list;
    +struct file *current_file;
    +
    +void menu_warn(struct menu *menu, const char *fmt, ...)
    +{
    +   va_list ap;
    +   va_start(ap, fmt);
    +   fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno);
    +   vfprintf(stderr, fmt, ap);
    +   fprintf(stderr, "\n");
    +   va_end(ap);
    +}
    +
    +static void prop_warn(struct property *prop, const char *fmt, ...)
    +{
    +   va_list ap;
    +   va_start(ap, fmt);
    +   fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno);
    +   vfprintf(stderr, fmt, ap);
    +   fprintf(stderr, "\n");
    +   va_end(ap);
    +}
    +
    +void _menu_init(void)
    +{
    +   current_entry = current_menu = &rootmenu;
    +   last_entry_ptr = &rootmenu.list;
    +}
    +
    +void menu_add_entry(struct symbol *sym)
    +{
    +   struct menu *menu;
    +
    +   menu = xmalloc(sizeof(*menu));
    +   memset(menu, 0, sizeof(*menu));
    +   menu->sym = sym;
    +   menu->parent = current_menu;
    +   menu->file = current_file;
    +   menu->lineno = zconf_lineno();
    +
    +   *last_entry_ptr = menu;
    +   last_entry_ptr = &menu->next;
    +   current_entry = menu;
    +   if (sym)
    +           menu_add_symbol(P_SYMBOL, sym, NULL);
    +}
    +
    +struct menu *menu_add_menu(void)
    +{
    +   last_entry_ptr = &current_entry->list;
    +   return current_menu = current_entry;
    +}
    +
    +void menu_end_menu(void)
    +{
    +   last_entry_ptr = &current_menu->next;
    +   current_menu = current_menu->parent;
    +}
    +
    +/*
    + * Rewrites 'm' to 'm' && MODULES, so that it evaluates to 'n' when running
    + * without modules
    + */
    +static struct expr *rewrite_m(struct expr *e)
    +{
    +   if (!e)
    +           return e;
    +
    +   switch (e->type) {
    +   case E_NOT:
    +           e->left.expr = rewrite_m(e->left.expr);
    +           break;
    +   case E_OR:
    +   case E_AND:
    +           e->left.expr = rewrite_m(e->left.expr);
    +           e->right.expr = rewrite_m(e->right.expr);
    +           break;
    +   case E_SYMBOL:
    +           /* change 'm' into 'm' && MODULES */
    +           if (e->left.sym == &symbol_mod)
    +                   return expr_alloc_and(e, 
expr_alloc_symbol(modules_sym));
    +           break;
    +   default:
    +           break;
    +   }
    +   return e;
    +}
    +
    +void menu_add_dep(struct expr *dep)
    +{
    +   current_entry->dep = expr_alloc_and(current_entry->dep, dep);
    +}
    +
    +void menu_set_type(int type)
    +{
    +   struct symbol *sym = current_entry->sym;
    +
    +   if (sym->type == type)
    +           return;
    +   if (sym->type == S_UNKNOWN) {
    +           sym->type = type;
    +           return;
    +   }
    +   menu_warn(current_entry,
    +           "ignoring type redefinition of '%s' from '%s' to '%s'",
    +           sym->name ? sym->name : "<choice>",
    +           sym_type_name(sym->type), sym_type_name(type));
    +}
    +
    +static struct property *menu_add_prop(enum prop_type type, char *prompt, 
struct expr *expr, struct expr *dep)
    +{
    +   struct property *prop = prop_alloc(type, current_entry->sym);
    +
    +   prop->menu = current_entry;
    +   prop->expr = expr;
    +   prop->visible.expr = dep;
    +
    +   if (prompt) {
    +           if (isspace(*prompt)) {
    +                   prop_warn(prop, "leading whitespace ignored");
    +                   while (isspace(*prompt))
    +                           prompt++;
    +           }
    +           if (current_entry->prompt && current_entry != &rootmenu)
    +                   prop_warn(prop, "prompt redefined");
    +
    +           /* Apply all upper menus' visibilities to actual prompts. */
    +           if(type == P_PROMPT) {
    +                   struct menu *menu = current_entry;
    +
    +                   while ((menu = menu->parent) != NULL) {
    +                           struct expr *dup_expr;
    +
    +                           if (!menu->visibility)
    +                                   continue;
    +                           /*
    +                            * Do not add a reference to the
    +                            * menu's visibility expression but
    +                            * use a copy of it.  Otherwise the
    +                            * expression reduction functions
    +                            * will modify expressions that have
    +                            * multiple references which can
    +                            * cause unwanted side effects.
    +                            */
    +                           dup_expr = expr_copy(menu->visibility);
    +
    +                           prop->visible.expr
    +                                   = expr_alloc_and(prop->visible.expr,
    +                                                    dup_expr);
    +                   }
    +           }
    +
    +           current_entry->prompt = prop;
    +   }
    +   prop->text = prompt;
    +
    +   return prop;
    +}
    +
    +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct 
expr *dep)
    +{
    +   return menu_add_prop(type, prompt, NULL, dep);
    +}
    +
    +void menu_add_visibility(struct expr *expr)
    +{
    +   current_entry->visibility = expr_alloc_and(current_entry->visibility,
    +       expr);
    +}
    +
    +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr 
*dep)
    +{
    +   menu_add_prop(type, NULL, expr, dep);
    +}
    +
    +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr 
*dep)
    +{
    +   menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep);
    +}
    +
    +void menu_add_option_modules(void)
    +{
    +   if (modules_sym)
    +           zconf_error("symbol '%s' redefines option 'modules' already 
defined by symbol '%s'",
    +                       current_entry->sym->name, modules_sym->name);
    +   modules_sym = current_entry->sym;
    +}
    +
    +void menu_add_option_defconfig_list(void)
    +{
    +   if (!sym_defconfig_list)
    +           sym_defconfig_list = current_entry->sym;
    +   else if (sym_defconfig_list != current_entry->sym)
    +           zconf_error("trying to redefine defconfig symbol");
    +   sym_defconfig_list->flags |= SYMBOL_NO_WRITE;
    +}
    +
    +void menu_add_option_allnoconfig_y(void)
    +{
    +   current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
    +}
    +
    +static int menu_validate_number(struct symbol *sym, struct symbol *sym2)
    +{
    +   return sym2->type == S_INT || sym2->type == S_HEX ||
    +          (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name));
    +}
    +
    +static void sym_check_prop(struct symbol *sym)
    +{
    +   struct property *prop;
    +   struct symbol *sym2;
    +   char *use;
    +
    +   for (prop = sym->prop; prop; prop = prop->next) {
    +           switch (prop->type) {
    +           case P_DEFAULT:
    +                   if ((sym->type == S_STRING || sym->type == S_INT || 
sym->type == S_HEX) &&
    +                       prop->expr->type != E_SYMBOL)
    +                           prop_warn(prop,
    +                               "default for config symbol '%s'"
    +                               " must be a single symbol", sym->name);
    +                   if (prop->expr->type != E_SYMBOL)
    +                           break;
    +                   sym2 = prop_get_symbol(prop);
    +                   if (sym->type == S_HEX || sym->type == S_INT) {
    +                           if (!menu_validate_number(sym, sym2))
    +                                   prop_warn(prop,
    +                                       "'%s': number is invalid",
    +                                       sym->name);
    +                   }
    +                   if (sym_is_choice(sym)) {
    +                           struct property *choice_prop =
    +                                   sym_get_choice_prop(sym2);
    +
    +                           if (!choice_prop ||
    +                               prop_get_symbol(choice_prop) != sym)
    +                                   prop_warn(prop,
    +                                             "choice default symbol '%s' 
is not contained in the choice",
    +                                             sym2->name);
    +                   }
    +                   break;
    +           case P_SELECT:
    +           case P_IMPLY:
    +                   use = prop->type == P_SELECT ? "select" : "imply";
    +                   sym2 = prop_get_symbol(prop);
    +                   if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE)
    +                           prop_warn(prop,
    +                               "config symbol '%s' uses %s, but is "
    +                               "not bool or tristate", sym->name, use);
    +                   else if (sym2->type != S_UNKNOWN &&
    +                            sym2->type != S_BOOLEAN &&
    +                            sym2->type != S_TRISTATE)
    +                           prop_warn(prop,
    +                               "'%s' has wrong type. '%s' only "
    +                               "accept arguments of bool and "
    +                               "tristate type", sym2->name, use);
    +                   break;
    +           case P_RANGE:
    +                   if (sym->type != S_INT && sym->type != S_HEX)
    +                           prop_warn(prop, "range is only allowed "
    +                                           "for int or hex symbols");
    +                   if (!menu_validate_number(sym, prop->expr->left.sym) ||
    +                       !menu_validate_number(sym, prop->expr->right.sym))
    +                           prop_warn(prop, "range is invalid");
    +                   break;
    +           default:
    +                   ;
    +           }
    +   }
    +}
    +
    +void menu_finalize(struct menu *parent)
    +{
    +   struct menu *menu, *last_menu;
    +   struct symbol *sym;
    +   struct property *prop;
    +   struct expr *parentdep, *basedep, *dep, *dep2, **ep;
    +
    +   sym = parent->sym;
    +   if (parent->list) {
    +           /*
    +            * This menu node has children. We (recursively) process them
    +            * and propagate parent dependencies before moving on.
    +            */
    +
    +           if (sym && sym_is_choice(sym)) {
    +                   if (sym->type == S_UNKNOWN) {
    +                           /* find the first choice value to find out 
choice type */
    +                           current_entry = parent;
    +                           for (menu = parent->list; menu; menu = 
menu->next) {
    +                                   if (menu->sym && menu->sym->type != 
S_UNKNOWN) {
    +                                           menu_set_type(menu->sym->type);
    +                                           break;
    +                                   }
    +                           }
    +                   }
    +                   /* set the type of the remaining choice values */
    +                   for (menu = parent->list; menu; menu = menu->next) {
    +                           current_entry = menu;
    +                           if (menu->sym && menu->sym->type == S_UNKNOWN)
    +                                   menu_set_type(sym->type);
    +                   }
    +
    +                   /*
    +                    * Use the choice itself as the parent dependency of
    +                    * the contained items. This turns the mode of the
    +                    * choice into an upper bound on the visibility of the
    +                    * choice value symbols.
    +                    */
    +                   parentdep = expr_alloc_symbol(sym);
    +           } else if (parent->prompt)
    +                   /* Menu node for 'menu' */
    +                   parentdep = parent->prompt->visible.expr;
    +           else
    +                   /* Menu node for 'if' */
    +                   parentdep = parent->dep;
    +
    +           /* For each child menu node... */
    +           for (menu = parent->list; menu; menu = menu->next) {
    +                   /*
    +                    * Propagate parent dependencies to the child menu
    +                    * node, also rewriting and simplifying expressions
    +                    */
    +                   basedep = rewrite_m(menu->dep);
    +                   basedep = expr_transform(basedep);
    +                   basedep = expr_alloc_and(expr_copy(parentdep), basedep);
    +                   basedep = expr_eliminate_dups(basedep);
    +                   menu->dep = basedep;
    +
    +                   if (menu->sym)
    +                           /*
    +                            * Note: For symbols, all prompts are included
    +                            * too in the symbol's own property list
    +                            */
    +                           prop = menu->sym->prop;
    +                   else
    +                           /*
    +                            * For non-symbol menu nodes, we just need to
    +                            * handle the prompt
    +                            */
    +                           prop = menu->prompt;
    +
    +                   /* For each property... */
    +                   for (; prop; prop = prop->next) {
    +                           if (prop->menu != menu)
    +                                   /*
    +                                    * Two possibilities:
    +                                    *
    +                                    * 1. The property lacks dependencies
    +                                    *    and so isn't location-specific,
    +                                    *    e.g. an 'option'
    +                                    *
    +                                    * 2. The property belongs to a symbol
    +                                    *    defined in multiple locations and
    +                                    *    is from some other location. It
    +                                    *    will be handled there in that
    +                                    *    case.
    +                                    *
    +                                    * Skip the property.
    +                                    */
    +                                   continue;
    +
    +                           /*
    +                            * Propagate parent dependencies to the
    +                            * property's condition, rewriting and
    +                            * simplifying expressions at the same time
    +                            */
    +                           dep = rewrite_m(prop->visible.expr);
    +                           dep = expr_transform(dep);
    +                           dep = expr_alloc_and(expr_copy(basedep), dep);
    +                           dep = expr_eliminate_dups(dep);
    +                           if (menu->sym && menu->sym->type != S_TRISTATE)
    +                                   dep = expr_trans_bool(dep);
    +                           prop->visible.expr = dep;
    +
    +                           /*
    +                            * Handle selects and implies, which modify the
    +                            * dependencies of the selected/implied symbol
    +                            */
    +                           if (prop->type == P_SELECT) {
    +                                   struct symbol *es = 
prop_get_symbol(prop);
    +                                   es->rev_dep.expr = 
expr_alloc_or(es->rev_dep.expr,
    +                                                   
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
    +                           } else if (prop->type == P_IMPLY) {
    +                                   struct symbol *es = 
prop_get_symbol(prop);
    +                                   es->implied.expr = 
expr_alloc_or(es->implied.expr,
    +                                                   
expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep)));
    +                           }
    +                   }
    +           }
    +
    +           if (sym && sym_is_choice(sym))
    +                   expr_free(parentdep);
    +
    +           /*
    +            * Recursively process children in the same fashion before
    +            * moving on
    +            */
    +           for (menu = parent->list; menu; menu = menu->next)
    +                   menu_finalize(menu);
    +   } else if (sym) {
    +           /*
    +            * Automatic submenu creation. If sym is a symbol and A, B, C,
    +            * ... are consecutive items (symbols, menus, ifs, etc.) that
    +            * all depend on sym, then the following menu structure is
    +            * created:
    +            *
    +            *      sym
    +            *       +-A
    +            *       +-B
    +            *       +-C
    +            *       ...
    +            *
    +            * This also works recursively, giving the following structure
    +            * if A is a symbol and B depends on A:
    +            *
    +            *      sym
    +            *       +-A
    +            *       | +-B
    +            *       +-C
    +            *       ...
    +            */
    +
    +           basedep = parent->prompt ? parent->prompt->visible.expr : NULL;
    +           basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no);
    +           basedep = expr_eliminate_dups(expr_transform(basedep));
    +
    +           /* Examine consecutive elements after sym */
    +           last_menu = NULL;
    +           for (menu = parent->next; menu; menu = menu->next) {
    +                   dep = menu->prompt ? menu->prompt->visible.expr : 
menu->dep;
    +                   if (!expr_contains_symbol(dep, sym))
    +                           /* No dependency, quit */
    +                           break;
    +                   if (expr_depends_symbol(dep, sym))
    +                           /* Absolute dependency, put in submenu */
    +                           goto next;
    +
    +                   /*
    +                    * Also consider it a dependency on sym if our
    +                    * dependencies contain sym and are a "superset" of
    +                    * sym's dependencies, e.g. '(sym || Q) && R' when sym
    +                    * depends on R.
    +                    *
    +                    * Note that 'R' might be from an enclosing menu or if,
    +                    * making this a more common case than it might seem.
    +                    */
    +                   dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no);
    +                   dep = expr_eliminate_dups(expr_transform(dep));
    +                   dep2 = expr_copy(basedep);
    +                   expr_eliminate_eq(&dep, &dep2);
    +                   expr_free(dep);
    +                   if (!expr_is_yes(dep2)) {
    +                           /* Not superset, quit */
    +                           expr_free(dep2);
    +                           break;
    +                   }
    +                   /* Superset, put in submenu */
    +                   expr_free(dep2);
    +           next:
    +                   menu_finalize(menu);
    +                   menu->parent = parent;
    +                   last_menu = menu;
    +           }
    +           expr_free(basedep);
    +           if (last_menu) {
    +                   parent->list = parent->next;
    +                   parent->next = last_menu->next;
    +                   last_menu->next = NULL;
    +           }
    +
    +           sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, 
parent->dep);
    +   }
    +   for (menu = parent->list; menu; menu = menu->next) {
    +           if (sym && sym_is_choice(sym) &&
    +               menu->sym && !sym_is_choice_value(menu->sym)) {
    +                   current_entry = menu;
    +                   menu->sym->flags |= SYMBOL_CHOICEVAL;
    +                   if (!menu->prompt)
    +                           menu_warn(menu, "choice value must have a 
prompt");
    +                   for (prop = menu->sym->prop; prop; prop = prop->next) {
    +                           if (prop->type == P_DEFAULT)
    +                                   prop_warn(prop, "defaults for choice "
    +                                             "values not supported");
    +                           if (prop->menu == menu)
    +                                   continue;
    +                           if (prop->type == P_PROMPT &&
    +                               prop->menu->parent->sym != sym)
    +                                   prop_warn(prop, "choice value used 
outside its choice group");
    +                   }
    +                   /* Non-tristate choice values of tristate choices must
    +                    * depend on the choice being set to Y. The choice
    +                    * values' dependencies were propagated to their
    +                    * properties above, so the change here must be re-
    +                    * propagated.
    +                    */
    +                   if (sym->type == S_TRISTATE && menu->sym->type != 
S_TRISTATE) {
    +                           basedep = expr_alloc_comp(E_EQUAL, sym, 
&symbol_yes);
    +                           menu->dep = expr_alloc_and(basedep, menu->dep);
    +                           for (prop = menu->sym->prop; prop; prop = 
prop->next) {
    +                                   if (prop->menu != menu)
    +                                           continue;
    +                                   prop->visible.expr = 
expr_alloc_and(expr_copy(basedep),
    +                                                                       
prop->visible.expr);
    +                           }
    +                   }
    +                   menu_add_symbol(P_CHOICE, sym, NULL);
    +                   prop = sym_get_choice_prop(sym);
    +                   for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr)
    +                           ;
    +                   *ep = expr_alloc_one(E_LIST, NULL);
    +                   (*ep)->right.sym = menu->sym;
    +           }
    +
    +           /*
    +            * This code serves two purposes:
    +            *
    +            * (1) Flattening 'if' blocks, which do not specify a submenu
    +            *     and only add dependencies.
    +            *
    +            *     (Automatic submenu creation might still create a submenu
    +            *     from an 'if' before this code runs.)
    +            *
    +            * (2) "Undoing" any automatic submenus created earlier below
    +            *     promptless symbols.
    +            *
    +            * Before:
    +            *
    +            *      A
    +            *      if ... (or promptless symbol)
    +            *       +-B
    +            *       +-C
    +            *      D
    +            *
    +            * After:
    +            *
    +            *      A
    +            *      if ... (or promptless symbol)
    +            *      B
    +            *      C
    +            *      D
    +            */
    +           if (menu->list && (!menu->prompt || !menu->prompt->text)) {
    +                   for (last_menu = menu->list; ; last_menu = 
last_menu->next) {
    +                           last_menu->parent = parent;
    +                           if (!last_menu->next)
    +                                   break;
    +                   }
    +                   last_menu->next = menu->next;
    +                   menu->next = menu->list;
    +                   menu->list = NULL;
    +           }
    +   }
    +
    +   if (sym && !(sym->flags & SYMBOL_WARNED)) {
    +           if (sym->type == S_UNKNOWN)
    +                   menu_warn(parent, "config symbol defined without type");
    +
    +           if (sym_is_choice(sym) && !parent->prompt)
    +                   menu_warn(parent, "choice must have a prompt");
    +
    +           /* Check properties connected to this symbol */
    +           sym_check_prop(sym);
    +           sym->flags |= SYMBOL_WARNED;
    +   }
    +
    +   /*
    +    * For non-optional choices, add a reverse dependency (corresponding to
    +    * a select) of '<visibility> && m'. This prevents the user from
    +    * setting the choice mode to 'n' when the choice is visible.
    +    *
    +    * This would also work for non-choice symbols, but only non-optional
    +    * choices clear SYMBOL_OPTIONAL as of writing. Choices are implemented
    +    * as a type of symbol.
    +    */
    +   if (sym && !sym_is_optional(sym) && parent->prompt) {
    +           sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr,
    +                           expr_alloc_and(parent->prompt->visible.expr,
    +                                   expr_alloc_symbol(&symbol_mod)));
    +   }
    +}
    +
    +bool menu_has_prompt(struct menu *menu)
    +{
    +   if (!menu->prompt)
    +           return false;
    +   return true;
    +}
    +
    +/*
    + * Determine if a menu is empty.
    + * A menu is considered empty if it contains no or only
    + * invisible entries.
    + */
    +bool menu_is_empty(struct menu *menu)
    +{
    +   struct menu *child;
    +
    +   for (child = menu->list; child; child = child->next) {
    +           if (menu_is_visible(child))
    +                   return(false);
    +   }
    +   return(true);
    +}
    +
    +bool menu_is_visible(struct menu *menu)
    +{
    +   struct menu *child;
    +   struct symbol *sym;
    +   tristate visible;
    +
    +   if (!menu->prompt)
    +           return false;
    +
    +   if (menu->visibility) {
    +           if (expr_calc_value(menu->visibility) == no)
    +                   return false;
    +   }
    +
    +   sym = menu->sym;
    +   if (sym) {
    +           sym_calc_value(sym);
    +           visible = menu->prompt->visible.tri;
    +   } else
    +           visible = menu->prompt->visible.tri = 
expr_calc_value(menu->prompt->visible.expr);
    +
    +   if (visible != no)
    +           return true;
    +
    +   if (!sym || sym_get_tristate_value(menu->sym) == no)
    +           return false;
    +
    +   for (child = menu->list; child; child = child->next) {
    +           if (menu_is_visible(child)) {
    +                   if (sym)
    +                           sym->flags |= SYMBOL_DEF_USER;
    +                   return true;
    +           }
    +   }
    +
    +   return false;
    +}
    +
    +const char *menu_get_prompt(struct menu *menu)
    +{
    +   if (menu->prompt)
    +           return menu->prompt->text;
    +   else if (menu->sym)
    +           return menu->sym->name;
    +   return NULL;
    +}
    +
    +struct menu *menu_get_root_menu(struct menu *menu)
    +{
    +   return &rootmenu;
    +}
    +
    +struct menu *menu_get_parent_menu(struct menu *menu)
    +{
    +   enum prop_type type;
    +
    +   for (; menu != &rootmenu; menu = menu->parent) {
    +           type = menu->prompt ? menu->prompt->type : 0;
    +           if (type == P_MENU)
    +                   break;
    +   }
    +   return menu;
    +}
    +
    +bool menu_has_help(struct menu *menu)
    +{
    +   return menu->help != NULL;
    +}
    +
    +const char *menu_get_help(struct menu *menu)
    +{
    +   if (menu->help)
    +           return menu->help;
    +   else
    +           return "";
    +}
    +
    +static void get_prompt_str(struct gstr *r, struct property *prop,
    +                      struct list_head *head)
    +{
    +   int i, j;
    +   struct menu *submenu[8], *menu, *location = NULL;
    +   struct jump_key *jump = NULL;
    +
    +   str_printf(r, "Prompt: %s\n", prop->text);
    +   menu = prop->menu->parent;
    +   for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
    +           bool accessible = menu_is_visible(menu);
    +
    +           submenu[i++] = menu;
    +           if (location == NULL && accessible)
    +                   location = menu;
    +   }
    +   if (head && location) {
    +           jump = xmalloc(sizeof(struct jump_key));
    +
    +           if (menu_is_visible(prop->menu)) {
    +                   /*
    +                    * There is not enough room to put the hint at the
    +                    * beginning of the "Prompt" line. Put the hint on the
    +                    * last "Location" line even when it would belong on
    +                    * the former.
    +                    */
    +                   jump->target = prop->menu;
    +           } else
    +                   jump->target = location;
    +
    +           if (list_empty(head))
    +                   jump->index = 0;
    +           else
    +                   jump->index = list_entry(head->prev, struct jump_key,
    +                                            entries)->index + 1;
    +
    +           list_add_tail(&jump->entries, head);
    +   }
    +
    +   if (i > 0) {
    +           str_printf(r, "  Location:\n");
    +           for (j = 4; --i >= 0; j += 2) {
    +                   menu = submenu[i];
    +                   if (jump && menu == location)
    +                           jump->offset = strlen(r->s);
    +                   str_printf(r, "%*c-> %s", j, ' ',
    +                              menu_get_prompt(menu));
    +                   if (menu->sym) {
    +                           str_printf(r, " (%s [=%s])", menu->sym->name ?
    +                                   menu->sym->name : "<choice>",
    +                                   sym_get_string_value(menu->sym));
    +                   }
    +                   str_append(r, "\n");
    +           }
    +   }
    +}
    +
    +/*
    + * get property of type P_SYMBOL
    + */
    +static struct property *get_symbol_prop(struct symbol *sym)
    +{
    +   struct property *prop = NULL;
    +
    +   for_all_properties(sym, prop, P_SYMBOL)
    +           break;
    +   return prop;
    +}
    +
    +static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
    +                            enum prop_type tok, const char *prefix)
    +{
    +   bool hit = false;
    +   struct property *prop;
    +
    +   for_all_properties(sym, prop, tok) {
    +           if (!hit) {
    +                   str_append(r, prefix);
    +                   hit = true;
    +           } else
    +                   str_printf(r, " && ");
    +           expr_gstr_print(prop->expr, r);
    +   }
    +   if (hit)
    +           str_append(r, "\n");
    +}
    +
    +/*
    + * head is optional and may be NULL
    + */
    +static void get_symbol_str(struct gstr *r, struct symbol *sym,
    +               struct list_head *head)
    +{
    +   struct property *prop;
    +
    +   if (sym && sym->name) {
    +           str_printf(r, "Symbol: %s [=%s]\n", sym->name,
    +                      sym_get_string_value(sym));
    +           str_printf(r, "Type  : %s\n", sym_type_name(sym->type));
    +           if (sym->type == S_INT || sym->type == S_HEX) {
    +                   prop = sym_get_range_prop(sym);
    +                   if (prop) {
    +                           str_printf(r, "Range : ");
    +                           expr_gstr_print(prop->expr, r);
    +                           str_append(r, "\n");
    +                   }
    +           }
    +   }
    +   for_all_prompts(sym, prop)
    +           get_prompt_str(r, prop, head);
    +
    +   prop = get_symbol_prop(sym);
    +   if (prop) {
    +           str_printf(r, "  Defined at %s:%d\n", prop->menu->file->name,
    +                   prop->menu->lineno);
    +           if (!expr_is_yes(prop->visible.expr)) {
    +                   str_append(r, "  Depends on: ");
    +                   expr_gstr_print(prop->visible.expr, r);
    +                   str_append(r, "\n");
    +           }
    +   }
    +
    +   get_symbol_props_str(r, sym, P_SELECT, "  Selects: ");
    +   if (sym->rev_dep.expr) {
    +           expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "  Selected 
by [y]:\n");
    +           expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "  Selected 
by [m]:\n");
    +           expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "  Selected by 
[n]:\n");
    +   }
    +
    +   get_symbol_props_str(r, sym, P_IMPLY, "  Implies: ");
    +   if (sym->implied.expr) {
    +           expr_gstr_print_revdep(sym->implied.expr, r, yes, "  Implied by 
[y]:\n");
    +           expr_gstr_print_revdep(sym->implied.expr, r, mod, "  Implied by 
[m]:\n");
    +           expr_gstr_print_revdep(sym->implied.expr, r, no, "  Implied by 
[n]:\n");
    +   }
    +
    +   str_append(r, "\n\n");
    +}
    +
    +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head 
*head)
    +{
    +   struct symbol *sym;
    +   struct gstr res = str_new();
    +   int i;
    +
    +   for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
    +           get_symbol_str(&res, sym, head);
    +   if (!i)
    +           str_append(&res, "No matches found.\n");
    +   return res;
    +}
    +
    +
    +void menu_get_ext_help(struct menu *menu, struct gstr *help)
    +{
    +   struct symbol *sym = menu->sym;
    +   const char *help_text = nohelp_text;
    +
    +   if (menu_has_help(menu)) {
    +           if (sym->name)
    +                   str_printf(help, "%s%s:\n\n", CONFIG_, sym->name);
    +           help_text = menu_get_help(menu);
    +   }
    +   str_printf(help, "%s\n", help_text);
    +   if (sym)
    +           get_symbol_str(help, sym, NULL);
    +}
    diff --git a/support/kconfig.new/merge_config.sh 
b/support/kconfig.new/merge_config.sh
    new file mode 100755
    index 0000000..d924c51
    --- /dev/null
    +++ b/support/kconfig.new/merge_config.sh
    @@ -0,0 +1,189 @@
    +#!/bin/sh
    +# SPDX-License-Identifier: GPL-2.0
    +#
    +#  merge_config.sh - Takes a list of config fragment values, and merges
    +#  them one by one. Provides warnings on overridden values, and specified
    +#  values that did not make it to the resulting .config file (due to missed
    +#  dependencies or config symbol removal).
    +#
    +#  Portions reused from kconf_check and generate_cfg:
    +#  
http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check
    +#  
http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg
    +#
    +#  Copyright (c) 2009-2010 Wind River Systems, Inc.
    +#  Copyright 2011 Linaro
    +
    +clean_up() {
    +   rm -f $TMP_FILE
    +   rm -f $MERGE_FILE
    +   exit
    +}
    +trap clean_up HUP INT TERM
    +
    +usage() {
    +   echo "Usage: $0 [OPTIONS] [CONFIG [...]]"
    +   echo "  -h    display this help text"
    +   echo "  -m    only merge the fragments, do not execute the make command"
    +   echo "  -n    use allnoconfig instead of alldefconfig"
    +   echo "  -r    list redundant entries when merging fragments"
    +   echo "  -y    make builtin have precedence over modules"
    +   echo "  -O    dir to put generated output files.  Consider setting 
\$KCONFIG_CONFIG instead."
    +   echo
    +   echo "Used prefix: '$CONFIG_PREFIX'. You can redefine it with \$CONFIG_ 
environment variable."
    +}
    +
    +RUNMAKE=true
    +ALLTARGET=alldefconfig
    +WARNREDUN=false
    +BUILTIN=false
    +OUTPUT=.
    +CONFIG_PREFIX=${CONFIG_-CONFIG_}
    +
    +while true; do
    +   case $1 in
    +   "-n")
    +           ALLTARGET=allnoconfig
    +           shift
    +           continue
    +           ;;
    +   "-m")
    +           RUNMAKE=false
    +           shift
    +           continue
    +           ;;
    +   "-h")
    +           usage
    +           exit
    +           ;;
    +   "-r")
    +           WARNREDUN=true
    +           shift
    +           continue
    +           ;;
    +   "-y")
    +           BUILTIN=true
    +           shift
    +           continue
    +           ;;
    +   "-O")
    +           if [ -d $2 ];then
    +                   OUTPUT=$(echo $2 | sed 's/\/*$//')
    +           else
    +                   echo "output directory $2 does not exist" 1>&2
    +                   exit 1
    +           fi
    +           shift 2
    +           continue
    +           ;;
    +   *)
    +           break
    +           ;;
    +   esac
    +done
    +
    +if [ "$#" -lt 1 ] ; then
    +   usage
    +   exit
    +fi
    +
    +if [ -z "$KCONFIG_CONFIG" ]; then
    +   if [ "$OUTPUT" != . ]; then
    +           KCONFIG_CONFIG=$(readlink -m -- "$OUTPUT/.config")
    +   else
    +           KCONFIG_CONFIG=.config
    +   fi
    +fi
    +
    +INITFILE=$1
    +shift;
    +
    +if [ ! -r "$INITFILE" ]; then
    +   echo "The base file '$INITFILE' does not exist.  Exit." >&2
    +   exit 1
    +fi
    +
    +MERGE_LIST=$*
    +SED_CONFIG_EXP1="s/^\(${CONFIG_PREFIX}[a-zA-Z0-9_]*\)=.*/\1/p"
    +SED_CONFIG_EXP2="s/^# \(${CONFIG_PREFIX}[a-zA-Z0-9_]*\) is not set$/\1/p"
    +
    +TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX)
    +MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX)
    +
    +echo "Using $INITFILE as base"
    +cat $INITFILE > $TMP_FILE
    +
    +# Merge files, printing warnings on overridden values
    +for ORIG_MERGE_FILE in $MERGE_LIST ; do
    +   echo "Merging $ORIG_MERGE_FILE"
    +   if [ ! -r "$ORIG_MERGE_FILE" ]; then
    +           echo "The merge file '$ORIG_MERGE_FILE' does not exist.  Exit." 
>&2
    +           exit 1
    +   fi
    +   cat $ORIG_MERGE_FILE > $MERGE_FILE
    +   CFG_LIST=$(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" 
$MERGE_FILE)
    +
    +   for CFG in $CFG_LIST ; do
    +           grep -q -w $CFG $TMP_FILE || continue
    +           PREV_VAL=$(grep -w $CFG $TMP_FILE)
    +           NEW_VAL=$(grep -w $CFG $MERGE_FILE)
    +           BUILTIN_FLAG=false
    +           if [ "$BUILTIN" = "true" ] && [ "${NEW_VAL#CONFIG_*=}" = "m" ] 
&& [ "${PREV_VAL#CONFIG_*=}" = "y" ]; then
    +                   echo Previous  value: $PREV_VAL
    +                   echo New value:       $NEW_VAL
    +                   echo -y passed, will not demote y to m
    +                   echo
    +                   BUILTIN_FLAG=true
    +           elif [ "x$PREV_VAL" != "x$NEW_VAL" ] ; then
    +                   echo Value of $CFG is redefined by fragment 
$ORIG_MERGE_FILE:
    +                   echo Previous  value: $PREV_VAL
    +                   echo New value:       $NEW_VAL
    +                   echo
    +           elif [ "$WARNREDUN" = "true" ]; then
    +                   echo Value of $CFG is redundant by fragment 
$ORIG_MERGE_FILE:
    +           fi
    +           if [ "$BUILTIN_FLAG" = "false" ]; then
    +                   sed -i "/$CFG[ =]/d" $TMP_FILE
    +           else
    +                   sed -i "/$CFG[ =]/d" $MERGE_FILE
    +           fi
    +   done
    +   cat $MERGE_FILE >> $TMP_FILE
    +done
    +
    +if [ "$RUNMAKE" = "false" ]; then
    +   cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG"
    +   echo "#"
    +   echo "# merged configuration written to $KCONFIG_CONFIG (needs make)"
    +   echo "#"
    +   clean_up
    +   exit
    +fi
    +
    +# If we have an output dir, setup the O= argument, otherwise leave
    +# it blank, since O=. will create an unnecessary ./source softlink
    +OUTPUT_ARG=""
    +if [ "$OUTPUT" != "." ] ; then
    +   OUTPUT_ARG="O=$OUTPUT"
    +fi
    +
    +
    +# Use the merged file as the starting point for:
    +# alldefconfig: Fills in any missing symbols with Kconfig default
    +# allnoconfig: Fills in any missing symbols with # CONFIG_* is not set
    +make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
    +
    +
    +# Check all specified config values took (might have missed-dependency 
issues)
    +for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" 
$TMP_FILE); do
    +
    +   REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
    +   ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG")
    +   if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
    +           echo "Value requested for $CFG not in final .config"
    +           echo "Requested value:  $REQUESTED_VAL"
    +           echo "Actual value:     $ACTUAL_VAL"
    +           echo ""
    +   fi
    +done
    +
    +clean_up
    diff --git a/support/kconfig.new/nconf-cfg.sh 
b/support/kconfig.new/nconf-cfg.sh
    new file mode 100755
    index 0000000..001559e
    --- /dev/null
    +++ b/support/kconfig.new/nconf-cfg.sh
    @@ -0,0 +1,47 @@
    +#!/bin/sh
    +# SPDX-License-Identifier: GPL-2.0
    +
    +PKG="ncursesw menuw panelw"
    +PKG2="ncurses menu panel"
    +
    +if [ -n "$(command -v pkg-config)" ]; then
    +   if pkg-config --exists $PKG; then
    +           echo cflags=\"$(pkg-config --cflags $PKG)\"
    +           echo libs=\"$(pkg-config --libs $PKG)\"
    +           exit 0
    +   fi
    +
    +   if pkg-config --exists $PKG2; then
    +           echo cflags=\"$(pkg-config --cflags $PKG2)\"
    +           echo libs=\"$(pkg-config --libs $PKG2)\"
    +           exit 0
    +   fi
    +fi
    +
    +# Check the default paths in case pkg-config is not installed.
    +# (Even if it is installed, some distributions such as openSUSE cannot
    +# find ncurses by pkg-config.)
    +if [ -f /usr/include/ncursesw/ncurses.h ]; then
    +   echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\"
    +   echo libs=\"-lncursesw -lmenuw -lpanelw\"
    +   exit 0
    +fi
    +
    +if [ -f /usr/include/ncurses/ncurses.h ]; then
    +   echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\"
    +   echo libs=\"-lncurses -lmenu -lpanel\"
    +   exit 0
    +fi
    +
    +if [ -f /usr/include/ncurses.h ]; then
    +   echo cflags=\"-D_GNU_SOURCE\"
    +   echo libs=\"-lncurses -lmenu -lpanel\"
    +   exit 0
    +fi
    +
    +echo >&2 "*"
    +echo >&2 "* Unable to find the ncurses package."
    +echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
    +echo >&2 "* depending on your distribution)."
    +echo >&2 "*"
    +exit 1
    diff --git a/support/kconfig.new/nconf.c b/support/kconfig.new/nconf.c
    new file mode 100644
    index 0000000..cbafe3b
    --- /dev/null
    +++ b/support/kconfig.new/nconf.c
    @@ -0,0 +1,1555 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@xxxxxxxxx>
    + *
    + * Derived from menuconfig.
    + */
    +#ifndef _GNU_SOURCE
    +#define _GNU_SOURCE
    +#endif
    +#include <string.h>
    +#include <stdlib.h>
    +
    +#include "lkc.h"
    +#include "nconf.h"
    +#include <ctype.h>
    +
    +static const char nconf_global_help[] =
    +"Help windows\n"
    +"------------\n"
    +"o  Global help:  Unless in a data entry window, pressing <F1> will give 
\n"
    +"   you the global help window, which you are just reading.\n"
    +"\n"
    +"o  A short version of the global help is available by pressing <F3>.\n"
    +"\n"
    +"o  Local help:  To get help related to the current menu entry, use any\n"
    +"   of <?> <h>, or if in a data entry window then press <F1>.\n"
    +"\n"
    +"\n"
    +"Menu entries\n"
    +"------------\n"
    +"This interface lets you select features and parameters for the kernel\n"
    +"build.  Kernel features can either be built-in, modularized, or 
removed.\n"
    +"Parameters must be entered as text or decimal or hexadecimal numbers.\n"
    +"\n"
    +"Menu entries beginning with following braces represent features that\n"
    +"  [ ]  can be built in or removed\n"
    +"  < >  can be built in, modularized or removed\n"
    +"  { }  can be built in or modularized, are selected by another feature\n"
    +"  - -  are selected by another feature\n"
    +"  XXX  cannot be selected.  Symbol Info <F2> tells you why.\n"
    +"*, M or whitespace inside braces means to build in, build as a module\n"
    +"or to exclude the feature respectively.\n"
    +"\n"
    +"To change any of these features, highlight it with the movement keys\n"
    +"listed below and press <y> to build it in, <m> to make it a module or\n"
    +"<n> to remove it.  You may press the <Space> key to cycle through the\n"
    +"available options.\n"
    +"\n"
    +"A trailing \"--->\" designates a submenu, a trailing \"----\" an\n"
    +"empty submenu.\n"
    +"\n"
    +"Menu navigation keys\n"
    +"----------------------------------------------------------------------\n"
    +"Linewise up                 <Up>\n"
    +"Linewise down               <Down>\n"
    +"Pagewise up                 <Page Up>\n"
    +"Pagewise down               <Page Down>\n"
    +"First entry                 <Home>\n"
    +"Last entry                  <End>\n"
    +"Enter a submenu             <Right>  <Enter>\n"
    +"Go back to parent menu      <Left>   <Esc>  <F5>\n"
    +"Close a help window         <Enter>  <Esc>  <F5>\n"
    +"Close entry window, apply   <Enter>\n"
    +"Close entry window, forget  <Esc>  <F5>\n"
    +"Start incremental, case-insensitive search for STRING in menu entries,\n"
    +"    no regex support, STRING is displayed in upper left corner\n"
    +"                            </>STRING\n"
    +"    Remove last character   <Backspace>\n"
    +"    Jump to next hit        <Down>\n"
    +"    Jump to previous hit    <Up>\n"
    +"Exit menu search mode       </>  <Esc>\n"
    +"Search for configuration variables with or without leading CONFIG_\n"
    +"                            <F8>RegExpr<Enter>\n"
    +"Verbose search help         <F8><F1>\n"
    +"----------------------------------------------------------------------\n"
    +"\n"
    +"Unless in a data entry window, key <1> may be used instead of <F1>,\n"
    +"<2> instead of <F2>, etc.\n"
    +"\n"
    +"\n"
    +"Radiolist (Choice list)\n"
    +"-----------------------\n"
    +"Use the movement keys listed above to select the option you wish to set\n"
    +"and press <Space>.\n"
    +"\n"
    +"\n"
    +"Data entry\n"
    +"----------\n"
    +"Enter the requested information and press <Enter>.  Hexadecimal values\n"
    +"may be entered without the \"0x\" prefix.\n"
    +"\n"
    +"\n"
    +"Text Box (Help Window)\n"
    +"----------------------\n"
    +"Use movement keys as listed in table above.\n"
    +"\n"
    +"Press any of <Enter> <Esc> <q> <F5> <F9> to exit.\n"
    +"\n"
    +"\n"
    +"Alternate configuration files\n"
    +"-----------------------------\n"
    +"nconfig supports switching between different configurations.\n"
    +"Press <F6> to save your current configuration.  Press <F7> and enter\n"
    +"a file name to load a previously saved configuration.\n"
    +"\n"
    +"\n"
    +"Terminal configuration\n"
    +"----------------------\n"
    +"If you use nconfig in a xterm window, make sure your TERM environment\n"
    +"variable specifies a terminal configuration which supports at least\n"
    +"16 colors.  Otherwise nconfig will look rather bad.\n"
    +"\n"
    +"If the \"stty size\" command reports the current terminalsize 
correctly,\n"
    +"nconfig will adapt to sizes larger than the traditional 80x25 
\"standard\"\n"
    +"and display longer menus properly.\n"
    +"\n"
    +"\n"
    +"Single menu mode\n"
    +"----------------\n"
    +"If you prefer to have all of the menu entries listed in a single menu,\n"
    +"rather than the default multimenu hierarchy, run nconfig with\n"
    +"NCONFIG_MODE environment variable set to single_menu.  Example:\n"
    +"\n"
    +"make NCONFIG_MODE=single_menu nconfig\n"
    +"\n"
    +"<Enter> will then unfold the appropriate category, or fold it if it\n"
    +"is already unfolded.  Folded menu entries will be designated by a\n"
    +"leading \"++>\" and unfolded entries by a leading \"-->\".\n"
    +"\n"
    +"Note that this mode can eventually be a little more CPU expensive than\n"
    +"the default mode, especially with a larger number of unfolded submenus.\n"
    +"\n",
    +menu_no_f_instructions[] =
    +"Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
    +"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
    +"\n"
    +"Use the following keys to navigate the menus:\n"
    +"Move up or down with <Up> and <Down>.\n"
    +"Enter a submenu with <Enter> or <Right>.\n"
    +"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
    +"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
    +"Pressing <Space> cycles through the available options.\n"
    +"To search for menu entries press </>.\n"
    +"<Esc> always leaves the current window.\n"
    +"\n"
    +"You do not have function keys support.\n"
    +"Press <1> instead of <F1>, <2> instead of <F2>, etc.\n"
    +"For verbose global help use key <1>.\n"
    +"For help related to the current menu entry press <?> or <h>.\n",
    +menu_instructions[] =
    +"Legend:  [*] built-in  [ ] excluded  <M> module  < > module capable.\n"
    +"Submenus are designated by a trailing \"--->\", empty ones by \"----\".\n"
    +"\n"
    +"Use the following keys to navigate the menus:\n"
    +"Move up or down with <Up> or <Down>.\n"
    +"Enter a submenu with <Enter> or <Right>.\n"
    +"Exit a submenu to its parent menu with <Esc> or <Left>.\n"
    +"Pressing <y> includes, <n> excludes, <m> modularizes features.\n"
    +"Pressing <Space> cycles through the available options.\n"
    +"To search for menu entries press </>.\n"
    +"<Esc> always leaves the current window.\n"
    +"\n"
    +"Pressing <1> may be used instead of <F1>, <2> instead of <F2>, etc.\n"
    +"For verbose global help press <F1>.\n"
    +"For help related to the current menu entry press <?> or <h>.\n",
    +radiolist_instructions[] =
    +"Press <Up>, <Down>, <Home> or <End> to navigate a radiolist, select\n"
    +"with <Space>.\n"
    +"For help related to the current entry press <?> or <h>.\n"
    +"For global help press <F1>.\n",
    +inputbox_instructions_int[] =
    +"Please enter a decimal value.\n"
    +"Fractions will not be accepted.\n"
    +"Press <Enter> to apply, <Esc> to cancel.",
    +inputbox_instructions_hex[] =
    +"Please enter a hexadecimal value.\n"
    +"Press <Enter> to apply, <Esc> to cancel.",
    +inputbox_instructions_string[] =
    +"Please enter a string value.\n"
    +"Press <Enter> to apply, <Esc> to cancel.",
    +setmod_text[] =
    +"This feature depends on another feature which has been configured as a\n"
    +"module.  As a result, the current feature will be built as a module too.",
    +load_config_text[] =
    +"Enter the name of the configuration file you wish to load.\n"
    +"Accept the name shown to restore the configuration you last\n"
    +"retrieved.  Leave empty to abort.",
    +load_config_help[] =
    +"For various reasons, one may wish to keep several different\n"
    +"configurations available on a single machine.\n"
    +"\n"
    +"If you have saved a previous configuration in a file other than the\n"
    +"default one, entering its name here will allow you to load and modify\n"
    +"that configuration.\n"
    +"\n"
    +"Leave empty to abort.\n",
    +save_config_text[] =
    +"Enter a filename to which this configuration should be saved\n"
    +"as an alternate.  Leave empty to abort.",
    +save_config_help[] =
    +"For various reasons, one may wish to keep several different\n"
    +"configurations available on a single machine.\n"
    +"\n"
    +"Entering a file name here will allow you to later retrieve, modify\n"
    +"and use the current configuration as an alternate to whatever\n"
    +"configuration options you have selected at that time.\n"
    +"\n"
    +"Leave empty to abort.\n",
    +search_help[] =
    +"Search for symbols (configuration variable names CONFIG_*) and display\n"
    +"their relations.  Regular expressions are supported.\n"
    +"Example:  Search for \"^FOO\".\n"
    +"Result:\n"
    +"-----------------------------------------------------------------\n"
    +"Symbol: FOO [ = m]\n"
    +"Prompt: Foo bus is used to drive the bar HW\n"
    +"Defined at drivers/pci/Kconfig:47\n"
    +"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
    +"Location:\n"
    +"  -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
    +"    -> PCI support (PCI [ = y])\n"
    +"      -> PCI access mode (<choice> [ = y])\n"
    +"Selects: LIBCRC32\n"
    +"Selected by: BAR\n"
    +"-----------------------------------------------------------------\n"
    +"o  The line 'Prompt:' shows the text displayed for this symbol in\n"
    +"   the menu hierarchy.\n"
    +"o  The 'Defined at' line tells at what file / line number the symbol is\n"
    +"   defined.\n"
    +"o  The 'Depends on:' line lists symbols that need to be defined for\n"
    +"   this symbol to be visible and selectable in the menu.\n"
    +"o  The 'Location:' lines tell, where in the menu structure this symbol\n"
    +"   is located.  A location followed by a [ = y] indicates that this is\n"
    +"   a selectable menu item, and the current value is displayed inside\n"
    +"   brackets.\n"
    +"o  The 'Selects:' line tells, what symbol will be automatically 
selected\n"
    +"   if this symbol is selected (y or m).\n"
    +"o  The 'Selected by' line tells what symbol has selected this symbol.\n"
    +"\n"
    +"Only relevant lines are shown.\n"
    +"\n\n"
    +"Search examples:\n"
    +"USB  => find all symbols containing USB\n"
    +"^USB => find all symbols starting with USB\n"
    +"USB$ => find all symbols ending with USB\n"
    +"\n";
    +
    +struct mitem {
    +   char str[256];
    +   char tag;
    +   void *usrptr;
    +   int is_visible;
    +};
    +
    +#define MAX_MENU_ITEMS 4096
    +static int show_all_items;
    +static int indent;
    +static struct menu *current_menu;
    +static int child_count;
    +static int single_menu_mode;
    +/* the window in which all information appears */
    +static WINDOW *main_window;
    +/* the largest size of the menu window */
    +static int mwin_max_lines;
    +static int mwin_max_cols;
    +/* the window in which we show option buttons */
    +static MENU *curses_menu;
    +static ITEM *curses_menu_items[MAX_MENU_ITEMS];
    +static struct mitem k_menu_items[MAX_MENU_ITEMS];
    +static int items_num;
    +static int global_exit;
    +/* the currently selected button */
    +static const char *current_instructions = menu_instructions;
    +
    +static char *dialog_input_result;
    +static int dialog_input_result_len;
    +
    +static void conf(struct menu *menu);
    +static void conf_choice(struct menu *menu);
    +static void conf_string(struct menu *menu);
    +static void conf_load(void);
    +static void conf_save(void);
    +static void show_help(struct menu *menu);
    +static int do_exit(void);
    +static void setup_windows(void);
    +static void search_conf(void);
    +
    +typedef void (*function_key_handler_t)(int *key, struct menu *menu);
    +static void handle_f1(int *key, struct menu *current_item);
    +static void handle_f2(int *key, struct menu *current_item);
    +static void handle_f3(int *key, struct menu *current_item);
    +static void handle_f4(int *key, struct menu *current_item);
    +static void handle_f5(int *key, struct menu *current_item);
    +static void handle_f6(int *key, struct menu *current_item);
    +static void handle_f7(int *key, struct menu *current_item);
    +static void handle_f8(int *key, struct menu *current_item);
    +static void handle_f9(int *key, struct menu *current_item);
    +
    +struct function_keys {
    +   const char *key_str;
    +   const char *func;
    +   function_key key;
    +   function_key_handler_t handler;
    +};
    +
    +static const int function_keys_num = 9;
    +static struct function_keys function_keys[] = {
    +   {
    +           .key_str = "F1",
    +           .func = "Help",
    +           .key = F_HELP,
    +           .handler = handle_f1,
    +   },
    +   {
    +           .key_str = "F2",
    +           .func = "SymInfo",
    +           .key = F_SYMBOL,
    +           .handler = handle_f2,
    +   },
    +   {
    +           .key_str = "F3",
    +           .func = "Help 2",
    +           .key = F_INSTS,
    +           .handler = handle_f3,
    +   },
    +   {
    +           .key_str = "F4",
    +           .func = "ShowAll",
    +           .key = F_CONF,
    +           .handler = handle_f4,
    +   },
    +   {
    +           .key_str = "F5",
    +           .func = "Back",
    +           .key = F_BACK,
    +           .handler = handle_f5,
    +   },
    +   {
    +           .key_str = "F6",
    +           .func = "Save",
    +           .key = F_SAVE,
    +           .handler = handle_f6,
    +   },
    +   {
    +           .key_str = "F7",
    +           .func = "Load",
    +           .key = F_LOAD,
    +           .handler = handle_f7,
    +   },
    +   {
    +           .key_str = "F8",
    +           .func = "SymSearch",
    +           .key = F_SEARCH,
    +           .handler = handle_f8,
    +   },
    +   {
    +           .key_str = "F9",
    +           .func = "Exit",
    +           .key = F_EXIT,
    +           .handler = handle_f9,
    +   },
    +};
    +
    +static void print_function_line(void)
    +{
    +   int i;
    +   int offset = 1;
    +   const int skip = 1;
    +   int lines = getmaxy(stdscr);
    +
    +   for (i = 0; i < function_keys_num; i++) {
    +           (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
    +           mvwprintw(main_window, lines-3, offset,
    +                           "%s",
    +                           function_keys[i].key_str);
    +           (void) wattrset(main_window, attributes[FUNCTION_TEXT]);
    +           offset += strlen(function_keys[i].key_str);
    +           mvwprintw(main_window, lines-3,
    +                           offset, "%s",
    +                           function_keys[i].func);
    +           offset += strlen(function_keys[i].func) + skip;
    +   }
    +   (void) wattrset(main_window, attributes[NORMAL]);
    +}
    +
    +/* help */
    +static void handle_f1(int *key, struct menu *current_item)
    +{
    +   show_scroll_win(main_window,
    +                   "Global help", nconf_global_help);
    +   return;
    +}
    +
    +/* symbole help */
    +static void handle_f2(int *key, struct menu *current_item)
    +{
    +   show_help(current_item);
    +   return;
    +}
    +
    +/* instructions */
    +static void handle_f3(int *key, struct menu *current_item)
    +{
    +   show_scroll_win(main_window,
    +                   "Short help",
    +                   current_instructions);
    +   return;
    +}
    +
    +/* config */
    +static void handle_f4(int *key, struct menu *current_item)
    +{
    +   int res = btn_dialog(main_window,
    +                   "Show all symbols?",
    +                   2,
    +                   "   <Show All>   ",
    +                   "<Don't show all>");
    +   if (res == 0)
    +           show_all_items = 1;
    +   else if (res == 1)
    +           show_all_items = 0;
    +
    +   return;
    +}
    +
    +/* back */
    +static void handle_f5(int *key, struct menu *current_item)
    +{
    +   *key = KEY_LEFT;
    +   return;
    +}
    +
    +/* save */
    +static void handle_f6(int *key, struct menu *current_item)
    +{
    +   conf_save();
    +   return;
    +}
    +
    +/* load */
    +static void handle_f7(int *key, struct menu *current_item)
    +{
    +   conf_load();
    +   return;
    +}
    +
    +/* search */
    +static void handle_f8(int *key, struct menu *current_item)
    +{
    +   search_conf();
    +   return;
    +}
    +
    +/* exit */
    +static void handle_f9(int *key, struct menu *current_item)
    +{
    +   do_exit();
    +   return;
    +}
    +
    +/* return != 0 to indicate the key was handles */
    +static int process_special_keys(int *key, struct menu *menu)
    +{
    +   int i;
    +
    +   if (*key == KEY_RESIZE) {
    +           setup_windows();
    +           return 1;
    +   }
    +
    +   for (i = 0; i < function_keys_num; i++) {
    +           if (*key == KEY_F(function_keys[i].key) ||
    +               *key == '0' + function_keys[i].key){
    +                   function_keys[i].handler(key, menu);
    +                   return 1;
    +           }
    +   }
    +
    +   return 0;
    +}
    +
    +static void clean_items(void)
    +{
    +   int i;
    +   for (i = 0; curses_menu_items[i]; i++)
    +           free_item(curses_menu_items[i]);
    +   bzero(curses_menu_items, sizeof(curses_menu_items));
    +   bzero(k_menu_items, sizeof(k_menu_items));
    +   items_num = 0;
    +}
    +
    +typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN,
    +   FIND_NEXT_MATCH_DOWN, FIND_NEXT_MATCH_UP} match_f;
    +
    +/* return the index of the matched item, or -1 if no such item exists */
    +static int get_mext_match(const char *match_str, match_f flag)
    +{
    +   int match_start = item_index(current_item(curses_menu));
    +   int index;
    +
    +   if (flag == FIND_NEXT_MATCH_DOWN)
    +           ++match_start;
    +   else if (flag == FIND_NEXT_MATCH_UP)
    +           --match_start;
    +
    +   index = match_start;
    +   index = (index + items_num) % items_num;
    +   while (true) {
    +           char *str = k_menu_items[index].str;
    +           if (strcasestr(str, match_str) != NULL)
    +                   return index;
    +           if (flag == FIND_NEXT_MATCH_UP ||
    +               flag == MATCH_TINKER_PATTERN_UP)
    +                   --index;
    +           else
    +                   ++index;
    +           index = (index + items_num) % items_num;
    +           if (index == match_start)
    +                   return -1;
    +   }
    +}
    +
    +/* Make a new item. */
    +static void item_make(struct menu *menu, char tag, const char *fmt, ...)
    +{
    +   va_list ap;
    +
    +   if (items_num > MAX_MENU_ITEMS-1)
    +           return;
    +
    +   bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
    +   k_menu_items[items_num].tag = tag;
    +   k_menu_items[items_num].usrptr = menu;
    +   if (menu != NULL)
    +           k_menu_items[items_num].is_visible =
    +                   menu_is_visible(menu);
    +   else
    +           k_menu_items[items_num].is_visible = 1;
    +
    +   va_start(ap, fmt);
    +   vsnprintf(k_menu_items[items_num].str,
    +             sizeof(k_menu_items[items_num].str),
    +             fmt, ap);
    +   va_end(ap);
    +
    +   if (!k_menu_items[items_num].is_visible)
    +           memcpy(k_menu_items[items_num].str, "XXX", 3);
    +
    +   curses_menu_items[items_num] = new_item(
    +                   k_menu_items[items_num].str,
    +                   k_menu_items[items_num].str);
    +   set_item_userptr(curses_menu_items[items_num],
    +                   &k_menu_items[items_num]);
    +   /*
    +   if (!k_menu_items[items_num].is_visible)
    +           item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
    +   */
    +
    +   items_num++;
    +   curses_menu_items[items_num] = NULL;
    +}
    +
    +/* very hackish. adds a string to the last item added */
    +static void item_add_str(const char *fmt, ...)
    +{
    +   va_list ap;
    +   int index = items_num-1;
    +   char new_str[256];
    +   char tmp_str[256];
    +
    +   if (index < 0)
    +           return;
    +
    +   va_start(ap, fmt);
    +   vsnprintf(new_str, sizeof(new_str), fmt, ap);
    +   va_end(ap);
    +   snprintf(tmp_str, sizeof(tmp_str), "%s%s",
    +                   k_menu_items[index].str, new_str);
    +   strncpy(k_menu_items[index].str,
    +           tmp_str,
    +           sizeof(k_menu_items[index].str));
    +
    +   free_item(curses_menu_items[index]);
    +   curses_menu_items[index] = new_item(
    +                   k_menu_items[index].str,
    +                   k_menu_items[index].str);
    +   set_item_userptr(curses_menu_items[index],
    +                   &k_menu_items[index]);
    +}
    +
    +/* get the tag of the currently selected item */
    +static char item_tag(void)
    +{
    +   ITEM *cur;
    +   struct mitem *mcur;
    +
    +   cur = current_item(curses_menu);
    +   if (cur == NULL)
    +           return 0;
    +   mcur = (struct mitem *) item_userptr(cur);
    +   return mcur->tag;
    +}
    +
    +static int curses_item_index(void)
    +{
    +   return  item_index(current_item(curses_menu));
    +}
    +
    +static void *item_data(void)
    +{
    +   ITEM *cur;
    +   struct mitem *mcur;
    +
    +   cur = current_item(curses_menu);
    +   if (!cur)
    +           return NULL;
    +   mcur = (struct mitem *) item_userptr(cur);
    +   return mcur->usrptr;
    +
    +}
    +
    +static int item_is_tag(char tag)
    +{
    +   return item_tag() == tag;
    +}
    +
    +static char filename[PATH_MAX+1];
    +static char menu_backtitle[PATH_MAX+128];
    +static const char *set_config_filename(const char *config_filename)
    +{
    +   int size;
    +
    +   size = snprintf(menu_backtitle, sizeof(menu_backtitle),
    +                   "%s - %s", config_filename, rootmenu.prompt->text);
    +   if (size >= sizeof(menu_backtitle))
    +           menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
    +
    +   size = snprintf(filename, sizeof(filename), "%s", config_filename);
    +   if (size >= sizeof(filename))
    +           filename[sizeof(filename)-1] = '\0';
    +   return menu_backtitle;
    +}
    +
    +/* return = 0 means we are successful.
    + * -1 means go on doing what you were doing
    + */
    +static int do_exit(void)
    +{
    +   int res;
    +   if (!conf_get_changed()) {
    +           global_exit = 1;
    +           return 0;
    +   }
    +   res = btn_dialog(main_window,
    +                   "Do you wish to save your new configuration?\n"
    +                           "<ESC> to cancel and resume nconfig.",
    +                   2,
    +                   "   <save>   ",
    +                   "<don't save>");
    +   if (res == KEY_EXIT) {
    +           global_exit = 0;
    +           return -1;
    +   }
    +
    +   /* if we got here, the user really wants to exit */
    +   switch (res) {
    +   case 0:
    +           res = conf_write(filename);
    +           if (res)
    +                   btn_dialog(
    +                           main_window,
    +                           "Error during writing of configuration.\n"
    +                             "Your configuration changes were NOT saved.",
    +                             1,
    +                             "<OK>");
    +           conf_write_autoconf(0);
    +           break;
    +   default:
    +           btn_dialog(
    +                   main_window,
    +                   "Your configuration changes were NOT saved.",
    +                   1,
    +                   "<OK>");
    +           break;
    +   }
    +   global_exit = 1;
    +   return 0;
    +}
    +
    +
    +static void search_conf(void)
    +{
    +   struct symbol **sym_arr;
    +   struct gstr res;
    +   struct gstr title;
    +   char *dialog_input;
    +   int dres;
    +
    +   title = str_new();
    +   str_printf( &title, "Enter (sub)string or regexp to search for "
    +                         "(with or without \"%s\")", CONFIG_);
    +
    +again:
    +   dres = dialog_inputbox(main_window,
    +                   "Search Configuration Parameter",
    +                   str_get(&title),
    +                   "", &dialog_input_result, &dialog_input_result_len);
    +   switch (dres) {
    +   case 0:
    +           break;
    +   case 1:
    +           show_scroll_win(main_window,
    +                           "Search Configuration", search_help);
    +           goto again;
    +   default:
    +           str_free(&title);
    +           return;
    +   }
    +
    +   /* strip the prefix if necessary */
    +   dialog_input = dialog_input_result;
    +   if (strncasecmp(dialog_input_result, CONFIG_, strlen(CONFIG_)) == 0)
    +           dialog_input += strlen(CONFIG_);
    +
    +   sym_arr = sym_re_search(dialog_input);
    +   res = get_relations_str(sym_arr, NULL);
    +   free(sym_arr);
    +   show_scroll_win(main_window,
    +                   "Search Results", str_get(&res));
    +   str_free(&res);
    +   str_free(&title);
    +}
    +
    +
    +static void build_conf(struct menu *menu)
    +{
    +   struct symbol *sym;
    +   struct property *prop;
    +   struct menu *child;
    +   int type, tmp, doint = 2;
    +   tristate val;
    +   char ch;
    +
    +   if (!menu || (!show_all_items && !menu_is_visible(menu)))
    +           return;
    +
    +   sym = menu->sym;
    +   prop = menu->prompt;
    +   if (!sym) {
    +           if (prop && menu != current_menu) {
    +                   const char *prompt = menu_get_prompt(menu);
    +                   enum prop_type ptype;
    +                   ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
    +                   switch (ptype) {
    +                   case P_MENU:
    +                           child_count++;
    +                           prompt = prompt;
    +                           if (single_menu_mode) {
    +                                   item_make(menu, 'm',
    +                                           "%s%*c%s",
    +                                           menu->data ? "-->" : "++>",
    +                                           indent + 1, ' ', prompt);
    +                           } else
    +                                   item_make(menu, 'm',
    +                                             "   %*c%s  %s",
    +                                             indent + 1, ' ', prompt,
    +                                             menu_is_empty(menu) ? "----" 
: "--->");
    +
    +                           if (single_menu_mode && menu->data)
    +                                   goto conf_childs;
    +                           return;
    +                   case P_COMMENT:
    +                           if (prompt) {
    +                                   child_count++;
    +                                   item_make(menu, ':',
    +                                           "   %*c*** %s ***",
    +                                           indent + 1, ' ',
    +                                           prompt);
    +                           }
    +                           break;
    +                   default:
    +                           if (prompt) {
    +                                   child_count++;
    +                                   item_make(menu, ':', "---%*c%s",
    +                                           indent + 1, ' ',
    +                                           prompt);
    +                           }
    +                   }
    +           } else
    +                   doint = 0;
    +           goto conf_childs;
    +   }
    +
    +   type = sym_get_type(sym);
    +   if (sym_is_choice(sym)) {
    +           struct symbol *def_sym = sym_get_choice_value(sym);
    +           struct menu *def_menu = NULL;
    +
    +           child_count++;
    +           for (child = menu->list; child; child = child->next) {
    +                   if (menu_is_visible(child) && child->sym == def_sym)
    +                           def_menu = child;
    +           }
    +
    +           val = sym_get_tristate_value(sym);
    +           if (sym_is_changable(sym)) {
    +                   switch (type) {
    +                   case S_BOOLEAN:
    +                           item_make(menu, 't', "[%c]",
    +                                           val == no ? ' ' : '*');
    +                           break;
    +                   case S_TRISTATE:
    +                           switch (val) {
    +                           case yes:
    +                                   ch = '*';
    +                                   break;
    +                           case mod:
    +                                   ch = 'M';
    +                                   break;
    +                           default:
    +                                   ch = ' ';
    +                                   break;
    +                           }
    +                           item_make(menu, 't', "<%c>", ch);
    +                           break;
    +                   }
    +           } else {
    +                   item_make(menu, def_menu ? 't' : ':', "   ");
    +           }
    +
    +           item_add_str("%*c%s", indent + 1,
    +                           ' ', menu_get_prompt(menu));
    +           if (val == yes) {
    +                   if (def_menu) {
    +                           item_add_str(" (%s)",
    +                                   menu_get_prompt(def_menu));
    +                           item_add_str("  --->");
    +                           if (def_menu->list) {
    +                                   indent += 2;
    +                                   build_conf(def_menu);
    +                                   indent -= 2;
    +                           }
    +                   }
    +                   return;
    +           }
    +   } else {
    +           if (menu == current_menu) {
    +                   item_make(menu, ':',
    +                           "---%*c%s", indent + 1,
    +                           ' ', menu_get_prompt(menu));
    +                   goto conf_childs;
    +           }
    +           child_count++;
    +           val = sym_get_tristate_value(sym);
    +           if (sym_is_choice_value(sym) && val == yes) {
    +                   item_make(menu, ':', "   ");
    +           } else {
    +                   switch (type) {
    +                   case S_BOOLEAN:
    +                           if (sym_is_changable(sym))
    +                                   item_make(menu, 't', "[%c]",
    +                                           val == no ? ' ' : '*');
    +                           else
    +                                   item_make(menu, 't', "-%c-",
    +                                           val == no ? ' ' : '*');
    +                           break;
    +                   case S_TRISTATE:
    +                           switch (val) {
    +                           case yes:
    +                                   ch = '*';
    +                                   break;
    +                           case mod:
    +                                   ch = 'M';
    +                                   break;
    +                           default:
    +                                   ch = ' ';
    +                                   break;
    +                           }
    +                           if (sym_is_changable(sym)) {
    +                                   if (sym->rev_dep.tri == mod)
    +                                           item_make(menu,
    +                                                   't', "{%c}", ch);
    +                                   else
    +                                           item_make(menu,
    +                                                   't', "<%c>", ch);
    +                           } else
    +                                   item_make(menu, 't', "-%c-", ch);
    +                           break;
    +                   default:
    +                           tmp = 2 + strlen(sym_get_string_value(sym));
    +                           item_make(menu, 's', "    (%s)",
    +                                           sym_get_string_value(sym));
    +                           tmp = indent - tmp + 4;
    +                           if (tmp < 0)
    +                                   tmp = 0;
    +                           item_add_str("%*c%s%s", tmp, ' ',
    +                                           menu_get_prompt(menu),
    +                                           (sym_has_value(sym) ||
    +                                            !sym_is_changable(sym)) ? "" :
    +                                           " (NEW)");
    +                           goto conf_childs;
    +                   }
    +           }
    +           item_add_str("%*c%s%s", indent + 1, ' ',
    +                           menu_get_prompt(menu),
    +                           (sym_has_value(sym) || !sym_is_changable(sym)) ?
    +                           "" : " (NEW)");
    +           if (menu->prompt && menu->prompt->type == P_MENU) {
    +                   item_add_str("  %s", menu_is_empty(menu) ? "----" : 
"--->");
    +                   return;
    +           }
    +   }
    +
    +conf_childs:
    +   indent += doint;
    +   for (child = menu->list; child; child = child->next)
    +           build_conf(child);
    +   indent -= doint;
    +}
    +
    +static void reset_menu(void)
    +{
    +   unpost_menu(curses_menu);
    +   clean_items();
    +}
    +
    +/* adjust the menu to show this item.
    + * prefer not to scroll the menu if possible*/
    +static void center_item(int selected_index, int *last_top_row)
    +{
    +   int toprow;
    +
    +   set_top_row(curses_menu, *last_top_row);
    +   toprow = top_row(curses_menu);
    +   if (selected_index < toprow ||
    +       selected_index >= toprow+mwin_max_lines) {
    +           toprow = max(selected_index-mwin_max_lines/2, 0);
    +           if (toprow >= item_count(curses_menu)-mwin_max_lines)
    +                   toprow = item_count(curses_menu)-mwin_max_lines;
    +           set_top_row(curses_menu, toprow);
    +   }
    +   set_current_item(curses_menu,
    +                   curses_menu_items[selected_index]);
    +   *last_top_row = toprow;
    +   post_menu(curses_menu);
    +   refresh_all_windows(main_window);
    +}
    +
    +/* this function assumes reset_menu has been called before */
    +static void show_menu(const char *prompt, const char *instructions,
    +           int selected_index, int *last_top_row)
    +{
    +   int maxx, maxy;
    +   WINDOW *menu_window;
    +
    +   current_instructions = instructions;
    +
    +   clear();
    +   (void) wattrset(main_window, attributes[NORMAL]);
    +   print_in_middle(stdscr, 1, 0, getmaxx(stdscr),
    +                   menu_backtitle,
    +                   attributes[MAIN_HEADING]);
    +
    +   (void) wattrset(main_window, attributes[MAIN_MENU_BOX]);
    +   box(main_window, 0, 0);
    +   (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]);
    +   mvwprintw(main_window, 0, 3, " %s ", prompt);
    +   (void) wattrset(main_window, attributes[NORMAL]);
    +
    +   set_menu_items(curses_menu, curses_menu_items);
    +
    +   /* position the menu at the middle of the screen */
    +   scale_menu(curses_menu, &maxy, &maxx);
    +   maxx = min(maxx, mwin_max_cols-2);
    +   maxy = mwin_max_lines;
    +   menu_window = derwin(main_window,
    +                   maxy,
    +                   maxx,
    +                   2,
    +                   (mwin_max_cols-maxx)/2);
    +   keypad(menu_window, TRUE);
    +   set_menu_win(curses_menu, menu_window);
    +   set_menu_sub(curses_menu, menu_window);
    +
    +   /* must reassert this after changing items, otherwise returns to a
    +    * default of 16
    +    */
    +   set_menu_format(curses_menu, maxy, 1);
    +   center_item(selected_index, last_top_row);
    +   set_menu_format(curses_menu, maxy, 1);
    +
    +   print_function_line();
    +
    +   /* Post the menu */
    +   post_menu(curses_menu);
    +   refresh_all_windows(main_window);
    +}
    +
    +static void adj_match_dir(match_f *match_direction)
    +{
    +   if (*match_direction == FIND_NEXT_MATCH_DOWN)
    +           *match_direction =
    +                   MATCH_TINKER_PATTERN_DOWN;
    +   else if (*match_direction == FIND_NEXT_MATCH_UP)
    +           *match_direction =
    +                   MATCH_TINKER_PATTERN_UP;
    +   /* else, do no change.. */
    +}
    +
    +struct match_state
    +{
    +   int in_search;
    +   match_f match_direction;
    +   char pattern[256];
    +};
    +
    +/* Return 0 means I have handled the key. In such a case, ans should hold 
the
    + * item to center, or -1 otherwise.
    + * Else return -1 .
    + */
    +static int do_match(int key, struct match_state *state, int *ans)
    +{
    +   char c = (char) key;
    +   int terminate_search = 0;
    +   *ans = -1;
    +   if (key == '/' || (state->in_search && key == 27)) {
    +           move(0, 0);
    +           refresh();
    +           clrtoeol();
    +           state->in_search = 1-state->in_search;
    +           bzero(state->pattern, sizeof(state->pattern));
    +           state->match_direction = MATCH_TINKER_PATTERN_DOWN;
    +           return 0;
    +   } else if (!state->in_search)
    +           return 1;
    +
    +   if (isalnum(c) || isgraph(c) || c == ' ') {
    +           state->pattern[strlen(state->pattern)] = c;
    +           state->pattern[strlen(state->pattern)] = '\0';
    +           adj_match_dir(&state->match_direction);
    +           *ans = get_mext_match(state->pattern,
    +                           state->match_direction);
    +   } else if (key == KEY_DOWN) {
    +           state->match_direction = FIND_NEXT_MATCH_DOWN;
    +           *ans = get_mext_match(state->pattern,
    +                           state->match_direction);
    +   } else if (key == KEY_UP) {
    +           state->match_direction = FIND_NEXT_MATCH_UP;
    +           *ans = get_mext_match(state->pattern,
    +                           state->match_direction);
    +   } else if (key == KEY_BACKSPACE || key == 8 || key == 127) {
    +           state->pattern[strlen(state->pattern)-1] = '\0';
    +           adj_match_dir(&state->match_direction);
    +   } else
    +           terminate_search = 1;
    +
    +   if (terminate_search) {
    +           state->in_search = 0;
    +           bzero(state->pattern, sizeof(state->pattern));
    +           move(0, 0);
    +           refresh();
    +           clrtoeol();
    +           return -1;
    +   }
    +   return 0;
    +}
    +
    +static void conf(struct menu *menu)
    +{
    +   struct menu *submenu = NULL;
    +   const char *prompt = menu_get_prompt(menu);
    +   struct symbol *sym;
    +   int res;
    +   int current_index = 0;
    +   int last_top_row = 0;
    +   struct match_state match_state = {
    +           .in_search = 0,
    +           .match_direction = MATCH_TINKER_PATTERN_DOWN,
    +           .pattern = "",
    +   };
    +
    +   while (!global_exit) {
    +           reset_menu();
    +           current_menu = menu;
    +           build_conf(menu);
    +           if (!child_count)
    +                   break;
    +
    +           show_menu(prompt ? prompt : "Main Menu",
    +                           menu_instructions,
    +                           current_index, &last_top_row);
    +           keypad((menu_win(curses_menu)), TRUE);
    +           while (!global_exit) {
    +                   if (match_state.in_search) {
    +                           mvprintw(0, 0,
    +                                   "searching: %s", match_state.pattern);
    +                           clrtoeol();
    +                   }
    +                   refresh_all_windows(main_window);
    +                   res = wgetch(menu_win(curses_menu));
    +                   if (!res)
    +                           break;
    +                   if (do_match(res, &match_state, &current_index) == 0) {
    +                           if (current_index != -1)
    +                                   center_item(current_index,
    +                                               &last_top_row);
    +                           continue;
    +                   }
    +                   if (process_special_keys(&res,
    +                                           (struct menu *) item_data()))
    +                           break;
    +                   switch (res) {
    +                   case KEY_DOWN:
    +                           menu_driver(curses_menu, REQ_DOWN_ITEM);
    +                           break;
    +                   case KEY_UP:
    +                           menu_driver(curses_menu, REQ_UP_ITEM);
    +                           break;
    +                   case KEY_NPAGE:
    +                           menu_driver(curses_menu, REQ_SCR_DPAGE);
    +                           break;
    +                   case KEY_PPAGE:
    +                           menu_driver(curses_menu, REQ_SCR_UPAGE);
    +                           break;
    +                   case KEY_HOME:
    +                           menu_driver(curses_menu, REQ_FIRST_ITEM);
    +                           break;
    +                   case KEY_END:
    +                           menu_driver(curses_menu, REQ_LAST_ITEM);
    +                           break;
    +                   case 'h':
    +                   case '?':
    +                           show_help((struct menu *) item_data());
    +                           break;
    +                   }
    +                   if (res == 10 || res == 27 ||
    +                           res == 32 || res == 'n' || res == 'y' ||
    +                           res == KEY_LEFT || res == KEY_RIGHT ||
    +                           res == 'm')
    +                           break;
    +                   refresh_all_windows(main_window);
    +           }
    +
    +           refresh_all_windows(main_window);
    +           /* if ESC or left*/
    +           if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
    +                   break;
    +
    +           /* remember location in the menu */
    +           last_top_row = top_row(curses_menu);
    +           current_index = curses_item_index();
    +
    +           if (!item_tag())
    +                   continue;
    +
    +           submenu = (struct menu *) item_data();
    +           if (!submenu || !menu_is_visible(submenu))
    +                   continue;
    +           sym = submenu->sym;
    +
    +           switch (res) {
    +           case ' ':
    +                   if (item_is_tag('t'))
    +                           sym_toggle_tristate_value(sym);
    +                   else if (item_is_tag('m'))
    +                           conf(submenu);
    +                   break;
    +           case KEY_RIGHT:
    +           case 10: /* ENTER WAS PRESSED */
    +                   switch (item_tag()) {
    +                   case 'm':
    +                           if (single_menu_mode)
    +                                   submenu->data =
    +                                           (void *) (long) !submenu->data;
    +                           else
    +                                   conf(submenu);
    +                           break;
    +                   case 't':
    +                           if (sym_is_choice(sym) &&
    +                               sym_get_tristate_value(sym) == yes)
    +                                   conf_choice(submenu);
    +                           else if (submenu->prompt &&
    +                                    submenu->prompt->type == P_MENU)
    +                                   conf(submenu);
    +                           else if (res == 10)
    +                                   sym_toggle_tristate_value(sym);
    +                           break;
    +                   case 's':
    +                           conf_string(submenu);
    +                           break;
    +                   }
    +                   break;
    +           case 'y':
    +                   if (item_is_tag('t')) {
    +                           if (sym_set_tristate_value(sym, yes))
    +                                   break;
    +                           if (sym_set_tristate_value(sym, mod))
    +                                   btn_dialog(main_window, setmod_text, 0);
    +                   }
    +                   break;
    +           case 'n':
    +                   if (item_is_tag('t'))
    +                           sym_set_tristate_value(sym, no);
    +                   break;
    +           case 'm':
    +                   if (item_is_tag('t'))
    +                           sym_set_tristate_value(sym, mod);
    +                   break;
    +           }
    +   }
    +}
    +
    +static void conf_message_callback(const char *s)
    +{
    +   btn_dialog(main_window, s, 1, "<OK>");
    +}
    +
    +static void show_help(struct menu *menu)
    +{
    +   struct gstr help;
    +
    +   if (!menu)
    +           return;
    +
    +   help = str_new();
    +   menu_get_ext_help(menu, &help);
    +   show_scroll_win(main_window, menu_get_prompt(menu), str_get(&help));
    +   str_free(&help);
    +}
    +
    +static void conf_choice(struct menu *menu)
    +{
    +   const char *prompt = menu_get_prompt(menu);
    +   struct menu *child = NULL;
    +   struct symbol *active;
    +   int selected_index = 0;
    +   int last_top_row = 0;
    +   int res, i = 0;
    +   struct match_state match_state = {
    +           .in_search = 0,
    +           .match_direction = MATCH_TINKER_PATTERN_DOWN,
    +           .pattern = "",
    +   };
    +
    +   active = sym_get_choice_value(menu->sym);
    +   /* this is mostly duplicated from the conf() function. */
    +   while (!global_exit) {
    +           reset_menu();
    +
    +           for (i = 0, child = menu->list; child; child = child->next) {
    +                   if (!show_all_items && !menu_is_visible(child))
    +                           continue;
    +
    +                   if (child->sym == sym_get_choice_value(menu->sym))
    +                           item_make(child, ':', "<X> %s",
    +                                           menu_get_prompt(child));
    +                   else if (child->sym)
    +                           item_make(child, ':', "    %s",
    +                                           menu_get_prompt(child));
    +                   else
    +                           item_make(child, ':', "*** %s ***",
    +                                           menu_get_prompt(child));
    +
    +                   if (child->sym == active){
    +                           last_top_row = top_row(curses_menu);
    +                           selected_index = i;
    +                   }
    +                   i++;
    +           }
    +           show_menu(prompt ? prompt : "Choice Menu",
    +                           radiolist_instructions,
    +                           selected_index,
    +                           &last_top_row);
    +           while (!global_exit) {
    +                   if (match_state.in_search) {
    +                           mvprintw(0, 0, "searching: %s",
    +                                    match_state.pattern);
    +                           clrtoeol();
    +                   }
    +                   refresh_all_windows(main_window);
    +                   res = wgetch(menu_win(curses_menu));
    +                   if (!res)
    +                           break;
    +                   if (do_match(res, &match_state, &selected_index) == 0) {
    +                           if (selected_index != -1)
    +                                   center_item(selected_index,
    +                                               &last_top_row);
    +                           continue;
    +                   }
    +                   if (process_special_keys(
    +                                           &res,
    +                                           (struct menu *) item_data()))
    +                           break;
    +                   switch (res) {
    +                   case KEY_DOWN:
    +                           menu_driver(curses_menu, REQ_DOWN_ITEM);
    +                           break;
    +                   case KEY_UP:
    +                           menu_driver(curses_menu, REQ_UP_ITEM);
    +                           break;
    +                   case KEY_NPAGE:
    +                           menu_driver(curses_menu, REQ_SCR_DPAGE);
    +                           break;
    +                   case KEY_PPAGE:
    +                           menu_driver(curses_menu, REQ_SCR_UPAGE);
    +                           break;
    +                   case KEY_HOME:
    +                           menu_driver(curses_menu, REQ_FIRST_ITEM);
    +                           break;
    +                   case KEY_END:
    +                           menu_driver(curses_menu, REQ_LAST_ITEM);
    +                           break;
    +                   case 'h':
    +                   case '?':
    +                           show_help((struct menu *) item_data());
    +                           break;
    +                   }
    +                   if (res == 10 || res == 27 || res == ' ' ||
    +                                   res == KEY_LEFT){
    +                           break;
    +                   }
    +                   refresh_all_windows(main_window);
    +           }
    +           /* if ESC or left */
    +           if (res == 27 || res == KEY_LEFT)
    +                   break;
    +
    +           child = item_data();
    +           if (!child || !menu_is_visible(child) || !child->sym)
    +                   continue;
    +           switch (res) {
    +           case ' ':
    +           case  10:
    +           case KEY_RIGHT:
    +                   sym_set_tristate_value(child->sym, yes);
    +                   return;
    +           case 'h':
    +           case '?':
    +                   show_help(child);
    +                   active = child->sym;
    +                   break;
    +           case KEY_EXIT:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void conf_string(struct menu *menu)
    +{
    +   const char *prompt = menu_get_prompt(menu);
    +
    +   while (1) {
    +           int res;
    +           const char *heading;
    +
    +           switch (sym_get_type(menu->sym)) {
    +           case S_INT:
    +                   heading = inputbox_instructions_int;
    +                   break;
    +           case S_HEX:
    +                   heading = inputbox_instructions_hex;
    +                   break;
    +           case S_STRING:
    +                   heading = inputbox_instructions_string;
    +                   break;
    +           default:
    +                   heading = "Internal nconf error!";
    +           }
    +           res = dialog_inputbox(main_window,
    +                           prompt ? prompt : "Main Menu",
    +                           heading,
    +                           sym_get_string_value(menu->sym),
    +                           &dialog_input_result,
    +                           &dialog_input_result_len);
    +           switch (res) {
    +           case 0:
    +                   if (sym_set_string_value(menu->sym,
    +                                           dialog_input_result))
    +                           return;
    +                   btn_dialog(main_window,
    +                           "You have made an invalid entry.", 0);
    +                   break;
    +           case 1:
    +                   show_help(menu);
    +                   break;
    +           case KEY_EXIT:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void conf_load(void)
    +{
    +   while (1) {
    +           int res;
    +           res = dialog_inputbox(main_window,
    +                           NULL, load_config_text,
    +                           filename,
    +                           &dialog_input_result,
    +                           &dialog_input_result_len);
    +           switch (res) {
    +           case 0:
    +                   if (!dialog_input_result[0])
    +                           return;
    +                   if (!conf_read(dialog_input_result)) {
    +                           set_config_filename(dialog_input_result);
    +                           sym_set_change_count(1);
    +                           return;
    +                   }
    +                   btn_dialog(main_window, "File does not exist!", 0);
    +                   break;
    +           case 1:
    +                   show_scroll_win(main_window,
    +                                   "Load Alternate Configuration",
    +                                   load_config_help);
    +                   break;
    +           case KEY_EXIT:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void conf_save(void)
    +{
    +   while (1) {
    +           int res;
    +           res = dialog_inputbox(main_window,
    +                           NULL, save_config_text,
    +                           filename,
    +                           &dialog_input_result,
    +                           &dialog_input_result_len);
    +           switch (res) {
    +           case 0:
    +                   if (!dialog_input_result[0])
    +                           return;
    +                   res = conf_write(dialog_input_result);
    +                   if (!res) {
    +                           set_config_filename(dialog_input_result);
    +                           return;
    +                   }
    +                   btn_dialog(main_window, "Can't create file!",
    +                           1, "<OK>");
    +                   break;
    +           case 1:
    +                   show_scroll_win(main_window,
    +                           "Save Alternate Configuration",
    +                           save_config_help);
    +                   break;
    +           case KEY_EXIT:
    +                   return;
    +           }
    +   }
    +}
    +
    +static void setup_windows(void)
    +{
    +   int lines, columns;
    +
    +   getmaxyx(stdscr, lines, columns);
    +
    +   if (main_window != NULL)
    +           delwin(main_window);
    +
    +   /* set up the menu and menu window */
    +   main_window = newwin(lines-2, columns-2, 2, 1);
    +   keypad(main_window, TRUE);
    +   mwin_max_lines = lines-7;
    +   mwin_max_cols = columns-6;
    +
    +   /* panels order is from bottom to top */
    +   new_panel(main_window);
    +}
    +
    +int main(int ac, char **av)
    +{
    +   int lines, columns;
    +   char *mode;
    +
    +   if (ac > 1 && strcmp(av[1], "-s") == 0) {
    +           /* Silence conf_read() until the real callback is set up */
    +           conf_set_message_callback(NULL);
    +           av++;
    +   }
    +   conf_parse(av[1]);
    +   conf_read(NULL);
    +
    +   mode = getenv("NCONFIG_MODE");
    +   if (mode) {
    +           if (!strcasecmp(mode, "single_menu"))
    +                   single_menu_mode = 1;
    +   }
    +
    +   /* Initialize curses */
    +   initscr();
    +   /* set color theme */
    +   set_colors();
    +
    +   cbreak();
    +   noecho();
    +   keypad(stdscr, TRUE);
    +   curs_set(0);
    +
    +   getmaxyx(stdscr, lines, columns);
    +   if (columns < 75 || lines < 20) {
    +           endwin();
    +           printf("Your terminal should have at "
    +                   "least 20 lines and 75 columns\n");
    +           return 1;
    +   }
    +
    +   notimeout(stdscr, FALSE);
    +#if NCURSES_REENTRANT
    +   set_escdelay(1);
    +#else
    +   ESCDELAY = 1;
    +#endif
    +
    +   /* set btns menu */
    +   curses_menu = new_menu(curses_menu_items);
    +   menu_opts_off(curses_menu, O_SHOWDESC);
    +   menu_opts_on(curses_menu, O_SHOWMATCH);
    +   menu_opts_on(curses_menu, O_ONEVALUE);
    +   menu_opts_on(curses_menu, O_NONCYCLIC);
    +   menu_opts_on(curses_menu, O_IGNORECASE);
    +   set_menu_mark(curses_menu, " ");
    +   set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
    +   set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
    +   set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
    +
    +   set_config_filename(conf_get_configname());
    +   setup_windows();
    +
    +   /* check for KEY_FUNC(1) */
    +   if (has_key(KEY_F(1)) == FALSE) {
    +           show_scroll_win(main_window,
    +                           "Instructions",
    +                           menu_no_f_instructions);
    +   }
    +
    +   conf_set_message_callback(conf_message_callback);
    +   /* do the work */
    +   while (!global_exit) {
    +           conf(&rootmenu);
    +           if (!global_exit && do_exit() == 0)
    +                   break;
    +   }
    +   /* ok, we are done */
    +   unpost_menu(curses_menu);
    +   free_menu(curses_menu);
    +   delwin(main_window);
    +   clear();
    +   refresh();
    +   endwin();
    +   return 0;
    +}
    diff --git a/support/kconfig.new/nconf.gui.c 
b/support/kconfig.new/nconf.gui.c
    new file mode 100644
    index 0000000..77f525a
    --- /dev/null
    +++ b/support/kconfig.new/nconf.gui.c
    @@ -0,0 +1,664 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@xxxxxxxxx>
    + *
    + * Derived from menuconfig.
    + */
    +#include "nconf.h"
    +#include "lkc.h"
    +
    +/* a list of all the different widgets we use */
    +attributes_t attributes[ATTR_MAX+1] = {0};
    +
    +/* available colors:
    +   COLOR_BLACK   0
    +   COLOR_RED     1
    +   COLOR_GREEN   2
    +   COLOR_YELLOW  3
    +   COLOR_BLUE    4
    +   COLOR_MAGENTA 5
    +   COLOR_CYAN    6
    +   COLOR_WHITE   7
    +   */
    +static void set_normal_colors(void)
    +{
    +   init_pair(NORMAL, -1, -1);
    +   init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
    +
    +   /* FORE is for the selected item */
    +   init_pair(MAIN_MENU_FORE, -1, -1);
    +   /* BACK for all the rest */
    +   init_pair(MAIN_MENU_BACK, -1, -1);
    +   init_pair(MAIN_MENU_GREY, -1, -1);
    +   init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
    +   init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
    +
    +   init_pair(SCROLLWIN_TEXT, -1, -1);
    +   init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
    +   init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
    +
    +   init_pair(DIALOG_TEXT, -1, -1);
    +   init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
    +   init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
    +   init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
    +
    +   init_pair(INPUT_BOX, COLOR_YELLOW, -1);
    +   init_pair(INPUT_HEADING, COLOR_GREEN, -1);
    +   init_pair(INPUT_TEXT, -1, -1);
    +   init_pair(INPUT_FIELD, -1, -1);
    +
    +   init_pair(FUNCTION_HIGHLIGHT, -1, -1);
    +   init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1);
    +}
    +
    +/* available attributes:
    +   A_NORMAL        Normal display (no highlight)
    +   A_STANDOUT      Best highlighting mode of the terminal.
    +   A_UNDERLINE     Underlining
    +   A_REVERSE       Reverse video
    +   A_BLINK         Blinking
    +   A_DIM           Half bright
    +   A_BOLD          Extra bright or bold
    +   A_PROTECT       Protected mode
    +   A_INVIS         Invisible or blank mode
    +   A_ALTCHARSET    Alternate character set
    +   A_CHARTEXT      Bit-mask to extract a character
    +   COLOR_PAIR(n)   Color-pair number n
    +   */
    +static void normal_color_theme(void)
    +{
    +   /* automatically add color... */
    +#define mkattr(name, attr) do { \
    +attributes[name] = attr | COLOR_PAIR(name); } while (0)
    +   mkattr(NORMAL, NORMAL);
    +   mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
    +
    +   mkattr(MAIN_MENU_FORE, A_REVERSE);
    +   mkattr(MAIN_MENU_BACK, A_NORMAL);
    +   mkattr(MAIN_MENU_GREY, A_NORMAL);
    +   mkattr(MAIN_MENU_HEADING, A_BOLD);
    +   mkattr(MAIN_MENU_BOX, A_NORMAL);
    +
    +   mkattr(SCROLLWIN_TEXT, A_NORMAL);
    +   mkattr(SCROLLWIN_HEADING, A_BOLD);
    +   mkattr(SCROLLWIN_BOX, A_BOLD);
    +
    +   mkattr(DIALOG_TEXT, A_BOLD);
    +   mkattr(DIALOG_BOX, A_BOLD);
    +   mkattr(DIALOG_MENU_FORE, A_STANDOUT);
    +   mkattr(DIALOG_MENU_BACK, A_NORMAL);
    +
    +   mkattr(INPUT_BOX, A_NORMAL);
    +   mkattr(INPUT_HEADING, A_BOLD);
    +   mkattr(INPUT_TEXT, A_NORMAL);
    +   mkattr(INPUT_FIELD, A_UNDERLINE);
    +
    +   mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
    +   mkattr(FUNCTION_TEXT, A_REVERSE);
    +}
    +
    +static void no_colors_theme(void)
    +{
    +   /* automatically add highlight, no color */
    +#define mkattrn(name, attr) { attributes[name] = attr; }
    +
    +   mkattrn(NORMAL, NORMAL);
    +   mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
    +
    +   mkattrn(MAIN_MENU_FORE, A_STANDOUT);
    +   mkattrn(MAIN_MENU_BACK, A_NORMAL);
    +   mkattrn(MAIN_MENU_GREY, A_NORMAL);
    +   mkattrn(MAIN_MENU_HEADING, A_BOLD);
    +   mkattrn(MAIN_MENU_BOX, A_NORMAL);
    +
    +   mkattrn(SCROLLWIN_TEXT, A_NORMAL);
    +   mkattrn(SCROLLWIN_HEADING, A_BOLD);
    +   mkattrn(SCROLLWIN_BOX, A_BOLD);
    +
    +   mkattrn(DIALOG_TEXT, A_NORMAL);
    +   mkattrn(DIALOG_BOX, A_BOLD);
    +   mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
    +   mkattrn(DIALOG_MENU_BACK, A_NORMAL);
    +
    +   mkattrn(INPUT_BOX, A_BOLD);
    +   mkattrn(INPUT_HEADING, A_BOLD);
    +   mkattrn(INPUT_TEXT, A_NORMAL);
    +   mkattrn(INPUT_FIELD, A_UNDERLINE);
    +
    +   mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
    +   mkattrn(FUNCTION_TEXT, A_REVERSE);
    +}
    +
    +void set_colors(void)
    +{
    +   start_color();
    +   use_default_colors();
    +   set_normal_colors();
    +   if (has_colors()) {
    +           normal_color_theme();
    +   } else {
    +           /* give defaults */
    +           no_colors_theme();
    +   }
    +}
    +
    +
    +/* this changes the windows attributes !!! */
    +void print_in_middle(WINDOW *win,
    +           int starty,
    +           int startx,
    +           int width,
    +           const char *string,
    +           chtype color)
    +{      int length, x, y;
    +   float temp;
    +
    +
    +   if (win == NULL)
    +           win = stdscr;
    +   getyx(win, y, x);
    +   if (startx != 0)
    +           x = startx;
    +   if (starty != 0)
    +           y = starty;
    +   if (width == 0)
    +           width = 80;
    +
    +   length = strlen(string);
    +   temp = (width - length) / 2;
    +   x = startx + (int)temp;
    +   (void) wattrset(win, color);
    +   mvwprintw(win, y, x, "%s", string);
    +   refresh();
    +}
    +
    +int get_line_no(const char *text)
    +{
    +   int i;
    +   int total = 1;
    +
    +   if (!text)
    +           return 0;
    +
    +   for (i = 0; text[i] != '\0'; i++)
    +           if (text[i] == '\n')
    +                   total++;
    +   return total;
    +}
    +
    +const char *get_line(const char *text, int line_no)
    +{
    +   int i;
    +   int lines = 0;
    +
    +   if (!text)
    +           return NULL;
    +
    +   for (i = 0; text[i] != '\0' && lines < line_no; i++)
    +           if (text[i] == '\n')
    +                   lines++;
    +   return text+i;
    +}
    +
    +int get_line_length(const char *line)
    +{
    +   int res = 0;
    +   while (*line != '\0' && *line != '\n') {
    +           line++;
    +           res++;
    +   }
    +   return res;
    +}
    +
    +/* print all lines to the window. */
    +void fill_window(WINDOW *win, const char *text)
    +{
    +   int x, y;
    +   int total_lines = get_line_no(text);
    +   int i;
    +
    +   getmaxyx(win, y, x);
    +   /* do not go over end of line */
    +   total_lines = min(total_lines, y);
    +   for (i = 0; i < total_lines; i++) {
    +           char tmp[x+10];
    +           const char *line = get_line(text, i);
    +           int len = get_line_length(line);
    +           strncpy(tmp, line, min(len, x));
    +           tmp[len] = '\0';
    +           mvwprintw(win, i, 0, "%s", tmp);
    +   }
    +}
    +
    +/* get the message, and buttons.
    + * each button must be a char*
    + * return the selected button
    + *
    + * this dialog is used for 2 different things:
    + * 1) show a text box, no buttons.
    + * 2) show a dialog, with horizontal buttons
    + */
    +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
    +{
    +   va_list ap;
    +   char *btn;
    +   int btns_width = 0;
    +   int msg_lines = 0;
    +   int msg_width = 0;
    +   int total_width;
    +   int win_rows = 0;
    +   WINDOW *win;
    +   WINDOW *msg_win;
    +   WINDOW *menu_win;
    +   MENU *menu;
    +   ITEM *btns[btn_num+1];
    +   int i, x, y;
    +   int res = -1;
    +
    +
    +   va_start(ap, btn_num);
    +   for (i = 0; i < btn_num; i++) {
    +           btn = va_arg(ap, char *);
    +           btns[i] = new_item(btn, "");
    +           btns_width += strlen(btn)+1;
    +   }
    +   va_end(ap);
    +   btns[btn_num] = NULL;
    +
    +   /* find the widest line of msg: */
    +   msg_lines = get_line_no(msg);
    +   for (i = 0; i < msg_lines; i++) {
    +           const char *line = get_line(msg, i);
    +           int len = get_line_length(line);
    +           if (msg_width < len)
    +                   msg_width = len;
    +   }
    +
    +   total_width = max(msg_width, btns_width);
    +   /* place dialog in middle of screen */
    +   y = (getmaxy(stdscr)-(msg_lines+4))/2;
    +   x = (getmaxx(stdscr)-(total_width+4))/2;
    +
    +
    +   /* create the windows */
    +   if (btn_num > 0)
    +           win_rows = msg_lines+4;
    +   else
    +           win_rows = msg_lines+2;
    +
    +   win = newwin(win_rows, total_width+4, y, x);
    +   keypad(win, TRUE);
    +   menu_win = derwin(win, 1, btns_width, win_rows-2,
    +                   1+(total_width+2-btns_width)/2);
    +   menu = new_menu(btns);
    +   msg_win = derwin(win, win_rows-2, msg_width, 1,
    +                   1+(total_width+2-msg_width)/2);
    +
    +   set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
    +   set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
    +
    +   (void) wattrset(win, attributes[DIALOG_BOX]);
    +   box(win, 0, 0);
    +
    +   /* print message */
    +   (void) wattrset(msg_win, attributes[DIALOG_TEXT]);
    +   fill_window(msg_win, msg);
    +
    +   set_menu_win(menu, win);
    +   set_menu_sub(menu, menu_win);
    +   set_menu_format(menu, 1, btn_num);
    +   menu_opts_off(menu, O_SHOWDESC);
    +   menu_opts_off(menu, O_SHOWMATCH);
    +   menu_opts_on(menu, O_ONEVALUE);
    +   menu_opts_on(menu, O_NONCYCLIC);
    +   set_menu_mark(menu, "");
    +   post_menu(menu);
    +
    +
    +   touchwin(win);
    +   refresh_all_windows(main_window);
    +   while ((res = wgetch(win))) {
    +           switch (res) {
    +           case KEY_LEFT:
    +                   menu_driver(menu, REQ_LEFT_ITEM);
    +                   break;
    +           case KEY_RIGHT:
    +                   menu_driver(menu, REQ_RIGHT_ITEM);
    +                   break;
    +           case 10: /* ENTER */
    +           case 27: /* ESCAPE */
    +           case ' ':
    +           case KEY_F(F_BACK):
    +           case KEY_F(F_EXIT):
    +                   break;
    +           }
    +           touchwin(win);
    +           refresh_all_windows(main_window);
    +
    +           if (res == 10 || res == ' ') {
    +                   res = item_index(current_item(menu));
    +                   break;
    +           } else if (res == 27 || res == KEY_F(F_BACK) ||
    +                           res == KEY_F(F_EXIT)) {
    +                   res = KEY_EXIT;
    +                   break;
    +           }
    +   }
    +
    +   unpost_menu(menu);
    +   free_menu(menu);
    +   for (i = 0; i < btn_num; i++)
    +           free_item(btns[i]);
    +
    +   delwin(win);
    +   return res;
    +}
    +
    +int dialog_inputbox(WINDOW *main_window,
    +           const char *title, const char *prompt,
    +           const char *init, char **resultp, int *result_len)
    +{
    +   int prompt_lines = 0;
    +   int prompt_width = 0;
    +   WINDOW *win;
    +   WINDOW *prompt_win;
    +   WINDOW *form_win;
    +   PANEL *panel;
    +   int i, x, y, lines, columns, win_lines, win_cols;
    +   int res = -1;
    +   int cursor_position = strlen(init);
    +   int cursor_form_win;
    +   char *result = *resultp;
    +
    +   getmaxyx(stdscr, lines, columns);
    +
    +   if (strlen(init)+1 > *result_len) {
    +           *result_len = strlen(init)+1;
    +           *resultp = result = xrealloc(result, *result_len);
    +   }
    +
    +   /* find the widest line of msg: */
    +   prompt_lines = get_line_no(prompt);
    +   for (i = 0; i < prompt_lines; i++) {
    +           const char *line = get_line(prompt, i);
    +           int len = get_line_length(line);
    +           prompt_width = max(prompt_width, len);
    +   }
    +
    +   if (title)
    +           prompt_width = max(prompt_width, strlen(title));
    +
    +   win_lines = min(prompt_lines+6, lines-2);
    +   win_cols = min(prompt_width+7, columns-2);
    +   prompt_lines = max(win_lines-6, 0);
    +   prompt_width = max(win_cols-7, 0);
    +
    +   /* place dialog in middle of screen */
    +   y = (lines-win_lines)/2;
    +   x = (columns-win_cols)/2;
    +
    +   strncpy(result, init, *result_len);
    +
    +   /* create the windows */
    +   win = newwin(win_lines, win_cols, y, x);
    +   prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
    +   form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
    +   keypad(form_win, TRUE);
    +
    +   (void) wattrset(form_win, attributes[INPUT_FIELD]);
    +
    +   (void) wattrset(win, attributes[INPUT_BOX]);
    +   box(win, 0, 0);
    +   (void) wattrset(win, attributes[INPUT_HEADING]);
    +   if (title)
    +           mvwprintw(win, 0, 3, "%s", title);
    +
    +   /* print message */
    +   (void) wattrset(prompt_win, attributes[INPUT_TEXT]);
    +   fill_window(prompt_win, prompt);
    +
    +   mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
    +   cursor_form_win = min(cursor_position, prompt_width-1);
    +   mvwprintw(form_win, 0, 0, "%s",
    +             result + cursor_position-cursor_form_win);
    +
    +   /* create panels */
    +   panel = new_panel(win);
    +
    +   /* show the cursor */
    +   curs_set(1);
    +
    +   touchwin(win);
    +   refresh_all_windows(main_window);
    +   while ((res = wgetch(form_win))) {
    +           int len = strlen(result);
    +           switch (res) {
    +           case 10: /* ENTER */
    +           case 27: /* ESCAPE */
    +           case KEY_F(F_HELP):
    +           case KEY_F(F_EXIT):
    +           case KEY_F(F_BACK):
    +                   break;
    +           case 8:   /* ^H */
    +           case 127: /* ^? */
    +           case KEY_BACKSPACE:
    +                   if (cursor_position > 0) {
    +                           memmove(&result[cursor_position-1],
    +                                           &result[cursor_position],
    +                                           len-cursor_position+1);
    +                           cursor_position--;
    +                           cursor_form_win--;
    +                           len--;
    +                   }
    +                   break;
    +           case KEY_DC:
    +                   if (cursor_position >= 0 && cursor_position < len) {
    +                           memmove(&result[cursor_position],
    +                                           &result[cursor_position+1],
    +                                           len-cursor_position+1);
    +                           len--;
    +                   }
    +                   break;
    +           case KEY_UP:
    +           case KEY_RIGHT:
    +                   if (cursor_position < len) {
    +                           cursor_position++;
    +                           cursor_form_win++;
    +                   }
    +                   break;
    +           case KEY_DOWN:
    +           case KEY_LEFT:
    +                   if (cursor_position > 0) {
    +                           cursor_position--;
    +                           cursor_form_win--;
    +                   }
    +                   break;
    +           case KEY_HOME:
    +                   cursor_position = 0;
    +                   cursor_form_win = 0;
    +                   break;
    +           case KEY_END:
    +                   cursor_position = len;
    +                   cursor_form_win = min(cursor_position, prompt_width-1);
    +                   break;
    +           default:
    +                   if ((isgraph(res) || isspace(res))) {
    +                           /* one for new char, one for '\0' */
    +                           if (len+2 > *result_len) {
    +                                   *result_len = len+2;
    +                                   *resultp = result = realloc(result,
    +                                                           *result_len);
    +                           }
    +                           /* insert the char at the proper position */
    +                           memmove(&result[cursor_position+1],
    +                                           &result[cursor_position],
    +                                           len-cursor_position+1);
    +                           result[cursor_position] = res;
    +                           cursor_position++;
    +                           cursor_form_win++;
    +                           len++;
    +                   } else {
    +                           mvprintw(0, 0, "unknown key: %d\n", res);
    +                   }
    +                   break;
    +           }
    +           if (cursor_form_win < 0)
    +                   cursor_form_win = 0;
    +           else if (cursor_form_win > prompt_width-1)
    +                   cursor_form_win = prompt_width-1;
    +
    +           wmove(form_win, 0, 0);
    +           wclrtoeol(form_win);
    +           mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
    +           mvwprintw(form_win, 0, 0, "%s",
    +                   result + cursor_position-cursor_form_win);
    +           wmove(form_win, 0, cursor_form_win);
    +           touchwin(win);
    +           refresh_all_windows(main_window);
    +
    +           if (res == 10) {
    +                   res = 0;
    +                   break;
    +           } else if (res == 27 || res == KEY_F(F_BACK) ||
    +                           res == KEY_F(F_EXIT)) {
    +                   res = KEY_EXIT;
    +                   break;
    +           } else if (res == KEY_F(F_HELP)) {
    +                   res = 1;
    +                   break;
    +           }
    +   }
    +
    +   /* hide the cursor */
    +   curs_set(0);
    +   del_panel(panel);
    +   delwin(prompt_win);
    +   delwin(form_win);
    +   delwin(win);
    +   return res;
    +}
    +
    +/* refresh all windows in the correct order */
    +void refresh_all_windows(WINDOW *main_window)
    +{
    +   update_panels();
    +   touchwin(main_window);
    +   refresh();
    +}
    +
    +/* layman's scrollable window... */
    +void show_scroll_win(WINDOW *main_window,
    +           const char *title,
    +           const char *text)
    +{
    +   int res;
    +   int total_lines = get_line_no(text);
    +   int x, y, lines, columns;
    +   int start_x = 0, start_y = 0;
    +   int text_lines = 0, text_cols = 0;
    +   int total_cols = 0;
    +   int win_cols = 0;
    +   int win_lines = 0;
    +   int i = 0;
    +   WINDOW *win;
    +   WINDOW *pad;
    +   PANEL *panel;
    +
    +   getmaxyx(stdscr, lines, columns);
    +
    +   /* find the widest line of msg: */
    +   total_lines = get_line_no(text);
    +   for (i = 0; i < total_lines; i++) {
    +           const char *line = get_line(text, i);
    +           int len = get_line_length(line);
    +           total_cols = max(total_cols, len+2);
    +   }
    +
    +   /* create the pad */
    +   pad = newpad(total_lines+10, total_cols+10);
    +   (void) wattrset(pad, attributes[SCROLLWIN_TEXT]);
    +   fill_window(pad, text);
    +
    +   win_lines = min(total_lines+4, lines-2);
    +   win_cols = min(total_cols+2, columns-2);
    +   text_lines = max(win_lines-4, 0);
    +   text_cols = max(win_cols-2, 0);
    +
    +   /* place window in middle of screen */
    +   y = (lines-win_lines)/2;
    +   x = (columns-win_cols)/2;
    +
    +   win = newwin(win_lines, win_cols, y, x);
    +   keypad(win, TRUE);
    +   /* show the help in the help window, and show the help panel */
    +   (void) wattrset(win, attributes[SCROLLWIN_BOX]);
    +   box(win, 0, 0);
    +   (void) wattrset(win, attributes[SCROLLWIN_HEADING]);
    +   mvwprintw(win, 0, 3, " %s ", title);
    +   panel = new_panel(win);
    +
    +   /* handle scrolling */
    +   do {
    +
    +           copywin(pad, win, start_y, start_x, 2, 2, text_lines,
    +                           text_cols, 0);
    +           print_in_middle(win,
    +                           text_lines+2,
    +                           0,
    +                           text_cols,
    +                           "<OK>",
    +                           attributes[DIALOG_MENU_FORE]);
    +           wrefresh(win);
    +
    +           res = wgetch(win);
    +           switch (res) {
    +           case KEY_NPAGE:
    +           case ' ':
    +           case 'd':
    +                   start_y += text_lines-2;
    +                   break;
    +           case KEY_PPAGE:
    +           case 'u':
    +                   start_y -= text_lines+2;
    +                   break;
    +           case KEY_HOME:
    +                   start_y = 0;
    +                   break;
    +           case KEY_END:
    +                   start_y = total_lines-text_lines;
    +                   break;
    +           case KEY_DOWN:
    +           case 'j':
    +                   start_y++;
    +                   break;
    +           case KEY_UP:
    +           case 'k':
    +                   start_y--;
    +                   break;
    +           case KEY_LEFT:
    +           case 'h':
    +                   start_x--;
    +                   break;
    +           case KEY_RIGHT:
    +           case 'l':
    +                   start_x++;
    +                   break;
    +           }
    +           if (res == 10 || res == 27 || res == 'q' ||
    +                   res == KEY_F(F_HELP) || res == KEY_F(F_BACK) ||
    +                   res == KEY_F(F_EXIT))
    +                   break;
    +           if (start_y < 0)
    +                   start_y = 0;
    +           if (start_y >= total_lines-text_lines)
    +                   start_y = total_lines-text_lines;
    +           if (start_x < 0)
    +                   start_x = 0;
    +           if (start_x >= total_cols-text_cols)
    +                   start_x = total_cols-text_cols;
    +   } while (res);
    +
    +   del_panel(panel);
    +   delwin(win);
    +   refresh_all_windows(main_window);
    +}
    diff --git a/support/kconfig.new/nconf.h b/support/kconfig.new/nconf.h
    new file mode 100644
    index 0000000..fa5245e
    --- /dev/null
    +++ b/support/kconfig.new/nconf.h
    @@ -0,0 +1,92 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2008 Nir Tzachar <nir.tzachar@xxxxxxxxx>
    + *
    + * Derived from menuconfig.
    + */
    +
    +#include <ctype.h>
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <limits.h>
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +#include <ncurses.h>
    +#include <menu.h>
    +#include <panel.h>
    +#include <form.h>
    +
    +#include <stdio.h>
    +#include <time.h>
    +#include <sys/time.h>
    +
    +#define max(a, b) ({\
    +           typeof(a) _a = a;\
    +           typeof(b) _b = b;\
    +           _a > _b ? _a : _b; })
    +
    +#define min(a, b) ({\
    +           typeof(a) _a = a;\
    +           typeof(b) _b = b;\
    +           _a < _b ? _a : _b; })
    +
    +typedef enum {
    +   NORMAL = 1,
    +   MAIN_HEADING,
    +   MAIN_MENU_BOX,
    +   MAIN_MENU_FORE,
    +   MAIN_MENU_BACK,
    +   MAIN_MENU_GREY,
    +   MAIN_MENU_HEADING,
    +   SCROLLWIN_TEXT,
    +   SCROLLWIN_HEADING,
    +   SCROLLWIN_BOX,
    +   DIALOG_TEXT,
    +   DIALOG_MENU_FORE,
    +   DIALOG_MENU_BACK,
    +   DIALOG_BOX,
    +   INPUT_BOX,
    +   INPUT_HEADING,
    +   INPUT_TEXT,
    +   INPUT_FIELD,
    +   FUNCTION_TEXT,
    +   FUNCTION_HIGHLIGHT,
    +   ATTR_MAX
    +} attributes_t;
    +extern attributes_t attributes[];
    +
    +typedef enum {
    +   F_HELP = 1,
    +   F_SYMBOL = 2,
    +   F_INSTS = 3,
    +   F_CONF = 4,
    +   F_BACK = 5,
    +   F_SAVE = 6,
    +   F_LOAD = 7,
    +   F_SEARCH = 8,
    +   F_EXIT = 9,
    +} function_key;
    +
    +void set_colors(void);
    +
    +/* this changes the windows attributes !!! */
    +void print_in_middle(WINDOW *win,
    +           int starty,
    +           int startx,
    +           int width,
    +           const char *string,
    +           chtype color);
    +int get_line_length(const char *line);
    +int get_line_no(const char *text);
    +const char *get_line(const char *text, int line_no);
    +void fill_window(WINDOW *win, const char *text);
    +int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
    +int dialog_inputbox(WINDOW *main_window,
    +           const char *title, const char *prompt,
    +           const char *init, char **resultp, int *result_len);
    +void refresh_all_windows(WINDOW *main_window);
    +void show_scroll_win(WINDOW *main_window,
    +           const char *title,
    +           const char *text);
    diff --git a/support/kconfig.new/parser.y b/support/kconfig.new/parser.y
    new file mode 100644
    index 0000000..60936c7
    --- /dev/null
    +++ b/support/kconfig.new/parser.y
    @@ -0,0 +1,731 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +%{
    +
    +#include <ctype.h>
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <stdbool.h>
    +
    +#include "lkc.h"
    +
    +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
    +
    +#define PRINTD             0x0001
    +#define DEBUG_PARSE        0x0002
    +
    +int cdebug = PRINTD;
    +
    +static void yyerror(const char *err);
    +static void zconfprint(const char *err, ...);
    +static void zconf_error(const char *err, ...);
    +static bool zconf_endtoken(const char *tokenname,
    +                      const char *expected_tokenname);
    +
    +struct symbol *symbol_hash[SYMBOL_HASHSIZE];
    +
    +static struct menu *current_menu, *current_entry;
    +
    +%}
    +
    +%union
    +{
    +   char *string;
    +   struct symbol *symbol;
    +   struct expr *expr;
    +   struct menu *menu;
    +   enum symbol_type type;
    +   enum variable_flavor flavor;
    +}
    +
    +%token <string> T_HELPTEXT
    +%token <string> T_WORD
    +%token <string> T_WORD_QUOTE
    +%token T_ALLNOCONFIG_Y
    +%token T_BOOL
    +%token T_CHOICE
    +%token T_CLOSE_PAREN
    +%token T_COLON_EQUAL
    +%token T_COMMENT
    +%token T_CONFIG
    +%token T_DEFAULT
    +%token T_DEFCONFIG_LIST
    +%token T_DEF_BOOL
    +%token T_DEF_TRISTATE
    +%token T_DEPENDS
    +%token T_ENDCHOICE
    +%token T_ENDIF
    +%token T_ENDMENU
    +%token T_HELP
    +%token T_HEX
    +%token T_IF
    +%token T_IMPLY
    +%token T_INT
    +%token T_MAINMENU
    +%token T_MENU
    +%token T_MENUCONFIG
    +%token T_MODULES
    +%token T_ON
    +%token T_OPEN_PAREN
    +%token T_OPTION
    +%token T_OPTIONAL
    +%token T_PLUS_EQUAL
    +%token T_PROMPT
    +%token T_RANGE
    +%token T_SELECT
    +%token T_SOURCE
    +%token T_STRING
    +%token T_TRISTATE
    +%token T_VISIBLE
    +%token T_EOL
    +%token <string> T_ASSIGN_VAL
    +
    +%left T_OR
    +%left T_AND
    +%left T_EQUAL T_UNEQUAL
    +%left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL
    +%nonassoc T_NOT
    +
    +%type <string> prompt
    +%type <symbol> nonconst_symbol
    +%type <symbol> symbol
    +%type <type> type logic_type default
    +%type <expr> expr
    +%type <expr> if_expr
    +%type <string> end
    +%type <menu> if_entry menu_entry choice_entry
    +%type <string> word_opt assign_val
    +%type <flavor> assign_op
    +
    +%destructor {
    +   fprintf(stderr, "%s:%d: missing end statement for this entry\n",
    +           $$->file->name, $$->lineno);
    +   if (current_menu == $$)
    +           menu_end_menu();
    +} if_entry menu_entry choice_entry
    +
    +%%
    +input: mainmenu_stmt stmt_list | stmt_list;
    +
    +/* mainmenu entry */
    +
    +mainmenu_stmt: T_MAINMENU prompt T_EOL
    +{
    +   menu_add_prompt(P_MENU, $2, NULL);
    +};
    +
    +stmt_list:
    +     /* empty */
    +   | stmt_list common_stmt
    +   | stmt_list choice_stmt
    +   | stmt_list menu_stmt
    +   | stmt_list T_WORD error T_EOL  { zconf_error("unknown statement 
\"%s\"", $2); }
    +   | stmt_list error T_EOL         { zconf_error("invalid statement"); }
    +;
    +
    +common_stmt:
    +     if_stmt
    +   | comment_stmt
    +   | config_stmt
    +   | menuconfig_stmt
    +   | source_stmt
    +   | assignment_stmt
    +;
    +
    +/* config/menuconfig entry */
    +
    +config_entry_start: T_CONFIG nonconst_symbol T_EOL
    +{
    +   $2->flags |= SYMBOL_OPTIONAL;
    +   menu_add_entry($2);
    +   printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), 
zconf_lineno(), $2->name);
    +};
    +
    +config_stmt: config_entry_start config_option_list
    +{
    +   printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), 
zconf_lineno());
    +};
    +
    +menuconfig_entry_start: T_MENUCONFIG nonconst_symbol T_EOL
    +{
    +   $2->flags |= SYMBOL_OPTIONAL;
    +   menu_add_entry($2);
    +   printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), 
zconf_lineno(), $2->name);
    +};
    +
    +menuconfig_stmt: menuconfig_entry_start config_option_list
    +{
    +   if (current_entry->prompt)
    +           current_entry->prompt->type = P_MENU;
    +   else
    +           zconfprint("warning: menuconfig statement without prompt");
    +   printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), 
zconf_lineno());
    +};
    +
    +config_option_list:
    +     /* empty */
    +   | config_option_list config_option
    +   | config_option_list depends
    +   | config_option_list help
    +;
    +
    +config_option: type prompt_stmt_opt T_EOL
    +{
    +   menu_set_type($1);
    +   printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
    +           zconf_curname(), zconf_lineno(),
    +           $1);
    +};
    +
    +config_option: T_PROMPT prompt if_expr T_EOL
    +{
    +   menu_add_prompt(P_PROMPT, $2, $3);
    +   printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
    +};
    +
    +config_option: default expr if_expr T_EOL
    +{
    +   menu_add_expr(P_DEFAULT, $2, $3);
    +   if ($1 != S_UNKNOWN)
    +           menu_set_type($1);
    +   printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
    +           zconf_curname(), zconf_lineno(),
    +           $1);
    +};
    +
    +config_option: T_SELECT nonconst_symbol if_expr T_EOL
    +{
    +   menu_add_symbol(P_SELECT, $2, $3);
    +   printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
    +};
    +
    +config_option: T_IMPLY nonconst_symbol if_expr T_EOL
    +{
    +   menu_add_symbol(P_IMPLY, $2, $3);
    +   printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
    +};
    +
    +config_option: T_RANGE symbol symbol if_expr T_EOL
    +{
    +   menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4);
    +   printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
    +};
    +
    +config_option: T_OPTION T_MODULES T_EOL
    +{
    +   menu_add_option_modules();
    +};
    +
    +config_option: T_OPTION T_DEFCONFIG_LIST T_EOL
    +{
    +   menu_add_option_defconfig_list();
    +};
    +
    +config_option: T_OPTION T_ALLNOCONFIG_Y T_EOL
    +{
    +   menu_add_option_allnoconfig_y();
    +};
    +
    +/* choice entry */
    +
    +choice: T_CHOICE word_opt T_EOL
    +{
    +   struct symbol *sym = sym_lookup($2, SYMBOL_CHOICE);
    +   sym->flags |= SYMBOL_NO_WRITE;
    +   menu_add_entry(sym);
    +   menu_add_expr(P_CHOICE, NULL, NULL);
    +   free($2);
    +   printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
    +};
    +
    +choice_entry: choice choice_option_list
    +{
    +   $$ = menu_add_menu();
    +};
    +
    +choice_end: end
    +{
    +   if (zconf_endtoken($1, "choice")) {
    +           menu_end_menu();
    +           printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), 
zconf_lineno());
    +   }
    +};
    +
    +choice_stmt: choice_entry choice_block choice_end
    +;
    +
    +choice_option_list:
    +     /* empty */
    +   | choice_option_list choice_option
    +   | choice_option_list depends
    +   | choice_option_list help
    +;
    +
    +choice_option: T_PROMPT prompt if_expr T_EOL
    +{
    +   menu_add_prompt(P_PROMPT, $2, $3);
    +   printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
    +};
    +
    +choice_option: logic_type prompt_stmt_opt T_EOL
    +{
    +   menu_set_type($1);
    +   printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
    +          zconf_curname(), zconf_lineno(), $1);
    +};
    +
    +choice_option: T_OPTIONAL T_EOL
    +{
    +   current_entry->sym->flags |= SYMBOL_OPTIONAL;
    +   printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), 
zconf_lineno());
    +};
    +
    +choice_option: T_DEFAULT nonconst_symbol if_expr T_EOL
    +{
    +   menu_add_symbol(P_DEFAULT, $2, $3);
    +   printd(DEBUG_PARSE, "%s:%d:default\n",
    +          zconf_curname(), zconf_lineno());
    +};
    +
    +type:
    +     logic_type
    +   | T_INT                 { $$ = S_INT; }
    +   | T_HEX                 { $$ = S_HEX; }
    +   | T_STRING              { $$ = S_STRING; }
    +
    +logic_type:
    +     T_BOOL                { $$ = S_BOOLEAN; }
    +   | T_TRISTATE            { $$ = S_TRISTATE; }
    +
    +default:
    +     T_DEFAULT             { $$ = S_UNKNOWN; }
    +   | T_DEF_BOOL            { $$ = S_BOOLEAN; }
    +   | T_DEF_TRISTATE        { $$ = S_TRISTATE; }
    +
    +choice_block:
    +     /* empty */
    +   | choice_block common_stmt
    +;
    +
    +/* if entry */
    +
    +if_entry: T_IF expr T_EOL
    +{
    +   printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
    +   menu_add_entry(NULL);
    +   menu_add_dep($2);
    +   $$ = menu_add_menu();
    +};
    +
    +if_end: end
    +{
    +   if (zconf_endtoken($1, "if")) {
    +           menu_end_menu();
    +           printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), 
zconf_lineno());
    +   }
    +};
    +
    +if_stmt: if_entry stmt_list if_end
    +;
    +
    +/* menu entry */
    +
    +menu: T_MENU prompt T_EOL
    +{
    +   menu_add_entry(NULL);
    +   menu_add_prompt(P_MENU, $2, NULL);
    +   printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
    +};
    +
    +menu_entry: menu menu_option_list
    +{
    +   $$ = menu_add_menu();
    +};
    +
    +menu_end: end
    +{
    +   if (zconf_endtoken($1, "menu")) {
    +           menu_end_menu();
    +           printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), 
zconf_lineno());
    +   }
    +};
    +
    +menu_stmt: menu_entry stmt_list menu_end
    +;
    +
    +menu_option_list:
    +     /* empty */
    +   | menu_option_list visible
    +   | menu_option_list depends
    +;
    +
    +source_stmt: T_SOURCE prompt T_EOL
    +{
    +   printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), 
zconf_lineno(), $2);
    +   zconf_nextfile($2);
    +   free($2);
    +};
    +
    +/* comment entry */
    +
    +comment: T_COMMENT prompt T_EOL
    +{
    +   menu_add_entry(NULL);
    +   menu_add_prompt(P_COMMENT, $2, NULL);
    +   printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
    +};
    +
    +comment_stmt: comment comment_option_list
    +;
    +
    +comment_option_list:
    +     /* empty */
    +   | comment_option_list depends
    +;
    +
    +/* help option */
    +
    +help_start: T_HELP T_EOL
    +{
    +   printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
    +   zconf_starthelp();
    +};
    +
    +help: help_start T_HELPTEXT
    +{
    +   if (current_entry->help) {
    +           free(current_entry->help);
    +           zconfprint("warning: '%s' defined with more than one help text 
-- only the last one will be used",
    +                      current_entry->sym->name ?: "<choice>");
    +   }
    +
    +   /* Is the help text empty or all whitespace? */
    +   if ($2[strspn($2, " \f\n\r\t\v")] == '\0')
    +           zconfprint("warning: '%s' defined with blank help text",
    +                      current_entry->sym->name ?: "<choice>");
    +
    +   current_entry->help = $2;
    +};
    +
    +/* depends option */
    +
    +depends: T_DEPENDS T_ON expr T_EOL
    +{
    +   menu_add_dep($3);
    +   printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), 
zconf_lineno());
    +};
    +
    +/* visibility option */
    +visible: T_VISIBLE if_expr T_EOL
    +{
    +   menu_add_visibility($2);
    +};
    +
    +/* prompt statement */
    +
    +prompt_stmt_opt:
    +     /* empty */
    +   | prompt if_expr
    +{
    +   menu_add_prompt(P_PROMPT, $1, $2);
    +};
    +
    +prompt:      T_WORD
    +   | T_WORD_QUOTE
    +;
    +
    +end:         T_ENDMENU T_EOL       { $$ = "menu"; }
    +   | T_ENDCHOICE T_EOL     { $$ = "choice"; }
    +   | T_ENDIF T_EOL         { $$ = "if"; }
    +;
    +
    +if_expr:  /* empty */                      { $$ = NULL; }
    +   | T_IF expr                     { $$ = $2; }
    +;
    +
    +expr:        symbol                                { $$ = 
expr_alloc_symbol($1); }
    +   | symbol T_LESS symbol                  { $$ = expr_alloc_comp(E_LTH, 
$1, $3); }
    +   | symbol T_LESS_EQUAL symbol            { $$ = expr_alloc_comp(E_LEQ, 
$1, $3); }
    +   | symbol T_GREATER symbol               { $$ = expr_alloc_comp(E_GTH, 
$1, $3); }
    +   | symbol T_GREATER_EQUAL symbol         { $$ = expr_alloc_comp(E_GEQ, 
$1, $3); }
    +   | symbol T_EQUAL symbol                 { $$ = expr_alloc_comp(E_EQUAL, 
$1, $3); }
    +   | symbol T_UNEQUAL symbol               { $$ = 
expr_alloc_comp(E_UNEQUAL, $1, $3); }
    +   | T_OPEN_PAREN expr T_CLOSE_PAREN       { $$ = $2; }
    +   | T_NOT expr                            { $$ = expr_alloc_one(E_NOT, 
$2); }
    +   | expr T_OR expr                        { $$ = expr_alloc_two(E_OR, $1, 
$3); }
    +   | expr T_AND expr                       { $$ = expr_alloc_two(E_AND, 
$1, $3); }
    +;
    +
    +/* For symbol definitions, selects, etc., where quotes are not accepted */
    +nonconst_symbol: T_WORD { $$ = sym_lookup($1, 0); free($1); };
    +
    +symbol:      nonconst_symbol
    +   | T_WORD_QUOTE  { $$ = sym_lookup($1, SYMBOL_CONST); free($1); }
    +;
    +
    +word_opt: /* empty */                      { $$ = NULL; }
    +   | T_WORD
    +
    +/* assignment statement */
    +
    +assignment_stmt:  T_WORD assign_op assign_val T_EOL        { 
variable_add($1, $3, $2); free($1); free($3); }
    +
    +assign_op:
    +     T_EQUAL       { $$ = VAR_RECURSIVE; }
    +   | T_COLON_EQUAL { $$ = VAR_SIMPLE; }
    +   | T_PLUS_EQUAL  { $$ = VAR_APPEND; }
    +;
    +
    +assign_val:
    +   /* empty */             { $$ = xstrdup(""); };
    +   | T_ASSIGN_VAL
    +;
    +
    +%%
    +
    +void conf_parse(const char *name)
    +{
    +   struct symbol *sym;
    +   int i;
    +
    +   zconf_initscan(name);
    +
    +   _menu_init();
    +
    +   if (getenv("ZCONF_DEBUG"))
    +           yydebug = 1;
    +   yyparse();
    +
    +   /* Variables are expanded in the parse phase. We can free them here. */
    +   variable_all_del();
    +
    +   if (yynerrs)
    +           exit(1);
    +   if (!modules_sym)
    +           modules_sym = sym_find( "n" );
    +
    +   if (!menu_has_prompt(&rootmenu)) {
    +           current_entry = &rootmenu;
    +           menu_add_prompt(P_MENU, "Main menu", NULL);
    +   }
    +
    +   menu_finalize(&rootmenu);
    +   for_all_symbols(i, sym) {
    +           if (sym_check_deps(sym))
    +                   yynerrs++;
    +   }
    +   if (yynerrs)
    +           exit(1);
    +   sym_set_change_count(1);
    +}
    +
    +static bool zconf_endtoken(const char *tokenname,
    +                      const char *expected_tokenname)
    +{
    +   if (strcmp(tokenname, expected_tokenname)) {
    +           zconf_error("unexpected '%s' within %s block",
    +                       tokenname, expected_tokenname);
    +           yynerrs++;
    +           return false;
    +   }
    +   if (current_menu->file != current_file) {
    +           zconf_error("'%s' in different file than '%s'",
    +                       tokenname, expected_tokenname);
    +           fprintf(stderr, "%s:%d: location of the '%s'\n",
    +                   current_menu->file->name, current_menu->lineno,
    +                   expected_tokenname);
    +           yynerrs++;
    +           return false;
    +   }
    +   return true;
    +}
    +
    +static void zconfprint(const char *err, ...)
    +{
    +   va_list ap;
    +
    +   fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
    +   va_start(ap, err);
    +   vfprintf(stderr, err, ap);
    +   va_end(ap);
    +   fprintf(stderr, "\n");
    +}
    +
    +static void zconf_error(const char *err, ...)
    +{
    +   va_list ap;
    +
    +   yynerrs++;
    +   fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
    +   va_start(ap, err);
    +   vfprintf(stderr, err, ap);
    +   va_end(ap);
    +   fprintf(stderr, "\n");
    +}
    +
    +static void yyerror(const char *err)
    +{
    +   fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, 
err);
    +}
    +
    +static void print_quoted_string(FILE *out, const char *str)
    +{
    +   const char *p;
    +   int len;
    +
    +   putc('"', out);
    +   while ((p = strchr(str, '"'))) {
    +           len = p - str;
    +           if (len)
    +                   fprintf(out, "%.*s", len, str);
    +           fputs("\\\"", out);
    +           str = p + 1;
    +   }
    +   fputs(str, out);
    +   putc('"', out);
    +}
    +
    +static void print_symbol(FILE *out, struct menu *menu)
    +{
    +   struct symbol *sym = menu->sym;
    +   struct property *prop;
    +
    +   if (sym_is_choice(sym))
    +           fprintf(out, "\nchoice\n");
    +   else
    +           fprintf(out, "\nconfig %s\n", sym->name);
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +           fputs("  bool\n", out);
    +           break;
    +   case S_TRISTATE:
    +           fputs("  tristate\n", out);
    +           break;
    +   case S_STRING:
    +           fputs("  string\n", out);
    +           break;
    +   case S_INT:
    +           fputs("  integer\n", out);
    +           break;
    +   case S_HEX:
    +           fputs("  hex\n", out);
    +           break;
    +   default:
    +           fputs("  ???\n", out);
    +           break;
    +   }
    +   for (prop = sym->prop; prop; prop = prop->next) {
    +           if (prop->menu != menu)
    +                   continue;
    +           switch (prop->type) {
    +           case P_PROMPT:
    +                   fputs("  prompt ", out);
    +                   print_quoted_string(out, prop->text);
    +                   if (!expr_is_yes(prop->visible.expr)) {
    +                           fputs(" if ", out);
    +                           expr_fprint(prop->visible.expr, out);
    +                   }
    +                   fputc('\n', out);
    +                   break;
    +           case P_DEFAULT:
    +                   fputs( "  default ", out);
    +                   expr_fprint(prop->expr, out);
    +                   if (!expr_is_yes(prop->visible.expr)) {
    +                           fputs(" if ", out);
    +                           expr_fprint(prop->visible.expr, out);
    +                   }
    +                   fputc('\n', out);
    +                   break;
    +           case P_CHOICE:
    +                   fputs("  #choice value\n", out);
    +                   break;
    +           case P_SELECT:
    +                   fputs( "  select ", out);
    +                   expr_fprint(prop->expr, out);
    +                   fputc('\n', out);
    +                   break;
    +           case P_IMPLY:
    +                   fputs( "  imply ", out);
    +                   expr_fprint(prop->expr, out);
    +                   fputc('\n', out);
    +                   break;
    +           case P_RANGE:
    +                   fputs( "  range ", out);
    +                   expr_fprint(prop->expr, out);
    +                   fputc('\n', out);
    +                   break;
    +           case P_MENU:
    +                   fputs( "  menu ", out);
    +                   print_quoted_string(out, prop->text);
    +                   fputc('\n', out);
    +                   break;
    +           case P_SYMBOL:
    +                   fputs( "  symbol ", out);
    +                   fprintf(out, "%s\n", prop->sym->name);
    +                   break;
    +           default:
    +                   fprintf(out, "  unknown prop %d!\n", prop->type);
    +                   break;
    +           }
    +   }
    +   if (menu->help) {
    +           int len = strlen(menu->help);
    +           while (menu->help[--len] == '\n')
    +                   menu->help[len] = 0;
    +           fprintf(out, "  help\n%s\n", menu->help);
    +   }
    +}
    +
    +void zconfdump(FILE *out)
    +{
    +   struct property *prop;
    +   struct symbol *sym;
    +   struct menu *menu;
    +
    +   menu = rootmenu.list;
    +   while (menu) {
    +           if ((sym = menu->sym))
    +                   print_symbol(out, menu);
    +           else if ((prop = menu->prompt)) {
    +                   switch (prop->type) {
    +                   case P_COMMENT:
    +                           fputs("\ncomment ", out);
    +                           print_quoted_string(out, prop->text);
    +                           fputs("\n", out);
    +                           break;
    +                   case P_MENU:
    +                           fputs("\nmenu ", out);
    +                           print_quoted_string(out, prop->text);
    +                           fputs("\n", out);
    +                           break;
    +                   default:
    +                           ;
    +                   }
    +                   if (!expr_is_yes(prop->visible.expr)) {
    +                           fputs("  depends ", out);
    +                           expr_fprint(prop->visible.expr, out);
    +                           fputc('\n', out);
    +                   }
    +           }
    +
    +           if (menu->list)
    +                   menu = menu->list;
    +           else if (menu->next)
    +                   menu = menu->next;
    +           else while ((menu = menu->parent)) {
    +                   if (menu->prompt && menu->prompt->type == P_MENU)
    +                           fputs("\nendmenu\n", out);
    +                   if (menu->next) {
    +                           menu = menu->next;
    +                           break;
    +                   }
    +           }
    +   }
    +}
    +
    +#include "util.c"
    +#include "menu.c"
    diff --git a/support/kconfig.new/preprocess.c 
b/support/kconfig.new/preprocess.c
    new file mode 100644
    index 0000000..592dfbf
    --- /dev/null
    +++ b/support/kconfig.new/preprocess.c
    @@ -0,0 +1,573 @@
    +// SPDX-License-Identifier: GPL-2.0
    +//
    +// Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@xxxxxxxxxxxxx>
    +
    +#include <ctype.h>
    +#include <stdarg.h>
    +#include <stdbool.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +
    +#include "list.h"
    +#include "lkc.h"
    +
    +#define ARRAY_SIZE(arr)            (sizeof(arr) / sizeof((arr)[0]))
    +
    +static char *expand_string_with_args(const char *in, int argc, char 
*argv[]);
    +
    +static void __attribute__((noreturn)) pperror(const char *format, ...)
    +{
    +   va_list ap;
    +
    +   fprintf(stderr, "%s:%d: ", current_file->name, yylineno);
    +   va_start(ap, format);
    +   vfprintf(stderr, format, ap);
    +   va_end(ap);
    +   fprintf(stderr, "\n");
    +
    +   exit(1);
    +}
    +
    +/*
    + * Environment variables
    + */
    +static LIST_HEAD(env_list);
    +
    +struct env {
    +   char *name;
    +   char *value;
    +   struct list_head node;
    +};
    +
    +static void env_add(const char *name, const char *value)
    +{
    +   struct env *e;
    +
    +   e = xmalloc(sizeof(*e));
    +   e->name = xstrdup(name);
    +   e->value = xstrdup(value);
    +
    +   list_add_tail(&e->node, &env_list);
    +}
    +
    +static void env_del(struct env *e)
    +{
    +   list_del(&e->node);
    +   free(e->name);
    +   free(e->value);
    +   free(e);
    +}
    +
    +/* The returned pointer must be freed when done */
    +static char *env_expand(const char *name)
    +{
    +   struct env *e;
    +   const char *value;
    +
    +   if (!*name)
    +           return NULL;
    +
    +   list_for_each_entry(e, &env_list, node) {
    +           if (!strcmp(name, e->name))
    +                   return xstrdup(e->value);
    +   }
    +
    +   value = getenv(name);
    +   if (!value)
    +           return NULL;
    +
    +   /*
    +    * We need to remember all referenced environment variables.
    +    * They will be written out to include/config/auto.conf.cmd
    +    */
    +   env_add(name, value);
    +
    +   return xstrdup(value);
    +}
    +
    +void env_write_dep(FILE *f, const char *autoconfig_name)
    +{
    +   struct env *e, *tmp;
    +
    +   list_for_each_entry_safe(e, tmp, &env_list, node) {
    +           fprintf(f, "ifneq \"$(%s)\" \"%s\"\n", e->name, e->value);
    +           fprintf(f, "%s: FORCE\n", autoconfig_name);
    +           fprintf(f, "endif\n");
    +           env_del(e);
    +   }
    +}
    +
    +/*
    + * Built-in functions
    + */
    +struct function {
    +   const char *name;
    +   unsigned int min_args;
    +   unsigned int max_args;
    +   char *(*func)(int argc, char *argv[]);
    +};
    +
    +static char *do_error_if(int argc, char *argv[])
    +{
    +   if (!strcmp(argv[0], "y"))
    +           pperror("%s", argv[1]);
    +
    +   return NULL;
    +}
    +
    +static char *do_filename(int argc, char *argv[])
    +{
    +   return xstrdup(current_file->name);
    +}
    +
    +static char *do_info(int argc, char *argv[])
    +{
    +   printf("%s\n", argv[0]);
    +
    +   return xstrdup("");
    +}
    +
    +static char *do_lineno(int argc, char *argv[])
    +{
    +   char buf[16];
    +
    +   sprintf(buf, "%d", yylineno);
    +
    +   return xstrdup(buf);
    +}
    +
    +static char *do_shell(int argc, char *argv[])
    +{
    +   FILE *p;
    +   char buf[256];
    +   char *cmd;
    +   size_t nread;
    +   int i;
    +
    +   cmd = argv[0];
    +
    +   p = popen(cmd, "r");
    +   if (!p) {
    +           perror(cmd);
    +           exit(1);
    +   }
    +
    +   nread = fread(buf, 1, sizeof(buf), p);
    +   if (nread == sizeof(buf))
    +           nread--;
    +
    +   /* remove trailing new lines */
    +   while (nread > 0 && buf[nread - 1] == '\n')
    +           nread--;
    +
    +   buf[nread] = 0;
    +
    +   /* replace a new line with a space */
    +   for (i = 0; i < nread; i++) {
    +           if (buf[i] == '\n')
    +                   buf[i] = ' ';
    +   }
    +
    +   if (pclose(p) == -1) {
    +           perror(cmd);
    +           exit(1);
    +   }
    +
    +   return xstrdup(buf);
    +}
    +
    +static char *do_warning_if(int argc, char *argv[])
    +{
    +   if (!strcmp(argv[0], "y"))
    +           fprintf(stderr, "%s:%d: %s\n",
    +                   current_file->name, yylineno, argv[1]);
    +
    +   return xstrdup("");
    +}
    +
    +static const struct function function_table[] = {
    +   /* Name         MIN     MAX     Function */
    +   { "error-if",   2,      2,      do_error_if },
    +   { "filename",   0,      0,      do_filename },
    +   { "info",       1,      1,      do_info },
    +   { "lineno",     0,      0,      do_lineno },
    +   { "shell",      1,      1,      do_shell },
    +   { "warning-if", 2,      2,      do_warning_if },
    +};
    +
    +#define FUNCTION_MAX_ARGS          16
    +
    +static char *function_expand(const char *name, int argc, char *argv[])
    +{
    +   const struct function *f;
    +   int i;
    +
    +   for (i = 0; i < ARRAY_SIZE(function_table); i++) {
    +           f = &function_table[i];
    +           if (strcmp(f->name, name))
    +                   continue;
    +
    +           if (argc < f->min_args)
    +                   pperror("too few function arguments passed to '%s'",
    +                           name);
    +
    +           if (argc > f->max_args)
    +                   pperror("too many function arguments passed to '%s'",
    +                           name);
    +
    +           return f->func(argc, argv);
    +   }
    +
    +   return NULL;
    +}
    +
    +/*
    + * Variables (and user-defined functions)
    + */
    +static LIST_HEAD(variable_list);
    +
    +struct variable {
    +   char *name;
    +   char *value;
    +   enum variable_flavor flavor;
    +   int exp_count;
    +   struct list_head node;
    +};
    +
    +static struct variable *variable_lookup(const char *name)
    +{
    +   struct variable *v;
    +
    +   list_for_each_entry(v, &variable_list, node) {
    +           if (!strcmp(name, v->name))
    +                   return v;
    +   }
    +
    +   return NULL;
    +}
    +
    +static char *variable_expand(const char *name, int argc, char *argv[])
    +{
    +   struct variable *v;
    +   char *res;
    +
    +   v = variable_lookup(name);
    +   if (!v)
    +           return NULL;
    +
    +   if (argc == 0 && v->exp_count)
    +           pperror("Recursive variable '%s' references itself 
(eventually)",
    +                   name);
    +
    +   if (v->exp_count > 1000)
    +           pperror("Too deep recursive expansion");
    +
    +   v->exp_count++;
    +
    +   if (v->flavor == VAR_RECURSIVE)
    +           res = expand_string_with_args(v->value, argc, argv);
    +   else
    +           res = xstrdup(v->value);
    +
    +   v->exp_count--;
    +
    +   return res;
    +}
    +
    +void variable_add(const char *name, const char *value,
    +             enum variable_flavor flavor)
    +{
    +   struct variable *v;
    +   char *new_value;
    +   bool append = false;
    +
    +   v = variable_lookup(name);
    +   if (v) {
    +           /* For defined variables, += inherits the existing flavor */
    +           if (flavor == VAR_APPEND) {
    +                   flavor = v->flavor;
    +                   append = true;
    +           } else {
    +                   free(v->value);
    +           }
    +   } else {
    +           /* For undefined variables, += assumes the recursive flavor */
    +           if (flavor == VAR_APPEND)
    +                   flavor = VAR_RECURSIVE;
    +
    +           v = xmalloc(sizeof(*v));
    +           v->name = xstrdup(name);
    +           v->exp_count = 0;
    +           list_add_tail(&v->node, &variable_list);
    +   }
    +
    +   v->flavor = flavor;
    +
    +   if (flavor == VAR_SIMPLE)
    +           new_value = expand_string(value);
    +   else
    +           new_value = xstrdup(value);
    +
    +   if (append) {
    +           v->value = xrealloc(v->value,
    +                               strlen(v->value) + strlen(new_value) + 2);
    +           strcat(v->value, " ");
    +           strcat(v->value, new_value);
    +           free(new_value);
    +   } else {
    +           v->value = new_value;
    +   }
    +}
    +
    +static void variable_del(struct variable *v)
    +{
    +   list_del(&v->node);
    +   free(v->name);
    +   free(v->value);
    +   free(v);
    +}
    +
    +void variable_all_del(void)
    +{
    +   struct variable *v, *tmp;
    +
    +   list_for_each_entry_safe(v, tmp, &variable_list, node)
    +           variable_del(v);
    +}
    +
    +/*
    + * Evaluate a clause with arguments.  argc/argv are arguments from the 
upper
    + * function call.
    + *
    + * Returned string must be freed when done
    + */
    +static char *eval_clause(const char *str, size_t len, int argc, char 
*argv[])
    +{
    +   char *tmp, *name, *res, *endptr, *prev, *p;
    +   int new_argc = 0;
    +   char *new_argv[FUNCTION_MAX_ARGS];
    +   int nest = 0;
    +   int i;
    +   unsigned long n;
    +
    +   tmp = xstrndup(str, len);
    +
    +   /*
    +    * If variable name is '1', '2', etc.  It is generally an argument
    +    * from a user-function call (i.e. local-scope variable).  If not
    +    * available, then look-up global-scope variables.
    +    */
    +   n = strtoul(tmp, &endptr, 10);
    +   if (!*endptr && n > 0 && n <= argc) {
    +           res = xstrdup(argv[n - 1]);
    +           goto free_tmp;
    +   }
    +
    +   prev = p = tmp;
    +
    +   /*
    +    * Split into tokens
    +    * The function name and arguments are separated by a comma.
    +    * For example, if the function call is like this:
    +    *   $(foo,$(x),$(y))
    +    *
    +    * The input string for this helper should be:
    +    *   foo,$(x),$(y)
    +    *
    +    * and split into:
    +    *   new_argv[0] = 'foo'
    +    *   new_argv[1] = '$(x)'
    +    *   new_argv[2] = '$(y)'
    +    */
    +   while (*p) {
    +           if (nest == 0 && *p == ',') {
    +                   *p = 0;
    +                   if (new_argc >= FUNCTION_MAX_ARGS)
    +                           pperror("too many function arguments");
    +                   new_argv[new_argc++] = prev;
    +                   prev = p + 1;
    +           } else if (*p == '(') {
    +                   nest++;
    +           } else if (*p == ')') {
    +                   nest--;
    +           }
    +
    +           p++;
    +   }
    +   new_argv[new_argc++] = prev;
    +
    +   /*
    +    * Shift arguments
    +    * new_argv[0] represents a function name or a variable name.  Put it
    +    * into 'name', then shift the rest of the arguments.  This simplifies
    +    * 'const' handling.
    +    */
    +   name = expand_string_with_args(new_argv[0], argc, argv);
    +   new_argc--;
    +   for (i = 0; i < new_argc; i++)
    +           new_argv[i] = expand_string_with_args(new_argv[i + 1],
    +                                                 argc, argv);
    +
    +   /* Search for variables */
    +   res = variable_expand(name, new_argc, new_argv);
    +   if (res)
    +           goto free;
    +
    +   /* Look for built-in functions */
    +   res = function_expand(name, new_argc, new_argv);
    +   if (res)
    +           goto free;
    +
    +   /* Last, try environment variable */
    +   if (new_argc == 0) {
    +           res = env_expand(name);
    +           if (res)
    +                   goto free;
    +   }
    +
    +   res = xstrdup("");
    +free:
    +   for (i = 0; i < new_argc; i++)
    +           free(new_argv[i]);
    +   free(name);
    +free_tmp:
    +   free(tmp);
    +
    +   return res;
    +}
    +
    +/*
    + * Expand a string that follows '$'
    + *
    + * For example, if the input string is
    + *     ($(FOO)$($(BAR)))$(BAZ)
    + * this helper evaluates
    + *     $($(FOO)$($(BAR)))
    + * and returns a new string containing the expansion (note that the string 
is
    + * recursively expanded), also advancing 'str' to point to the next 
character
    + * after the corresponding closing parenthesis, in this case, *str will be
    + *     $(BAR)
    + */
    +static char *expand_dollar_with_args(const char **str, int argc, char 
*argv[])
    +{
    +   const char *p = *str;
    +   const char *q;
    +   int nest = 0;
    +
    +   /*
    +    * In Kconfig, variable/function references always start with "$(".
    +    * Neither single-letter variables as in $A nor curly braces as in ${CC}
    +    * are supported.  '$' not followed by '(' loses its special meaning.
    +    */
    +   if (*p != '(') {
    +           *str = p;
    +           return xstrdup("$");
    +   }
    +
    +   p++;
    +   q = p;
    +   while (*q) {
    +           if (*q == '(') {
    +                   nest++;
    +           } else if (*q == ')') {
    +                   if (nest-- == 0)
    +                           break;
    +           }
    +           q++;
    +   }
    +
    +   if (!*q)
    +           pperror("unterminated reference to '%s': missing ')'", p);
    +
    +   /* Advance 'str' to after the expanded initial portion of the string */
    +   *str = q + 1;
    +
    +   return eval_clause(p, q - p, argc, argv);
    +}
    +
    +char *expand_dollar(const char **str)
    +{
    +   return expand_dollar_with_args(str, 0, NULL);
    +}
    +
    +static char *__expand_string(const char **str, bool (*is_end)(char c),
    +                        int argc, char *argv[])
    +{
    +   const char *in, *p;
    +   char *expansion, *out;
    +   size_t in_len, out_len;
    +
    +   out = xmalloc(1);
    +   *out = 0;
    +   out_len = 1;
    +
    +   p = in = *str;
    +
    +   while (1) {
    +           if (*p == '$') {
    +                   in_len = p - in;
    +                   p++;
    +                   expansion = expand_dollar_with_args(&p, argc, argv);
    +                   out_len += in_len + strlen(expansion);
    +                   out = xrealloc(out, out_len);
    +                   strncat(out, in, in_len);
    +                   strcat(out, expansion);
    +                   free(expansion);
    +                   in = p;
    +                   continue;
    +           }
    +
    +           if (is_end(*p))
    +                   break;
    +
    +           p++;
    +   }
    +
    +   in_len = p - in;
    +   out_len += in_len;
    +   out = xrealloc(out, out_len);
    +   strncat(out, in, in_len);
    +
    +   /* Advance 'str' to the end character */
    +   *str = p;
    +
    +   return out;
    +}
    +
    +static bool is_end_of_str(char c)
    +{
    +   return !c;
    +}
    +
    +/*
    + * Expand variables and functions in the given string.  Undefined variables
    + * expand to an empty string.
    + * The returned string must be freed when done.
    + */
    +static char *expand_string_with_args(const char *in, int argc, char 
*argv[])
    +{
    +   return __expand_string(&in, is_end_of_str, argc, argv);
    +}
    +
    +char *expand_string(const char *in)
    +{
    +   return expand_string_with_args(in, 0, NULL);
    +}
    +
    +static bool is_end_of_token(char c)
    +{
    +   return !(isalnum(c) || c == '_' || c == '-');
    +}
    +
    +/*
    + * Expand variables in a token.  The parsing stops when a token separater
    + * (in most cases, it is a whitespace) is encountered.  'str' is updated to
    + * point to the next character.
    + *
    + * The returned string must be freed when done.
    + */
    +char *expand_one_token(const char **str)
    +{
    +   return __expand_string(str, is_end_of_token, 0, NULL);
    +}
    diff --git a/support/kconfig.new/qconf-cfg.sh 
b/support/kconfig.new/qconf-cfg.sh
    new file mode 100755
    index 0000000..02ccc0a
    --- /dev/null
    +++ b/support/kconfig.new/qconf-cfg.sh
    @@ -0,0 +1,32 @@
    +#!/bin/sh
    +# SPDX-License-Identifier: GPL-2.0
    +
    +PKG="Qt5Core Qt5Gui Qt5Widgets"
    +PKG2="QtCore QtGui"
    +
    +if [ -z "$(command -v pkg-config)" ]; then
    +   echo >&2 "*"
    +   echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it."
    +   echo >&2 "*"
    +   exit 1
    +fi
    +
    +if pkg-config --exists $PKG; then
    +   echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags Qt5Core Qt5Gui 
Qt5Widgets)\"
    +   echo libs=\"$(pkg-config --libs $PKG)\"
    +   echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\"
    +   exit 0
    +fi
    +
    +if pkg-config --exists $PKG2; then
    +   echo cflags=\"$(pkg-config --cflags $PKG2)\"
    +   echo libs=\"$(pkg-config --libs $PKG2)\"
    +   echo moc=\"$(pkg-config --variable=moc_location QtCore)\"
    +   exit 0
    +fi
    +
    +echo >&2 "*"
    +echo >&2 "* Could not find Qt via pkg-config."
    +echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in 
PKG_CONFIG_PATH"
    +echo >&2 "*"
    +exit 1
    diff --git a/support/kconfig.new/qconf.cc b/support/kconfig.new/qconf.cc
    new file mode 100644
    index 0000000..ce7fc87
    --- /dev/null
    +++ b/support/kconfig.new/qconf.cc
    @@ -0,0 +1,1896 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@xxxxxxxxx>
    + */
    +
    +#include <qglobal.h>
    +
    +#include <QMainWindow>
    +#include <QList>
    +#include <qtextbrowser.h>
    +#include <QAction>
    +#include <QFileDialog>
    +#include <QMenu>
    +
    +#include <qapplication.h>
    +#include <qdesktopwidget.h>
    +#include <qtoolbar.h>
    +#include <qlayout.h>
    +#include <qsplitter.h>
    +#include <qlineedit.h>
    +#include <qlabel.h>
    +#include <qpushbutton.h>
    +#include <qmenubar.h>
    +#include <qmessagebox.h>
    +#include <qregexp.h>
    +#include <qevent.h>
    +
    +#include <stdlib.h>
    +
    +#include "lkc.h"
    +#include "qconf.h"
    +
    +#include "qconf.moc"
    +#include "images.h"
    +
    +
    +static QApplication *configApp;
    +static ConfigSettings *configSettings;
    +
    +QAction *ConfigMainWindow::saveAction;
    +
    +static inline QString qgettext(const char* str)
    +{
    +   return QString::fromLocal8Bit(str);
    +}
    +
    +ConfigSettings::ConfigSettings()
    +   : QSettings("kernel.org", "qconf")
    +{
    +}
    +
    +/**
    + * Reads a list of integer values from the application settings.
    + */
    +QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
    +{
    +   QList<int> result;
    +
    +   if (contains(key))
    +   {
    +           QStringList entryList = value(key).toStringList();
    +           QStringList::Iterator it;
    +
    +           for (it = entryList.begin(); it != entryList.end(); ++it)
    +                   result.push_back((*it).toInt());
    +
    +           *ok = true;
    +   }
    +   else
    +           *ok = false;
    +
    +   return result;
    +}
    +
    +/**
    + * Writes a list of integer values to the application settings.
    + */
    +bool ConfigSettings::writeSizes(const QString& key, const QList<int>& 
value)
    +{
    +   QStringList stringList;
    +   QList<int>::ConstIterator it;
    +
    +   for (it = value.begin(); it != value.end(); ++it)
    +           stringList.push_back(QString::number(*it));
    +   setValue(key, stringList);
    +
    +   return true;
    +}
    +
    +
    +/*
    + * set the new data
    + * TODO check the value
    + */
    +void ConfigItem::okRename(int col)
    +{
    +}
    +
    +/*
    + * update the displayed of a menu entry
    + */
    +void ConfigItem::updateMenu(void)
    +{
    +   ConfigList* list;
    +   struct symbol* sym;
    +   struct property *prop;
    +   QString prompt;
    +   int type;
    +   tristate expr;
    +
    +   list = listView();
    +   if (goParent) {
    +           setPixmap(promptColIdx, list->menuBackPix);
    +           prompt = "..";
    +           goto set_prompt;
    +   }
    +
    +   sym = menu->sym;
    +   prop = menu->prompt;
    +   prompt = qgettext(menu_get_prompt(menu));
    +
    +   if (prop) switch (prop->type) {
    +   case P_MENU:
    +           if (list->mode == singleMode || list->mode == symbolMode) {
    +                   /* a menuconfig entry is displayed differently
    +                    * depending whether it's at the view root or a child.
    +                    */
    +                   if (sym && list->rootEntry == menu)
    +                           break;
    +                   setPixmap(promptColIdx, list->menuPix);
    +           } else {
    +                   if (sym)
    +                           break;
    +                   setPixmap(promptColIdx, QIcon());
    +           }
    +           goto set_prompt;
    +   case P_COMMENT:
    +           setPixmap(promptColIdx, QIcon());
    +           goto set_prompt;
    +   default:
    +           ;
    +   }
    +   if (!sym)
    +           goto set_prompt;
    +
    +   setText(nameColIdx, QString::fromLocal8Bit(sym->name));
    +
    +   type = sym_get_type(sym);
    +   switch (type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           char ch;
    +
    +           if (!sym_is_changable(sym) && list->optMode == normalOpt) {
    +                   setPixmap(promptColIdx, QIcon());
    +                   setText(noColIdx, QString::null);
    +                   setText(modColIdx, QString::null);
    +                   setText(yesColIdx, QString::null);
    +                   break;
    +           }
    +           expr = sym_get_tristate_value(sym);
    +           switch (expr) {
    +           case yes:
    +                   if (sym_is_choice_value(sym) && type == S_BOOLEAN)
    +                           setPixmap(promptColIdx, list->choiceYesPix);
    +                   else
    +                           setPixmap(promptColIdx, list->symbolYesPix);
    +                   setText(yesColIdx, "Y");
    +                   ch = 'Y';
    +                   break;
    +           case mod:
    +                   setPixmap(promptColIdx, list->symbolModPix);
    +                   setText(modColIdx, "M");
    +                   ch = 'M';
    +                   break;
    +           default:
    +                   if (sym_is_choice_value(sym) && type == S_BOOLEAN)
    +                           setPixmap(promptColIdx, list->choiceNoPix);
    +                   else
    +                           setPixmap(promptColIdx, list->symbolNoPix);
    +                   setText(noColIdx, "N");
    +                   ch = 'N';
    +                   break;
    +           }
    +           if (expr != no)
    +                   setText(noColIdx, sym_tristate_within_range(sym, no) ? 
"_" : 0);
    +           if (expr != mod)
    +                   setText(modColIdx, sym_tristate_within_range(sym, mod) 
? "_" : 0);
    +           if (expr != yes)
    +                   setText(yesColIdx, sym_tristate_within_range(sym, yes) 
? "_" : 0);
    +
    +           setText(dataColIdx, QChar(ch));
    +           break;
    +   case S_INT:
    +   case S_HEX:
    +   case S_STRING:
    +           const char* data;
    +
    +           data = sym_get_string_value(sym);
    +
    +           setText(dataColIdx, data);
    +           if (type == S_STRING)
    +                   prompt = QString("%1: %2").arg(prompt).arg(data);
    +           else
    +                   prompt = QString("(%2) %1").arg(prompt).arg(data);
    +           break;
    +   }
    +   if (!sym_has_value(sym) && visible)
    +           prompt += " (NEW)";
    +set_prompt:
    +   setText(promptColIdx, prompt);
    +}
    +
    +void ConfigItem::testUpdateMenu(bool v)
    +{
    +   ConfigItem* i;
    +
    +   visible = v;
    +   if (!menu)
    +           return;
    +
    +   sym_calc_value(menu->sym);
    +   if (menu->flags & MENU_CHANGED) {
    +           /* the menu entry changed, so update all list items */
    +           menu->flags &= ~MENU_CHANGED;
    +           for (i = (ConfigItem*)menu->data; i; i = i->nextItem)
    +                   i->updateMenu();
    +   } else if (listView()->updateAll)
    +           updateMenu();
    +}
    +
    +
    +/*
    + * construct a menu entry
    + */
    +void ConfigItem::init(void)
    +{
    +   if (menu) {
    +           ConfigList* list = listView();
    +           nextItem = (ConfigItem*)menu->data;
    +           menu->data = this;
    +
    +           if (list->mode != fullMode)
    +                   setExpanded(true);
    +           sym_calc_value(menu->sym);
    +   }
    +   updateMenu();
    +}
    +
    +/*
    + * destruct a menu entry
    + */
    +ConfigItem::~ConfigItem(void)
    +{
    +   if (menu) {
    +           ConfigItem** ip = (ConfigItem**)&menu->data;
    +           for (; *ip; ip = &(*ip)->nextItem) {
    +                   if (*ip == this) {
    +                           *ip = nextItem;
    +                           break;
    +                   }
    +           }
    +   }
    +}
    +
    +ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
    +   : Parent(parent)
    +{
    +   connect(this, SIGNAL(editingFinished()), SLOT(hide()));
    +}
    +
    +void ConfigLineEdit::show(ConfigItem* i)
    +{
    +   item = i;
    +   if (sym_get_string_value(item->menu->sym))
    +           
setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym)));
    +   else
    +           setText(QString::null);
    +   Parent::show();
    +   setFocus();
    +}
    +
    +void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
    +{
    +   switch (e->key()) {
    +   case Qt::Key_Escape:
    +           break;
    +   case Qt::Key_Return:
    +   case Qt::Key_Enter:
    +           sym_set_string_value(item->menu->sym, text().toLatin1());
    +           parent()->updateList(item);
    +           break;
    +   default:
    +           Parent::keyPressEvent(e);
    +           return;
    +   }
    +   e->accept();
    +   parent()->list->setFocus();
    +   hide();
    +}
    +
    +ConfigList::ConfigList(ConfigView* p, const char *name)
    +   : Parent(p),
    +     updateAll(false),
    +     symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), 
symbolNoPix(xpm_symbol_no),
    +     choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
    +     menuPix(xpm_menu), menuInvPix(xpm_menu_inv), 
menuBackPix(xpm_menuback), voidPix(xpm_void),
    +     showName(false), showRange(false), showData(false), mode(singleMode), 
optMode(normalOpt),
    +     rootEntry(0), headerPopup(0)
    +{
    +   int i;
    +
    +   setObjectName(name);
    +   setSortingEnabled(false);
    +   setRootIsDecorated(true);
    +
    +   setVerticalScrollMode(ScrollPerPixel);
    +   setHorizontalScrollMode(ScrollPerPixel);
    +
    +   setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << 
"Y" << "Value");
    +
    +   connect(this, SIGNAL(itemSelectionChanged(void)),
    +           SLOT(updateSelection(void)));
    +
    +   if (name) {
    +           configSettings->beginGroup(name);
    +           showName = configSettings->value("/showName", false).toBool();
    +           showRange = configSettings->value("/showRange", false).toBool();
    +           showData = configSettings->value("/showData", false).toBool();
    +           optMode = (enum optionMode)configSettings->value("/optionMode", 
0).toInt();
    +           configSettings->endGroup();
    +           connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
    +   }
    +
    +   addColumn(promptColIdx);
    +
    +   reinit();
    +}
    +
    +bool ConfigList::menuSkip(struct menu *menu)
    +{
    +   if (optMode == normalOpt && menu_is_visible(menu))
    +           return false;
    +   if (optMode == promptOpt && menu_has_prompt(menu))
    +           return false;
    +   if (optMode == allOpt)
    +           return false;
    +   return true;
    +}
    +
    +void ConfigList::reinit(void)
    +{
    +   removeColumn(dataColIdx);
    +   removeColumn(yesColIdx);
    +   removeColumn(modColIdx);
    +   removeColumn(noColIdx);
    +   removeColumn(nameColIdx);
    +
    +   if (showName)
    +           addColumn(nameColIdx);
    +   if (showRange) {
    +           addColumn(noColIdx);
    +           addColumn(modColIdx);
    +           addColumn(yesColIdx);
    +   }
    +   if (showData)
    +           addColumn(dataColIdx);
    +
    +   updateListAll();
    +}
    +
    +void ConfigList::saveSettings(void)
    +{
    +   if (!objectName().isEmpty()) {
    +           configSettings->beginGroup(objectName());
    +           configSettings->setValue("/showName", showName);
    +           configSettings->setValue("/showRange", showRange);
    +           configSettings->setValue("/showData", showData);
    +           configSettings->setValue("/optionMode", (int)optMode);
    +           configSettings->endGroup();
    +   }
    +}
    +
    +ConfigItem* ConfigList::findConfigItem(struct menu *menu)
    +{
    +   ConfigItem* item = (ConfigItem*)menu->data;
    +
    +   for (; item; item = item->nextItem) {
    +           if (this == item->listView())
    +                   break;
    +   }
    +
    +   return item;
    +}
    +
    +void ConfigList::updateSelection(void)
    +{
    +   struct menu *menu;
    +   enum prop_type type;
    +
    +   if (selectedItems().count() == 0)
    +           return;
    +
    +   ConfigItem* item = (ConfigItem*)selectedItems().first();
    +   if (!item)
    +           return;
    +
    +   menu = item->menu;
    +   emit menuChanged(menu);
    +   if (!menu)
    +           return;
    +   type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
    +   if (mode == menuMode && type == P_MENU)
    +           emit menuSelected(menu);
    +}
    +
    +void ConfigList::updateList(ConfigItem* item)
    +{
    +   ConfigItem* last = 0;
    +
    +   if (!rootEntry) {
    +           if (mode != listMode)
    +                   goto update;
    +           QTreeWidgetItemIterator it(this);
    +           ConfigItem* item;
    +
    +           while (*it) {
    +                   item = (ConfigItem*)(*it);
    +                   if (!item->menu)
    +                           continue;
    +                   item->testUpdateMenu(menu_is_visible(item->menu));
    +
    +                   ++it;
    +           }
    +           return;
    +   }
    +
    +   if (rootEntry != &rootmenu && (mode == singleMode ||
    +       (mode == symbolMode && rootEntry->parent != &rootmenu))) {
    +           item = (ConfigItem *)topLevelItem(0);
    +           if (!item)
    +                   item = new ConfigItem(this, 0, true);
    +           last = item;
    +   }
    +   if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & 
MENU_ROOT))) &&
    +       rootEntry->sym && rootEntry->prompt) {
    +           item = last ? last->nextSibling() : firstChild();
    +           if (!item)
    +                   item = new ConfigItem(this, last, rootEntry, true);
    +           else
    +                   item->testUpdateMenu(true);
    +
    +           updateMenuList(item, rootEntry);
    +           update();
    +           resizeColumnToContents(0);
    +           return;
    +   }
    +update:
    +   updateMenuList(this, rootEntry);
    +   update();
    +   resizeColumnToContents(0);
    +}
    +
    +void ConfigList::setValue(ConfigItem* item, tristate val)
    +{
    +   struct symbol* sym;
    +   int type;
    +   tristate oldval;
    +
    +   sym = item->menu ? item->menu->sym : 0;
    +   if (!sym)
    +           return;
    +
    +   type = sym_get_type(sym);
    +   switch (type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           oldval = sym_get_tristate_value(sym);
    +
    +           if (!sym_set_tristate_value(sym, val))
    +                   return;
    +           if (oldval == no && item->menu->list)
    +                   item->setExpanded(true);
    +           parent()->updateList(item);
    +           break;
    +   }
    +}
    +
    +void ConfigList::changeValue(ConfigItem* item)
    +{
    +   struct symbol* sym;
    +   struct menu* menu;
    +   int type, oldexpr, newexpr;
    +
    +   menu = item->menu;
    +   if (!menu)
    +           return;
    +   sym = menu->sym;
    +   if (!sym) {
    +           if (item->menu->list)
    +                   item->setExpanded(!item->isExpanded());
    +           return;
    +   }
    +
    +   type = sym_get_type(sym);
    +   switch (type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           oldexpr = sym_get_tristate_value(sym);
    +           newexpr = sym_toggle_tristate_value(sym);
    +           if (item->menu->list) {
    +                   if (oldexpr == newexpr)
    +                           item->setExpanded(!item->isExpanded());
    +                   else if (oldexpr == no)
    +                           item->setExpanded(true);
    +           }
    +           if (oldexpr != newexpr)
    +                   parent()->updateList(item);
    +           break;
    +   case S_INT:
    +   case S_HEX:
    +   case S_STRING:
    +           parent()->lineEdit->show(item);
    +           break;
    +   }
    +}
    +
    +void ConfigList::setRootMenu(struct menu *menu)
    +{
    +   enum prop_type type;
    +
    +   if (rootEntry == menu)
    +           return;
    +   type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN;
    +   if (type != P_MENU)
    +           return;
    +   updateMenuList(this, 0);
    +   rootEntry = menu;
    +   updateListAll();
    +   if (currentItem()) {
    +           currentItem()->setSelected(hasFocus());
    +           scrollToItem(currentItem());
    +   }
    +}
    +
    +void ConfigList::setParentMenu(void)
    +{
    +   ConfigItem* item;
    +   struct menu *oldroot;
    +
    +   oldroot = rootEntry;
    +   if (rootEntry == &rootmenu)
    +           return;
    +   setRootMenu(menu_get_parent_menu(rootEntry->parent));
    +
    +   QTreeWidgetItemIterator it(this);
    +   while (*it) {
    +           item = (ConfigItem *)(*it);
    +           if (item->menu == oldroot) {
    +                   setCurrentItem(item);
    +                   scrollToItem(item);
    +                   break;
    +           }
    +
    +           ++it;
    +   }
    +}
    +
    +/*
    + * update all the children of a menu entry
    + *   removes/adds the entries from the parent widget as necessary
    + *
    + * parent: either the menu list widget or a menu entry widget
    + * menu: entry to be updated
    + */
    +void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
    +{
    +   struct menu* child;
    +   ConfigItem* item;
    +   ConfigItem* last;
    +   bool visible;
    +   enum prop_type type;
    +
    +   if (!menu) {
    +           while (parent->childCount() > 0)
    +           {
    +                   delete parent->takeChild(0);
    +           }
    +
    +           return;
    +   }
    +
    +   last = parent->firstChild();
    +   if (last && !last->goParent)
    +           last = 0;
    +   for (child = menu->list; child; child = child->next) {
    +           item = last ? last->nextSibling() : parent->firstChild();
    +           type = child->prompt ? child->prompt->type : P_UNKNOWN;
    +
    +           switch (mode) {
    +           case menuMode:
    +                   if (!(child->flags & MENU_ROOT))
    +                           goto hide;
    +                   break;
    +           case symbolMode:
    +                   if (child->flags & MENU_ROOT)
    +                           goto hide;
    +                   break;
    +           default:
    +                   break;
    +           }
    +
    +           visible = menu_is_visible(child);
    +           if (!menuSkip(child)) {
    +                   if (!child->sym && !child->list && !child->prompt)
    +                           continue;
    +                   if (!item || item->menu != child)
    +                           item = new ConfigItem(parent, last, child, 
visible);
    +                   else
    +                           item->testUpdateMenu(visible);
    +
    +                   if (mode == fullMode || mode == menuMode || type != 
P_MENU)
    +                           updateMenuList(item, child);
    +                   else
    +                           updateMenuList(item, 0);
    +                   last = item;
    +                   continue;
    +           }
    +   hide:
    +           if (item && item->menu == child) {
    +                   last = parent->firstChild();
    +                   if (last == item)
    +                           last = 0;
    +                   else while (last->nextSibling() != item)
    +                           last = last->nextSibling();
    +                   delete item;
    +           }
    +   }
    +}
    +
    +void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
    +{
    +   struct menu* child;
    +   ConfigItem* item;
    +   ConfigItem* last;
    +   bool visible;
    +   enum prop_type type;
    +
    +   if (!menu) {
    +           while (parent->topLevelItemCount() > 0)
    +           {
    +                   delete parent->takeTopLevelItem(0);
    +           }
    +
    +           return;
    +   }
    +
    +   last = (ConfigItem*)parent->topLevelItem(0);
    +   if (last && !last->goParent)
    +           last = 0;
    +   for (child = menu->list; child; child = child->next) {
    +           item = last ? last->nextSibling() : 
(ConfigItem*)parent->topLevelItem(0);
    +           type = child->prompt ? child->prompt->type : P_UNKNOWN;
    +
    +           switch (mode) {
    +           case menuMode:
    +                   if (!(child->flags & MENU_ROOT))
    +                           goto hide;
    +                   break;
    +           case symbolMode:
    +                   if (child->flags & MENU_ROOT)
    +                           goto hide;
    +                   break;
    +           default:
    +                   break;
    +           }
    +
    +           visible = menu_is_visible(child);
    +           if (!menuSkip(child)) {
    +                   if (!child->sym && !child->list && !child->prompt)
    +                           continue;
    +                   if (!item || item->menu != child)
    +                           item = new ConfigItem(parent, last, child, 
visible);
    +                   else
    +                           item->testUpdateMenu(visible);
    +
    +                   if (mode == fullMode || mode == menuMode || type != 
P_MENU)
    +                           updateMenuList(item, child);
    +                   else
    +                           updateMenuList(item, 0);
    +                   last = item;
    +                   continue;
    +           }
    +   hide:
    +           if (item && item->menu == child) {
    +                   last = (ConfigItem*)parent->topLevelItem(0);
    +                   if (last == item)
    +                           last = 0;
    +                   else while (last->nextSibling() != item)
    +                           last = last->nextSibling();
    +                   delete item;
    +           }
    +   }
    +}
    +
    +void ConfigList::keyPressEvent(QKeyEvent* ev)
    +{
    +   QTreeWidgetItem* i = currentItem();
    +   ConfigItem* item;
    +   struct menu *menu;
    +   enum prop_type type;
    +
    +   if (ev->key() == Qt::Key_Escape && mode != fullMode && mode != 
listMode) {
    +           emit parentSelected();
    +           ev->accept();
    +           return;
    +   }
    +
    +   if (!i) {
    +           Parent::keyPressEvent(ev);
    +           return;
    +   }
    +   item = (ConfigItem*)i;
    +
    +   switch (ev->key()) {
    +   case Qt::Key_Return:
    +   case Qt::Key_Enter:
    +           if (item->goParent) {
    +                   emit parentSelected();
    +                   break;
    +           }
    +           menu = item->menu;
    +           if (!menu)
    +                   break;
    +           type = menu->prompt ? menu->prompt->type : P_UNKNOWN;
    +           if (type == P_MENU && rootEntry != menu &&
    +               mode != fullMode && mode != menuMode) {
    +                   emit menuSelected(menu);
    +                   break;
    +           }
    +   case Qt::Key_Space:
    +           changeValue(item);
    +           break;
    +   case Qt::Key_N:
    +           setValue(item, no);
    +           break;
    +   case Qt::Key_M:
    +           setValue(item, mod);
    +           break;
    +   case Qt::Key_Y:
    +           setValue(item, yes);
    +           break;
    +   default:
    +           Parent::keyPressEvent(ev);
    +           return;
    +   }
    +   ev->accept();
    +}
    +
    +void ConfigList::mousePressEvent(QMouseEvent* e)
    +{
    +   //QPoint p(contentsToViewport(e->pos()));
    +   //printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
    +   Parent::mousePressEvent(e);
    +}
    +
    +void ConfigList::mouseReleaseEvent(QMouseEvent* e)
    +{
    +   QPoint p = e->pos();
    +   ConfigItem* item = (ConfigItem*)itemAt(p);
    +   struct menu *menu;
    +   enum prop_type ptype;
    +   QIcon icon;
    +   int idx, x;
    +
    +   if (!item)
    +           goto skip;
    +
    +   menu = item->menu;
    +   x = header()->offset() + p.x();
    +   idx = header()->logicalIndexAt(x);
    +   switch (idx) {
    +   case promptColIdx:
    +           icon = item->pixmap(promptColIdx);
    +           if (!icon.isNull()) {
    +                   int off = header()->sectionPosition(0) + 
visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be 
a way to do it properly.
    +                   if (x >= off && x < off + 
icon.availableSizes().first().width()) {
    +                           if (item->goParent) {
    +                                   emit parentSelected();
    +                                   break;
    +                           } else if (!menu)
    +                                   break;
    +                           ptype = menu->prompt ? menu->prompt->type : 
P_UNKNOWN;
    +                           if (ptype == P_MENU && rootEntry != menu &&
    +                               mode != fullMode && mode != menuMode)
    +                                   emit menuSelected(menu);
    +                           else
    +                                   changeValue(item);
    +                   }
    +           }
    +           break;
    +   case noColIdx:
    +           setValue(item, no);
    +           break;
    +   case modColIdx:
    +           setValue(item, mod);
    +           break;
    +   case yesColIdx:
    +           setValue(item, yes);
    +           break;
    +   case dataColIdx:
    +           changeValue(item);
    +           break;
    +   }
    +
    +skip:
    +   //printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
    +   Parent::mouseReleaseEvent(e);
    +}
    +
    +void ConfigList::mouseMoveEvent(QMouseEvent* e)
    +{
    +   //QPoint p(contentsToViewport(e->pos()));
    +   //printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
    +   Parent::mouseMoveEvent(e);
    +}
    +
    +void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
    +{
    +   QPoint p = e->pos(); // TODO: Check if this works(was 
contentsToViewport).
    +   ConfigItem* item = (ConfigItem*)itemAt(p);
    +   struct menu *menu;
    +   enum prop_type ptype;
    +
    +   if (!item)
    +           goto skip;
    +   if (item->goParent) {
    +           emit parentSelected();
    +           goto skip;
    +   }
    +   menu = item->menu;
    +   if (!menu)
    +           goto skip;
    +   ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
    +   if (ptype == P_MENU && (mode == singleMode || mode == symbolMode))
    +           emit menuSelected(menu);
    +   else if (menu->sym)
    +           changeValue(item);
    +
    +skip:
    +   //printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
    +   Parent::mouseDoubleClickEvent(e);
    +}
    +
    +void ConfigList::focusInEvent(QFocusEvent *e)
    +{
    +   struct menu *menu = NULL;
    +
    +   Parent::focusInEvent(e);
    +
    +   ConfigItem* item = (ConfigItem *)currentItem();
    +   if (item) {
    +           item->setSelected(true);
    +           menu = item->menu;
    +   }
    +   emit gotFocus(menu);
    +}
    +
    +void ConfigList::contextMenuEvent(QContextMenuEvent *e)
    +{
    +   if (e->y() <= header()->geometry().bottom()) {
    +           if (!headerPopup) {
    +                   QAction *action;
    +
    +                   headerPopup = new QMenu(this);
    +                   action = new QAction("Show Name", this);
    +                     action->setCheckable(true);
    +                     connect(action, SIGNAL(toggled(bool)),
    +                             parent(), SLOT(setShowName(bool)));
    +                     connect(parent(), SIGNAL(showNameChanged(bool)),
    +                             action, SLOT(setOn(bool)));
    +                     action->setChecked(showName);
    +                     headerPopup->addAction(action);
    +                   action = new QAction("Show Range", this);
    +                     action->setCheckable(true);
    +                     connect(action, SIGNAL(toggled(bool)),
    +                             parent(), SLOT(setShowRange(bool)));
    +                     connect(parent(), SIGNAL(showRangeChanged(bool)),
    +                             action, SLOT(setOn(bool)));
    +                     action->setChecked(showRange);
    +                     headerPopup->addAction(action);
    +                   action = new QAction("Show Data", this);
    +                     action->setCheckable(true);
    +                     connect(action, SIGNAL(toggled(bool)),
    +                             parent(), SLOT(setShowData(bool)));
    +                     connect(parent(), SIGNAL(showDataChanged(bool)),
    +                             action, SLOT(setOn(bool)));
    +                     action->setChecked(showData);
    +                     headerPopup->addAction(action);
    +           }
    +           headerPopup->exec(e->globalPos());
    +           e->accept();
    +   } else
    +           e->ignore();
    +}
    +
    +ConfigView*ConfigView::viewList;
    +QAction *ConfigView::showNormalAction;
    +QAction *ConfigView::showAllAction;
    +QAction *ConfigView::showPromptAction;
    +
    +ConfigView::ConfigView(QWidget* parent, const char *name)
    +   : Parent(parent)
    +{
    +   setObjectName(name);
    +   QVBoxLayout *verticalLayout = new QVBoxLayout(this);
    +   verticalLayout->setContentsMargins(0, 0, 0, 0);
    +
    +   list = new ConfigList(this);
    +   verticalLayout->addWidget(list);
    +   lineEdit = new ConfigLineEdit(this);
    +   lineEdit->hide();
    +   verticalLayout->addWidget(lineEdit);
    +
    +   this->nextView = viewList;
    +   viewList = this;
    +}
    +
    +ConfigView::~ConfigView(void)
    +{
    +   ConfigView** vp;
    +
    +   for (vp = &viewList; *vp; vp = &(*vp)->nextView) {
    +           if (*vp == this) {
    +                   *vp = nextView;
    +                   break;
    +           }
    +   }
    +}
    +
    +void ConfigView::setOptionMode(QAction *act)
    +{
    +   if (act == showNormalAction)
    +           list->optMode = normalOpt;
    +   else if (act == showAllAction)
    +           list->optMode = allOpt;
    +   else
    +           list->optMode = promptOpt;
    +
    +   list->updateListAll();
    +}
    +
    +void ConfigView::setShowName(bool b)
    +{
    +   if (list->showName != b) {
    +           list->showName = b;
    +           list->reinit();
    +           emit showNameChanged(b);
    +   }
    +}
    +
    +void ConfigView::setShowRange(bool b)
    +{
    +   if (list->showRange != b) {
    +           list->showRange = b;
    +           list->reinit();
    +           emit showRangeChanged(b);
    +   }
    +}
    +
    +void ConfigView::setShowData(bool b)
    +{
    +   if (list->showData != b) {
    +           list->showData = b;
    +           list->reinit();
    +           emit showDataChanged(b);
    +   }
    +}
    +
    +void ConfigList::setAllOpen(bool open)
    +{
    +   QTreeWidgetItemIterator it(this);
    +
    +   while (*it) {
    +           (*it)->setExpanded(open);
    +
    +           ++it;
    +   }
    +}
    +
    +void ConfigView::updateList(ConfigItem* item)
    +{
    +   ConfigView* v;
    +
    +   for (v = viewList; v; v = v->nextView)
    +           v->list->updateList(item);
    +}
    +
    +void ConfigView::updateListAll(void)
    +{
    +   ConfigView* v;
    +
    +   for (v = viewList; v; v = v->nextView)
    +           v->list->updateListAll();
    +}
    +
    +ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
    +   : Parent(parent), sym(0), _menu(0)
    +{
    +   setObjectName(name);
    +
    +
    +   if (!objectName().isEmpty()) {
    +           configSettings->beginGroup(objectName());
    +           setShowDebug(configSettings->value("/showDebug", 
false).toBool());
    +           configSettings->endGroup();
    +           connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
    +   }
    +}
    +
    +void ConfigInfoView::saveSettings(void)
    +{
    +   if (!objectName().isEmpty()) {
    +           configSettings->beginGroup(objectName());
    +           configSettings->setValue("/showDebug", showDebug());
    +           configSettings->endGroup();
    +   }
    +}
    +
    +void ConfigInfoView::setShowDebug(bool b)
    +{
    +   if (_showDebug != b) {
    +           _showDebug = b;
    +           if (_menu)
    +                   menuInfo();
    +           else if (sym)
    +                   symbolInfo();
    +           emit showDebugChanged(b);
    +   }
    +}
    +
    +void ConfigInfoView::setInfo(struct menu *m)
    +{
    +   if (_menu == m)
    +           return;
    +   _menu = m;
    +   sym = NULL;
    +   if (!_menu)
    +           clear();
    +   else
    +           menuInfo();
    +}
    +
    +void ConfigInfoView::symbolInfo(void)
    +{
    +   QString str;
    +
    +   str += "<big>Symbol: <b>";
    +   str += print_filter(sym->name);
    +   str += "</b></big><br><br>value: ";
    +   str += print_filter(sym_get_string_value(sym));
    +   str += "<br>visibility: ";
    +   str += sym->visible == yes ? "y" : sym->visible == mod ? "m" : "n";
    +   str += "<br>";
    +   str += debug_info(sym);
    +
    +   setText(str);
    +}
    +
    +void ConfigInfoView::menuInfo(void)
    +{
    +   struct symbol* sym;
    +   QString head, debug, help;
    +
    +   sym = _menu->sym;
    +   if (sym) {
    +           if (_menu->prompt) {
    +                   head += "<big><b>";
    +                   head += print_filter(_menu->prompt->text);
    +                   head += "</b></big>";
    +                   if (sym->name) {
    +                           head += " (";
    +                           if (showDebug())
    +                                   head += QString().sprintf("<a 
href=\"s%p\">", sym);
    +                           head += print_filter(sym->name);
    +                           if (showDebug())
    +                                   head += "</a>";
    +                           head += ")";
    +                   }
    +           } else if (sym->name) {
    +                   head += "<big><b>";
    +                   if (showDebug())
    +                           head += QString().sprintf("<a href=\"s%p\">", 
sym);
    +                   head += print_filter(sym->name);
    +                   if (showDebug())
    +                           head += "</a>";
    +                   head += "</b></big>";
    +           }
    +           head += "<br><br>";
    +
    +           if (showDebug())
    +                   debug = debug_info(sym);
    +
    +           struct gstr help_gstr = str_new();
    +           menu_get_ext_help(_menu, &help_gstr);
    +           help = print_filter(str_get(&help_gstr));
    +           str_free(&help_gstr);
    +   } else if (_menu->prompt) {
    +           head += "<big><b>";
    +           head += print_filter(_menu->prompt->text);
    +           head += "</b></big><br><br>";
    +           if (showDebug()) {
    +                   if (_menu->prompt->visible.expr) {
    +                           debug += "&nbsp;&nbsp;dep: ";
    +                           expr_print(_menu->prompt->visible.expr, 
expr_print_help, &debug, E_NONE);
    +                           debug += "<br><br>";
    +                   }
    +           }
    +   }
    +   if (showDebug())
    +           debug += QString().sprintf("defined at %s:%d<br><br>", 
_menu->file->name, _menu->lineno);
    +
    +   setText(head + debug + help);
    +}
    +
    +QString ConfigInfoView::debug_info(struct symbol *sym)
    +{
    +   QString debug;
    +
    +   debug += "type: ";
    +   debug += print_filter(sym_type_name(sym->type));
    +   if (sym_is_choice(sym))
    +           debug += " (choice)";
    +   debug += "<br>";
    +   if (sym->rev_dep.expr) {
    +           debug += "reverse dep: ";
    +           expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE);
    +           debug += "<br>";
    +   }
    +   for (struct property *prop = sym->prop; prop; prop = prop->next) {
    +           switch (prop->type) {
    +           case P_PROMPT:
    +           case P_MENU:
    +                   debug += QString().sprintf("prompt: <a href=\"m%p\">", 
prop->menu);
    +                   debug += print_filter(prop->text);
    +                   debug += "</a><br>";
    +                   break;
    +           case P_DEFAULT:
    +           case P_SELECT:
    +           case P_RANGE:
    +                   debug += prop_get_type_name(prop->type);
    +                   debug += ": ";
    +                   expr_print(prop->expr, expr_print_help, &debug, E_NONE);
    +                   debug += "<br>";
    +                   break;
    +           case P_CHOICE:
    +                   if (sym_is_choice(sym)) {
    +                           debug += "choice: ";
    +                           expr_print(prop->expr, expr_print_help, &debug, 
E_NONE);
    +                           debug += "<br>";
    +                   }
    +                   break;
    +           default:
    +                   debug += "unknown property: ";
    +                   debug += prop_get_type_name(prop->type);
    +                   debug += "<br>";
    +           }
    +           if (prop->visible.expr) {
    +                   debug += "&nbsp;&nbsp;&nbsp;&nbsp;dep: ";
    +                   expr_print(prop->visible.expr, expr_print_help, &debug, 
E_NONE);
    +                   debug += "<br>";
    +           }
    +   }
    +   debug += "<br>";
    +
    +   return debug;
    +}
    +
    +QString ConfigInfoView::print_filter(const QString &str)
    +{
    +   QRegExp re("[<>&\"\\n]");
    +   QString res = str;
    +   for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
    +           switch (res[i].toLatin1()) {
    +           case '<':
    +                   res.replace(i, 1, "&lt;");
    +                   i += 4;
    +                   break;
    +           case '>':
    +                   res.replace(i, 1, "&gt;");
    +                   i += 4;
    +                   break;
    +           case '&':
    +                   res.replace(i, 1, "&amp;");
    +                   i += 5;
    +                   break;
    +           case '"':
    +                   res.replace(i, 1, "&quot;");
    +                   i += 6;
    +                   break;
    +           case '\n':
    +                   res.replace(i, 1, "<br>");
    +                   i += 4;
    +                   break;
    +           }
    +   }
    +   return res;
    +}
    +
    +void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const 
char *str)
    +{
    +   QString* text = reinterpret_cast<QString*>(data);
    +   QString str2 = print_filter(str);
    +
    +   if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) {
    +           *text += QString().sprintf("<a href=\"s%p\">", sym);
    +           *text += str2;
    +           *text += "</a>";
    +   } else
    +           *text += str2;
    +}
    +
    +QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
    +{
    +   QMenu* popup = Parent::createStandardContextMenu(pos);
    +   QAction* action = new QAction("Show Debug Info", popup);
    +     action->setCheckable(true);
    +     connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
    +     connect(this, SIGNAL(showDebugChanged(bool)), action, 
SLOT(setOn(bool)));
    +     action->setChecked(showDebug());
    +   popup->addSeparator();
    +   popup->addAction(action);
    +   return popup;
    +}
    +
    +void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
    +{
    +   Parent::contextMenuEvent(e);
    +}
    +
    +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const 
char *name)
    +   : Parent(parent), result(NULL)
    +{
    +   setObjectName(name);
    +   setWindowTitle("Search Config");
    +
    +   QVBoxLayout* layout1 = new QVBoxLayout(this);
    +   layout1->setContentsMargins(11, 11, 11, 11);
    +   layout1->setSpacing(6);
    +   QHBoxLayout* layout2 = new QHBoxLayout(0);
    +   layout2->setContentsMargins(0, 0, 0, 0);
    +   layout2->setSpacing(6);
    +   layout2->addWidget(new QLabel("Find:", this));
    +   editField = new QLineEdit(this);
    +   connect(editField, SIGNAL(returnPressed()), SLOT(search()));
    +   layout2->addWidget(editField);
    +   searchButton = new QPushButton("Search", this);
    +   searchButton->setAutoDefault(false);
    +   connect(searchButton, SIGNAL(clicked()), SLOT(search()));
    +   layout2->addWidget(searchButton);
    +   layout1->addLayout(layout2);
    +
    +   split = new QSplitter(this);
    +   split->setOrientation(Qt::Vertical);
    +   list = new ConfigView(split, name);
    +   list->list->mode = listMode;
    +   info = new ConfigInfoView(split, name);
    +   connect(list->list, SIGNAL(menuChanged(struct menu *)),
    +           info, SLOT(setInfo(struct menu *)));
    +   connect(list->list, SIGNAL(menuChanged(struct menu *)),
    +           parent, SLOT(setMenuLink(struct menu *)));
    +
    +   layout1->addWidget(split);
    +
    +   if (name) {
    +           QVariant x, y;
    +           int width, height;
    +           bool ok;
    +
    +           configSettings->beginGroup(name);
    +           width = configSettings->value("/window width", parent->width() 
/ 2).toInt();
    +           height = configSettings->value("/window height", 
parent->height() / 2).toInt();
    +           resize(width, height);
    +           x = configSettings->value("/window x");
    +           y = configSettings->value("/window y");
    +           if ((x.isValid())&&(y.isValid()))
    +                   move(x.toInt(), y.toInt());
    +           QList<int> sizes = configSettings->readSizes("/split", &ok);
    +           if (ok)
    +                   split->setSizes(sizes);
    +           configSettings->endGroup();
    +           connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
    +   }
    +}
    +
    +void ConfigSearchWindow::saveSettings(void)
    +{
    +   if (!objectName().isEmpty()) {
    +           configSettings->beginGroup(objectName());
    +           configSettings->setValue("/window x", pos().x());
    +           configSettings->setValue("/window y", pos().y());
    +           configSettings->setValue("/window width", size().width());
    +           configSettings->setValue("/window height", size().height());
    +           configSettings->writeSizes("/split", split->sizes());
    +           configSettings->endGroup();
    +   }
    +}
    +
    +void ConfigSearchWindow::search(void)
    +{
    +   struct symbol **p;
    +   struct property *prop;
    +   ConfigItem *lastItem = NULL;
    +
    +   free(result);
    +   list->list->clear();
    +   info->clear();
    +
    +   result = sym_re_search(editField->text().toLatin1());
    +   if (!result)
    +           return;
    +   for (p = result; *p; p++) {
    +           for_all_prompts((*p), prop)
    +                   lastItem = new ConfigItem(list->list, lastItem, 
prop->menu,
    +                                             menu_is_visible(prop->menu));
    +   }
    +}
    +
    +/*
    + * Construct the complete config widget
    + */
    +ConfigMainWindow::ConfigMainWindow(void)
    +   : searchWindow(0)
    +{
    +   QMenuBar* menu;
    +   bool ok = true;
    +   QVariant x, y;
    +   int width, height;
    +   char title[256];
    +
    +   QDesktopWidget *d = configApp->desktop();
    +   snprintf(title, sizeof(title), "%s%s",
    +           rootmenu.prompt->text,
    +           ""
    +           );
    +   setWindowTitle(title);
    +
    +   width = configSettings->value("/window width", d->width() - 64).toInt();
    +   height = configSettings->value("/window height", d->height() - 
64).toInt();
    +   resize(width, height);
    +   x = configSettings->value("/window x");
    +   y = configSettings->value("/window y");
    +   if ((x.isValid())&&(y.isValid()))
    +           move(x.toInt(), y.toInt());
    +
    +   split1 = new QSplitter(this);
    +   split1->setOrientation(Qt::Horizontal);
    +   setCentralWidget(split1);
    +
    +   menuView = new ConfigView(split1, "menu");
    +   menuList = menuView->list;
    +
    +   split2 = new QSplitter(split1);
    +   split2->setOrientation(Qt::Vertical);
    +
    +   // create config tree
    +   configView = new ConfigView(split2, "config");
    +   configList = configView->list;
    +
    +   helpText = new ConfigInfoView(split2, "help");
    +
    +   setTabOrder(configList, helpText);
    +   configList->setFocus();
    +
    +   menu = menuBar();
    +   toolBar = new QToolBar("Tools", this);
    +   addToolBar(toolBar);
    +
    +   backAction = new QAction(QPixmap(xpm_back), "Back", this);
    +     connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
    +     backAction->setEnabled(false);
    +   QAction *quitAction = new QAction("&Quit", this);
    +   quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
    +     connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
    +   QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this);
    +   loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
    +     connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
    +   saveAction = new QAction(QPixmap(xpm_save), "&Save", this);
    +   saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
    +     connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
    +   conf_set_changed_callback(conf_changed);
    +   // Set saveAction's initial state
    +   conf_changed();
    +   configname = xstrdup(conf_get_configname());
    +
    +   QAction *saveAsAction = new QAction("Save &As...", this);
    +     connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
    +   QAction *searchAction = new QAction("&Find", this);
    +   searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
    +     connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
    +   singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", 
this);
    +   singleViewAction->setCheckable(true);
    +     connect(singleViewAction, SIGNAL(triggered(bool)), 
SLOT(showSingleView()));
    +   splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", 
this);
    +   splitViewAction->setCheckable(true);
    +     connect(splitViewAction, SIGNAL(triggered(bool)), 
SLOT(showSplitView()));
    +   fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this);
    +   fullViewAction->setCheckable(true);
    +     connect(fullViewAction, SIGNAL(triggered(bool)), 
SLOT(showFullView()));
    +
    +   QAction *showNameAction = new QAction("Show Name", this);
    +     showNameAction->setCheckable(true);
    +     connect(showNameAction, SIGNAL(toggled(bool)), configView, 
SLOT(setShowName(bool)));
    +     showNameAction->setChecked(configView->showName());
    +   QAction *showRangeAction = new QAction("Show Range", this);
    +     showRangeAction->setCheckable(true);
    +     connect(showRangeAction, SIGNAL(toggled(bool)), configView, 
SLOT(setShowRange(bool)));
    +   QAction *showDataAction = new QAction("Show Data", this);
    +     showDataAction->setCheckable(true);
    +     connect(showDataAction, SIGNAL(toggled(bool)), configView, 
SLOT(setShowData(bool)));
    +
    +   QActionGroup *optGroup = new QActionGroup(this);
    +   optGroup->setExclusive(true);
    +   connect(optGroup, SIGNAL(triggered(QAction*)), configView,
    +           SLOT(setOptionMode(QAction *)));
    +   connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
    +           SLOT(setOptionMode(QAction *)));
    +
    +   configView->showNormalAction = new QAction("Show Normal Options", 
optGroup);
    +   configView->showAllAction = new QAction("Show All Options", optGroup);
    +   configView->showPromptAction = new QAction("Show Prompt Options", 
optGroup);
    +   configView->showNormalAction->setCheckable(true);
    +   configView->showAllAction->setCheckable(true);
    +   configView->showPromptAction->setCheckable(true);
    +
    +   QAction *showDebugAction = new QAction("Show Debug Info", this);
    +     showDebugAction->setCheckable(true);
    +     connect(showDebugAction, SIGNAL(toggled(bool)), helpText, 
SLOT(setShowDebug(bool)));
    +     showDebugAction->setChecked(helpText->showDebug());
    +
    +   QAction *showIntroAction = new QAction("Introduction", this);
    +     connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
    +   QAction *showAboutAction = new QAction("About", this);
    +     connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
    +
    +   // init tool bar
    +   toolBar->addAction(backAction);
    +   toolBar->addSeparator();
    +   toolBar->addAction(loadAction);
    +   toolBar->addAction(saveAction);
    +   toolBar->addSeparator();
    +   toolBar->addAction(singleViewAction);
    +   toolBar->addAction(splitViewAction);
    +   toolBar->addAction(fullViewAction);
    +
    +   // create config menu
    +   QMenu* config = menu->addMenu("&File");
    +   config->addAction(loadAction);
    +   config->addAction(saveAction);
    +   config->addAction(saveAsAction);
    +   config->addSeparator();
    +   config->addAction(quitAction);
    +
    +   // create edit menu
    +   QMenu* editMenu = menu->addMenu("&Edit");
    +   editMenu->addAction(searchAction);
    +
    +   // create options menu
    +   QMenu* optionMenu = menu->addMenu("&Option");
    +   optionMenu->addAction(showNameAction);
    +   optionMenu->addAction(showRangeAction);
    +   optionMenu->addAction(showDataAction);
    +   optionMenu->addSeparator();
    +   optionMenu->addActions(optGroup->actions());
    +   optionMenu->addSeparator();
    +   optionMenu->addAction(showDebugAction);
    +
    +   // create help menu
    +   menu->addSeparator();
    +   QMenu* helpMenu = menu->addMenu("&Help");
    +   helpMenu->addAction(showIntroAction);
    +   helpMenu->addAction(showAboutAction);
    +
    +   connect(configList, SIGNAL(menuChanged(struct menu *)),
    +           helpText, SLOT(setInfo(struct menu *)));
    +   connect(configList, SIGNAL(menuSelected(struct menu *)),
    +           SLOT(changeMenu(struct menu *)));
    +   connect(configList, SIGNAL(parentSelected()),
    +           SLOT(goBack()));
    +   connect(menuList, SIGNAL(menuChanged(struct menu *)),
    +           helpText, SLOT(setInfo(struct menu *)));
    +   connect(menuList, SIGNAL(menuSelected(struct menu *)),
    +           SLOT(changeMenu(struct menu *)));
    +
    +   connect(configList, SIGNAL(gotFocus(struct menu *)),
    +           helpText, SLOT(setInfo(struct menu *)));
    +   connect(menuList, SIGNAL(gotFocus(struct menu *)),
    +           helpText, SLOT(setInfo(struct menu *)));
    +   connect(menuList, SIGNAL(gotFocus(struct menu *)),
    +           SLOT(listFocusChanged(void)));
    +   connect(helpText, SIGNAL(menuSelected(struct menu *)),
    +           SLOT(setMenuLink(struct menu *)));
    +
    +   QString listMode = configSettings->value("/listMode", 
"symbol").toString();
    +   if (listMode == "single")
    +           showSingleView();
    +   else if (listMode == "full")
    +           showFullView();
    +   else /*if (listMode == "split")*/
    +           showSplitView();
    +
    +   // UI setup done, restore splitter positions
    +   QList<int> sizes = configSettings->readSizes("/split1", &ok);
    +   if (ok)
    +           split1->setSizes(sizes);
    +
    +   sizes = configSettings->readSizes("/split2", &ok);
    +   if (ok)
    +           split2->setSizes(sizes);
    +}
    +
    +void ConfigMainWindow::loadConfig(void)
    +{
    +   QString str;
    +   QByteArray ba;
    +   const char *name;
    +
    +   str = QFileDialog::getOpenFileName(this, "", configname);
    +   if (str.isNull())
    +           return;
    +
    +   ba = str.toLocal8Bit();
    +   name = ba.data();
    +
    +   if (conf_read(name))
    +           QMessageBox::information(this, "qconf", "Unable to load 
configuration!");
    +
    +   free(configname);
    +   configname = xstrdup(name);
    +
    +   ConfigView::updateListAll();
    +}
    +
    +bool ConfigMainWindow::saveConfig(void)
    +{
    +   if (conf_write(configname)) {
    +           QMessageBox::information(this, "qconf", "Unable to save 
configuration!");
    +           return false;
    +   }
    +   conf_write_autoconf(0);
    +
    +   return true;
    +}
    +
    +void ConfigMainWindow::saveConfigAs(void)
    +{
    +   QString str;
    +   QByteArray ba;
    +   const char *name;
    +
    +   str = QFileDialog::getSaveFileName(this, "", configname);
    +   if (str.isNull())
    +           return;
    +
    +   ba = str.toLocal8Bit();
    +   name = ba.data();
    +
    +   if (conf_write(name)) {
    +           QMessageBox::information(this, "qconf", "Unable to save 
configuration!");
    +   }
    +   conf_write_autoconf(0);
    +
    +   free(configname);
    +   configname = xstrdup(name);
    +}
    +
    +void ConfigMainWindow::searchConfig(void)
    +{
    +   if (!searchWindow)
    +           searchWindow = new ConfigSearchWindow(this, "search");
    +   searchWindow->show();
    +}
    +
    +void ConfigMainWindow::changeMenu(struct menu *menu)
    +{
    +   configList->setRootMenu(menu);
    +   if (configList->rootEntry->parent == &rootmenu)
    +           backAction->setEnabled(false);
    +   else
    +           backAction->setEnabled(true);
    +}
    +
    +void ConfigMainWindow::setMenuLink(struct menu *menu)
    +{
    +   struct menu *parent;
    +   ConfigList* list = NULL;
    +   ConfigItem* item;
    +
    +   if (configList->menuSkip(menu))
    +           return;
    +
    +   switch (configList->mode) {
    +   case singleMode:
    +           list = configList;
    +           parent = menu_get_parent_menu(menu);
    +           if (!parent)
    +                   return;
    +           list->setRootMenu(parent);
    +           break;
    +   case symbolMode:
    +           if (menu->flags & MENU_ROOT) {
    +                   configList->setRootMenu(menu);
    +                   configList->clearSelection();
    +                   list = menuList;
    +           } else {
    +                   list = configList;
    +                   parent = menu_get_parent_menu(menu->parent);
    +                   if (!parent)
    +                           return;
    +                   item = menuList->findConfigItem(parent);
    +                   if (item) {
    +                           item->setSelected(true);
    +                           menuList->scrollToItem(item);
    +                   }
    +                   list->setRootMenu(parent);
    +           }
    +           break;
    +   case fullMode:
    +           list = configList;
    +           break;
    +   default:
    +           break;
    +   }
    +
    +   if (list) {
    +           item = list->findConfigItem(menu);
    +           if (item) {
    +                   item->setSelected(true);
    +                   list->scrollToItem(item);
    +                   list->setFocus();
    +           }
    +   }
    +}
    +
    +void ConfigMainWindow::listFocusChanged(void)
    +{
    +   if (menuList->mode == menuMode)
    +           configList->clearSelection();
    +}
    +
    +void ConfigMainWindow::goBack(void)
    +{
    +   ConfigItem* item, *oldSelection;
    +
    +   configList->setParentMenu();
    +   if (configList->rootEntry == &rootmenu)
    +           backAction->setEnabled(false);
    +
    +   if (menuList->selectedItems().count() == 0)
    +           return;
    +
    +   item = (ConfigItem*)menuList->selectedItems().first();
    +   oldSelection = item;
    +   while (item) {
    +           if (item->menu == configList->rootEntry) {
    +                   oldSelection->setSelected(false);
    +                   item->setSelected(true);
    +                   break;
    +           }
    +           item = (ConfigItem*)item->parent();
    +   }
    +}
    +
    +void ConfigMainWindow::showSingleView(void)
    +{
    +   singleViewAction->setEnabled(false);
    +   singleViewAction->setChecked(true);
    +   splitViewAction->setEnabled(true);
    +   splitViewAction->setChecked(false);
    +   fullViewAction->setEnabled(true);
    +   fullViewAction->setChecked(false);
    +
    +   menuView->hide();
    +   menuList->setRootMenu(0);
    +   configList->mode = singleMode;
    +   if (configList->rootEntry == &rootmenu)
    +           configList->updateListAll();
    +   else
    +           configList->setRootMenu(&rootmenu);
    +   configList->setFocus();
    +}
    +
    +void ConfigMainWindow::showSplitView(void)
    +{
    +   singleViewAction->setEnabled(true);
    +   singleViewAction->setChecked(false);
    +   splitViewAction->setEnabled(false);
    +   splitViewAction->setChecked(true);
    +   fullViewAction->setEnabled(true);
    +   fullViewAction->setChecked(false);
    +
    +   configList->mode = symbolMode;
    +   if (configList->rootEntry == &rootmenu)
    +           configList->updateListAll();
    +   else
    +           configList->setRootMenu(&rootmenu);
    +   configList->setAllOpen(true);
    +   configApp->processEvents();
    +   menuList->mode = menuMode;
    +   menuList->setRootMenu(&rootmenu);
    +   menuList->setAllOpen(true);
    +   menuView->show();
    +   menuList->setFocus();
    +}
    +
    +void ConfigMainWindow::showFullView(void)
    +{
    +   singleViewAction->setEnabled(true);
    +   singleViewAction->setChecked(false);
    +   splitViewAction->setEnabled(true);
    +   splitViewAction->setChecked(false);
    +   fullViewAction->setEnabled(false);
    +   fullViewAction->setChecked(true);
    +
    +   menuView->hide();
    +   menuList->setRootMenu(0);
    +   configList->mode = fullMode;
    +   if (configList->rootEntry == &rootmenu)
    +           configList->updateListAll();
    +   else
    +           configList->setRootMenu(&rootmenu);
    +   configList->setFocus();
    +}
    +
    +/*
    + * ask for saving configuration before quitting
    + * TODO ask only when something changed
    + */
    +void ConfigMainWindow::closeEvent(QCloseEvent* e)
    +{
    +   if (!conf_get_changed()) {
    +           e->accept();
    +           return;
    +   }
    +   QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
    +                   QMessageBox::Yes | QMessageBox::Default, 
QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape);
    +   mb.setButtonText(QMessageBox::Yes, "&Save Changes");
    +   mb.setButtonText(QMessageBox::No, "&Discard Changes");
    +   mb.setButtonText(QMessageBox::Cancel, "Cancel Exit");
    +   switch (mb.exec()) {
    +   case QMessageBox::Yes:
    +           if (saveConfig())
    +                   e->accept();
    +           else
    +                   e->ignore();
    +           break;
    +   case QMessageBox::No:
    +           e->accept();
    +           break;
    +   case QMessageBox::Cancel:
    +           e->ignore();
    +           break;
    +   }
    +}
    +
    +void ConfigMainWindow::showIntro(void)
    +{
    +   static const QString str = "Welcome to the qconf graphical 
configuration tool.\n\n"
    +           "For each option, a blank box indicates the feature is 
disabled, a check\n"
    +           "indicates it is enabled, and a dot indicates that it is to be 
compiled\n"
    +           "as a module.  Clicking on the box will cycle through the three 
states.\n\n"
    +           "If you do not see an option (e.g., a device driver) that you 
believe\n"
    +           "should be present, try turning on Show All Options under the 
Options menu.\n"
    +           "Although there is no cross reference yet to help you figure 
out what other\n"
    +           "options must be enabled to support the option you are 
interested in, you can\n"
    +           "still view the help of a grayed-out option.\n\n"
    +           "Toggling Show Debug Info under the Options menu will show the 
dependencies,\n"
    +           "which you can then match by examining other options.\n\n";
    +
    +   QMessageBox::information(this, "qconf", str);
    +}
    +
    +void ConfigMainWindow::showAbout(void)
    +{
    +   static const QString str = "qconf is Copyright (C) 2002 Roman Zippel 
<zippel@xxxxxxxxxxxxxx>.\n"
    +           "Copyright (C) 2015 Boris Barbulovski 
<bbarbulovski@xxxxxxxxx>.\n\n"
    +           "Bug reports and feature request can also be entered at 
http://bugzilla.kernel.org/\n";;
    +
    +   QMessageBox::information(this, "qconf", str);
    +}
    +
    +void ConfigMainWindow::saveSettings(void)
    +{
    +   configSettings->setValue("/window x", pos().x());
    +   configSettings->setValue("/window y", pos().y());
    +   configSettings->setValue("/window width", size().width());
    +   configSettings->setValue("/window height", size().height());
    +
    +   QString entry;
    +   switch(configList->mode) {
    +   case singleMode :
    +           entry = "single";
    +           break;
    +
    +   case symbolMode :
    +           entry = "split";
    +           break;
    +
    +   case fullMode :
    +           entry = "full";
    +           break;
    +
    +   default:
    +           break;
    +   }
    +   configSettings->setValue("/listMode", entry);
    +
    +   configSettings->writeSizes("/split1", split1->sizes());
    +   configSettings->writeSizes("/split2", split2->sizes());
    +}
    +
    +void ConfigMainWindow::conf_changed(void)
    +{
    +   if (saveAction)
    +           saveAction->setEnabled(conf_get_changed());
    +}
    +
    +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);
    +   }
    +}
    +
    +static const char *progname;
    +
    +static void usage(void)
    +{
    +   printf("%s [-s] <config>\n", progname);
    +   exit(0);
    +}
    +
    +int main(int ac, char** av)
    +{
    +   ConfigMainWindow* v;
    +   const char *name;
    +
    +   progname = av[0];
    +   configApp = new QApplication(ac, av);
    +   if (ac > 1 && av[1][0] == '-') {
    +           switch (av[1][1]) {
    +           case 's':
    +                   conf_set_message_callback(NULL);
    +                   break;
    +           case 'h':
    +           case '?':
    +                   usage();
    +           }
    +           name = av[2];
    +   } else
    +           name = av[1];
    +   if (!name)
    +           usage();
    +
    +   conf_parse(name);
    +   fixup_rootmenu(&rootmenu);
    +   conf_read(NULL);
    +   //zconfdump(stdout);
    +
    +   configSettings = new ConfigSettings();
    +   configSettings->beginGroup("/kconfig/qconf");
    +   v = new ConfigMainWindow();
    +
    +   //zconfdump(stdout);
    +   configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
    +   configApp->connect(configApp, SIGNAL(aboutToQuit()), v, 
SLOT(saveSettings()));
    +   v->show();
    +   configApp->exec();
    +
    +   configSettings->endGroup();
    +   delete configSettings;
    +   delete v;
    +   delete configApp;
    +
    +   return 0;
    +}
    diff --git a/support/kconfig.new/qconf.h b/support/kconfig.new/qconf.h
    new file mode 100644
    index 0000000..45bfe9b
    --- /dev/null
    +++ b/support/kconfig.new/qconf.h
    @@ -0,0 +1,331 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include <QTextBrowser>
    +#include <QTreeWidget>
    +#include <QMainWindow>
    +#include <QHeaderView>
    +#include <qsettings.h>
    +#include <QPushButton>
    +#include <QSettings>
    +#include <QLineEdit>
    +#include <QSplitter>
    +#include <QCheckBox>
    +#include <QDialog>
    +#include "expr.h"
    +
    +class ConfigView;
    +class ConfigList;
    +class ConfigItem;
    +class ConfigLineEdit;
    +class ConfigMainWindow;
    +
    +class ConfigSettings : public QSettings {
    +public:
    +   ConfigSettings();
    +   QList<int> readSizes(const QString& key, bool *ok);
    +   bool writeSizes(const QString& key, const QList<int>& value);
    +};
    +
    +enum colIdx {
    +   promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, 
colNr
    +};
    +enum listMode {
    +   singleMode, menuMode, symbolMode, fullMode, listMode
    +};
    +enum optionMode {
    +   normalOpt = 0, allOpt, promptOpt
    +};
    +
    +class ConfigList : public QTreeWidget {
    +   Q_OBJECT
    +   typedef class QTreeWidget Parent;
    +public:
    +   ConfigList(ConfigView* p, const char *name = 0);
    +   void reinit(void);
    +   ConfigView* parent(void) const
    +   {
    +           return (ConfigView*)Parent::parent();
    +   }
    +   ConfigItem* findConfigItem(struct menu *);
    +
    +protected:
    +   void keyPressEvent(QKeyEvent *e);
    +   void mousePressEvent(QMouseEvent *e);
    +   void mouseReleaseEvent(QMouseEvent *e);
    +   void mouseMoveEvent(QMouseEvent *e);
    +   void mouseDoubleClickEvent(QMouseEvent *e);
    +   void focusInEvent(QFocusEvent *e);
    +   void contextMenuEvent(QContextMenuEvent *e);
    +
    +public slots:
    +   void setRootMenu(struct menu *menu);
    +
    +   void updateList(ConfigItem *item);
    +   void setValue(ConfigItem* item, tristate val);
    +   void changeValue(ConfigItem* item);
    +   void updateSelection(void);
    +   void saveSettings(void);
    +signals:
    +   void menuChanged(struct menu *menu);
    +   void menuSelected(struct menu *menu);
    +   void parentSelected(void);
    +   void gotFocus(struct menu *);
    +
    +public:
    +   void updateListAll(void)
    +   {
    +           updateAll = true;
    +           updateList(NULL);
    +           updateAll = false;
    +   }
    +   ConfigList* listView()
    +   {
    +           return this;
    +   }
    +   ConfigItem* firstChild() const
    +   {
    +           return (ConfigItem *)children().first();
    +   }
    +   void addColumn(colIdx idx)
    +   {
    +           showColumn(idx);
    +   }
    +   void removeColumn(colIdx idx)
    +   {
    +           hideColumn(idx);
    +   }
    +   void setAllOpen(bool open);
    +   void setParentMenu(void);
    +
    +   bool menuSkip(struct menu *);
    +
    +   void updateMenuList(ConfigItem *parent, struct menu*);
    +   void updateMenuList(ConfigList *parent, struct menu*);
    +
    +   bool updateAll;
    +
    +   QPixmap symbolYesPix, symbolModPix, symbolNoPix;
    +   QPixmap choiceYesPix, choiceNoPix;
    +   QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
    +
    +   bool showName, showRange, showData;
    +   enum listMode mode;
    +   enum optionMode optMode;
    +   struct menu *rootEntry;
    +   QPalette disabledColorGroup;
    +   QPalette inactivedColorGroup;
    +   QMenu* headerPopup;
    +};
    +
    +class ConfigItem : public QTreeWidgetItem {
    +   typedef class QTreeWidgetItem Parent;
    +public:
    +   ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool 
v)
    +   : Parent(parent, after), nextItem(0), menu(m), visible(v), 
goParent(false)
    +   {
    +           init();
    +   }
    +   ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool 
v)
    +   : Parent(parent, after), nextItem(0), menu(m), visible(v), 
goParent(false)
    +   {
    +           init();
    +   }
    +   ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
    +   : Parent(parent, after), nextItem(0), menu(0), visible(v), 
goParent(true)
    +   {
    +           init();
    +   }
    +   ~ConfigItem(void);
    +   void init(void);
    +   void okRename(int col);
    +   void updateMenu(void);
    +   void testUpdateMenu(bool v);
    +   ConfigList* listView() const
    +   {
    +           return (ConfigList*)Parent::treeWidget();
    +   }
    +   ConfigItem* firstChild() const
    +   {
    +           return (ConfigItem *)Parent::child(0);
    +   }
    +   ConfigItem* nextSibling()
    +   {
    +           ConfigItem *ret = NULL;
    +           ConfigItem *_parent = (ConfigItem *)parent();
    +
    +           if(_parent) {
    +                   ret = (ConfigItem 
*)_parent->child(_parent->indexOfChild(this)+1);
    +           } else {
    +                   QTreeWidget *_treeWidget = treeWidget();
    +                   ret = (ConfigItem 
*)_treeWidget->topLevelItem(_treeWidget->indexOfTopLevelItem(this)+1);
    +           }
    +
    +           return ret;
    +   }
    +   void setText(colIdx idx, const QString& text)
    +   {
    +           Parent::setText(idx, text);
    +   }
    +   QString text(colIdx idx) const
    +   {
    +           return Parent::text(idx);
    +   }
    +   void setPixmap(colIdx idx, const QIcon &icon)
    +   {
    +           Parent::setIcon(idx, icon);
    +   }
    +   const QIcon pixmap(colIdx idx) const
    +   {
    +           return icon(idx);
    +   }
    +   // TODO: Implement paintCell
    +
    +   ConfigItem* nextItem;
    +   struct menu *menu;
    +   bool visible;
    +   bool goParent;
    +};
    +
    +class ConfigLineEdit : public QLineEdit {
    +   Q_OBJECT
    +   typedef class QLineEdit Parent;
    +public:
    +   ConfigLineEdit(ConfigView* parent);
    +   ConfigView* parent(void) const
    +   {
    +           return (ConfigView*)Parent::parent();
    +   }
    +   void show(ConfigItem *i);
    +   void keyPressEvent(QKeyEvent *e);
    +
    +public:
    +   ConfigItem *item;
    +};
    +
    +class ConfigView : public QWidget {
    +   Q_OBJECT
    +   typedef class QWidget Parent;
    +public:
    +   ConfigView(QWidget* parent, const char *name = 0);
    +   ~ConfigView(void);
    +   static void updateList(ConfigItem* item);
    +   static void updateListAll(void);
    +
    +   bool showName(void) const { return list->showName; }
    +   bool showRange(void) const { return list->showRange; }
    +   bool showData(void) const { return list->showData; }
    +public slots:
    +   void setShowName(bool);
    +   void setShowRange(bool);
    +   void setShowData(bool);
    +   void setOptionMode(QAction *);
    +signals:
    +   void showNameChanged(bool);
    +   void showRangeChanged(bool);
    +   void showDataChanged(bool);
    +public:
    +   ConfigList* list;
    +   ConfigLineEdit* lineEdit;
    +
    +   static ConfigView* viewList;
    +   ConfigView* nextView;
    +
    +   static QAction *showNormalAction;
    +   static QAction *showAllAction;
    +   static QAction *showPromptAction;
    +};
    +
    +class ConfigInfoView : public QTextBrowser {
    +   Q_OBJECT
    +   typedef class QTextBrowser Parent;
    +public:
    +   ConfigInfoView(QWidget* parent, const char *name = 0);
    +   bool showDebug(void) const { return _showDebug; }
    +
    +public slots:
    +   void setInfo(struct menu *menu);
    +   void saveSettings(void);
    +   void setShowDebug(bool);
    +
    +signals:
    +   void showDebugChanged(bool);
    +   void menuSelected(struct menu *);
    +
    +protected:
    +   void symbolInfo(void);
    +   void menuInfo(void);
    +   QString debug_info(struct symbol *sym);
    +   static QString print_filter(const QString &str);
    +   static void expr_print_help(void *data, struct symbol *sym, const char 
*str);
    +   QMenu *createStandardContextMenu(const QPoint & pos);
    +   void contextMenuEvent(QContextMenuEvent *e);
    +
    +   struct symbol *sym;
    +   struct menu *_menu;
    +   bool _showDebug;
    +};
    +
    +class ConfigSearchWindow : public QDialog {
    +   Q_OBJECT
    +   typedef class QDialog Parent;
    +public:
    +   ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0);
    +
    +public slots:
    +   void saveSettings(void);
    +   void search(void);
    +
    +protected:
    +   QLineEdit* editField;
    +   QPushButton* searchButton;
    +   QSplitter* split;
    +   ConfigView* list;
    +   ConfigInfoView* info;
    +
    +   struct symbol **result;
    +};
    +
    +class ConfigMainWindow : public QMainWindow {
    +   Q_OBJECT
    +
    +   char *configname;
    +   static QAction *saveAction;
    +   static void conf_changed(void);
    +public:
    +   ConfigMainWindow(void);
    +public slots:
    +   void changeMenu(struct menu *);
    +   void setMenuLink(struct menu *);
    +   void listFocusChanged(void);
    +   void goBack(void);
    +   void loadConfig(void);
    +   bool saveConfig(void);
    +   void saveConfigAs(void);
    +   void searchConfig(void);
    +   void showSingleView(void);
    +   void showSplitView(void);
    +   void showFullView(void);
    +   void showIntro(void);
    +   void showAbout(void);
    +   void saveSettings(void);
    +
    +protected:
    +   void closeEvent(QCloseEvent *e);
    +
    +   ConfigSearchWindow *searchWindow;
    +   ConfigView *menuView;
    +   ConfigList *menuList;
    +   ConfigView *configView;
    +   ConfigList *configList;
    +   ConfigInfoView *helpText;
    +   QToolBar *toolBar;
    +   QAction *backAction;
    +   QAction *singleViewAction;
    +   QAction *splitViewAction;
    +   QAction *fullViewAction;
    +   QSplitter *split1;
    +   QSplitter *split2;
    +};
    diff --git a/support/kconfig.new/streamline_config.pl 
b/support/kconfig.new/streamline_config.pl
    new file mode 100755
    index 0000000..08d76d7
    --- /dev/null
    +++ b/support/kconfig.new/streamline_config.pl
    @@ -0,0 +1,682 @@
    +#!/usr/bin/env perl
    +# SPDX-License-Identifier: GPL-2.0
    +#
    +# Copyright 2005-2009 - Steven Rostedt
    +#
    +#  It's simple enough to figure out how this works.
    +#  If not, then you can ask me at stripconfig@xxxxxxxxxxx
    +#
    +# What it does?
    +#
    +#   If you have installed a Linux kernel from a distribution
    +#   that turns on way too many modules than you need, and
    +#   you only want the modules you use, then this program
    +#   is perfect for you.
    +#
    +#   It gives you the ability to turn off all the modules that are
    +#   not loaded on your system.
    +#
    +# Howto:
    +#
    +#  1. Boot up the kernel that you want to stream line the config on.
    +#  2. Change directory to the directory holding the source of the
    +#       kernel that you just booted.
    +#  3. Copy the configuraton file to this directory as .config
    +#  4. Have all your devices that you need modules for connected and
    +#      operational (make sure that their corresponding modules are loaded)
    +#  5. Run this script redirecting the output to some other file
    +#       like config_strip.
    +#  6. Back up your old config (if you want too).
    +#  7. copy the config_strip file to .config
    +#  8. Run "make oldconfig"
    +#
    +#  Now your kernel is ready to be built with only the modules that
    +#  are loaded.
    +#
    +# Here's what I did with my Debian distribution.
    +#
    +#    cd /usr/src/linux-2.6.10
    +#    cp /boot/config-2.6.10-1-686-smp .config
    +#    ~/bin/streamline_config > config_strip
    +#    mv .config config_sav
    +#    mv config_strip .config
    +#    make oldconfig
    +#
    +use warnings;
    +use strict;
    +use Getopt::Long;
    +
    +# set the environment variable LOCALMODCONFIG_DEBUG to get
    +# debug output.
    +my $debugprint = 0;
    +$debugprint = 1 if (defined($ENV{LOCALMODCONFIG_DEBUG}));
    +
    +sub dprint {
    +    return if (!$debugprint);
    +    print STDERR @_;
    +}
    +
    +my $config = ".config";
    +
    +my $uname = `uname -r`;
    +chomp $uname;
    +
    +my @searchconfigs = (
    +   {
    +       "file" => ".config",
    +       "exec" => "cat",
    +   },
    +   {
    +       "file" => "/proc/config.gz",
    +       "exec" => "zcat",
    +   },
    +   {
    +       "file" => "/boot/config-$uname",
    +       "exec" => "cat",
    +   },
    +   {
    +       "file" => "/boot/vmlinuz-$uname",
    +       "exec" => "scripts/extract-ikconfig",
    +       "test" => "scripts/extract-ikconfig",
    +   },
    +   {
    +       "file" => "vmlinux",
    +       "exec" => "scripts/extract-ikconfig",
    +       "test" => "scripts/extract-ikconfig",
    +   },
    +   {
    +       "file" => "/lib/modules/$uname/kernel/kernel/configs.ko",
    +       "exec" => "scripts/extract-ikconfig",
    +       "test" => "scripts/extract-ikconfig",
    +   },
    +   {
    +       "file" => "kernel/configs.ko",
    +       "exec" => "scripts/extract-ikconfig",
    +       "test" => "scripts/extract-ikconfig",
    +   },
    +   {
    +       "file" => "kernel/configs.o",
    +       "exec" => "scripts/extract-ikconfig",
    +       "test" => "scripts/extract-ikconfig",
    +   },
    +);
    +
    +sub read_config {
    +    foreach my $conf (@searchconfigs) {
    +   my $file = $conf->{"file"};
    +
    +   next if ( ! -f "$file");
    +
    +   if (defined($conf->{"test"})) {
    +       `$conf->{"test"} $conf->{"file"} 2>/dev/null`;
    +       next if ($?);
    +   }
    +
    +   my $exec = $conf->{"exec"};
    +
    +   print STDERR "using config: '$file'\n";
    +
    +   open(my $infile, '-|', "$exec $file") || die "Failed to run $exec 
$file";
    +   my @x = <$infile>;
    +   close $infile;
    +   return @x;
    +    }
    +    die "No config file found";
    +}
    +
    +my @config_file = read_config;
    +
    +# Parse options
    +my $localmodconfig = 0;
    +my $localyesconfig = 0;
    +
    +GetOptions("localmodconfig" => \$localmodconfig,
    +      "localyesconfig" => \$localyesconfig);
    +
    +# Get the build source and top level Kconfig file (passed in)
    +my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
    +my $kconfig = $ARGV[1];
    +my $lsmod_file = $ENV{'LSMOD'};
    +
    +my @makefiles = `find $ksource -name Makefile -or -name Kbuild 
2>/dev/null`;
    +chomp @makefiles;
    +
    +my %depends;
    +my %selects;
    +my %prompts;
    +my %objects;
    +my $var;
    +my $iflevel = 0;
    +my @ifdeps;
    +
    +# prevent recursion
    +my %read_kconfigs;
    +
    +sub read_kconfig {
    +    my ($kconfig) = @_;
    +
    +    my $state = "NONE";
    +    my $config;
    +
    +    my $cont = 0;
    +    my $line;
    +
    +    my $source = "$ksource/$kconfig";
    +    my $last_source = "";
    +
    +    # Check for any environment variables used
    +    while ($source =~ /\$\((\w+)\)/ && $last_source ne $source) {
    +   my $env = $1;
    +   $last_source = $source;
    +   $source =~ s/\$\($env\)/$ENV{$env}/;
    +    }
    +
    +    open(my $kinfile, '<', $source) || die "Can't open $kconfig";
    +    while (<$kinfile>) {
    +   chomp;
    +
    +   # Make sure that lines ending with \ continue
    +   if ($cont) {
    +       $_ = $line . " " . $_;
    +   }
    +
    +   if (s/\\$//) {
    +       $cont = 1;
    +       $line = $_;
    +       next;
    +   }
    +
    +   $cont = 0;
    +
    +   # collect any Kconfig sources
    +   if (/^source\s+"?([^"]+)/) {
    +       my $kconfig = $1;
    +       # prevent reading twice.
    +       if (!defined($read_kconfigs{$kconfig})) {
    +           $read_kconfigs{$kconfig} = 1;
    +           read_kconfig($kconfig);
    +       }
    +       next;
    +   }
    +
    +   # configs found
    +   if (/^\s*(menu)?config\s+(\S+)\s*$/) {
    +       $state = "NEW";
    +       $config = $2;
    +
    +       # Add depends for 'if' nesting
    +       for (my $i = 0; $i < $iflevel; $i++) {
    +           if ($i) {
    +               $depends{$config} .= " " . $ifdeps[$i];
    +           } else {
    +               $depends{$config} = $ifdeps[$i];
    +           }
    +           $state = "DEP";
    +       }
    +
    +   # collect the depends for the config
    +   } elsif ($state eq "NEW" && /^\s*depends\s+on\s+(.*)$/) {
    +       $state = "DEP";
    +       $depends{$config} = $1;
    +   } elsif ($state eq "DEP" && /^\s*depends\s+on\s+(.*)$/) {
    +       $depends{$config} .= " " . $1;
    +   } elsif ($state eq "DEP" && /^\s*def(_(bool|tristate)|ault)\s+(\S.*)$/) 
{
    +       my $dep = $3;
    +       if ($dep !~ /^\s*(y|m|n)\s*$/) {
    +           $dep =~ s/.*\sif\s+//;
    +           $depends{$config} .= " " . $dep;
    +           dprint "Added default depends $dep to $config\n";
    +       }
    +
    +   # Get the configs that select this config
    +   } elsif ($state ne "NONE" && /^\s*select\s+(\S+)/) {
    +       my $conf = $1;
    +       if (defined($selects{$conf})) {
    +           $selects{$conf} .= " " . $config;
    +       } else {
    +           $selects{$conf} = $config;
    +       }
    +
    +   # configs without prompts must be selected
    +   } elsif ($state ne "NONE" && /^\s*(tristate\s+\S|prompt\b)/) {
    +       # note if the config has a prompt
    +       $prompts{$config} = 1;
    +
    +   # Check for if statements
    +   } elsif (/^if\s+(.*\S)\s*$/) {
    +       my $deps = $1;
    +       # remove beginning and ending non text
    +       $deps =~ s/^[^a-zA-Z0-9_]*//;
    +       $deps =~ s/[^a-zA-Z0-9_]*$//;
    +
    +       my @deps = split /[^a-zA-Z0-9_]+/, $deps;
    +
    +       $ifdeps[$iflevel++] = join ':', @deps;
    +
    +   } elsif (/^endif/) {
    +
    +       $iflevel-- if ($iflevel);
    +
    +   # stop on "help" and keywords that end a menu entry
    +   } elsif (/^\s*(---)?help(---)?\s*$/ || /^(comment|choice|menu)\b/) {
    +       $state = "NONE";
    +   }
    +    }
    +    close($kinfile);
    +}
    +
    +if ($kconfig) {
    +    read_kconfig($kconfig);
    +}
    +
    +# Makefiles can use variables to define their dependencies
    +sub convert_vars {
    +    my ($line, %vars) = @_;
    +
    +    my $process = "";
    +
    +    while ($line =~ s/^(.*?)(\$\((.*?)\))//) {
    +   my $start = $1;
    +   my $variable = $2;
    +   my $var = $3;
    +
    +   if (defined($vars{$var})) {
    +       $process .= $start . $vars{$var};
    +   } else {
    +       $process .= $start . $variable;
    +   }
    +    }
    +
    +    $process .= $line;
    +
    +    return $process;
    +}
    +
    +# Read all Makefiles to map the configs to the objects
    +foreach my $makefile (@makefiles) {
    +
    +    my $line = "";
    +    my %make_vars;
    +
    +    open(my $infile, '<', $makefile) || die "Can't open $makefile";
    +    while (<$infile>) {
    +   # if this line ends with a backslash, continue
    +   chomp;
    +   if (/^(.*)\\$/) {
    +       $line .= $1;
    +       next;
    +   }
    +
    +   $line .= $_;
    +   $_ = $line;
    +   $line = "";
    +
    +   my $objs;
    +
    +   # Convert variables in a line (could define configs)
    +   $_ = convert_vars($_, %make_vars);
    +
    +   # collect objects after obj-$(CONFIG_FOO_BAR)
    +   if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) {
    +       $var = $1;
    +       $objs = $2;
    +
    +   # check if variables are set
    +   } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) {
    +       $make_vars{$1} = $2;
    +   }
    +   if (defined($objs)) {
    +       foreach my $obj (split /\s+/,$objs) {
    +           $obj =~ s/-/_/g;
    +           if ($obj =~ /(.*)\.o$/) {
    +               # Objects may be enabled by more than one config.
    +               # Store configs in an array.
    +               my @arr;
    +
    +               if (defined($objects{$1})) {
    +                   @arr = @{$objects{$1}};
    +               }
    +
    +               $arr[$#arr+1] = $var;
    +
    +               # The objects have a hash mapping to a reference
    +               # of an array of configs.
    +               $objects{$1} = \@arr;
    +           }
    +       }
    +   }
    +    }
    +    close($infile);
    +}
    +
    +my %modules;
    +my $linfile;
    +
    +if (defined($lsmod_file)) {
    +    if ( ! -f $lsmod_file) {
    +   if ( -f $ENV{'objtree'}."/".$lsmod_file) {
    +       $lsmod_file = $ENV{'objtree'}."/".$lsmod_file;
    +   } else {
    +           die "$lsmod_file not found";
    +   }
    +    }
    +
    +    my $otype = ( -x $lsmod_file) ? '-|' : '<';
    +    open($linfile, $otype, $lsmod_file);
    +
    +} else {
    +
    +    # see what modules are loaded on this system
    +    my $lsmod;
    +
    +    foreach my $dir ( ("/sbin", "/bin", "/usr/sbin", "/usr/bin") ) {
    +   if ( -x "$dir/lsmod" ) {
    +       $lsmod = "$dir/lsmod";
    +       last;
    +   }
    +}
    +    if (!defined($lsmod)) {
    +   # try just the path
    +   $lsmod = "lsmod";
    +    }
    +
    +    open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
    +}
    +
    +while (<$linfile>) {
    +   next if (/^Module/);  # Skip the first line.
    +   if (/^(\S+)/) {
    +           $modules{$1} = 1;
    +   }
    +}
    +close ($linfile);
    +
    +# add to the configs hash all configs that are needed to enable
    +# a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
    +# where we know we need bar.o so we add FOO to the list.
    +my %configs;
    +foreach my $module (keys(%modules)) {
    +    if (defined($objects{$module})) {
    +   my @arr = @{$objects{$module}};
    +   foreach my $conf (@arr) {
    +       $configs{$conf} = $module;
    +       dprint "$conf added by direct ($module)\n";
    +       if ($debugprint) {
    +           my $c=$conf;
    +           $c =~ s/^CONFIG_//;
    +           if (defined($depends{$c})) {
    +               dprint " deps = $depends{$c}\n";
    +           } else {
    +               dprint " no deps\n";
    +           }
    +       }
    +   }
    +    } else {
    +   # Most likely, someone has a custom (binary?) module loaded.
    +   print STDERR "$module config not found!!\n";
    +    }
    +}
    +
    +# Read the current config, and see what is enabled. We want to
    +# ignore configs that we would not enable anyway.
    +
    +my %orig_configs;
    +my $valid = "A-Za-z_0-9";
    +
    +foreach my $line (@config_file) {
    +    $_ = $line;
    +
    +    if (/(CONFIG_[$valid]*)=(m|y)/) {
    +   $orig_configs{$1} = $2;
    +    }
    +}
    +
    +my $repeat = 1;
    +
    +my $depconfig;
    +
    +#
    +# Note, we do not care about operands (like: &&, ||, !) we want to add any
    +# config that is in the depend list of another config. This script does
    +# not enable configs that are not already enabled. If we come across a
    +# config A that depends on !B, we can still add B to the list of depends
    +# to keep on. If A was on in the original config, B would not have been
    +# and B would not be turned on by this script.
    +#
    +sub parse_config_depends
    +{
    +    my ($p) = @_;
    +
    +    while ($p =~ /[$valid]/) {
    +
    +   if ($p =~ /^[^$valid]*([$valid]+)/) {
    +       my $conf = "CONFIG_" . $1;
    +
    +       $p =~ s/^[^$valid]*[$valid]+//;
    +
    +       # We only need to process if the depend config is a module
    +       if (!defined($orig_configs{$conf}) || $orig_configs{$conf} eq "y") {
    +           next;
    +       }
    +
    +       if (!defined($configs{$conf})) {
    +           # We must make sure that this config has its
    +           # dependencies met.
    +           $repeat = 1; # do again
    +           dprint "$conf selected by depend $depconfig\n";
    +           $configs{$conf} = 1;
    +       }
    +   } else {
    +       die "this should never happen";
    +   }
    +    }
    +}
    +
    +# Select is treated a bit differently than depends. We call this
    +# when a config has no prompt and requires another config to be
    +# selected. We use to just select all configs that selected this
    +# config, but found that that can balloon into enabling hundreds
    +# of configs that we do not care about.
    +#
    +# The idea is we look at all the configs that select it. If one
    +# is already in our list of configs to enable, then there's nothing
    +# else to do. If there isn't, we pick the first config that was
    +# enabled in the orignal config and use that.
    +sub parse_config_selects
    +{
    +    my ($config, $p) = @_;
    +
    +    my $next_config;
    +
    +    while ($p =~ /[$valid]/) {
    +
    +   if ($p =~ /^[^$valid]*([$valid]+)/) {
    +       my $conf = "CONFIG_" . $1;
    +
    +       $p =~ s/^[^$valid]*[$valid]+//;
    +
    +       # Make sure that this config exists in the current .config file
    +       if (!defined($orig_configs{$conf})) {
    +           dprint "$conf not set for $config select\n";
    +           next;
    +       }
    +
    +       # Check if something other than a module selects this config
    +       if (defined($orig_configs{$conf}) && $orig_configs{$conf} ne "m") {
    +           dprint "$conf (non module) selects config, we are good\n";
    +           # we are good with this
    +           return;
    +       }
    +       if (defined($configs{$conf})) {
    +           dprint "$conf selects $config so we are good\n";
    +           # A set config selects this config, we are good
    +           return;
    +       }
    +       # Set this config to be selected
    +       if (!defined($next_config)) {
    +           $next_config = $conf;
    +       }
    +   } else {
    +       die "this should never happen";
    +   }
    +    }
    +
    +    # If no possible config selected this, then something happened.
    +    if (!defined($next_config)) {
    +   print STDERR "WARNING: $config is required, but nothing in the\n";
    +   print STDERR "  current config selects it.\n";
    +   return;
    +    }
    +
    +    # If we are here, then we found no config that is set and
    +    # selects this config. Repeat.
    +    $repeat = 1;
    +    # Make this config need to be selected
    +    $configs{$next_config} = 1;
    +    dprint "$next_config selected by select $config\n";
    +}
    +
    +my %process_selects;
    +
    +# loop through all configs, select their dependencies.
    +sub loop_depend {
    +    $repeat = 1;
    +
    +    while ($repeat) {
    +   $repeat = 0;
    +
    +      forloop:
    +   foreach my $config (keys %configs) {
    +
    +       # If this config is not a module, we do not need to process it
    +       if (defined($orig_configs{$config}) && $orig_configs{$config} ne 
"m") {
    +           next forloop;
    +       }
    +
    +       $config =~ s/^CONFIG_//;
    +       $depconfig = $config;
    +
    +       if (defined($depends{$config})) {
    +           # This config has dependencies. Make sure they are also included
    +           parse_config_depends $depends{$config};
    +       }
    +
    +       # If the config has no prompt, then we need to check if a config
    +       # that is enabled selected it. Or if we need to enable one.
    +       if (!defined($prompts{$config}) && defined($selects{$config})) {
    +           $process_selects{$config} = 1;
    +       }
    +   }
    +    }
    +}
    +
    +sub loop_select {
    +
    +    foreach my $config (keys %process_selects) {
    +   $config =~ s/^CONFIG_//;
    +
    +   dprint "Process select $config\n";
    +
    +   # config has no prompt and must be selected.
    +   parse_config_selects $config, $selects{$config};
    +    }
    +}
    +
    +while ($repeat) {
    +    # Get the first set of configs and their dependencies.
    +    loop_depend;
    +
    +    $repeat = 0;
    +
    +    # Now we need to see if we have to check selects;
    +    loop_select;
    +}
    +
    +my %setconfigs;
    +
    +# Finally, read the .config file and turn off any module enabled that
    +# we could not find a reason to keep enabled.
    +foreach my $line (@config_file) {
    +    $_ = $line;
    +
    +    if (/CONFIG_IKCONFIG/) {
    +   if (/# CONFIG_IKCONFIG is not set/) {
    +       # enable IKCONFIG at least as a module
    +       print "CONFIG_IKCONFIG=m\n";
    +       # don't ask about PROC
    +       print "# CONFIG_IKCONFIG_PROC is not set\n";
    +   } else {
    +       print;
    +   }
    +   next;
    +    }
    +
    +    if (/CONFIG_MODULE_SIG_KEY="(.+)"/) {
    +        my $orig_cert = $1;
    +        my $default_cert = "certs/signing_key.pem";
    +
    +        # Check that the logic in this script still matches the one in 
Kconfig
    +        if (!defined($depends{"MODULE_SIG_KEY"}) ||
    +            $depends{"MODULE_SIG_KEY"} !~ /"\Q$default_cert\E"/) {
    +            print STDERR "WARNING: MODULE_SIG_KEY assertion failure, ",
    +                "update needed to ", __FILE__, " line ", __LINE__, "\n";
    +            print;
    +        } elsif ($orig_cert ne $default_cert && ! -f $orig_cert) {
    +            print STDERR "Module signature verification enabled but ",
    +                "module signing key \"$orig_cert\" not found. Resetting ",
    +                "signing key to default value.\n";
    +            print "CONFIG_MODULE_SIG_KEY=\"$default_cert\"\n";
    +        } else {
    +            print;
    +        }
    +        next;
    +    }
    +
    +    if (/CONFIG_SYSTEM_TRUSTED_KEYS="(.+)"/) {
    +        my $orig_keys = $1;
    +
    +        if (! -f $orig_keys) {
    +            print STDERR "System keyring enabled but keys \"$orig_keys\" ",
    +                "not found. Resetting keys to default value.\n";
    +            print "CONFIG_SYSTEM_TRUSTED_KEYS=\"\"\n";
    +        } else {
    +            print;
    +        }
    +        next;
    +    }
    +
    +    if (/^(CONFIG.*)=(m|y)/) {
    +   if (defined($configs{$1})) {
    +       if ($localyesconfig) {
    +           $setconfigs{$1} = 'y';
    +           print "$1=y\n";
    +           next;
    +       } else {
    +           $setconfigs{$1} = $2;
    +       }
    +   } elsif ($2 eq "m") {
    +       print "# $1 is not set\n";
    +       next;
    +   }
    +    }
    +    print;
    +}
    +
    +# Integrity check, make sure all modules that we want enabled do
    +# indeed have their configs set.
    +loop:
    +foreach my $module (keys(%modules)) {
    +    if (defined($objects{$module})) {
    +   my @arr = @{$objects{$module}};
    +   foreach my $conf (@arr) {
    +       if (defined($setconfigs{$conf})) {
    +           next loop;
    +       }
    +   }
    +   print STDERR "module $module did not have configs";
    +   foreach my $conf (@arr) {
    +       print STDERR " " , $conf;
    +   }
    +   print STDERR "\n";
    +    }
    +}
    diff --git a/support/kconfig.new/symbol.c b/support/kconfig.new/symbol.c
    new file mode 100644
    index 0000000..1f9266d
    --- /dev/null
    +++ b/support/kconfig.new/symbol.c
    @@ -0,0 +1,1331 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + */
    +
    +#include <ctype.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <regex.h>
    +#include <sys/utsname.h>
    +
    +#include "lkc.h"
    +
    +struct symbol symbol_yes = {
    +   .name = "y",
    +   .curr = { "y", yes },
    +   .flags = SYMBOL_CONST|SYMBOL_VALID,
    +}, symbol_mod = {
    +   .name = "m",
    +   .curr = { "m", mod },
    +   .flags = SYMBOL_CONST|SYMBOL_VALID,
    +}, symbol_no = {
    +   .name = "n",
    +   .curr = { "n", no },
    +   .flags = SYMBOL_CONST|SYMBOL_VALID,
    +}, symbol_empty = {
    +   .name = "",
    +   .curr = { "", no },
    +   .flags = SYMBOL_VALID,
    +};
    +
    +struct symbol *sym_defconfig_list;
    +struct symbol *modules_sym;
    +tristate modules_val;
    +
    +enum symbol_type sym_get_type(struct symbol *sym)
    +{
    +   enum symbol_type type = sym->type;
    +
    +   if (type == S_TRISTATE) {
    +           if (sym_is_choice_value(sym) && sym->visible == yes)
    +                   type = S_BOOLEAN;
    +           else if (modules_val == no)
    +                   type = S_BOOLEAN;
    +   }
    +   return type;
    +}
    +
    +const char *sym_type_name(enum symbol_type type)
    +{
    +   switch (type) {
    +   case S_BOOLEAN:
    +           return "bool";
    +   case S_TRISTATE:
    +           return "tristate";
    +   case S_INT:
    +           return "integer";
    +   case S_HEX:
    +           return "hex";
    +   case S_STRING:
    +           return "string";
    +   case S_UNKNOWN:
    +           return "unknown";
    +   }
    +   return "???";
    +}
    +
    +struct property *sym_get_choice_prop(struct symbol *sym)
    +{
    +   struct property *prop;
    +
    +   for_all_choices(sym, prop)
    +           return prop;
    +   return NULL;
    +}
    +
    +static struct property *sym_get_default_prop(struct symbol *sym)
    +{
    +   struct property *prop;
    +
    +   for_all_defaults(sym, prop) {
    +           prop->visible.tri = expr_calc_value(prop->visible.expr);
    +           if (prop->visible.tri != no)
    +                   return prop;
    +   }
    +   return NULL;
    +}
    +
    +struct property *sym_get_range_prop(struct symbol *sym)
    +{
    +   struct property *prop;
    +
    +   for_all_properties(sym, prop, P_RANGE) {
    +           prop->visible.tri = expr_calc_value(prop->visible.expr);
    +           if (prop->visible.tri != no)
    +                   return prop;
    +   }
    +   return NULL;
    +}
    +
    +static long long sym_get_range_val(struct symbol *sym, int base)
    +{
    +   sym_calc_value(sym);
    +   switch (sym->type) {
    +   case S_INT:
    +           base = 10;
    +           break;
    +   case S_HEX:
    +           base = 16;
    +           break;
    +   default:
    +           break;
    +   }
    +   return strtoll(sym->curr.val, NULL, base);
    +}
    +
    +static void sym_validate_range(struct symbol *sym)
    +{
    +   struct property *prop;
    +   int base;
    +   long long val, val2;
    +   char str[64];
    +
    +   switch (sym->type) {
    +   case S_INT:
    +           base = 10;
    +           break;
    +   case S_HEX:
    +           base = 16;
    +           break;
    +   default:
    +           return;
    +   }
    +   prop = sym_get_range_prop(sym);
    +   if (!prop)
    +           return;
    +   val = strtoll(sym->curr.val, NULL, base);
    +   val2 = sym_get_range_val(prop->expr->left.sym, base);
    +   if (val >= val2) {
    +           val2 = sym_get_range_val(prop->expr->right.sym, base);
    +           if (val <= val2)
    +                   return;
    +   }
    +   if (sym->type == S_INT)
    +           sprintf(str, "%lld", val2);
    +   else
    +           sprintf(str, "0x%llx", val2);
    +   sym->curr.val = xstrdup(str);
    +}
    +
    +static void sym_set_changed(struct symbol *sym)
    +{
    +   struct property *prop;
    +
    +   sym->flags |= SYMBOL_CHANGED;
    +   for (prop = sym->prop; prop; prop = prop->next) {
    +           if (prop->menu)
    +                   prop->menu->flags |= MENU_CHANGED;
    +   }
    +}
    +
    +static void sym_set_all_changed(void)
    +{
    +   struct symbol *sym;
    +   int i;
    +
    +   for_all_symbols(i, sym)
    +           sym_set_changed(sym);
    +}
    +
    +static void sym_calc_visibility(struct symbol *sym)
    +{
    +   struct property *prop;
    +   struct symbol *choice_sym = NULL;
    +   tristate tri;
    +
    +   /* any prompt visible? */
    +   tri = no;
    +
    +   if (sym_is_choice_value(sym))
    +           choice_sym = prop_get_symbol(sym_get_choice_prop(sym));
    +
    +   for_all_prompts(sym, prop) {
    +           prop->visible.tri = expr_calc_value(prop->visible.expr);
    +           /*
    +            * Tristate choice_values with visibility 'mod' are
    +            * not visible if the corresponding choice's value is
    +            * 'yes'.
    +            */
    +           if (choice_sym && sym->type == S_TRISTATE &&
    +               prop->visible.tri == mod && choice_sym->curr.tri == yes)
    +                   prop->visible.tri = no;
    +
    +           tri = EXPR_OR(tri, prop->visible.tri);
    +   }
    +   if (tri == mod && (sym->type != S_TRISTATE || modules_val == no))
    +           tri = yes;
    +   if (sym->visible != tri) {
    +           sym->visible = tri;
    +           sym_set_changed(sym);
    +   }
    +   if (sym_is_choice_value(sym))
    +           return;
    +   /* defaulting to "yes" if no explicit "depends on" are given */
    +   tri = yes;
    +   if (sym->dir_dep.expr)
    +           tri = expr_calc_value(sym->dir_dep.expr);
    +   if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
    +           tri = yes;
    +   if (sym->dir_dep.tri != tri) {
    +           sym->dir_dep.tri = tri;
    +           sym_set_changed(sym);
    +   }
    +   tri = no;
    +   if (sym->rev_dep.expr)
    +           tri = expr_calc_value(sym->rev_dep.expr);
    +   if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
    +           tri = yes;
    +   if (sym->rev_dep.tri != tri) {
    +           sym->rev_dep.tri = tri;
    +           sym_set_changed(sym);
    +   }
    +   tri = no;
    +   if (sym->implied.expr && sym->dir_dep.tri != no)
    +           tri = expr_calc_value(sym->implied.expr);
    +   if (tri == mod && sym_get_type(sym) == S_BOOLEAN)
    +           tri = yes;
    +   if (sym->implied.tri != tri) {
    +           sym->implied.tri = tri;
    +           sym_set_changed(sym);
    +   }
    +}
    +
    +/*
    + * Find the default symbol for a choice.
    + * First try the default values for the choice symbol
    + * Next locate the first visible choice value
    + * Return NULL if none was found
    + */
    +struct symbol *sym_choice_default(struct symbol *sym)
    +{
    +   struct symbol *def_sym;
    +   struct property *prop;
    +   struct expr *e;
    +
    +   /* any of the defaults visible? */
    +   for_all_defaults(sym, prop) {
    +           prop->visible.tri = expr_calc_value(prop->visible.expr);
    +           if (prop->visible.tri == no)
    +                   continue;
    +           def_sym = prop_get_symbol(prop);
    +           if (def_sym->visible != no)
    +                   return def_sym;
    +   }
    +
    +   /* just get the first visible value */
    +   prop = sym_get_choice_prop(sym);
    +   expr_list_for_each_sym(prop->expr, e, def_sym)
    +           if (def_sym->visible != no)
    +                   return def_sym;
    +
    +   /* failed to locate any defaults */
    +   return NULL;
    +}
    +
    +static struct symbol *sym_calc_choice(struct symbol *sym)
    +{
    +   struct symbol *def_sym;
    +   struct property *prop;
    +   struct expr *e;
    +   int flags;
    +
    +   /* first calculate all choice values' visibilities */
    +   flags = sym->flags;
    +   prop = sym_get_choice_prop(sym);
    +   expr_list_for_each_sym(prop->expr, e, def_sym) {
    +           sym_calc_visibility(def_sym);
    +           if (def_sym->visible != no)
    +                   flags &= def_sym->flags;
    +   }
    +
    +   sym->flags &= flags | ~SYMBOL_DEF_USER;
    +
    +   /* is the user choice visible? */
    +   def_sym = sym->def[S_DEF_USER].val;
    +   if (def_sym && def_sym->visible != no)
    +           return def_sym;
    +
    +   def_sym = sym_choice_default(sym);
    +
    +   if (def_sym == NULL)
    +           /* no choice? reset tristate value */
    +           sym->curr.tri = no;
    +
    +   return def_sym;
    +}
    +
    +static void sym_warn_unmet_dep(struct symbol *sym)
    +{
    +   struct gstr gs = str_new();
    +
    +   str_printf(&gs,
    +              "\nWARNING: unmet direct dependencies detected for %s\n",
    +              sym->name);
    +   str_printf(&gs,
    +              "  Depends on [%c]: ",
    +              sym->dir_dep.tri == mod ? 'm' : 'n');
    +   expr_gstr_print(sym->dir_dep.expr, &gs);
    +   str_printf(&gs, "\n");
    +
    +   expr_gstr_print_revdep(sym->rev_dep.expr, &gs, yes,
    +                          "  Selected by [y]:\n");
    +   expr_gstr_print_revdep(sym->rev_dep.expr, &gs, mod,
    +                          "  Selected by [m]:\n");
    +
    +   fputs(str_get(&gs), stderr);
    +}
    +
    +void sym_calc_value(struct symbol *sym)
    +{
    +   struct symbol_value newval, oldval;
    +   struct property *prop;
    +   struct expr *e;
    +
    +   if (!sym)
    +           return;
    +
    +   if (sym->flags & SYMBOL_VALID)
    +           return;
    +
    +   if (sym_is_choice_value(sym) &&
    +       sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) {
    +           sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES;
    +           prop = sym_get_choice_prop(sym);
    +           sym_calc_value(prop_get_symbol(prop));
    +   }
    +
    +   sym->flags |= SYMBOL_VALID;
    +
    +   oldval = sym->curr;
    +
    +   switch (sym->type) {
    +   case S_INT:
    +   case S_HEX:
    +   case S_STRING:
    +           newval = symbol_empty.curr;
    +           break;
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           newval = symbol_no.curr;
    +           break;
    +   default:
    +           sym->curr.val = sym->name;
    +           sym->curr.tri = no;
    +           return;
    +   }
    +   sym->flags &= ~SYMBOL_WRITE;
    +
    +   sym_calc_visibility(sym);
    +
    +   if (sym->visible != no)
    +           sym->flags |= SYMBOL_WRITE;
    +
    +   /* set default if recursively called */
    +   sym->curr = newval;
    +
    +   switch (sym_get_type(sym)) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           if (sym_is_choice_value(sym) && sym->visible == yes) {
    +                   prop = sym_get_choice_prop(sym);
    +                   newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? 
yes : no;
    +           } else {
    +                   if (sym->visible != no) {
    +                           /* if the symbol is visible use the user value
    +                            * if available, otherwise try the default value
    +                            */
    +                           if (sym_has_value(sym)) {
    +                                   newval.tri = 
EXPR_AND(sym->def[S_DEF_USER].tri,
    +                                                         sym->visible);
    +                                   goto calc_newval;
    +                           }
    +                   }
    +                   if (sym->rev_dep.tri != no)
    +                           sym->flags |= SYMBOL_WRITE;
    +                   if (!sym_is_choice(sym)) {
    +                           prop = sym_get_default_prop(sym);
    +                           if (prop) {
    +                                   newval.tri = 
EXPR_AND(expr_calc_value(prop->expr),
    +                                                         
prop->visible.tri);
    +                                   if (newval.tri != no)
    +                                           sym->flags |= SYMBOL_WRITE;
    +                           }
    +                           if (sym->implied.tri != no) {
    +                                   sym->flags |= SYMBOL_WRITE;
    +                                   newval.tri = EXPR_OR(newval.tri, 
sym->implied.tri);
    +                           }
    +                   }
    +           calc_newval:
    +                   if (sym->dir_dep.tri < sym->rev_dep.tri)
    +                           sym_warn_unmet_dep(sym);
    +                   newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri);
    +           }
    +           if (newval.tri == mod &&
    +               (sym_get_type(sym) == S_BOOLEAN || sym->implied.tri == yes))
    +                   newval.tri = yes;
    +           break;
    +   case S_STRING:
    +   case S_HEX:
    +   case S_INT:
    +           if (sym->visible != no && sym_has_value(sym)) {
    +                   newval.val = sym->def[S_DEF_USER].val;
    +                   break;
    +           }
    +           prop = sym_get_default_prop(sym);
    +           if (prop) {
    +                   struct symbol *ds = prop_get_symbol(prop);
    +                   if (ds) {
    +                           sym->flags |= SYMBOL_WRITE;
    +                           sym_calc_value(ds);
    +                           newval.val = ds->curr.val;
    +                   }
    +           }
    +           break;
    +   default:
    +           ;
    +   }
    +
    +   sym->curr = newval;
    +   if (sym_is_choice(sym) && newval.tri == yes)
    +           sym->curr.val = sym_calc_choice(sym);
    +   sym_validate_range(sym);
    +
    +   if (memcmp(&oldval, &sym->curr, sizeof(oldval))) {
    +           sym_set_changed(sym);
    +           if (modules_sym == sym) {
    +                   sym_set_all_changed();
    +                   modules_val = modules_sym->curr.tri;
    +           }
    +   }
    +
    +   if (sym_is_choice(sym)) {
    +           struct symbol *choice_sym;
    +
    +           prop = sym_get_choice_prop(sym);
    +           expr_list_for_each_sym(prop->expr, e, choice_sym) {
    +                   if ((sym->flags & SYMBOL_WRITE) &&
    +                       choice_sym->visible != no)
    +                           choice_sym->flags |= SYMBOL_WRITE;
    +                   if (sym->flags & SYMBOL_CHANGED)
    +                           sym_set_changed(choice_sym);
    +           }
    +   }
    +
    +   if (sym->flags & SYMBOL_NO_WRITE)
    +           sym->flags &= ~SYMBOL_WRITE;
    +
    +   if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES)
    +           set_all_choice_values(sym);
    +}
    +
    +void sym_clear_all_valid(void)
    +{
    +   struct symbol *sym;
    +   int i;
    +
    +   for_all_symbols(i, sym)
    +           sym->flags &= ~SYMBOL_VALID;
    +   sym_add_change_count(1);
    +   sym_calc_value(modules_sym);
    +}
    +
    +bool sym_tristate_within_range(struct symbol *sym, tristate val)
    +{
    +   int type = sym_get_type(sym);
    +
    +   if (sym->visible == no)
    +           return false;
    +
    +   if (type != S_BOOLEAN && type != S_TRISTATE)
    +           return false;
    +
    +   if (type == S_BOOLEAN && val == mod)
    +           return false;
    +   if (sym->visible <= sym->rev_dep.tri)
    +           return false;
    +   if (sym->implied.tri == yes && val == mod)
    +           return false;
    +   if (sym_is_choice_value(sym) && sym->visible == yes)
    +           return val == yes;
    +   return val >= sym->rev_dep.tri && val <= sym->visible;
    +}
    +
    +bool sym_set_tristate_value(struct symbol *sym, tristate val)
    +{
    +   tristate oldval = sym_get_tristate_value(sym);
    +
    +   if (oldval != val && !sym_tristate_within_range(sym, val))
    +           return false;
    +
    +   if (!(sym->flags & SYMBOL_DEF_USER)) {
    +           sym->flags |= SYMBOL_DEF_USER;
    +           sym_set_changed(sym);
    +   }
    +   /*
    +    * setting a choice value also resets the new flag of the choice
    +    * symbol and all other choice values.
    +    */
    +   if (sym_is_choice_value(sym) && val == yes) {
    +           struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym));
    +           struct property *prop;
    +           struct expr *e;
    +
    +           cs->def[S_DEF_USER].val = sym;
    +           cs->flags |= SYMBOL_DEF_USER;
    +           prop = sym_get_choice_prop(cs);
    +           for (e = prop->expr; e; e = e->left.expr) {
    +                   if (e->right.sym->visible != no)
    +                           e->right.sym->flags |= SYMBOL_DEF_USER;
    +           }
    +   }
    +
    +   sym->def[S_DEF_USER].tri = val;
    +   if (oldval != val)
    +           sym_clear_all_valid();
    +
    +   return true;
    +}
    +
    +tristate sym_toggle_tristate_value(struct symbol *sym)
    +{
    +   tristate oldval, newval;
    +
    +   oldval = newval = sym_get_tristate_value(sym);
    +   do {
    +           switch (newval) {
    +           case no:
    +                   newval = mod;
    +                   break;
    +           case mod:
    +                   newval = yes;
    +                   break;
    +           case yes:
    +                   newval = no;
    +                   break;
    +           }
    +           if (sym_set_tristate_value(sym, newval))
    +                   break;
    +   } while (oldval != newval);
    +   return newval;
    +}
    +
    +bool sym_string_valid(struct symbol *sym, const char *str)
    +{
    +   signed char ch;
    +
    +   switch (sym->type) {
    +   case S_STRING:
    +           return true;
    +   case S_INT:
    +           ch = *str++;
    +           if (ch == '-')
    +                   ch = *str++;
    +           if (!isdigit(ch))
    +                   return false;
    +           if (ch == '0' && *str != 0)
    +                   return false;
    +           while ((ch = *str++)) {
    +                   if (!isdigit(ch))
    +                           return false;
    +           }
    +           return true;
    +   case S_HEX:
    +           if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
    +                   str += 2;
    +           ch = *str++;
    +           do {
    +                   if (!isxdigit(ch))
    +                           return false;
    +           } while ((ch = *str++));
    +           return true;
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           switch (str[0]) {
    +           case 'y': case 'Y':
    +           case 'm': case 'M':
    +           case 'n': case 'N':
    +                   return true;
    +           }
    +           return false;
    +   default:
    +           return false;
    +   }
    +}
    +
    +bool sym_string_within_range(struct symbol *sym, const char *str)
    +{
    +   struct property *prop;
    +   long long val;
    +
    +   switch (sym->type) {
    +   case S_STRING:
    +           return sym_string_valid(sym, str);
    +   case S_INT:
    +           if (!sym_string_valid(sym, str))
    +                   return false;
    +           prop = sym_get_range_prop(sym);
    +           if (!prop)
    +                   return true;
    +           val = strtoll(str, NULL, 10);
    +           return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
    +                  val <= sym_get_range_val(prop->expr->right.sym, 10);
    +   case S_HEX:
    +           if (!sym_string_valid(sym, str))
    +                   return false;
    +           prop = sym_get_range_prop(sym);
    +           if (!prop)
    +                   return true;
    +           val = strtoll(str, NULL, 16);
    +           return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
    +                  val <= sym_get_range_val(prop->expr->right.sym, 16);
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           switch (str[0]) {
    +           case 'y': case 'Y':
    +                   return sym_tristate_within_range(sym, yes);
    +           case 'm': case 'M':
    +                   return sym_tristate_within_range(sym, mod);
    +           case 'n': case 'N':
    +                   return sym_tristate_within_range(sym, no);
    +           }
    +           return false;
    +   default:
    +           return false;
    +   }
    +}
    +
    +bool sym_set_string_value(struct symbol *sym, const char *newval)
    +{
    +   const char *oldval;
    +   char *val;
    +   int size;
    +
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           switch (newval[0]) {
    +           case 'y': case 'Y':
    +                   return sym_set_tristate_value(sym, yes);
    +           case 'm': case 'M':
    +                   return sym_set_tristate_value(sym, mod);
    +           case 'n': case 'N':
    +                   return sym_set_tristate_value(sym, no);
    +           }
    +           return false;
    +   default:
    +           ;
    +   }
    +
    +   if (!sym_string_within_range(sym, newval))
    +           return false;
    +
    +   if (!(sym->flags & SYMBOL_DEF_USER)) {
    +           sym->flags |= SYMBOL_DEF_USER;
    +           sym_set_changed(sym);
    +   }
    +
    +   oldval = sym->def[S_DEF_USER].val;
    +   size = strlen(newval) + 1;
    +   if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && 
newval[1] != 'X'))) {
    +           size += 2;
    +           sym->def[S_DEF_USER].val = val = xmalloc(size);
    +           *val++ = '0';
    +           *val++ = 'x';
    +   } else if (!oldval || strcmp(oldval, newval))
    +           sym->def[S_DEF_USER].val = val = xmalloc(size);
    +   else
    +           return true;
    +
    +   strcpy(val, newval);
    +   free((void *)oldval);
    +   sym_clear_all_valid();
    +
    +   return true;
    +}
    +
    +/*
    + * Find the default value associated to a symbol.
    + * For tristate symbol handle the modules=n case
    + * in which case "m" becomes "y".
    + * If the symbol does not have any default then fallback
    + * to the fixed default values.
    + */
    +const char *sym_get_string_default(struct symbol *sym)
    +{
    +   struct property *prop;
    +   struct symbol *ds;
    +   const char *str;
    +   tristate val;
    +
    +   sym_calc_visibility(sym);
    +   sym_calc_value(modules_sym);
    +   val = symbol_no.curr.tri;
    +   str = symbol_empty.curr.val;
    +
    +   /* If symbol has a default value look it up */
    +   prop = sym_get_default_prop(sym);
    +   if (prop != NULL) {
    +           switch (sym->type) {
    +           case S_BOOLEAN:
    +           case S_TRISTATE:
    +                   /* The visibility may limit the value from yes => mod */
    +                   val = EXPR_AND(expr_calc_value(prop->expr), 
prop->visible.tri);
    +                   break;
    +           default:
    +                   /*
    +                    * The following fails to handle the situation
    +                    * where a default value is further limited by
    +                    * the valid range.
    +                    */
    +                   ds = prop_get_symbol(prop);
    +                   if (ds != NULL) {
    +                           sym_calc_value(ds);
    +                           str = (const char *)ds->curr.val;
    +                   }
    +           }
    +   }
    +
    +   /* Handle select statements */
    +   val = EXPR_OR(val, sym->rev_dep.tri);
    +
    +   /* transpose mod to yes if modules are not enabled */
    +   if (val == mod)
    +           if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no)
    +                   val = yes;
    +
    +   /* transpose mod to yes if type is bool */
    +   if (sym->type == S_BOOLEAN && val == mod)
    +           val = yes;
    +
    +   /* adjust the default value if this symbol is implied by another */
    +   if (val < sym->implied.tri)
    +           val = sym->implied.tri;
    +
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           switch (val) {
    +           case no: return "n";
    +           case mod: return "m";
    +           case yes: return "y";
    +           }
    +   case S_INT:
    +   case S_HEX:
    +           return str;
    +   case S_STRING:
    +           return str;
    +   case S_UNKNOWN:
    +           break;
    +   }
    +   return "";
    +}
    +
    +const char *sym_get_string_value(struct symbol *sym)
    +{
    +   tristate val;
    +
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +   case S_TRISTATE:
    +           val = sym_get_tristate_value(sym);
    +           switch (val) {
    +           case no:
    +                   return "n";
    +           case mod:
    +                   sym_calc_value(modules_sym);
    +                   return (modules_sym->curr.tri == no) ? "n" : "m";
    +           case yes:
    +                   return "y";
    +           }
    +           break;
    +   default:
    +           ;
    +   }
    +   return (const char *)sym->curr.val;
    +}
    +
    +bool sym_is_changable(struct symbol *sym)
    +{
    +   return sym->visible > sym->rev_dep.tri;
    +}
    +
    +static unsigned strhash(const char *s)
    +{
    +   /* fnv32 hash */
    +   unsigned hash = 2166136261U;
    +   for (; *s; s++)
    +           hash = (hash ^ *s) * 0x01000193;
    +   return hash;
    +}
    +
    +struct symbol *sym_lookup(const char *name, int flags)
    +{
    +   struct symbol *symbol;
    +   char *new_name;
    +   int hash;
    +
    +   if (name) {
    +           if (name[0] && !name[1]) {
    +                   switch (name[0]) {
    +                   case 'y': return &symbol_yes;
    +                   case 'm': return &symbol_mod;
    +                   case 'n': return &symbol_no;
    +                   }
    +           }
    +           hash = strhash(name) % SYMBOL_HASHSIZE;
    +
    +           for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) 
{
    +                   if (symbol->name &&
    +                       !strcmp(symbol->name, name) &&
    +                       (flags ? symbol->flags & flags
    +                              : !(symbol->flags & 
(SYMBOL_CONST|SYMBOL_CHOICE))))
    +                           return symbol;
    +           }
    +           new_name = xstrdup(name);
    +   } else {
    +           new_name = NULL;
    +           hash = 0;
    +   }
    +
    +   symbol = xmalloc(sizeof(*symbol));
    +   memset(symbol, 0, sizeof(*symbol));
    +   symbol->name = new_name;
    +   symbol->type = S_UNKNOWN;
    +   symbol->flags |= flags;
    +
    +   symbol->next = symbol_hash[hash];
    +   symbol_hash[hash] = symbol;
    +
    +   return symbol;
    +}
    +
    +struct symbol *sym_find(const char *name)
    +{
    +   struct symbol *symbol = NULL;
    +   int hash = 0;
    +
    +   if (!name)
    +           return NULL;
    +
    +   if (name[0] && !name[1]) {
    +           switch (name[0]) {
    +           case 'y': return &symbol_yes;
    +           case 'm': return &symbol_mod;
    +           case 'n': return &symbol_no;
    +           }
    +   }
    +   hash = strhash(name) % SYMBOL_HASHSIZE;
    +
    +   for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
    +           if (symbol->name &&
    +               !strcmp(symbol->name, name) &&
    +               !(symbol->flags & SYMBOL_CONST))
    +                           break;
    +   }
    +
    +   return symbol;
    +}
    +
    +const char *sym_escape_string_value(const char *in)
    +{
    +   const char *p;
    +   size_t reslen;
    +   char *res;
    +   size_t l;
    +
    +   reslen = strlen(in) + strlen("\"\"") + 1;
    +
    +   p = in;
    +   for (;;) {
    +           l = strcspn(p, "\"\\");
    +           p += l;
    +
    +           if (p[0] == '\0')
    +                   break;
    +
    +           reslen++;
    +           p++;
    +   }
    +
    +   res = xmalloc(reslen);
    +   res[0] = '\0';
    +
    +   strcat(res, "\"");
    +
    +   p = in;
    +   for (;;) {
    +           l = strcspn(p, "\"\\");
    +           strncat(res, p, l);
    +           p += l;
    +
    +           if (p[0] == '\0')
    +                   break;
    +
    +           strcat(res, "\\");
    +           strncat(res, p++, 1);
    +   }
    +
    +   strcat(res, "\"");
    +   return res;
    +}
    +
    +struct sym_match {
    +   struct symbol   *sym;
    +   off_t           so, eo;
    +};
    +
    +/* Compare matched symbols as thus:
    + * - first, symbols that match exactly
    + * - then, alphabetical sort
    + */
    +static int sym_rel_comp(const void *sym1, const void *sym2)
    +{
    +   const struct sym_match *s1 = sym1;
    +   const struct sym_match *s2 = sym2;
    +   int exact1, exact2;
    +
    +   /* Exact match:
    +    * - if matched length on symbol s1 is the length of that symbol,
    +    *   then this symbol should come first;
    +    * - if matched length on symbol s2 is the length of that symbol,
    +    *   then this symbol should come first.
    +    * Note: since the search can be a regexp, both symbols may match
    +    * exactly; if this is the case, we can't decide which comes first,
    +    * and we fallback to sorting alphabetically.
    +    */
    +   exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
    +   exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
    +   if (exact1 && !exact2)
    +           return -1;
    +   if (!exact1 && exact2)
    +           return 1;
    +
    +   /* As a fallback, sort symbols alphabetically */
    +   return strcmp(s1->sym->name, s2->sym->name);
    +}
    +
    +struct symbol **sym_re_search(const char *pattern)
    +{
    +   struct symbol *sym, **sym_arr = NULL;
    +   struct sym_match *sym_match_arr = NULL;
    +   int i, cnt, size;
    +   regex_t re;
    +   regmatch_t match[1];
    +
    +   cnt = size = 0;
    +   /* Skip if empty */
    +   if (strlen(pattern) == 0)
    +           return NULL;
    +   if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE))
    +           return NULL;
    +
    +   for_all_symbols(i, sym) {
    +           if (sym->flags & SYMBOL_CONST || !sym->name)
    +                   continue;
    +           if (regexec(&re, sym->name, 1, match, 0))
    +                   continue;
    +           if (cnt >= size) {
    +                   void *tmp;
    +                   size += 16;
    +                   tmp = realloc(sym_match_arr, size * sizeof(struct 
sym_match));
    +                   if (!tmp)
    +                           goto sym_re_search_free;
    +                   sym_match_arr = tmp;
    +           }
    +           sym_calc_value(sym);
    +           /* As regexec returned 0, we know we have a match, so
    +            * we can use match[0].rm_[se]o without further checks
    +            */
    +           sym_match_arr[cnt].so = match[0].rm_so;
    +           sym_match_arr[cnt].eo = match[0].rm_eo;
    +           sym_match_arr[cnt++].sym = sym;
    +   }
    +   if (sym_match_arr) {
    +           qsort(sym_match_arr, cnt, sizeof(struct sym_match), 
sym_rel_comp);
    +           sym_arr = malloc((cnt+1) * sizeof(struct symbol *));
    +           if (!sym_arr)
    +                   goto sym_re_search_free;
    +           for (i = 0; i < cnt; i++)
    +                   sym_arr[i] = sym_match_arr[i].sym;
    +           sym_arr[cnt] = NULL;
    +   }
    +sym_re_search_free:
    +   /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
    +   free(sym_match_arr);
    +   regfree(&re);
    +
    +   return sym_arr;
    +}
    +
    +/*
    + * When we check for recursive dependencies we use a stack to save
    + * current state so we can print out relevant info to user.
    + * The entries are located on the call stack so no need to free memory.
    + * Note insert() remove() must always match to properly clear the stack.
    + */
    +static struct dep_stack {
    +   struct dep_stack *prev, *next;
    +   struct symbol *sym;
    +   struct property *prop;
    +   struct expr **expr;
    +} *check_top;
    +
    +static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
    +{
    +   memset(stack, 0, sizeof(*stack));
    +   if (check_top)
    +           check_top->next = stack;
    +   stack->prev = check_top;
    +   stack->sym = sym;
    +   check_top = stack;
    +}
    +
    +static void dep_stack_remove(void)
    +{
    +   check_top = check_top->prev;
    +   if (check_top)
    +           check_top->next = NULL;
    +}
    +
    +/*
    + * Called when we have detected a recursive dependency.
    + * check_top point to the top of the stact so we use
    + * the ->prev pointer to locate the bottom of the stack.
    + */
    +static void sym_check_print_recursive(struct symbol *last_sym)
    +{
    +   struct dep_stack *stack;
    +   struct symbol *sym, *next_sym;
    +   struct menu *menu = NULL;
    +   struct property *prop;
    +   struct dep_stack cv_stack;
    +
    +   if (sym_is_choice_value(last_sym)) {
    +           dep_stack_insert(&cv_stack, last_sym);
    +           last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
    +   }
    +
    +   for (stack = check_top; stack != NULL; stack = stack->prev)
    +           if (stack->sym == last_sym)
    +                   break;
    +   if (!stack) {
    +           fprintf(stderr, "unexpected recursive dependency error\n");
    +           return;
    +   }
    +
    +   for (; stack; stack = stack->next) {
    +           sym = stack->sym;
    +           next_sym = stack->next ? stack->next->sym : last_sym;
    +           prop = stack->prop;
    +           if (prop == NULL)
    +                   prop = stack->sym->prop;
    +
    +           /* for choice values find the menu entry (used below) */
    +           if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
    +                   for (prop = sym->prop; prop; prop = prop->next) {
    +                           menu = prop->menu;
    +                           if (prop->menu)
    +                                   break;
    +                   }
    +           }
    +           if (stack->sym == last_sym)
    +                   fprintf(stderr, "%s:%d:error: recursive dependency 
detected!\n",
    +                           prop->file->name, prop->lineno);
    +
    +           if (sym_is_choice(sym)) {
    +                   fprintf(stderr, "%s:%d:\tchoice %s contains symbol 
%s\n",
    +                           menu->file->name, menu->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           } else if (sym_is_choice_value(sym)) {
    +                   fprintf(stderr, "%s:%d:\tsymbol %s is part of choice 
%s\n",
    +                           menu->file->name, menu->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           } else if (stack->expr == &sym->dir_dep.expr) {
    +                   fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
    +                           prop->file->name, prop->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           } else if (stack->expr == &sym->rev_dep.expr) {
    +                   fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
    +                           prop->file->name, prop->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           } else if (stack->expr == &sym->implied.expr) {
    +                   fprintf(stderr, "%s:%d:\tsymbol %s is implied by %s\n",
    +                           prop->file->name, prop->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           } else if (stack->expr) {
    +                   fprintf(stderr, "%s:%d:\tsymbol %s %s value contains 
%s\n",
    +                           prop->file->name, prop->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           prop_get_type_name(prop->type),
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           } else {
    +                   fprintf(stderr, "%s:%d:\tsymbol %s %s is visible 
depending on %s\n",
    +                           prop->file->name, prop->lineno,
    +                           sym->name ? sym->name : "<choice>",
    +                           prop_get_type_name(prop->type),
    +                           next_sym->name ? next_sym->name : "<choice>");
    +           }
    +   }
    +
    +   fprintf(stderr,
    +           "For a resolution refer to 
Documentation/kbuild/kconfig-language.txt\n"
    +           "subsection \"Kconfig recursive dependency limitations\"\n"
    +           "\n");
    +
    +   if (check_top == &cv_stack)
    +           dep_stack_remove();
    +}
    +
    +static struct symbol *sym_check_expr_deps(struct expr *e)
    +{
    +   struct symbol *sym;
    +
    +   if (!e)
    +           return NULL;
    +   switch (e->type) {
    +   case E_OR:
    +   case E_AND:
    +           sym = sym_check_expr_deps(e->left.expr);
    +           if (sym)
    +                   return sym;
    +           return sym_check_expr_deps(e->right.expr);
    +   case E_NOT:
    +           return sym_check_expr_deps(e->left.expr);
    +   case E_EQUAL:
    +   case E_GEQ:
    +   case E_GTH:
    +   case E_LEQ:
    +   case E_LTH:
    +   case E_UNEQUAL:
    +           sym = sym_check_deps(e->left.sym);
    +           if (sym)
    +                   return sym;
    +           return sym_check_deps(e->right.sym);
    +   case E_SYMBOL:
    +           return sym_check_deps(e->left.sym);
    +   default:
    +           break;
    +   }
    +   fprintf(stderr, "Oops! How to check %d?\n", e->type);
    +   return NULL;
    +}
    +
    +/* return NULL when dependencies are OK */
    +static struct symbol *sym_check_sym_deps(struct symbol *sym)
    +{
    +   struct symbol *sym2;
    +   struct property *prop;
    +   struct dep_stack stack;
    +
    +   dep_stack_insert(&stack, sym);
    +
    +   stack.expr = &sym->dir_dep.expr;
    +   sym2 = sym_check_expr_deps(sym->dir_dep.expr);
    +   if (sym2)
    +           goto out;
    +
    +   stack.expr = &sym->rev_dep.expr;
    +   sym2 = sym_check_expr_deps(sym->rev_dep.expr);
    +   if (sym2)
    +           goto out;
    +
    +   stack.expr = &sym->implied.expr;
    +   sym2 = sym_check_expr_deps(sym->implied.expr);
    +   if (sym2)
    +           goto out;
    +
    +   stack.expr = NULL;
    +
    +   for (prop = sym->prop; prop; prop = prop->next) {
    +           if (prop->type == P_CHOICE || prop->type == P_SELECT ||
    +               prop->type == P_IMPLY)
    +                   continue;
    +           stack.prop = prop;
    +           sym2 = sym_check_expr_deps(prop->visible.expr);
    +           if (sym2)
    +                   break;
    +           if (prop->type != P_DEFAULT || sym_is_choice(sym))
    +                   continue;
    +           stack.expr = &prop->expr;
    +           sym2 = sym_check_expr_deps(prop->expr);
    +           if (sym2)
    +                   break;
    +           stack.expr = NULL;
    +   }
    +
    +out:
    +   dep_stack_remove();
    +
    +   return sym2;
    +}
    +
    +static struct symbol *sym_check_choice_deps(struct symbol *choice)
    +{
    +   struct symbol *sym, *sym2;
    +   struct property *prop;
    +   struct expr *e;
    +   struct dep_stack stack;
    +
    +   dep_stack_insert(&stack, choice);
    +
    +   prop = sym_get_choice_prop(choice);
    +   expr_list_for_each_sym(prop->expr, e, sym)
    +           sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
    +
    +   choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
    +   sym2 = sym_check_sym_deps(choice);
    +   choice->flags &= ~SYMBOL_CHECK;
    +   if (sym2)
    +           goto out;
    +
    +   expr_list_for_each_sym(prop->expr, e, sym) {
    +           sym2 = sym_check_sym_deps(sym);
    +           if (sym2)
    +                   break;
    +   }
    +out:
    +   expr_list_for_each_sym(prop->expr, e, sym)
    +           sym->flags &= ~SYMBOL_CHECK;
    +
    +   if (sym2 && sym_is_choice_value(sym2) &&
    +       prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
    +           sym2 = choice;
    +
    +   dep_stack_remove();
    +
    +   return sym2;
    +}
    +
    +struct symbol *sym_check_deps(struct symbol *sym)
    +{
    +   struct symbol *sym2;
    +   struct property *prop;
    +
    +   if (sym->flags & SYMBOL_CHECK) {
    +           sym_check_print_recursive(sym);
    +           return sym;
    +   }
    +   if (sym->flags & SYMBOL_CHECKED)
    +           return NULL;
    +
    +   if (sym_is_choice_value(sym)) {
    +           struct dep_stack stack;
    +
    +           /* for choice groups start the check with main choice symbol */
    +           dep_stack_insert(&stack, sym);
    +           prop = sym_get_choice_prop(sym);
    +           sym2 = sym_check_deps(prop_get_symbol(prop));
    +           dep_stack_remove();
    +   } else if (sym_is_choice(sym)) {
    +           sym2 = sym_check_choice_deps(sym);
    +   } else {
    +           sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED);
    +           sym2 = sym_check_sym_deps(sym);
    +           sym->flags &= ~SYMBOL_CHECK;
    +   }
    +
    +   return sym2;
    +}
    +
    +struct property *prop_alloc(enum prop_type type, struct symbol *sym)
    +{
    +   struct property *prop;
    +   struct property **propp;
    +
    +   prop = xmalloc(sizeof(*prop));
    +   memset(prop, 0, sizeof(*prop));
    +   prop->type = type;
    +   prop->sym = sym;
    +   prop->file = current_file;
    +   prop->lineno = zconf_lineno();
    +
    +   /* append property to the prop list of symbol */
    +   if (sym) {
    +           for (propp = &sym->prop; *propp; propp = &(*propp)->next)
    +                   ;
    +           *propp = prop;
    +   }
    +
    +   return prop;
    +}
    +
    +struct symbol *prop_get_symbol(struct property *prop)
    +{
    +   if (prop->expr && (prop->expr->type == E_SYMBOL ||
    +                      prop->expr->type == E_LIST))
    +           return prop->expr->left.sym;
    +   return NULL;
    +}
    +
    +const char *prop_get_type_name(enum prop_type type)
    +{
    +   switch (type) {
    +   case P_PROMPT:
    +           return "prompt";
    +   case P_COMMENT:
    +           return "comment";
    +   case P_MENU:
    +           return "menu";
    +   case P_DEFAULT:
    +           return "default";
    +   case P_CHOICE:
    +           return "choice";
    +   case P_SELECT:
    +           return "select";
    +   case P_IMPLY:
    +           return "imply";
    +   case P_RANGE:
    +           return "range";
    +   case P_SYMBOL:
    +           return "symbol";
    +   case P_UNKNOWN:
    +           break;
    +   }
    +   return "unknown";
    +}
    diff --git a/support/kconfig.new/tests/auto_submenu/Kconfig 
b/support/kconfig.new/tests/auto_submenu/Kconfig
    new file mode 100644
    index 0000000..b20761e
    --- /dev/null
    +++ b/support/kconfig.new/tests/auto_submenu/Kconfig
    @@ -0,0 +1,52 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +config A
    +   bool "A"
    +   default y
    +
    +config A0
    +   bool "A0"
    +   depends on A
    +   default y
    +   help
    +     This depends on A, so should be a submenu of A.
    +
    +config A0_0
    +   bool "A1_0"
    +   depends on A0
    +   help
    +     Submenus are created recursively.
    +     This should be a submenu of A0.
    +
    +config A1
    +   bool "A1"
    +   depends on A
    +   default y
    +   help
    +     This should line up with A0.
    +
    +choice
    +   prompt "choice"
    +   depends on A1
    +   help
    +     Choice should become a submenu as well.
    +
    +config A1_0
    +   bool "A1_0"
    +
    +config A1_1
    +   bool "A1_1"
    +
    +endchoice
    +
    +config B
    +   bool "B"
    +   help
    +     This is independent of A.
    +
    +config C
    +   bool "C"
    +   depends on A
    +   help
    +     This depends on A, but not a consecutive item, so can/should not
    +     be a submenu.
    diff --git a/support/kconfig.new/tests/auto_submenu/__init__.py 
b/support/kconfig.new/tests/auto_submenu/__init__.py
    new file mode 100644
    index 0000000..25abd92
    --- /dev/null
    +++ b/support/kconfig.new/tests/auto_submenu/__init__.py
    @@ -0,0 +1,13 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Create submenu for symbols that depend on the preceding one.
    +
    +If a symbols has dependency on the preceding symbol, the menu entry
    +should become the submenu of the preceding one, and displayed with
    +deeper indentation.
    +"""
    +
    +
    +def test(conf):
    +    assert conf.oldaskconfig() == 0
    +    assert conf.stdout_contains('expected_stdout')
    diff --git a/support/kconfig.new/tests/auto_submenu/expected_stdout 
b/support/kconfig.new/tests/auto_submenu/expected_stdout
    new file mode 100644
    index 0000000..bf5236f
    --- /dev/null
    +++ b/support/kconfig.new/tests/auto_submenu/expected_stdout
    @@ -0,0 +1,10 @@
    +A (A) [Y/n/?] (NEW) 
    +  A0 (A0) [Y/n/?] (NEW) 
    +    A1_0 (A0_0) [N/y/?] (NEW) 
    +  A1 (A1) [Y/n/?] (NEW) 
    +    choice
    +    > 1. A1_0 (A1_0) (NEW)
    +      2. A1_1 (A1_1) (NEW)
    +    choice[1-2?]: 
    +B (B) [N/y/?] (NEW) 
    +C (C) [N/y/?] (NEW) 
    diff --git a/support/kconfig.new/tests/choice/Kconfig 
b/support/kconfig.new/tests/choice/Kconfig
    new file mode 100644
    index 0000000..a412205
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/Kconfig
    @@ -0,0 +1,56 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +config MODULES
    +   bool "Enable loadable module support"
    +   option modules
    +   default y
    +
    +choice
    +   prompt "boolean choice"
    +   default BOOL_CHOICE1
    +
    +config BOOL_CHOICE0
    +   bool "choice 0"
    +
    +config BOOL_CHOICE1
    +   bool "choice 1"
    +
    +endchoice
    +
    +choice
    +   prompt "optional boolean choice"
    +   optional
    +   default OPT_BOOL_CHOICE1
    +
    +config OPT_BOOL_CHOICE0
    +   bool "choice 0"
    +
    +config OPT_BOOL_CHOICE1
    +   bool "choice 1"
    +
    +endchoice
    +
    +choice
    +   prompt "tristate choice"
    +   default TRI_CHOICE1
    +
    +config TRI_CHOICE0
    +   tristate "choice 0"
    +
    +config TRI_CHOICE1
    +   tristate "choice 1"
    +
    +endchoice
    +
    +choice
    +   prompt "optional tristate choice"
    +   optional
    +   default OPT_TRI_CHOICE1
    +
    +config OPT_TRI_CHOICE0
    +   tristate "choice 0"
    +
    +config OPT_TRI_CHOICE1
    +   tristate "choice 1"
    +
    +endchoice
    diff --git a/support/kconfig.new/tests/choice/__init__.py 
b/support/kconfig.new/tests/choice/__init__.py
    new file mode 100644
    index 0000000..4318fce
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/__init__.py
    @@ -0,0 +1,41 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Basic choice tests.
    +
    +The handling of 'choice' is a bit complicated part in Kconfig.
    +
    +The behavior of 'y' choice is intuitive.  If choice values are tristate,
    +the choice can be 'm' where each value can be enabled independently.
    +Also, if a choice is marked as 'optional', the whole choice can be
    +invisible.
    +"""
    +
    +
    +def test_oldask0(conf):
    +    assert conf.oldaskconfig() == 0
    +    assert conf.stdout_contains('oldask0_expected_stdout')
    +
    +
    +def test_oldask1(conf):
    +    assert conf.oldaskconfig('oldask1_config') == 0
    +    assert conf.stdout_contains('oldask1_expected_stdout')
    +
    +
    +def test_allyes(conf):
    +    assert conf.allyesconfig() == 0
    +    assert conf.config_contains('allyes_expected_config')
    +
    +
    +def test_allmod(conf):
    +    assert conf.allmodconfig() == 0
    +    assert conf.config_contains('allmod_expected_config')
    +
    +
    +def test_allno(conf):
    +    assert conf.allnoconfig() == 0
    +    assert conf.config_contains('allno_expected_config')
    +
    +
    +def test_alldef(conf):
    +    assert conf.alldefconfig() == 0
    +    assert conf.config_contains('alldef_expected_config')
    diff --git a/support/kconfig.new/tests/choice/alldef_expected_config 
b/support/kconfig.new/tests/choice/alldef_expected_config
    new file mode 100644
    index 0000000..7a754bf
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/alldef_expected_config
    @@ -0,0 +1,5 @@
    +CONFIG_MODULES=y
    +# CONFIG_BOOL_CHOICE0 is not set
    +CONFIG_BOOL_CHOICE1=y
    +# CONFIG_TRI_CHOICE0 is not set
    +# CONFIG_TRI_CHOICE1 is not set
    diff --git a/support/kconfig.new/tests/choice/allmod_expected_config 
b/support/kconfig.new/tests/choice/allmod_expected_config
    new file mode 100644
    index 0000000..f1f5dcd
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/allmod_expected_config
    @@ -0,0 +1,9 @@
    +CONFIG_MODULES=y
    +# CONFIG_BOOL_CHOICE0 is not set
    +CONFIG_BOOL_CHOICE1=y
    +# CONFIG_OPT_BOOL_CHOICE0 is not set
    +CONFIG_OPT_BOOL_CHOICE1=y
    +CONFIG_TRI_CHOICE0=m
    +CONFIG_TRI_CHOICE1=m
    +CONFIG_OPT_TRI_CHOICE0=m
    +CONFIG_OPT_TRI_CHOICE1=m
    diff --git a/support/kconfig.new/tests/choice/allno_expected_config 
b/support/kconfig.new/tests/choice/allno_expected_config
    new file mode 100644
    index 0000000..b88ee7a
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/allno_expected_config
    @@ -0,0 +1,5 @@
    +# CONFIG_MODULES is not set
    +# CONFIG_BOOL_CHOICE0 is not set
    +CONFIG_BOOL_CHOICE1=y
    +# CONFIG_TRI_CHOICE0 is not set
    +CONFIG_TRI_CHOICE1=y
    diff --git a/support/kconfig.new/tests/choice/allyes_expected_config 
b/support/kconfig.new/tests/choice/allyes_expected_config
    new file mode 100644
    index 0000000..e5a062a
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/allyes_expected_config
    @@ -0,0 +1,9 @@
    +CONFIG_MODULES=y
    +# CONFIG_BOOL_CHOICE0 is not set
    +CONFIG_BOOL_CHOICE1=y
    +# CONFIG_OPT_BOOL_CHOICE0 is not set
    +CONFIG_OPT_BOOL_CHOICE1=y
    +# CONFIG_TRI_CHOICE0 is not set
    +CONFIG_TRI_CHOICE1=y
    +# CONFIG_OPT_TRI_CHOICE0 is not set
    +CONFIG_OPT_TRI_CHOICE1=y
    diff --git a/support/kconfig.new/tests/choice/oldask0_expected_stdout 
b/support/kconfig.new/tests/choice/oldask0_expected_stdout
    new file mode 100644
    index 0000000..b251bba
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/oldask0_expected_stdout
    @@ -0,0 +1,10 @@
    +Enable loadable module support (MODULES) [Y/n/?] (NEW) 
    +boolean choice
    +  1. choice 0 (BOOL_CHOICE0) (NEW)
    +> 2. choice 1 (BOOL_CHOICE1) (NEW)
    +choice[1-2?]: 
    +optional boolean choice [N/y/?] (NEW) 
    +tristate choice [M/y/?] (NEW) 
    +  choice 0 (TRI_CHOICE0) [N/m/?] (NEW) 
    +  choice 1 (TRI_CHOICE1) [N/m/?] (NEW) 
    +optional tristate choice [N/m/y/?] (NEW) 
    diff --git a/support/kconfig.new/tests/choice/oldask1_config 
b/support/kconfig.new/tests/choice/oldask1_config
    new file mode 100644
    index 0000000..b67bfe3
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/oldask1_config
    @@ -0,0 +1,2 @@
    +# CONFIG_MODULES is not set
    +CONFIG_OPT_BOOL_CHOICE0=y
    diff --git a/support/kconfig.new/tests/choice/oldask1_expected_stdout 
b/support/kconfig.new/tests/choice/oldask1_expected_stdout
    new file mode 100644
    index 0000000..c2125e9
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice/oldask1_expected_stdout
    @@ -0,0 +1,15 @@
    +Enable loadable module support (MODULES) [N/y/?] 
    +boolean choice
    +  1. choice 0 (BOOL_CHOICE0) (NEW)
    +> 2. choice 1 (BOOL_CHOICE1) (NEW)
    +choice[1-2?]: 
    +optional boolean choice [Y/n/?] (NEW) 
    +optional boolean choice
    +> 1. choice 0 (OPT_BOOL_CHOICE0)
    +  2. choice 1 (OPT_BOOL_CHOICE1) (NEW)
    +choice[1-2?]: 
    +tristate choice
    +  1. choice 0 (TRI_CHOICE0) (NEW)
    +> 2. choice 1 (TRI_CHOICE1) (NEW)
    +choice[1-2?]: 
    +optional tristate choice [N/y/?] 
    diff --git a/support/kconfig.new/tests/choice_value_with_m_dep/Kconfig 
b/support/kconfig.new/tests/choice_value_with_m_dep/Kconfig
    new file mode 100644
    index 0000000..7106c26
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice_value_with_m_dep/Kconfig
    @@ -0,0 +1,21 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +config MODULES
    +   def_bool y
    +   option modules
    +
    +config DEP
    +   tristate
    +   default m
    +
    +choice
    +   prompt "Tristate Choice"
    +
    +config CHOICE0
    +   tristate "Choice 0"
    +
    +config CHOICE1
    +   tristate "Choice 1"
    +   depends on DEP
    +
    +endchoice
    diff --git a/support/kconfig.new/tests/choice_value_with_m_dep/__init__.py 
b/support/kconfig.new/tests/choice_value_with_m_dep/__init__.py
    new file mode 100644
    index 0000000..075b4e0
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice_value_with_m_dep/__init__.py
    @@ -0,0 +1,16 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Hide tristate choice values with mod dependency in y choice.
    +
    +If tristate choice values depend on symbols set to 'm', they should be
    +hidden when the choice containing them is changed from 'm' to 'y'
    +(i.e. exclusive choice).
    +
    +Related Linux commit: fa64e5f6a35efd5e77d639125d973077ca506074
    +"""
    +
    +
    +def test(conf):
    +    assert conf.oldaskconfig('config', 'y') == 0
    +    assert conf.config_contains('expected_config')
    +    assert conf.stdout_contains('expected_stdout')
    diff --git a/support/kconfig.new/tests/choice_value_with_m_dep/config 
b/support/kconfig.new/tests/choice_value_with_m_dep/config
    new file mode 100644
    index 0000000..3a126b7
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice_value_with_m_dep/config
    @@ -0,0 +1,2 @@
    +CONFIG_CHOICE0=m
    +CONFIG_CHOICE1=m
    diff --git 
a/support/kconfig.new/tests/choice_value_with_m_dep/expected_config 
b/support/kconfig.new/tests/choice_value_with_m_dep/expected_config
    new file mode 100644
    index 0000000..4d07b44
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice_value_with_m_dep/expected_config
    @@ -0,0 +1,3 @@
    +CONFIG_MODULES=y
    +CONFIG_DEP=m
    +CONFIG_CHOICE0=y
    diff --git 
a/support/kconfig.new/tests/choice_value_with_m_dep/expected_stdout 
b/support/kconfig.new/tests/choice_value_with_m_dep/expected_stdout
    new file mode 100644
    index 0000000..2b50ab6
    --- /dev/null
    +++ b/support/kconfig.new/tests/choice_value_with_m_dep/expected_stdout
    @@ -0,0 +1,4 @@
    +Tristate Choice [M/y/?] y
    +Tristate Choice
    +> 1. Choice 0 (CHOICE0)
    +choice[1]: 1
    diff --git a/support/kconfig.new/tests/conftest.py 
b/support/kconfig.new/tests/conftest.py
    new file mode 100644
    index 0000000..0345ef6
    --- /dev/null
    +++ b/support/kconfig.new/tests/conftest.py
    @@ -0,0 +1,291 @@
    +# SPDX-License-Identifier: GPL-2.0
    +#
    +# Copyright (C) 2018 Masahiro Yamada <yamada.masahiro@xxxxxxxxxxxxx>
    +#
    +
    +"""
    +Kconfig unit testing framework.
    +
    +This provides fixture functions commonly used from test files.
    +"""
    +
    +import os
    +import pytest
    +import shutil
    +import subprocess
    +import tempfile
    +
    +CONF_PATH = os.path.abspath(os.path.join('scripts', 'kconfig', 'conf'))
    +
    +
    +class Conf:
    +    """Kconfig runner and result checker.
    +
    +    This class provides methods to run text-based interface of Kconfig
    +    (scripts/kconfig/conf) and retrieve the resulted configuration,
    +    stdout, and stderr.  It also provides methods to compare those
    +    results with expectations.
    +    """
    +
    +    def __init__(self, request):
    +        """Create a new Conf instance.
    +
    +        request: object to introspect the requesting test module
    +        """
    +        # the directory of the test being run
    +        self._test_dir = os.path.dirname(str(request.fspath))
    +
    +    # runners
    +    def _run_conf(self, mode, dot_config=None, out_file='.config',
    +                  interactive=False, in_keys=None, extra_env={}):
    +        """Run text-based Kconfig executable and save the result.
    +
    +        mode: input mode option (--oldaskconfig, --defconfig=<file> etc.)
    +        dot_config: .config file to use for configuration base
    +        out_file: file name to contain the output config data
    +        interactive: flag to specify the interactive mode
    +        in_keys: key inputs for interactive modes
    +        extra_env: additional environments
    +        returncode: exit status of the Kconfig executable
    +        """
    +        command = [CONF_PATH, mode, 'Kconfig']
    +
    +        # Override 'srctree' environment to make the test as the top 
directory
    +        extra_env['srctree'] = self._test_dir
    +
    +        # Run Kconfig in a temporary directory.
    +        # This directory is automatically removed when done.
    +        with tempfile.TemporaryDirectory() as temp_dir:
    +
    +            # if .config is given, copy it to the working directory
    +            if dot_config:
    +                shutil.copyfile(os.path.join(self._test_dir, dot_config),
    +                                os.path.join(temp_dir, '.config'))
    +
    +            ps = subprocess.Popen(command,
    +                                  stdin=subprocess.PIPE,
    +                                  stdout=subprocess.PIPE,
    +                                  stderr=subprocess.PIPE,
    +                                  cwd=temp_dir,
    +                                  env=dict(os.environ, **extra_env))
    +
    +            # If input key sequence is given, feed it to stdin.
    +            if in_keys:
    +                ps.stdin.write(in_keys.encode('utf-8'))
    +
    +            while ps.poll() is None:
    +                # For interactive modes such as oldaskconfig, oldconfig,
    +                # send 'Enter' key until the program finishes.
    +                if interactive:
    +                    ps.stdin.write(b'\n')
    +
    +            self.retcode = ps.returncode
    +            self.stdout = ps.stdout.read().decode()
    +            self.stderr = ps.stderr.read().decode()
    +
    +            # Retrieve the resulted config data only when .config is 
supposed
    +            # to exist.  If the command fails, the .config does not exist.
    +            # 'listnewconfig' does not produce .config in the first place.
    +            if self.retcode == 0 and out_file:
    +                with open(os.path.join(temp_dir, out_file)) as f:
    +                    self.config = f.read()
    +            else:
    +                self.config = None
    +
    +        # Logging:
    +        # Pytest captures the following information by default.  In failure
    +        # of tests, the captured log will be displayed.  This will be 
useful to
    +        # figure out what has happened.
    +
    +        print("[command]\n{}\n".format(' '.join(command)))
    +
    +        print("[retcode]\n{}\n".format(self.retcode))
    +
    +        print("[stdout]")
    +        print(self.stdout)
    +
    +        print("[stderr]")
    +        print(self.stderr)
    +
    +        if self.config is not None:
    +            print("[output for '{}']".format(out_file))
    +            print(self.config)
    +
    +        return self.retcode
    +
    +    def oldaskconfig(self, dot_config=None, in_keys=None):
    +        """Run oldaskconfig.
    +
    +        dot_config: .config file to use for configuration base (optional)
    +        in_key: key inputs (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._run_conf('--oldaskconfig', dot_config=dot_config,
    +                              interactive=True, in_keys=in_keys)
    +
    +    def oldconfig(self, dot_config=None, in_keys=None):
    +        """Run oldconfig.
    +
    +        dot_config: .config file to use for configuration base (optional)
    +        in_key: key inputs (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._run_conf('--oldconfig', dot_config=dot_config,
    +                              interactive=True, in_keys=in_keys)
    +
    +    def olddefconfig(self, dot_config=None):
    +        """Run olddefconfig.
    +
    +        dot_config: .config file to use for configuration base (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._run_conf('--olddefconfig', dot_config=dot_config)
    +
    +    def defconfig(self, defconfig):
    +        """Run defconfig.
    +
    +        defconfig: defconfig file for input
    +        returncode: exit status of the Kconfig executable
    +        """
    +        defconfig_path = os.path.join(self._test_dir, defconfig)
    +        return self._run_conf('--defconfig={}'.format(defconfig_path))
    +
    +    def _allconfig(self, mode, all_config):
    +        if all_config:
    +            all_config_path = os.path.join(self._test_dir, all_config)
    +            extra_env = {'KCONFIG_ALLCONFIG': all_config_path}
    +        else:
    +            extra_env = {}
    +
    +        return self._run_conf('--{}config'.format(mode), 
extra_env=extra_env)
    +
    +    def allyesconfig(self, all_config=None):
    +        """Run allyesconfig.
    +
    +        all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._allconfig('allyes', all_config)
    +
    +    def allmodconfig(self, all_config=None):
    +        """Run allmodconfig.
    +
    +        all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._allconfig('allmod', all_config)
    +
    +    def allnoconfig(self, all_config=None):
    +        """Run allnoconfig.
    +
    +        all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._allconfig('allno', all_config)
    +
    +    def alldefconfig(self, all_config=None):
    +        """Run alldefconfig.
    +
    +        all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._allconfig('alldef', all_config)
    +
    +    def randconfig(self, all_config=None):
    +        """Run randconfig.
    +
    +        all_config: fragment config file for KCONFIG_ALLCONFIG (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._allconfig('rand', all_config)
    +
    +    def savedefconfig(self, dot_config):
    +        """Run savedefconfig.
    +
    +        dot_config: .config file for input
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._run_conf('--savedefconfig', out_file='defconfig')
    +
    +    def listnewconfig(self, dot_config=None):
    +        """Run listnewconfig.
    +
    +        dot_config: .config file to use for configuration base (optional)
    +        returncode: exit status of the Kconfig executable
    +        """
    +        return self._run_conf('--listnewconfig', dot_config=dot_config,
    +                              out_file=None)
    +
    +    # checkers
    +    def _read_and_compare(self, compare, expected):
    +        """Compare the result with expectation.
    +
    +        compare: function to compare the result with expectation
    +        expected: file that contains the expected data
    +        """
    +        with open(os.path.join(self._test_dir, expected)) as f:
    +            expected_data = f.read()
    +        return compare(self, expected_data)
    +
    +    def _contains(self, attr, expected):
    +        return self._read_and_compare(
    +                                    lambda s, e: getattr(s, attr).find(e) 
>= 0,
    +                                    expected)
    +
    +    def _matches(self, attr, expected):
    +        return self._read_and_compare(lambda s, e: getattr(s, attr) == e,
    +                                      expected)
    +
    +    def config_contains(self, expected):
    +        """Check if resulted configuration contains expected data.
    +
    +        expected: file that contains the expected data
    +        returncode: True if result contains the expected data, False 
otherwise
    +        """
    +        return self._contains('config', expected)
    +
    +    def config_matches(self, expected):
    +        """Check if resulted configuration exactly matches expected data.
    +
    +        expected: file that contains the expected data
    +        returncode: True if result matches the expected data, False 
otherwise
    +        """
    +        return self._matches('config', expected)
    +
    +    def stdout_contains(self, expected):
    +        """Check if resulted stdout contains expected data.
    +
    +        expected: file that contains the expected data
    +        returncode: True if result contains the expected data, False 
otherwise
    +        """
    +        return self._contains('stdout', expected)
    +
    +    def stdout_matches(self, expected):
    +        """Check if resulted stdout exactly matches expected data.
    +
    +        expected: file that contains the expected data
    +        returncode: True if result matches the expected data, False 
otherwise
    +        """
    +        return self._matches('stdout', expected)
    +
    +    def stderr_contains(self, expected):
    +        """Check if resulted stderr contains expected data.
    +
    +        expected: file that contains the expected data
    +        returncode: True if result contains the expected data, False 
otherwise
    +        """
    +        return self._contains('stderr', expected)
    +
    +    def stderr_matches(self, expected):
    +        """Check if resulted stderr exactly matches expected data.
    +
    +        expected: file that contains the expected data
    +        returncode: True if result matches the expected data, False 
otherwise
    +        """
    +        return self._matches('stderr', expected)
    +
    +
    +@pytest.fixture(scope="module")
    +def conf(request):
    +    """Create a Conf instance and provide it to test functions."""
    +    return Conf(request)
    diff --git a/support/kconfig.new/tests/err_recursive_dep/Kconfig 
b/support/kconfig.new/tests/err_recursive_dep/Kconfig
    new file mode 100644
    index 0000000..ebdb3ff
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_dep/Kconfig
    @@ -0,0 +1,63 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +# depends on itself
    +
    +config A
    +   bool "A"
    +   depends on A
    +
    +# select itself
    +
    +config B
    +   bool
    +   select B
    +
    +# depends on each other
    +
    +config C1
    +   bool "C1"
    +   depends on C2
    +
    +config C2
    +   bool "C2"
    +   depends on C1
    +
    +# depends on and select
    +
    +config D1
    +   bool "D1"
    +   depends on D2
    +   select D2
    +
    +config D2
    +   bool
    +
    +# depends on and imply
    +
    +config E1
    +   bool "E1"
    +   depends on E2
    +   imply E2
    +
    +config E2
    +   bool "E2"
    +
    +# property
    +
    +config F1
    +   bool "F1"
    +   default F2
    +
    +config F2
    +   bool "F2"
    +   depends on F1
    +
    +# menu
    +
    +menu "menu depending on its content"
    +   depends on G
    +
    +config G
    +   bool "G"
    +
    +endmenu
    diff --git a/support/kconfig.new/tests/err_recursive_dep/__init__.py 
b/support/kconfig.new/tests/err_recursive_dep/__init__.py
    new file mode 100644
    index 0000000..5f3821b
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_dep/__init__.py
    @@ -0,0 +1,10 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Detect recursive dependency error.
    +
    +Recursive dependency should be treated as an error.
    +"""
    +
    +def test(conf):
    +    assert conf.oldaskconfig() == 1
    +    assert conf.stderr_contains('expected_stderr')
    diff --git a/support/kconfig.new/tests/err_recursive_dep/expected_stderr 
b/support/kconfig.new/tests/err_recursive_dep/expected_stderr
    new file mode 100644
    index 0000000..84679b1
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_dep/expected_stderr
    @@ -0,0 +1,38 @@
    +Kconfig:11:error: recursive dependency detected!
    +Kconfig:11:        symbol B is selected by B
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    +
    +Kconfig:5:error: recursive dependency detected!
    +Kconfig:5: symbol A depends on A
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    +
    +Kconfig:17:error: recursive dependency detected!
    +Kconfig:17:        symbol C1 depends on C2
    +Kconfig:21:        symbol C2 depends on C1
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    +
    +Kconfig:32:error: recursive dependency detected!
    +Kconfig:32:        symbol D2 is selected by D1
    +Kconfig:27:        symbol D1 depends on D2
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    +
    +Kconfig:37:error: recursive dependency detected!
    +Kconfig:37:        symbol E1 depends on E2
    +Kconfig:42:        symbol E2 is implied by E1
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    +
    +Kconfig:60:error: recursive dependency detected!
    +Kconfig:60:        symbol G depends on G
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    +
    +Kconfig:51:error: recursive dependency detected!
    +Kconfig:51:        symbol F2 depends on F1
    +Kconfig:49:        symbol F1 default value contains F2
    +For a resolution refer to Documentation/kbuild/kconfig-language.txt
    +subsection "Kconfig recursive dependency limitations"
    diff --git a/support/kconfig.new/tests/err_recursive_inc/Kconfig 
b/support/kconfig.new/tests/err_recursive_inc/Kconfig
    new file mode 100644
    index 0000000..c6f4ade
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_inc/Kconfig
    @@ -0,0 +1,2 @@
    +# SPDX-License-Identifier: GPL-2.0-only
    +source "Kconfig.inc1"
    diff --git a/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc1 
b/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc1
    new file mode 100644
    index 0000000..01cbf0d
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc1
    @@ -0,0 +1,5 @@
    +# SPDX-License-Identifier: GPL-2.0-only
    +
    +
    +
    +source "Kconfig.inc2"
    diff --git a/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc2 
b/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc2
    new file mode 100644
    index 0000000..8235107
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc2
    @@ -0,0 +1,4 @@
    +# SPDX-License-Identifier: GPL-2.0-only
    +
    +
    +source "Kconfig.inc3"
    diff --git a/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc3 
b/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc3
    new file mode 100644
    index 0000000..c6f4ade
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_inc/Kconfig.inc3
    @@ -0,0 +1,2 @@
    +# SPDX-License-Identifier: GPL-2.0-only
    +source "Kconfig.inc1"
    diff --git a/support/kconfig.new/tests/err_recursive_inc/__init__.py 
b/support/kconfig.new/tests/err_recursive_inc/__init__.py
    new file mode 100644
    index 0000000..27aa189
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_inc/__init__.py
    @@ -0,0 +1,11 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Detect recursive inclusion error.
    +
    +If recursive inclusion is detected, it should fail with error messages.
    +"""
    +
    +
    +def test(conf):
    +    assert conf.oldaskconfig() != 0
    +    assert conf.stderr_contains('expected_stderr')
    diff --git a/support/kconfig.new/tests/err_recursive_inc/expected_stderr 
b/support/kconfig.new/tests/err_recursive_inc/expected_stderr
    new file mode 100644
    index 0000000..b070a31
    --- /dev/null
    +++ b/support/kconfig.new/tests/err_recursive_inc/expected_stderr
    @@ -0,0 +1,6 @@
    +Recursive inclusion detected.
    +Inclusion path:
    +  current file : Kconfig.inc1
    +  included from: Kconfig.inc3:2
    +  included from: Kconfig.inc2:4
    +  included from: Kconfig.inc1:5
    diff --git a/support/kconfig.new/tests/inter_choice/Kconfig 
b/support/kconfig.new/tests/inter_choice/Kconfig
    new file mode 100644
    index 0000000..5698a40
    --- /dev/null
    +++ b/support/kconfig.new/tests/inter_choice/Kconfig
    @@ -0,0 +1,25 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +config MODULES
    +   def_bool y
    +   option modules
    +
    +choice
    +   prompt "Choice"
    +
    +config CHOICE_VAL0
    +   tristate "Choice 0"
    +
    +config CHOIVE_VAL1
    +   tristate "Choice 1"
    +
    +endchoice
    +
    +choice
    +   prompt "Another choice"
    +   depends on CHOICE_VAL0
    +
    +config DUMMY
    +   bool "dummy"
    +
    +endchoice
    diff --git a/support/kconfig.new/tests/inter_choice/__init__.py 
b/support/kconfig.new/tests/inter_choice/__init__.py
    new file mode 100644
    index 0000000..ffea6b1
    --- /dev/null
    +++ b/support/kconfig.new/tests/inter_choice/__init__.py
    @@ -0,0 +1,15 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Do not affect user-assigned choice value by another choice.
    +
    +Handling of state flags for choices is complecated.  In old days,
    +the defconfig result of a choice could be affected by another choice
    +if those choices interact by 'depends on', 'select', etc.
    +
    +Related Linux commit: fbe98bb9ed3dae23e320c6b113e35f129538d14a
    +"""
    +
    +
    +def test(conf):
    +    assert conf.defconfig('defconfig') == 0
    +    assert conf.config_contains('expected_config')
    diff --git a/support/kconfig.new/tests/inter_choice/defconfig 
b/support/kconfig.new/tests/inter_choice/defconfig
    new file mode 100644
    index 0000000..162c414
    --- /dev/null
    +++ b/support/kconfig.new/tests/inter_choice/defconfig
    @@ -0,0 +1 @@
    +CONFIG_CHOICE_VAL0=y
    diff --git a/support/kconfig.new/tests/inter_choice/expected_config 
b/support/kconfig.new/tests/inter_choice/expected_config
    new file mode 100644
    index 0000000..5dceefb
    --- /dev/null
    +++ b/support/kconfig.new/tests/inter_choice/expected_config
    @@ -0,0 +1,4 @@
    +CONFIG_MODULES=y
    +CONFIG_CHOICE_VAL0=y
    +# CONFIG_CHOIVE_VAL1 is not set
    +CONFIG_DUMMY=y
    diff --git a/support/kconfig.new/tests/new_choice_with_dep/Kconfig 
b/support/kconfig.new/tests/new_choice_with_dep/Kconfig
    new file mode 100644
    index 0000000..127731c
    --- /dev/null
    +++ b/support/kconfig.new/tests/new_choice_with_dep/Kconfig
    @@ -0,0 +1,39 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +config A
    +   bool "A"
    +   help
    +     This is a new symbol.
    +
    +choice
    +   prompt "Choice ?"
    +   depends on A
    +   help
    +     "depends on A" has been newly added.
    +
    +config CHOICE_B
    +   bool "Choice B"
    +
    +config CHOICE_C
    +   bool "Choice C"
    +   help
    +     This is a new symbol, so should be asked.
    +
    +endchoice
    +
    +choice
    +   prompt "Choice2 ?"
    +
    +config CHOICE_D
    +   bool "Choice D"
    +
    +config CHOICE_E
    +   bool "Choice E"
    +
    +config CHOICE_F
    +   bool "Choice F"
    +   depends on A
    +   help
    +     This is a new symbol, so should be asked.
    +
    +endchoice
    diff --git a/support/kconfig.new/tests/new_choice_with_dep/__init__.py 
b/support/kconfig.new/tests/new_choice_with_dep/__init__.py
    new file mode 100644
    index 0000000..fe9d322
    --- /dev/null
    +++ b/support/kconfig.new/tests/new_choice_with_dep/__init__.py
    @@ -0,0 +1,15 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Ask new choice values when they become visible.
    +
    +If new choice values are added with new dependency, and they become
    +visible during user configuration, oldconfig should recognize them
    +as (NEW), and ask the user for choice.
    +
    +Related Linux commit: 5d09598d488f081e3be23f885ed65cbbe2d073b5
    +"""
    +
    +
    +def test(conf):
    +    assert conf.oldconfig('config', 'y') == 0
    +    assert conf.stdout_contains('expected_stdout')
    diff --git a/support/kconfig.new/tests/new_choice_with_dep/config 
b/support/kconfig.new/tests/new_choice_with_dep/config
    new file mode 100644
    index 0000000..47ef95d
    --- /dev/null
    +++ b/support/kconfig.new/tests/new_choice_with_dep/config
    @@ -0,0 +1,3 @@
    +CONFIG_CHOICE_B=y
    +# CONFIG_CHOICE_D is not set
    +CONFIG_CHOICE_E=y
    diff --git a/support/kconfig.new/tests/new_choice_with_dep/expected_stdout 
b/support/kconfig.new/tests/new_choice_with_dep/expected_stdout
    new file mode 100644
    index 0000000..74dc0bc
    --- /dev/null
    +++ b/support/kconfig.new/tests/new_choice_with_dep/expected_stdout
    @@ -0,0 +1,10 @@
    +A (A) [N/y/?] (NEW) y
    +  Choice ?
    +  > 1. Choice B (CHOICE_B)
    +    2. Choice C (CHOICE_C) (NEW)
    +  choice[1-2?]: 
    +Choice2 ?
    +  1. Choice D (CHOICE_D)
    +> 2. Choice E (CHOICE_E)
    +  3. Choice F (CHOICE_F) (NEW)
    +choice[1-3?]: 
    diff --git a/support/kconfig.new/tests/no_write_if_dep_unmet/Kconfig 
b/support/kconfig.new/tests/no_write_if_dep_unmet/Kconfig
    new file mode 100644
    index 0000000..4767aab
    --- /dev/null
    +++ b/support/kconfig.new/tests/no_write_if_dep_unmet/Kconfig
    @@ -0,0 +1,16 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +config A
    +   bool "A"
    +
    +choice
    +   prompt "Choice ?"
    +   depends on A
    +
    +config CHOICE_B
    +   bool "Choice B"
    +
    +config CHOICE_C
    +   bool "Choice C"
    +
    +endchoice
    diff --git a/support/kconfig.new/tests/no_write_if_dep_unmet/__init__.py 
b/support/kconfig.new/tests/no_write_if_dep_unmet/__init__.py
    new file mode 100644
    index 0000000..ffd469d
    --- /dev/null
    +++ b/support/kconfig.new/tests/no_write_if_dep_unmet/__init__.py
    @@ -0,0 +1,20 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Do not write choice values to .config if the dependency is unmet.
    +
    +"# CONFIG_... is not set" should not be written into the .config file
    +for symbols with unmet dependency.
    +
    +This was not working correctly for choice values because choice needs
    +a bit different symbol computation.
    +
    +This checks that no unneeded "# COFIG_... is not set" is contained in
    +the .config file.
    +
    +Related Linux commit: cb67ab2cd2b8abd9650292c986c79901e3073a59
    +"""
    +
    +
    +def test(conf):
    +    assert conf.oldaskconfig('config', 'n') == 0
    +    assert conf.config_matches('expected_config')
    diff --git a/support/kconfig.new/tests/no_write_if_dep_unmet/config 
b/support/kconfig.new/tests/no_write_if_dep_unmet/config
    new file mode 100644
    index 0000000..abd280e
    --- /dev/null
    +++ b/support/kconfig.new/tests/no_write_if_dep_unmet/config
    @@ -0,0 +1 @@
    +CONFIG_A=y
    diff --git 
a/support/kconfig.new/tests/no_write_if_dep_unmet/expected_config 
b/support/kconfig.new/tests/no_write_if_dep_unmet/expected_config
    new file mode 100644
    index 0000000..4732288
    --- /dev/null
    +++ b/support/kconfig.new/tests/no_write_if_dep_unmet/expected_config
    @@ -0,0 +1,5 @@
    +#
    +# Automatically generated file; DO NOT EDIT.
    +# Main menu
    +#
    +# CONFIG_A is not set
    diff --git a/support/kconfig.new/tests/preprocess/builtin_func/Kconfig 
b/support/kconfig.new/tests/preprocess/builtin_func/Kconfig
    new file mode 100644
    index 0000000..baa3288
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/builtin_func/Kconfig
    @@ -0,0 +1,27 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +# 'info' prints the argument to stdout.
    +$(info,hello world 0)
    +
    +# 'warning-if', if the first argument is y, sends the second argument to 
stderr,
    +# and the message is prefixed with the current file name and line number.
    +$(warning-if,y,hello world 1)
    +
    +# 'error-if' is similar, but it terminates the parsing immediately.
    +# The following is just no-op since the first argument is not y.
    +$(error-if,n,this should not be printed)
    +
    +# Shorthand
    +warning = $(warning-if,y,$(1))
    +
    +# 'shell' executes a command, and returns its stdout.
    +$(warning,$(shell,echo hello world 3))
    +
    +# Every newline in the output is replaced with a space,
    +# but any trailing newlines are deleted.
    +$(warning,$(shell,printf 'hello\nworld\n\n4\n\n\n'))
    +
    +# 'filename' is expanded to the currently parsed file name,
    +# 'lineno' to the line number.
    +$(warning,filename=$(filename))
    +$(warning,lineno=$(lineno))
    diff --git a/support/kconfig.new/tests/preprocess/builtin_func/__init__.py 
b/support/kconfig.new/tests/preprocess/builtin_func/__init__.py
    new file mode 100644
    index 0000000..2e53ba0
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/builtin_func/__init__.py
    @@ -0,0 +1,9 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Built-in function tests.
    +"""
    +
    +def test(conf):
    +    assert conf.oldaskconfig() == 0
    +    assert conf.stdout_contains('expected_stdout')
    +    assert conf.stderr_matches('expected_stderr')
    diff --git 
a/support/kconfig.new/tests/preprocess/builtin_func/expected_stderr 
b/support/kconfig.new/tests/preprocess/builtin_func/expected_stderr
    new file mode 100644
    index 0000000..33ea9ca
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/builtin_func/expected_stderr
    @@ -0,0 +1,5 @@
    +Kconfig:8: hello world 1
    +Kconfig:18: hello world 3
    +Kconfig:22: hello world  4
    +Kconfig:26: filename=Kconfig
    +Kconfig:27: lineno=27
    diff --git 
a/support/kconfig.new/tests/preprocess/builtin_func/expected_stdout 
b/support/kconfig.new/tests/preprocess/builtin_func/expected_stdout
    new file mode 100644
    index 0000000..82de3a7
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/builtin_func/expected_stdout
    @@ -0,0 +1 @@
    +hello world 0
    diff --git 
a/support/kconfig.new/tests/preprocess/circular_expansion/Kconfig 
b/support/kconfig.new/tests/preprocess/circular_expansion/Kconfig
    new file mode 100644
    index 0000000..6838997
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/circular_expansion/Kconfig
    @@ -0,0 +1,5 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +X = $(Y)
    +Y = $(X)
    +$(info $(X))
    diff --git 
a/support/kconfig.new/tests/preprocess/circular_expansion/__init__.py 
b/support/kconfig.new/tests/preprocess/circular_expansion/__init__.py
    new file mode 100644
    index 0000000..419bda3
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/circular_expansion/__init__.py
    @@ -0,0 +1,11 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Detect circular variable expansion.
    +
    +If a recursively expanded variable references itself (eventually),
    +it should fail with an error message.
    +"""
    +
    +def test(conf):
    +    assert conf.oldaskconfig() != 0
    +    assert conf.stderr_matches('expected_stderr')
    diff --git 
a/support/kconfig.new/tests/preprocess/circular_expansion/expected_stderr 
b/support/kconfig.new/tests/preprocess/circular_expansion/expected_stderr
    new file mode 100644
    index 0000000..cde68fa
    --- /dev/null
    +++ 
b/support/kconfig.new/tests/preprocess/circular_expansion/expected_stderr
    @@ -0,0 +1 @@
    +Kconfig:5: Recursive variable 'X' references itself (eventually)
    diff --git a/support/kconfig.new/tests/preprocess/escape/Kconfig 
b/support/kconfig.new/tests/preprocess/escape/Kconfig
    new file mode 100644
    index 0000000..4e3f444
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/escape/Kconfig
    @@ -0,0 +1,44 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +# Shorthand
    +warning = $(warning-if,y,$(1))
    +
    +# You can not pass commas directly to a function since they are treated as
    +# delimiters. You can use the following trick to do so.
    +comma   := ,
    +$(warning,hello$(comma) world)
    +
    +# Like Make, single quotes, double quotes, spaces are treated verbatim.
    +# The following prints the text as-is.
    +$(warning,  ' " '"   ' ''' "'")
    +
    +# Unlike Make, '$' has special meaning only when it is followed by '('.
    +# No need to escape '$' itself.
    +$(warning,$)
    +$(warning,$$)
    +$ := 1
    +$(warning,$($))
    +
    +# You need a trick to escape '$' followed by '('
    +# The following should print "$(X)". It should not be expanded further.
    +dollar := $
    +$(warning,$(dollar)(X))
    +
    +# You need a trick to treat unbalanced parentheses.
    +# The following should print "(".
    +left_paren := (
    +$(warning,$(left_paren))
    +
    +# A simple expanded should not be expanded multiple times.
    +# The following should print "$(X)". It should not be expanded further.
    +Y := $(dollar)(X)
    +$(warning,$(Y))
    +
    +# The following should print "$(X)" as well.
    +Y = $(dollar)(X)
    +$(warning,$(Y))
    +
    +# The following should print "$(".
    +# It should not be emit "unterminated reference" error.
    +unterminated := $(dollar)(
    +$(warning,$(unterminated))
    diff --git a/support/kconfig.new/tests/preprocess/escape/__init__.py 
b/support/kconfig.new/tests/preprocess/escape/__init__.py
    new file mode 100644
    index 0000000..7ee8e74
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/escape/__init__.py
    @@ -0,0 +1,8 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Escape sequence tests.
    +"""
    +
    +def test(conf):
    +    assert conf.oldaskconfig() == 0
    +    assert conf.stderr_matches('expected_stderr')
    diff --git a/support/kconfig.new/tests/preprocess/escape/expected_stderr 
b/support/kconfig.new/tests/preprocess/escape/expected_stderr
    new file mode 100644
    index 0000000..1c00957
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/escape/expected_stderr
    @@ -0,0 +1,10 @@
    +Kconfig:9: hello, world
    +Kconfig:13:   ' " '"   ' ''' "'"
    +Kconfig:17: $
    +Kconfig:18: $$
    +Kconfig:20: 1
    +Kconfig:25: $(X)
    +Kconfig:30: (
    +Kconfig:35: $(X)
    +Kconfig:39: $(X)
    +Kconfig:44: $(
    diff --git a/support/kconfig.new/tests/preprocess/variable/Kconfig 
b/support/kconfig.new/tests/preprocess/variable/Kconfig
    new file mode 100644
    index 0000000..9ce2f95
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/variable/Kconfig
    @@ -0,0 +1,53 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +# Shorthand
    +warning = $(warning-if,y,$(1))
    +
    +# Simply expanded variable.
    +X := 1
    +SIMPLE := $(X)
    +X := 2
    +$(warning,SIMPLE = $(SIMPLE))
    +
    +# Recursively expanded variable.
    +X := 1
    +RECURSIVE = $(X)
    +X := 2
    +$(warning,RECURSIVE = $(RECURSIVE))
    +
    +# Append something to a simply expanded variable.
    +Y := 3
    +SIMPLE += $(Y)
    +Y := 4
    +$(warning,SIMPLE = $(SIMPLE))
    +
    +# Append something to a recursively expanded variable.
    +Y := 3
    +RECURSIVE += $(Y)
    +Y := 4
    +$(warning,RECURSIVE = $(RECURSIVE))
    +
    +# Use += operator to an undefined variable.
    +# This works as a recursively expanded variable.
    +Y := 3
    +UNDEFINED_VARIABLE += $(Y)
    +Y := 4
    +$(warning,UNDEFINED_VARIABLE = $(UNDEFINED_VARIABLE))
    +
    +# You can use variable references for the lefthand side of assignment 
statement.
    +X := A
    +Y := B
    +$(X)$(Y) := 5
    +$(warning,AB = $(AB))
    +
    +# User-defined function.
    +greeting = $(1), my name is $(2).
    +$(warning,$(greeting,Hello,John))
    +
    +# The number of arguments is not checked for user-defined functions.
    +# If some arguments are optional, it is useful to pass fewer parameters.
    +# $(2) will be blank in this case.
    +$(warning,$(greeting,Hello))
    +
    +# Unreferenced parameters are just ignored.
    +$(warning,$(greeting,Hello,John,ignored,ignored))
    diff --git a/support/kconfig.new/tests/preprocess/variable/__init__.py 
b/support/kconfig.new/tests/preprocess/variable/__init__.py
    new file mode 100644
    index 0000000..e88b170
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/variable/__init__.py
    @@ -0,0 +1,8 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Variable and user-defined function tests.
    +"""
    +
    +def test(conf):
    +    assert conf.oldaskconfig() == 0
    +    assert conf.stderr_matches('expected_stderr')
    diff --git a/support/kconfig.new/tests/preprocess/variable/expected_stderr 
b/support/kconfig.new/tests/preprocess/variable/expected_stderr
    new file mode 100644
    index 0000000..a4841c3
    --- /dev/null
    +++ b/support/kconfig.new/tests/preprocess/variable/expected_stderr
    @@ -0,0 +1,9 @@
    +Kconfig:10: SIMPLE = 1
    +Kconfig:16: RECURSIVE = 2
    +Kconfig:22: SIMPLE = 1 3
    +Kconfig:28: RECURSIVE = 2 4
    +Kconfig:35: UNDEFINED_VARIABLE = 4
    +Kconfig:41: AB = 5
    +Kconfig:45: Hello, my name is John.
    +Kconfig:50: Hello, my name is .
    +Kconfig:53: Hello, my name is John.
    diff --git a/support/kconfig.new/tests/pytest.ini 
b/support/kconfig.new/tests/pytest.ini
    new file mode 100644
    index 0000000..85d7ce8
    --- /dev/null
    +++ b/support/kconfig.new/tests/pytest.ini
    @@ -0,0 +1,7 @@
    +[pytest]
    +addopts = --verbose
    +
    +# Pytest requires that test files have unique names, because pytest imports
    +# them as top-level modules.  It is silly to prefix or suffix a test file 
with
    +# the directory name that contains it.  Use __init__.py for all test files.
    +python_files = __init__.py
    diff --git a/support/kconfig.new/tests/rand_nested_choice/Kconfig 
b/support/kconfig.new/tests/rand_nested_choice/Kconfig
    new file mode 100644
    index 0000000..8350de7
    --- /dev/null
    +++ b/support/kconfig.new/tests/rand_nested_choice/Kconfig
    @@ -0,0 +1,35 @@
    +# SPDX-License-Identifier: GPL-2.0
    +
    +choice
    +   prompt "choice"
    +
    +config A
    +   bool "A"
    +
    +config B
    +   bool "B"
    +
    +if B
    +choice
    +   prompt "sub choice"
    +
    +config C
    +   bool "C"
    +
    +config D
    +   bool "D"
    +
    +if D
    +choice
    +   prompt "subsub choice"
    +
    +config E
    +   bool "E"
    +
    +endchoice
    +endif # D
    +
    +endchoice
    +endif # B
    +
    +endchoice
    diff --git a/support/kconfig.new/tests/rand_nested_choice/__init__.py 
b/support/kconfig.new/tests/rand_nested_choice/__init__.py
    new file mode 100644
    index 0000000..9e4b2db
    --- /dev/null
    +++ b/support/kconfig.new/tests/rand_nested_choice/__init__.py
    @@ -0,0 +1,17 @@
    +# SPDX-License-Identifier: GPL-2.0
    +"""
    +Set random values recursively in nested choices.
    +
    +Kconfig can create a choice-in-choice structure by using 'if' statement.
    +randconfig should correctly set random choice values.
    +
    +Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29
    +"""
    +
    +
    +def test(conf):
    +    for i in range(20):
    +        assert conf.randconfig() == 0
    +        assert (conf.config_contains('expected_stdout0') or
    +                conf.config_contains('expected_stdout1') or
    +                conf.config_contains('expected_stdout2'))
    diff --git a/support/kconfig.new/tests/rand_nested_choice/expected_stdout0 
b/support/kconfig.new/tests/rand_nested_choice/expected_stdout0
    new file mode 100644
    index 0000000..05450f3
    --- /dev/null
    +++ b/support/kconfig.new/tests/rand_nested_choice/expected_stdout0
    @@ -0,0 +1,2 @@
    +CONFIG_A=y
    +# CONFIG_B is not set
    diff --git a/support/kconfig.new/tests/rand_nested_choice/expected_stdout1 
b/support/kconfig.new/tests/rand_nested_choice/expected_stdout1
    new file mode 100644
    index 0000000..37ab295
    --- /dev/null
    +++ b/support/kconfig.new/tests/rand_nested_choice/expected_stdout1
    @@ -0,0 +1,4 @@
    +# CONFIG_A is not set
    +CONFIG_B=y
    +CONFIG_C=y
    +# CONFIG_D is not set
    diff --git a/support/kconfig.new/tests/rand_nested_choice/expected_stdout2 
b/support/kconfig.new/tests/rand_nested_choice/expected_stdout2
    new file mode 100644
    index 0000000..849ff47
    --- /dev/null
    +++ b/support/kconfig.new/tests/rand_nested_choice/expected_stdout2
    @@ -0,0 +1,5 @@
    +# CONFIG_A is not set
    +CONFIG_B=y
    +# CONFIG_C is not set
    +CONFIG_D=y
    +CONFIG_E=y
    diff --git a/support/kconfig.new/util.c b/support/kconfig.new/util.c
    new file mode 100644
    index 0000000..2958539
    --- /dev/null
    +++ b/support/kconfig.new/util.c
    @@ -0,0 +1,129 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2002-2005 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + * Copyright (C) 2002-2005 Sam Ravnborg <sam@xxxxxxxxxxxx>
    + */
    +
    +#include <stdarg.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include "lkc.h"
    +
    +/* file already present in list? If not add it */
    +struct file *file_lookup(const char *name)
    +{
    +   struct file *file;
    +
    +   for (file = file_list; file; file = file->next) {
    +           if (!strcmp(name, file->name)) {
    +                   return file;
    +           }
    +   }
    +
    +   file = xmalloc(sizeof(*file));
    +   memset(file, 0, sizeof(*file));
    +   file->name = xstrdup(name);
    +   file->next = file_list;
    +   file_list = file;
    +   return file;
    +}
    +
    +/* Allocate initial growable string */
    +struct gstr str_new(void)
    +{
    +   struct gstr gs;
    +   gs.s = xmalloc(sizeof(char) * 64);
    +   gs.len = 64;
    +   gs.max_width = 0;
    +   strcpy(gs.s, "\0");
    +   return gs;
    +}
    +
    +/* Free storage for growable string */
    +void str_free(struct gstr *gs)
    +{
    +   if (gs->s)
    +           free(gs->s);
    +   gs->s = NULL;
    +   gs->len = 0;
    +}
    +
    +/* Append to growable string */
    +void str_append(struct gstr *gs, const char *s)
    +{
    +   size_t l;
    +   if (s) {
    +           l = strlen(gs->s) + strlen(s) + 1;
    +           if (l > gs->len) {
    +                   gs->s = xrealloc(gs->s, l);
    +                   gs->len = l;
    +           }
    +           strcat(gs->s, s);
    +   }
    +}
    +
    +/* Append printf formatted string to growable string */
    +void str_printf(struct gstr *gs, const char *fmt, ...)
    +{
    +   va_list ap;
    +   char s[10000]; /* big enough... */
    +   va_start(ap, fmt);
    +   vsnprintf(s, sizeof(s), fmt, ap);
    +   str_append(gs, s);
    +   va_end(ap);
    +}
    +
    +/* Retrieve value of growable string */
    +const char *str_get(struct gstr *gs)
    +{
    +   return gs->s;
    +}
    +
    +void *xmalloc(size_t size)
    +{
    +   void *p = malloc(size);
    +   if (p)
    +           return p;
    +   fprintf(stderr, "Out of memory.\n");
    +   exit(1);
    +}
    +
    +void *xcalloc(size_t nmemb, size_t size)
    +{
    +   void *p = calloc(nmemb, size);
    +   if (p)
    +           return p;
    +   fprintf(stderr, "Out of memory.\n");
    +   exit(1);
    +}
    +
    +void *xrealloc(void *p, size_t size)
    +{
    +   p = realloc(p, size);
    +   if (p)
    +           return p;
    +   fprintf(stderr, "Out of memory.\n");
    +   exit(1);
    +}
    +
    +char *xstrdup(const char *s)
    +{
    +   char *p;
    +
    +   p = strdup(s);
    +   if (p)
    +           return p;
    +   fprintf(stderr, "Out of memory.\n");
    +   exit(1);
    +}
    +
    +char *xstrndup(const char *s, size_t n)
    +{
    +   char *p;
    +
    +   p = strndup(s, n);
    +   if (p)
    +           return p;
    +   fprintf(stderr, "Out of memory.\n");
    +   exit(1);
    +}
    diff --git a/support/kconfig.new/zconf.lex.c 
b/support/kconfig.new/zconf.lex.c
    new file mode 100644
    index 0000000..b258776
    --- /dev/null
    +++ b/support/kconfig.new/zconf.lex.c
    @@ -0,0 +1,2820 @@
    +
    +#define  YY_INT_ALIGNED short int
    +
    +/* A lexical scanner generated by flex */
    +
    +#define FLEX_SCANNER
    +#define YY_FLEX_MAJOR_VERSION 2
    +#define YY_FLEX_MINOR_VERSION 6
    +#define YY_FLEX_SUBMINOR_VERSION 1
    +#if YY_FLEX_SUBMINOR_VERSION > 0
    +#define FLEX_BETA
    +#endif
    +
    +/* First, we deal with  platform-specific or compiler-specific issues. */
    +
    +/* begin standard C headers. */
    +#include <stdio.h>
    +#include <string.h>
    +#include <errno.h>
    +#include <stdlib.h>
    +
    +/* end standard C headers. */
    +
    +/* flex integer type definitions */
    +
    +#ifndef FLEXINT_H
    +#define FLEXINT_H
    +
    +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
    +
    +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
    +
    +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
    + * if you want the limit (max/min) macros for int types. 
    + */
    +#ifndef __STDC_LIMIT_MACROS
    +#define __STDC_LIMIT_MACROS 1
    +#endif
    +
    +#include <inttypes.h>
    +typedef int8_t flex_int8_t;
    +typedef uint8_t flex_uint8_t;
    +typedef int16_t flex_int16_t;
    +typedef uint16_t flex_uint16_t;
    +typedef int32_t flex_int32_t;
    +typedef uint32_t flex_uint32_t;
    +#else
    +typedef signed char flex_int8_t;
    +typedef short int flex_int16_t;
    +typedef int flex_int32_t;
    +typedef unsigned char flex_uint8_t; 
    +typedef unsigned short int flex_uint16_t;
    +typedef unsigned int flex_uint32_t;
    +
    +/* Limits of integral types. */
    +#ifndef INT8_MIN
    +#define INT8_MIN               (-128)
    +#endif
    +#ifndef INT16_MIN
    +#define INT16_MIN              (-32767-1)
    +#endif
    +#ifndef INT32_MIN
    +#define INT32_MIN              (-2147483647-1)
    +#endif
    +#ifndef INT8_MAX
    +#define INT8_MAX               (127)
    +#endif
    +#ifndef INT16_MAX
    +#define INT16_MAX              (32767)
    +#endif
    +#ifndef INT32_MAX
    +#define INT32_MAX              (2147483647)
    +#endif
    +#ifndef UINT8_MAX
    +#define UINT8_MAX              (255U)
    +#endif
    +#ifndef UINT16_MAX
    +#define UINT16_MAX             (65535U)
    +#endif
    +#ifndef UINT32_MAX
    +#define UINT32_MAX             (4294967295U)
    +#endif
    +
    +#endif /* ! C99 */
    +
    +#endif /* ! FLEXINT_H */
    +
    +/* TODO: this is always defined, so inline it */
    +#define yyconst const
    +
    +#if defined(__GNUC__) && __GNUC__ >= 3
    +#define yynoreturn __attribute__((__noreturn__))
    +#else
    +#define yynoreturn
    +#endif
    +
    +/* Returned upon end-of-file. */
    +#define YY_NULL 0
    +
    +/* Promotes a possibly negative, possibly signed char to an unsigned
    + * integer for use as an array index.  If the signed char is negative,
    + * we want to instead treat it as an 8-bit unsigned char, hence the
    + * double cast.
    + */
    +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
    +
    +/* Enter a start condition.  This macro really ought to take a parameter,
    + * but we do it the disgusting crufty way forced on us by the ()-less
    + * definition of BEGIN.
    + */
    +#define BEGIN (yy_start) = 1 + 2 *
    +
    +/* Translate the current start state into a value that can be later handed
    + * to BEGIN to return to the state.  The YYSTATE alias is for lex
    + * compatibility.
    + */
    +#define YY_START (((yy_start) - 1) / 2)
    +#define YYSTATE YY_START
    +
    +/* Action number for EOF rule of a given start state. */
    +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
    +
    +/* Special action meaning "start processing a new file". */
    +#define YY_NEW_FILE yyrestart(yyin  )
    +
    +#define YY_END_OF_BUFFER_CHAR 0
    +
    +/* Size of default input buffer. */
    +#ifndef YY_BUF_SIZE
    +#ifdef __ia64__
    +/* On IA-64, the buffer size is 16k, not 8k.
    + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
    + * Ditto for the __ia64__ case accordingly.
    + */
    +#define YY_BUF_SIZE 32768
    +#else
    +#define YY_BUF_SIZE 16384
    +#endif /* __ia64__ */
    +#endif
    +
    +/* The state buf must be large enough to hold one state per character in 
the main buffer.
    + */
    +#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
    +
    +#ifndef YY_TYPEDEF_YY_BUFFER_STATE
    +#define YY_TYPEDEF_YY_BUFFER_STATE
    +typedef struct yy_buffer_state *YY_BUFFER_STATE;
    +#endif
    +
    +#ifndef YY_TYPEDEF_YY_SIZE_T
    +#define YY_TYPEDEF_YY_SIZE_T
    +typedef size_t yy_size_t;
    +#endif
    +
    +extern int yyleng;
    +
    +extern FILE *yyin, *yyout;
    +
    +#define EOB_ACT_CONTINUE_SCAN 0
    +#define EOB_ACT_END_OF_FILE 1
    +#define EOB_ACT_LAST_MATCH 2
    +
    +    /* Note: We specifically omit the test for yy_rule_can_match_eol 
because it requires
    +     *       access to the local variable yy_act. Since yyless() is a 
macro, it would break
    +     *       existing scanners that call yyless() from OUTSIDE yylex.
    +     *       One obvious solution it to make yy_act a global. I tried 
that, and saw
    +     *       a 5% performance hit in a non-yylineno scanner, because 
yy_act is
    +     *       normally declared as a register variable-- so it is not worth 
it.
    +     */
    +    #define  YY_LESS_LINENO(n) \
    +            do { \
    +                int yyl;\
    +                for ( yyl = n; yyl < yyleng; ++yyl )\
    +                    if ( yytext[yyl] == '\n' )\
    +                        --yylineno;\
    +            }while(0)
    +    #define YY_LINENO_REWIND_TO(dst) \
    +            do {\
    +                const char *p;\
    +                for ( p = yy_cp-1; p >= (dst); --p)\
    +                    if ( *p == '\n' )\
    +                        --yylineno;\
    +            }while(0)
    +    
    +/* Return all but the first "n" matched characters back to the input 
stream. */
    +#define yyless(n) \
    +   do \
    +           { \
    +           /* Undo effects of setting up yytext. */ \
    +        int yyless_macro_arg = (n); \
    +        YY_LESS_LINENO(yyless_macro_arg);\
    +           *yy_cp = (yy_hold_char); \
    +           YY_RESTORE_YY_MORE_OFFSET \
    +           (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
    +           YY_DO_BEFORE_ACTION; /* set up yytext again */ \
    +           } \
    +   while ( 0 )
    +
    +#define unput(c) yyunput( c, (yytext_ptr)  )
    +
    +#ifndef YY_STRUCT_YY_BUFFER_STATE
    +#define YY_STRUCT_YY_BUFFER_STATE
    +struct yy_buffer_state
    +   {
    +   FILE *yy_input_file;
    +
    +   char *yy_ch_buf;                /* input buffer */
    +   char *yy_buf_pos;               /* current position in input buffer */
    +
    +   /* Size of input buffer in bytes, not including room for EOB
    +    * characters.
    +    */
    +   int yy_buf_size;
    +
    +   /* Number of characters read into yy_ch_buf, not including EOB
    +    * characters.
    +    */
    +   int yy_n_chars;
    +
    +   /* Whether we "own" the buffer - i.e., we know we created it,
    +    * and can realloc() it to grow it, and should free() it to
    +    * delete it.
    +    */
    +   int yy_is_our_buffer;
    +
    +   /* Whether this is an "interactive" input source; if so, and
    +    * if we're using stdio for input, then we want to use getc()
    +    * instead of fread(), to make sure we stop fetching input after
    +    * each newline.
    +    */
    +   int yy_is_interactive;
    +
    +   /* Whether we're considered to be at the beginning of a line.
    +    * If so, '^' rules will be active on the next match, otherwise
    +    * not.
    +    */
    +   int yy_at_bol;
    +
    +    int yy_bs_lineno; /**< The line count. */
    +    int yy_bs_column; /**< The column count. */
    +
    +   /* Whether to try to fill the input buffer when we reach the
    +    * end of it.
    +    */
    +   int yy_fill_buffer;
    +
    +   int yy_buffer_status;
    +
    +#define YY_BUFFER_NEW 0
    +#define YY_BUFFER_NORMAL 1
    +   /* When an EOF's been seen but there's still some text to process
    +    * then we mark the buffer as YY_EOF_PENDING, to indicate that we
    +    * shouldn't try reading from the input source any more.  We might
    +    * still have a bunch of tokens to match, though, because of
    +    * possible backing-up.
    +    *
    +    * When we actually see the EOF, we change the status to "new"
    +    * (via yyrestart()), so that the user can continue scanning by
    +    * just pointing yyin at a new input file.
    +    */
    +#define YY_BUFFER_EOF_PENDING 2
    +
    +   };
    +#endif /* !YY_STRUCT_YY_BUFFER_STATE */
    +
    +/* Stack of input buffers. */
    +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
    +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
    +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */
    +
    +/* We provide macros for accessing buffer states in case in the
    + * future we want to put the buffer states in a more general
    + * "scanner state".
    + *
    + * Returns the top of the stack, or NULL.
    + */
    +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
    +                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
    +                          : NULL)
    +
    +/* Same as previous macro, but useful when we know that the buffer stack 
is not
    + * NULL or when we need an lvalue. For internal use only.
    + */
    +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
    +
    +/* yy_hold_char holds the character lost when yytext is formed. */
    +static char yy_hold_char;
    +static int yy_n_chars;             /* number of characters read into 
yy_ch_buf */
    +int yyleng;
    +
    +/* Points to current character in buffer. */
    +static char *yy_c_buf_p = NULL;
    +static int yy_init = 0;            /* whether we need to initialize */
    +static int yy_start = 0;   /* start state number */
    +
    +/* Flag which is used to allow yywrap()'s to do buffer switches
    + * instead of setting up a fresh yyin.  A bit of a hack ...
    + */
    +static int yy_did_buffer_switch_on_eof;
    +
    +void yyrestart (FILE *input_file  );
    +void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
    +YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
    +void yy_delete_buffer (YY_BUFFER_STATE b  );
    +void yy_flush_buffer (YY_BUFFER_STATE b  );
    +void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
    +void yypop_buffer_state (void );
    +
    +static void yyensure_buffer_stack (void );
    +static void yy_load_buffer_state (void );
    +static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
    +
    +#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
    +
    +YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
    +YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
    +YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
    +
    +void *yyalloc (yy_size_t  );
    +void *yyrealloc (void *,yy_size_t  );
    +void yyfree (void *  );
    +
    +#define yy_new_buffer yy_create_buffer
    +
    +#define yy_set_interactive(is_interactive) \
    +   { \
    +   if ( ! YY_CURRENT_BUFFER ){ \
    +        yyensure_buffer_stack (); \
    +           YY_CURRENT_BUFFER_LVALUE =    \
    +            yy_create_buffer(yyin,YY_BUF_SIZE ); \
    +   } \
    +   YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
    +   }
    +
    +#define yy_set_bol(at_bol) \
    +   { \
    +   if ( ! YY_CURRENT_BUFFER ){\
    +        yyensure_buffer_stack (); \
    +           YY_CURRENT_BUFFER_LVALUE =    \
    +            yy_create_buffer(yyin,YY_BUF_SIZE ); \
    +   } \
    +   YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
    +   }
    +
    +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
    +
    +/* Begin user sect3 */
    +
    +#define yywrap() (/*CONSTCOND*/1)
    +#define YY_SKIP_YYWRAP
    +
    +typedef unsigned char YY_CHAR;
    +
    +FILE *yyin = NULL, *yyout = NULL;
    +
    +typedef int yy_state_type;
    +
    +extern int yylineno;
    +
    +int yylineno = 1;
    +
    +extern char *yytext;
    +#ifdef yytext_ptr
    +#undef yytext_ptr
    +#endif
    +#define yytext_ptr yytext
    +
    +static yyconst flex_int16_t yy_nxt[][21] =
    +    {
    +    {
    +        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    +        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    +        0
    +    },
    +
    +    {
    +       13,   14,   15,   16,   14,   14,   17,   14,   14,   14,
    +       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
    +       14
    +    },
    +
    +    {
    +       13,   14,   15,   16,   14,   14,   17,   14,   14,   14,
    +       14,   14,   14,   14,   14,   14,   14,   14,   14,   14,
    +       14
    +    },
    +
    +    {
    +       13,   18,   19,   20,   18,   18,   18,   21,   18,   18,
    +
    +       18,   18,   22,   23,   18,   24,   18,   25,   18,   18,
    +       18
    +    },
    +
    +    {
    +       13,   18,   19,   20,   18,   18,   18,   21,   18,   18,
    +       18,   18,   22,   23,   18,   24,   18,   25,   18,   18,
    +       18
    +    },
    +
    +    {
    +       13,   26,   27,   28,   26,   26,   26,   26,   26,   26,
    +       26,   26,   26,   26,   26,   26,   26,   26,   26,   26,
    +       26
    +    },
    +
    +    {
    +       13,   26,   27,   28,   26,   26,   26,   26,   26,   26,
    +       26,   26,   26,   26,   26,   26,   26,   26,   26,   26,
    +
    +       26
    +    },
    +
    +    {
    +       13,   29,   29,   30,   29,   31,   29,   32,   29,   31,
    +       29,   29,   29,   29,   29,   29,   29,   29,   29,   33,
    +       29
    +    },
    +
    +    {
    +       13,   29,   29,   30,   29,   31,   29,   32,   29,   31,
    +       29,   29,   29,   29,   29,   29,   29,   29,   29,   33,
    +       29
    +    },
    +
    +    {
    +       13,   34,   35,   36,   37,   38,   39,   40,   41,   38,
    +       42,   43,   34,   44,   44,   34,   45,   46,   47,   48,
    +       49
    +
    +    },
    +
    +    {
    +       13,   34,   35,   36,   37,   38,   39,   40,   41,   38,
    +       42,   43,   34,   44,   44,   34,   45,   46,   47,   48,
    +       49
    +    },
    +
    +    {
    +       13,   50,   51,   52,   50,   50,   50,   50,   50,   50,
    +       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
    +       50
    +    },
    +
    +    {
    +       13,   50,   51,   52,   50,   50,   50,   50,   50,   50,
    +       50,   50,   50,   50,   50,   50,   50,   50,   50,   50,
    +       50
    +    },
    +
    +    {
    +      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,
    +
    +      -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,  -13,
    +      -13
    +    },
    +
    +    {
    +       13,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
    +      -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,  -14,
    +      -14
    +    },
    +
    +    {
    +       13,  -15,   53,   54,  -15,  -15,   55,  -15,  -15,  -15,
    +      -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,  -15,
    +      -15
    +    },
    +
    +    {
    +       13,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
    +      -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,  -16,
    +
    +      -16
    +    },
    +
    +    {
    +       13,   56,   56,   57,   56,   56,   56,   56,   56,   56,
    +       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
    +       56
    +    },
    +
    +    {
    +       13,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
    +      -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,  -18,
    +      -18
    +    },
    +
    +    {
    +       13,  -19,   58,  -19,  -19,  -19,  -19,  -19,  -19,  -19,
    +      -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,  -19,
    +      -19
    +
    +    },
    +
    +    {
    +       13,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,
    +      -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,  -20,
    +      -20
    +    },
    +
    +    {
    +       13,  -21,  -21,  -21,  -21,  -21,  -21,   59,  -21,  -21,
    +      -21,  -21,  -21,   59,  -21,  -21,  -21,  -21,  -21,  -21,
    +      -21
    +    },
    +
    +    {
    +       13,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,  -22,
    +      -22,  -22,  -22,  -22,  -22,  -22,  -22,   60,  -22,  -22,
    +      -22
    +    },
    +
    +    {
    +       13,  -23,  -23,  -23,  -23,  -23,  -23,   59,  -23,  -23,
    +
    +      -23,  -23,  -23,   61,  -23,  -23,  -23,  -23,  -23,  -23,
    +      -23
    +    },
    +
    +    {
    +       13,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,  -24,
    +      -24,  -24,  -24,  -24,  -24,  -24,  -24,   62,  -24,  -24,
    +      -24
    +    },
    +
    +    {
    +       13,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,
    +      -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,  -25,
    +      -25
    +    },
    +
    +    {
    +       13,   63,   63,  -26,   63,   63,   63,   63,   63,   63,
    +       63,   63,   63,   63,   63,   63,   63,   63,   63,   63,
    +
    +       63
    +    },
    +
    +    {
    +       13,  -27,   64,   65,  -27,  -27,  -27,  -27,  -27,  -27,
    +      -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,  -27,
    +      -27
    +    },
    +
    +    {
    +       13,   66,  -28,  -28,   66,   66,   66,   66,   66,   66,
    +       66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
    +       66
    +    },
    +
    +    {
    +       13,   67,   67,   68,   67,  -29,   67,  -29,   67,  -29,
    +       67,   67,   67,   67,   67,   67,   67,   67,   67,  -29,
    +       67
    +
    +    },
    +
    +    {
    +       13,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,
    +      -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,  -30,
    +      -30
    +    },
    +
    +    {
    +       13,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,
    +      -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,  -31,
    +      -31
    +    },
    +
    +    {
    +       13,   69,   69,  -32,   69,   69,   69,   69,   69,   69,
    +       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
    +       69
    +    },
    +
    +    {
    +       13,   70,   70,   71,   70,   70,   70,   70,   70,   70,
    +
    +       70,   70,   70,   70,   70,   70,   70,   70,   70,   70,
    +       70
    +    },
    +
    +    {
    +       13,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
    +      -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,  -34,
    +      -34
    +    },
    +
    +    {
    +       13,  -35,   72,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
    +      -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,  -35,
    +      -35
    +    },
    +
    +    {
    +       13,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
    +      -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,  -36,
    +
    +      -36
    +    },
    +
    +    {
    +       13,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,  -37,
    +      -37,  -37,  -37,  -37,  -37,  -37,  -37,   73,  -37,  -37,
    +      -37
    +    },
    +
    +    {
    +       13,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
    +      -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,  -38,
    +      -38
    +    },
    +
    +    {
    +       13,   74,   74,  -39,   74,   74,   74,   74,   74,   74,
    +       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
    +       74
    +
    +    },
    +
    +    {
    +       13,  -40,  -40,  -40,  -40,  -40,  -40,   75,  -40,  -40,
    +      -40,  -40,  -40,   75,   75,  -40,  -40,  -40,  -40,  -40,
    +      -40
    +    },
    +
    +    {
    +       13,  -41,  -41,  -41,  -41,  -41,  -41,  -41,   76,  -41,
    +      -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,  -41,
    +      -41
    +    },
    +
    +    {
    +       13,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,
    +      -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,  -42,
    +      -42
    +    },
    +
    +    {
    +       13,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
    +
    +      -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,  -43,
    +      -43
    +    },
    +
    +    {
    +       13,  -44,  -44,  -44,  -44,  -44,  -44,   75,  -44,  -44,
    +      -44,  -44,  -44,   77,   77,  -44,  -44,  -44,  -44,  -44,
    +      -44
    +    },
    +
    +    {
    +       13,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,  -45,
    +      -45,  -45,  -45,  -45,  -45,  -45,  -45,   78,  -45,  -45,
    +      -45
    +    },
    +
    +    {
    +       13,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,
    +      -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,  -46,
    +
    +      -46
    +    },
    +
    +    {
    +       13,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,  -47,
    +      -47,  -47,  -47,  -47,  -47,  -47,  -47,   79,  -47,  -47,
    +      -47
    +    },
    +
    +    {
    +       13,  -48,  -48,   80,  -48,  -48,  -48,  -48,  -48,  -48,
    +      -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,  -48,
    +      -48
    +    },
    +
    +    {
    +       13,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,
    +      -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,  -49,
    +       81
    +
    +    },
    +
    +    {
    +       13,   82,   83,  -50,   82,   82,   82,   82,   82,   82,
    +       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
    +       82
    +    },
    +
    +    {
    +       13,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,
    +      -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,  -51,
    +      -51
    +    },
    +
    +    {
    +       13,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
    +      -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,  -52,
    +      -52
    +    },
    +
    +    {
    +       13,  -53,   53,   54,  -53,  -53,   55,  -53,  -53,  -53,
    +
    +      -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,  -53,
    +      -53
    +    },
    +
    +    {
    +       13,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
    +      -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,  -54,
    +      -54
    +    },
    +
    +    {
    +       13,   56,   56,   57,   56,   56,   56,   56,   56,   56,
    +       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
    +       56
    +    },
    +
    +    {
    +       13,   56,   56,   57,   56,   56,   56,   56,   56,   56,
    +       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
    +
    +       56
    +    },
    +
    +    {
    +       13,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
    +      -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,  -57,
    +      -57
    +    },
    +
    +    {
    +       13,  -58,   58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
    +      -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,  -58,
    +      -58
    +    },
    +
    +    {
    +       13,  -59,  -59,  -59,  -59,  -59,  -59,   59,  -59,  -59,
    +      -59,  -59,  -59,   59,  -59,  -59,  -59,  -59,  -59,  -59,
    +      -59
    +
    +    },
    +
    +    {
    +       13,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
    +      -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,  -60,
    +      -60
    +    },
    +
    +    {
    +       13,  -61,  -61,  -61,  -61,  -61,  -61,   59,  -61,  -61,
    +      -61,  -61,  -61,   61,  -61,  -61,  -61,  -61,  -61,  -61,
    +      -61
    +    },
    +
    +    {
    +       13,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,
    +      -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,  -62,
    +      -62
    +    },
    +
    +    {
    +       13,   63,   63,  -63,   63,   63,   63,   63,   63,   63,
    +
    +       63,   63,   63,   63,   63,   63,   63,   63,   63,   63,
    +       63
    +    },
    +
    +    {
    +       13,  -64,   64,   65,  -64,  -64,  -64,  -64,  -64,  -64,
    +      -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,  -64,
    +      -64
    +    },
    +
    +    {
    +       13,   66,  -65,  -65,   66,   66,   66,   66,   66,   66,
    +       66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
    +       66
    +    },
    +
    +    {
    +       13,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,
    +      -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,  -66,
    +
    +      -66
    +    },
    +
    +    {
    +       13,   67,   67,   68,   67,  -67,   67,  -67,   67,  -67,
    +       67,   67,   67,   67,   67,   67,   67,   67,   67,  -67,
    +       67
    +    },
    +
    +    {
    +       13,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,
    +      -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,  -68,
    +      -68
    +    },
    +
    +    {
    +       13,   69,   69,  -69,   69,   69,   69,   69,   69,   69,
    +       69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
    +       69
    +
    +    },
    +
    +    {
    +       13,  -70,  -70,   71,  -70,  -70,  -70,  -70,  -70,  -70,
    +      -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,  -70,
    +      -70
    +    },
    +
    +    {
    +       13,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,
    +      -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,  -71,
    +      -71
    +    },
    +
    +    {
    +       13,  -72,   72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,
    +      -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,  -72,
    +      -72
    +    },
    +
    +    {
    +       13,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,
    +
    +      -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,  -73,
    +      -73
    +    },
    +
    +    {
    +       13,   74,   74,  -74,   74,   74,   74,   74,   74,   74,
    +       74,   74,   74,   74,   74,   74,   74,   74,   74,   74,
    +       74
    +    },
    +
    +    {
    +       13,  -75,  -75,  -75,  -75,  -75,  -75,   75,  -75,  -75,
    +      -75,  -75,  -75,   75,   75,  -75,  -75,  -75,  -75,  -75,
    +      -75
    +    },
    +
    +    {
    +       13,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,
    +      -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,  -76,
    +
    +      -76
    +    },
    +
    +    {
    +       13,  -77,  -77,  -77,  -77,  -77,  -77,   75,  -77,  -77,
    +      -77,  -77,  -77,   77,   77,  -77,  -77,  -77,  -77,  -77,
    +      -77
    +    },
    +
    +    {
    +       13,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,
    +      -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,  -78,
    +      -78
    +    },
    +
    +    {
    +       13,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,
    +      -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,
    +      -79
    +
    +    },
    +
    +    {
    +       13,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
    +      -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,  -80,
    +      -80
    +    },
    +
    +    {
    +       13,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,
    +      -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,  -81,
    +      -81
    +    },
    +
    +    {
    +       13,   82,   83,  -82,   82,   82,   82,   82,   82,   82,
    +       82,   82,   82,   82,   82,   82,   82,   82,   82,   82,
    +       82
    +    },
    +
    +    {
    +       13,   83,   83,  -83,   83,   83,   83,   83,   83,   83,
    +
    +       83,   83,   83,   83,   83,   83,   83,   83,   83,   83,
    +       83
    +    },
    +
    +    } ;
    +
    +static yy_state_type yy_get_previous_state (void );
    +static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
    +static int yy_get_next_buffer (void );
    +static void yynoreturn yy_fatal_error (yyconst char* msg  );
    +
    +/* Done after the current pattern has been matched and before the
    + * corresponding action - sets up yytext.
    + */
    +#define YY_DO_BEFORE_ACTION \
    +   (yytext_ptr) = yy_bp; \
    +   yyleng = (int) (yy_cp - yy_bp); \
    +   (yy_hold_char) = *yy_cp; \
    +   *yy_cp = '\0'; \
    +   (yy_c_buf_p) = yy_cp;
    +
    +#define YY_NUM_RULES 47
    +#define YY_END_OF_BUFFER 48
    +/* This struct is not used in this scanner,
    +   but its presence is necessary. */
    +struct yy_trans_info
    +   {
    +   flex_int32_t yy_verify;
    +   flex_int32_t yy_nxt;
    +   };
    +static yyconst flex_int16_t yy_accept[84] =
    +    {   0,
    +        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    +        0,    0,   48,    5,    4,    2,    3,   12,   11,   13,
    +        7,   12,    6,   12,    8,   46,   43,   45,   38,   42,
    +       41,   36,   40,   35,   34,   29,   21,   28,   32,   31,
    +       35,   19,   20,   30,   26,   22,   27,   35,   35,   14,
    +       16,   15,    4,    2,    3,    3,    1,   11,    7,   10,
    +        6,    9,   46,   43,   45,   44,   38,   37,   36,   40,
    +       39,   34,   23,   32,   31,   17,   30,   24,   25,   33,
    +       18,   14,   14
    +    } ;
    +
    +static yyconst YY_CHAR yy_ec[256] =
    +    {   0,
    +        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    2,    4,    5,    6,    7,    1,    8,    9,   10,
    +       11,    1,   12,    1,   13,   14,   14,   13,   13,   13,
    +       13,   13,   13,   13,   13,   13,   13,   15,    1,   16,
    +       17,   18,    1,    1,   13,   13,   13,   13,   13,   13,
    +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
    +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
    +        1,   19,    1,    1,   13,    1,   13,   13,   13,   13,
    +
    +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
    +       13,   13,   13,   13,   13,   13,   13,   13,   13,   13,
    +       13,   13,    1,   20,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
    +        1,    1,    1,    1,    1
    +    } ;
    +
    +/* Table of booleans, true if rule could match eol. */
    +static yyconst flex_int32_t yy_rule_can_match_eol[48] =
    +    {   0,
    +1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 
    +    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 
    +    0, 0, 1, 0, 1, 1, 0, 0,     };
    +
    +extern int yy_flex_debug;
    +int yy_flex_debug = 0;
    +
    +/* The intent behind this definition is that it'll catch
    + * any uses of REJECT which flex missed.
    + */
    +#define REJECT reject_used_but_not_detected
    +#define yymore() yymore_used_but_not_detected
    +#define YY_MORE_ADJ 0
    +#define YY_RESTORE_YY_MORE_OFFSET
    +char *yytext;
    +
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + * Released under the terms of the GNU GPL v2.0.
    + */
    +
    +#include <assert.h>
    +#include <limits.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +
    +#include "lkc.h"
    +
    +#define START_STRSIZE      16
    +
    +static struct {
    +   struct file *file;
    +   int lineno;
    +} current_pos;
    +
    +static char *text;
    +static int text_size, text_asize;
    +
    +struct buffer {
    +   struct buffer *parent;
    +   YY_BUFFER_STATE state;
    +};
    +
    +struct buffer *current_buf;
    +
    +static int last_ts, first_ts;
    +
    +static char *expand_token(const char *in, size_t n);
    +static void append_expanded_string(const char *in);
    +static void zconf_endhelp(void);
    +static void zconf_endfile(void);
    +
    +static void new_string(void)
    +{
    +   text = xmalloc(START_STRSIZE);
    +   text_asize = START_STRSIZE;
    +   text_size = 0;
    +   *text = 0;
    +}
    +
    +static void append_string(const char *str, int size)
    +{
    +   int new_size = text_size + size + 1;
    +   if (new_size > text_asize) {
    +           new_size += START_STRSIZE - 1;
    +           new_size &= -START_STRSIZE;
    +           text = xrealloc(text, new_size);
    +           text_asize = new_size;
    +   }
    +   memcpy(text + text_size, str, size);
    +   text_size += size;
    +   text[text_size] = 0;
    +}
    +
    +static void alloc_string(const char *str, int size)
    +{
    +   text = xmalloc(size + 1);
    +   memcpy(text, str, size);
    +   text[size] = 0;
    +}
    +
    +static void warn_ignored_character(char chr)
    +{
    +   fprintf(stderr,
    +           "%s:%d:warning: ignoring unsupported character '%c'\n",
    +           zconf_curname(), zconf_lineno(), chr);
    +}
    +
    +#define INITIAL 0
    +#define COMMAND 1
    +#define HELP 2
    +#define STRING 3
    +#define PARAM 4
    +#define ASSIGN_VAL 5
    +
    +#ifndef YY_NO_UNISTD_H
    +/* Special case for "unistd.h", since it is non-ANSI. We include it way
    + * down here because we want the user's section 1 to have been scanned 
first.
    + * The user has a chance to override it with an option.
    + */
    +#include <unistd.h>
    +#endif
    +
    +#ifndef YY_EXTRA_TYPE
    +#define YY_EXTRA_TYPE void *
    +#endif
    +
    +static int yy_init_globals (void );
    +
    +/* Accessor methods to globals.
    +   These are made visible to non-reentrant scanners for convenience. */
    +
    +int yylex_destroy (void );
    +
    +int yyget_debug (void );
    +
    +void yyset_debug (int debug_flag  );
    +
    +YY_EXTRA_TYPE yyget_extra (void );
    +
    +void yyset_extra (YY_EXTRA_TYPE user_defined  );
    +
    +FILE *yyget_in (void );
    +
    +void yyset_in  (FILE * _in_str  );
    +
    +FILE *yyget_out (void );
    +
    +void yyset_out  (FILE * _out_str  );
    +
    +                   int yyget_leng (void );
    +
    +char *yyget_text (void );
    +
    +int yyget_lineno (void );
    +
    +void yyset_lineno (int _line_number  );
    +
    +/* Macros after this point can all be overridden by user definitions in
    + * section 1.
    + */
    +
    +#ifndef YY_SKIP_YYWRAP
    +#ifdef __cplusplus
    +extern "C" int yywrap (void );
    +#else
    +extern int yywrap (void );
    +#endif
    +#endif
    +
    +#ifndef YY_NO_UNPUT
    +    
    +    static void yyunput (int c,char *buf_ptr  );
    +    
    +#endif
    +
    +#ifndef yytext_ptr
    +static void yy_flex_strncpy (char *,yyconst char *,int );
    +#endif
    +
    +#ifdef YY_NEED_STRLEN
    +static int yy_flex_strlen (yyconst char * );
    +#endif
    +
    +#ifndef YY_NO_INPUT
    +
    +#ifdef __cplusplus
    +static int yyinput (void );
    +#else
    +static int input (void );
    +#endif
    +
    +#endif
    +
    +/* Amount of stuff to slurp up with each read. */
    +#ifndef YY_READ_BUF_SIZE
    +#ifdef __ia64__
    +/* On IA-64, the buffer size is 16k, not 8k */
    +#define YY_READ_BUF_SIZE 16384
    +#else
    +#define YY_READ_BUF_SIZE 8192
    +#endif /* __ia64__ */
    +#endif
    +
    +/* Copy whatever the last rule matched to the standard output. */
    +#ifndef ECHO
    +/* This used to be an fputs(), but since the string might contain NUL's,
    + * we now use fwrite().
    + */
    +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } 
while (0)
    +#endif
    +
    +/* Gets input and stuffs it into "buf".  number of characters read, or 
YY_NULL,
    + * is returned in "result".
    + */
    +#ifndef YY_INPUT
    +#define YY_INPUT(buf,result,max_size) \
    +   errno=0; \
    +   while ( (result = (int) read( fileno(yyin), buf, max_size )) < 0 ) \
    +   { \
    +           if( errno != EINTR) \
    +           { \
    +                   YY_FATAL_ERROR( "input in flex scanner failed" ); \
    +                   break; \
    +           } \
    +           errno=0; \
    +           clearerr(yyin); \
    +   }\
    +\
    +
    +#endif
    +
    +/* No semi-colon after return; correct usage is to write "yyterminate();" -
    + * we don't want an extra ';' after the "return" because that will cause
    + * some compilers to complain about unreachable statements.
    + */
    +#ifndef yyterminate
    +#define yyterminate() return YY_NULL
    +#endif
    +
    +/* Number of entries by which start-condition stack grows. */
    +#ifndef YY_START_STACK_INCR
    +#define YY_START_STACK_INCR 25
    +#endif
    +
    +/* Report a fatal error. */
    +#ifndef YY_FATAL_ERROR
    +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
    +#endif
    +
    +/* end tables serialization structures and prototypes */
    +
    +/* Default declaration of generated scanner - a define so the user can
    + * easily add parameters.
    + */
    +#ifndef YY_DECL
    +#define YY_DECL_IS_OURS 1
    +
    +extern int yylex (void);
    +
    +#define YY_DECL int yylex (void)
    +#endif /* !YY_DECL */
    +
    +/* Code executed at the beginning of each rule, after yytext and yyleng
    + * have been set up.
    + */
    +#ifndef YY_USER_ACTION
    +#define YY_USER_ACTION
    +#endif
    +
    +/* Code executed at the end of each rule. */
    +#ifndef YY_BREAK
    +#define YY_BREAK /*LINTED*/break;
    +#endif
    +
    +#define YY_RULE_SETUP \
    +   YY_USER_ACTION
    +
    +/** The main scanner function which does all the work.
    + */
    +YY_DECL
    +{
    +   yy_state_type yy_current_state;
    +   char *yy_cp, *yy_bp;
    +   int yy_act;
    +    
    +   if ( !(yy_init) )
    +           {
    +           (yy_init) = 1;
    +
    +#ifdef YY_USER_INIT
    +           YY_USER_INIT;
    +#endif
    +
    +           if ( ! (yy_start) )
    +                   (yy_start) = 1; /* first start state */
    +
    +           if ( ! yyin )
    +                   yyin = stdin;
    +
    +           if ( ! yyout )
    +                   yyout = stdout;
    +
    +           if ( ! YY_CURRENT_BUFFER ) {
    +                   yyensure_buffer_stack ();
    +                   YY_CURRENT_BUFFER_LVALUE =
    +                           yy_create_buffer(yyin,YY_BUF_SIZE );
    +           }
    +
    +           yy_load_buffer_state( );
    +           }
    +
    +   {
    +
    +   int str = 0;
    +   int ts, i;
    +
    +   while ( /*CONSTCOND*/1 )                /* loops until end-of-file is 
reached */
    +           {
    +           yy_cp = (yy_c_buf_p);
    +
    +           /* Support of yytext. */
    +           *yy_cp = (yy_hold_char);
    +
    +           /* yy_bp points to the position in yy_ch_buf of the start of
    +            * the current run.
    +            */
    +           yy_bp = yy_cp;
    +
    +           yy_current_state = (yy_start);
    +yy_match:
    +           while ( (yy_current_state = yy_nxt[yy_current_state][ 
yy_ec[YY_SC_TO_UI(*yy_cp)]  ]) > 0 )
    +                   ++yy_cp;
    +
    +           yy_current_state = -yy_current_state;
    +
    +yy_find_action:
    +           yy_act = yy_accept[yy_current_state];
    +
    +           YY_DO_BEFORE_ACTION;
    +
    +           if ( yy_act != YY_END_OF_BUFFER && 
yy_rule_can_match_eol[yy_act] )
    +                   {
    +                   int yyl;
    +                   for ( yyl = 0; yyl < yyleng; ++yyl )
    +                           if ( yytext[yyl] == '\n' )
    +                                   
    +    yylineno++;
    +;
    +                   }
    +
    +do_action: /* This label is used only to access EOF actions. */
    +
    +           switch ( yy_act )
    +   { /* beginning of action switch */
    +case 1:
    +/* rule 1 can match eol */
    +case 2:
    +/* rule 2 can match eol */
    +YY_RULE_SETUP
    +{
    +   return T_EOL;
    +}
    +   YY_BREAK
    +case 3:
    +YY_RULE_SETUP
    +
    +   YY_BREAK
    +case 4:
    +YY_RULE_SETUP
    +{
    +   BEGIN(COMMAND);
    +}
    +   YY_BREAK
    +case 5:
    +YY_RULE_SETUP
    +{
    +   unput(yytext[0]);
    +   BEGIN(COMMAND);
    +}
    +   YY_BREAK
    +
    +case 6:
    +YY_RULE_SETUP
    +{
    +           const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
    +           current_pos.file = current_file;
    +           current_pos.lineno = yylineno;
    +           if (id && id->flags & TF_COMMAND) {
    +                   BEGIN(PARAM);
    +                   yylval.id = id;
    +                   return id->token;
    +           }
    +           alloc_string(yytext, yyleng);
    +           yylval.string = text;
    +           return T_VARIABLE;
    +   }
    +   YY_BREAK
    +case 7:
    +YY_RULE_SETUP
    +{
    +           /* this token includes at least one '$' */
    +           yylval.string = expand_token(yytext, yyleng);
    +           if (strlen(yylval.string))
    +                   return T_VARIABLE;
    +           free(yylval.string);
    +   }
    +   YY_BREAK
    +case 8:
    +YY_RULE_SETUP
    +{ BEGIN(ASSIGN_VAL); yylval.flavor = VAR_RECURSIVE; return T_ASSIGN; }
    +   YY_BREAK
    +case 9:
    +YY_RULE_SETUP
    +{ BEGIN(ASSIGN_VAL); yylval.flavor = VAR_SIMPLE; return T_ASSIGN; }
    +   YY_BREAK
    +case 10:
    +YY_RULE_SETUP
    +{ BEGIN(ASSIGN_VAL); yylval.flavor = VAR_APPEND; return T_ASSIGN; }
    +   YY_BREAK
    +case 11:
    +YY_RULE_SETUP
    +
    +   YY_BREAK
    +case 12:
    +YY_RULE_SETUP
    +warn_ignored_character(*yytext);
    +   YY_BREAK
    +case 13:
    +/* rule 13 can match eol */
    +YY_RULE_SETUP
    +{
    +           BEGIN(INITIAL);
    +           return T_EOL;
    +   }
    +   YY_BREAK
    +
    +case 14:
    +YY_RULE_SETUP
    +{
    +           alloc_string(yytext, yyleng);
    +           yylval.string = text;
    +           return T_ASSIGN_VAL;
    +   }
    +   YY_BREAK
    +case 15:
    +/* rule 15 can match eol */
    +YY_RULE_SETUP
    +{ BEGIN(INITIAL); return T_EOL; }
    +   YY_BREAK
    +case 16:
    +YY_RULE_SETUP
    +
    +   YY_BREAK
    +
    +case 17:
    +YY_RULE_SETUP
    +return T_AND;
    +   YY_BREAK
    +case 18:
    +YY_RULE_SETUP
    +return T_OR;
    +   YY_BREAK
    +case 19:
    +YY_RULE_SETUP
    +return T_OPEN_PAREN;
    +   YY_BREAK
    +case 20:
    +YY_RULE_SETUP
    +return T_CLOSE_PAREN;
    +   YY_BREAK
    +case 21:
    +YY_RULE_SETUP
    +return T_NOT;
    +   YY_BREAK
    +case 22:
    +YY_RULE_SETUP
    +return T_EQUAL;
    +   YY_BREAK
    +case 23:
    +YY_RULE_SETUP
    +return T_UNEQUAL;
    +   YY_BREAK
    +case 24:
    +YY_RULE_SETUP
    +return T_LESS_EQUAL;
    +   YY_BREAK
    +case 25:
    +YY_RULE_SETUP
    +return T_GREATER_EQUAL;
    +   YY_BREAK
    +case 26:
    +YY_RULE_SETUP
    +return T_LESS;
    +   YY_BREAK
    +case 27:
    +YY_RULE_SETUP
    +return T_GREATER;
    +   YY_BREAK
    +case 28:
    +YY_RULE_SETUP
    +{
    +           str = yytext[0];
    +           new_string();
    +           BEGIN(STRING);
    +   }
    +   YY_BREAK
    +case 29:
    +/* rule 29 can match eol */
    +YY_RULE_SETUP
    +BEGIN(INITIAL); return T_EOL;
    +   YY_BREAK
    +case 30:
    +YY_RULE_SETUP
    +{
    +           const struct kconf_id *id = kconf_id_lookup(yytext, yyleng);
    +           if (id && id->flags & TF_PARAM) {
    +                   yylval.id = id;
    +                   return id->token;
    +           }
    +           alloc_string(yytext, yyleng);
    +           yylval.string = text;
    +           return T_WORD;
    +   }
    +   YY_BREAK
    +case 31:
    +YY_RULE_SETUP
    +{
    +           /* this token includes at least one '$' */
    +           yylval.string = expand_token(yytext, yyleng);
    +           if (strlen(yylval.string))
    +                   return T_WORD;
    +           free(yylval.string);
    +   }
    +   YY_BREAK
    +case 32:
    +YY_RULE_SETUP
    +/* comment */
    +   YY_BREAK
    +case 33:
    +/* rule 33 can match eol */
    +YY_RULE_SETUP
    +;
    +   YY_BREAK
    +case 34:
    +YY_RULE_SETUP
    +
    +   YY_BREAK
    +case 35:
    +YY_RULE_SETUP
    +warn_ignored_character(*yytext);
    +   YY_BREAK
    +case YY_STATE_EOF(PARAM):
    +{
    +           BEGIN(INITIAL);
    +   }
    +   YY_BREAK
    +
    +case 36:
    +YY_RULE_SETUP
    +append_expanded_string(yytext);
    +   YY_BREAK
    +case 37:
    +/* rule 37 can match eol */
    +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
    +YY_LINENO_REWIND_TO(yy_cp - 1);
    +(yy_c_buf_p) = yy_cp -= 1;
    +YY_DO_BEFORE_ACTION; /* set up yytext again */
    +YY_RULE_SETUP
    +{
    +           append_string(yytext, yyleng);
    +           yylval.string = text;
    +           return T_WORD_QUOTE;
    +   }
    +   YY_BREAK
    +case 38:
    +YY_RULE_SETUP
    +{
    +           append_string(yytext, yyleng);
    +   }
    +   YY_BREAK
    +case 39:
    +/* rule 39 can match eol */
    +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
    +YY_LINENO_REWIND_TO(yy_cp - 1);
    +(yy_c_buf_p) = yy_cp -= 1;
    +YY_DO_BEFORE_ACTION; /* set up yytext again */
    +YY_RULE_SETUP
    +{
    +           append_string(yytext + 1, yyleng - 1);
    +           yylval.string = text;
    +           return T_WORD_QUOTE;
    +   }
    +   YY_BREAK
    +case 40:
    +YY_RULE_SETUP
    +{
    +           append_string(yytext + 1, yyleng - 1);
    +   }
    +   YY_BREAK
    +case 41:
    +YY_RULE_SETUP
    +{
    +           if (str == yytext[0]) {
    +                   BEGIN(PARAM);
    +                   yylval.string = text;
    +                   return T_WORD_QUOTE;
    +           } else
    +                   append_string(yytext, 1);
    +   }
    +   YY_BREAK
    +case 42:
    +/* rule 42 can match eol */
    +YY_RULE_SETUP
    +{
    +           fprintf(stderr,
    +                   "%s:%d:warning: multi-line strings not supported\n",
    +                   zconf_curname(), zconf_lineno());
    +           BEGIN(INITIAL);
    +           return T_EOL;
    +   }
    +   YY_BREAK
    +case YY_STATE_EOF(STRING):
    +{
    +           BEGIN(INITIAL);
    +   }
    +   YY_BREAK
    +
    +case 43:
    +YY_RULE_SETUP
    +{
    +           ts = 0;
    +           for (i = 0; i < yyleng; i++) {
    +                   if (yytext[i] == '\t')
    +                           ts = (ts & ~7) + 8;
    +                   else
    +                           ts++;
    +           }
    +           last_ts = ts;
    +           if (first_ts) {
    +                   if (ts < first_ts) {
    +                           zconf_endhelp();
    +                           return T_HELPTEXT;
    +                   }
    +                   ts -= first_ts;
    +                   while (ts > 8) {
    +                           append_string("        ", 8);
    +                           ts -= 8;
    +                   }
    +                   append_string("        ", ts);
    +           }
    +   }
    +   YY_BREAK
    +case 44:
    +/* rule 44 can match eol */
    +*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
    +YY_LINENO_REWIND_TO(yy_cp - 1);
    +(yy_c_buf_p) = yy_cp -= 1;
    +YY_DO_BEFORE_ACTION; /* set up yytext again */
    +YY_RULE_SETUP
    +{
    +           zconf_endhelp();
    +           return T_HELPTEXT;
    +   }
    +   YY_BREAK
    +case 45:
    +/* rule 45 can match eol */
    +YY_RULE_SETUP
    +{
    +           append_string("\n", 1);
    +   }
    +   YY_BREAK
    +case 46:
    +YY_RULE_SETUP
    +{
    +           while (yyleng) {
    +                   if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != 
'\t'))
    +                           break;
    +                   yyleng--;
    +           }
    +           append_string(yytext, yyleng);
    +           if (!first_ts)
    +                   first_ts = last_ts;
    +   }
    +   YY_BREAK
    +case YY_STATE_EOF(HELP):
    +{
    +           zconf_endhelp();
    +           return T_HELPTEXT;
    +   }
    +   YY_BREAK
    +
    +case YY_STATE_EOF(INITIAL):
    +case YY_STATE_EOF(COMMAND):
    +case YY_STATE_EOF(ASSIGN_VAL):
    +{
    +   if (current_file) {
    +           zconf_endfile();
    +           return T_EOL;
    +   }
    +   fclose(yyin);
    +   yyterminate();
    +}
    +   YY_BREAK
    +case 47:
    +YY_RULE_SETUP
    +YY_FATAL_ERROR( "flex scanner jammed" );
    +   YY_BREAK
    +
    +   case YY_END_OF_BUFFER:
    +           {
    +           /* Amount of text matched not including the EOB char. */
    +           int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 
1;
    +
    +           /* Undo the effects of YY_DO_BEFORE_ACTION. */
    +           *yy_cp = (yy_hold_char);
    +           YY_RESTORE_YY_MORE_OFFSET
    +
    +           if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == 
YY_BUFFER_NEW )
    +                   {
    +                   /* We're scanning a new file or input source.  It's
    +                    * possible that this happened because the user
    +                    * just pointed yyin at a new source and called
    +                    * yylex().  If so, then we have to assure
    +                    * consistency between YY_CURRENT_BUFFER and our
    +                    * globals.  Here is the right place to do so, because
    +                    * this is the first action (other than possibly a
    +                    * back-up) that will match for the new input source.
    +                    */
    +                   (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
    +                   YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
    +                   YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = 
YY_BUFFER_NORMAL;
    +                   }
    +
    +           /* Note that here we test for yy_c_buf_p "<=" to the position
    +            * of the first EOB in the buffer, since yy_c_buf_p will
    +            * already have been incremented past the NUL character
    +            * (since all states make transitions on EOB to the
    +            * end-of-buffer state).  Contrast this with the test
    +            * in input().
    +            */
    +           if ( (yy_c_buf_p) <= 
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
    +                   { /* This was really a NUL. */
    +                   yy_state_type yy_next_state;
    +
    +                   (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
    +
    +                   yy_current_state = yy_get_previous_state(  );
    +
    +                   /* Okay, we're now positioned to make the NUL
    +                    * transition.  We couldn't have
    +                    * yy_get_previous_state() go ahead and do it
    +                    * for us because it doesn't know how to deal
    +                    * with the possibility of jamming (and we don't
    +                    * want to build jamming into it because then it
    +                    * will run more slowly).
    +                    */
    +
    +                   yy_next_state = yy_try_NUL_trans( yy_current_state );
    +
    +                   yy_bp = (yytext_ptr) + YY_MORE_ADJ;
    +
    +                   if ( yy_next_state )
    +                           {
    +                           /* Consume the NUL. */
    +                           yy_cp = ++(yy_c_buf_p);
    +                           yy_current_state = yy_next_state;
    +                           goto yy_match;
    +                           }
    +
    +                   else
    +                           {
    +                           yy_cp = (yy_c_buf_p);
    +                           goto yy_find_action;
    +                           }
    +                   }
    +
    +           else switch ( yy_get_next_buffer(  ) )
    +                   {
    +                   case EOB_ACT_END_OF_FILE:
    +                           {
    +                           (yy_did_buffer_switch_on_eof) = 0;
    +
    +                           if ( yywrap( ) )
    +                                   {
    +                                   /* Note: because we've taken care in
    +                                    * yy_get_next_buffer() to have set up
    +                                    * yytext, we can now set up
    +                                    * yy_c_buf_p so that if some total
    +                                    * hoser (like flex itself) wants to
    +                                    * call the scanner after we return the
    +                                    * YY_NULL, it'll still work - another
    +                                    * YY_NULL will get returned.
    +                                    */
    +                                   (yy_c_buf_p) = (yytext_ptr) + 
YY_MORE_ADJ;
    +
    +                                   yy_act = YY_STATE_EOF(YY_START);
    +                                   goto do_action;
    +                                   }
    +
    +                           else
    +                                   {
    +                                   if ( ! (yy_did_buffer_switch_on_eof) )
    +                                           YY_NEW_FILE;
    +                                   }
    +                           break;
    +                           }
    +
    +                   case EOB_ACT_CONTINUE_SCAN:
    +                           (yy_c_buf_p) =
    +                                   (yytext_ptr) + 
yy_amount_of_matched_text;
    +
    +                           yy_current_state = yy_get_previous_state(  );
    +
    +                           yy_cp = (yy_c_buf_p);
    +                           yy_bp = (yytext_ptr) + YY_MORE_ADJ;
    +                           goto yy_match;
    +
    +                   case EOB_ACT_LAST_MATCH:
    +                           (yy_c_buf_p) =
    +                           
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
    +
    +                           yy_current_state = yy_get_previous_state(  );
    +
    +                           yy_cp = (yy_c_buf_p);
    +                           yy_bp = (yytext_ptr) + YY_MORE_ADJ;
    +                           goto yy_find_action;
    +                   }
    +           break;
    +           }
    +
    +   default:
    +           YY_FATAL_ERROR(
    +                   "fatal flex scanner internal error--no action found" );
    +   } /* end of action switch */
    +           } /* end of scanning one token */
    +   } /* end of user's declarations */
    +} /* end of yylex */
    +
    +/* yy_get_next_buffer - try to read in a new buffer
    + *
    + * Returns a code representing an action:
    + * EOB_ACT_LAST_MATCH -
    + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
    + * EOB_ACT_END_OF_FILE - end of file
    + */
    +static int yy_get_next_buffer (void)
    +{
    +           char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
    +   char *source = (yytext_ptr);
    +   int number_to_move, i;
    +   int ret_val;
    +
    +   if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 
1] )
    +           YY_FATAL_ERROR(
    +           "fatal flex scanner internal error--end of buffer missed" );
    +
    +   if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
    +           { /* Don't try to fill the buffer, so this is an EOF. */
    +           if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
    +                   {
    +                   /* We matched a single character, the EOB, so
    +                    * treat this as a final EOF.
    +                    */
    +                   return EOB_ACT_END_OF_FILE;
    +                   }
    +
    +           else
    +                   {
    +                   /* We matched some text prior to the EOB, first
    +                    * process it.
    +                    */
    +                   return EOB_ACT_LAST_MATCH;
    +                   }
    +           }
    +
    +   /* Try to read more data. */
    +
    +   /* First move last chars to start of buffer. */
    +   number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1);
    +
    +   for ( i = 0; i < number_to_move; ++i )
    +           *(dest++) = *(source++);
    +
    +   if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == 
YY_BUFFER_EOF_PENDING )
    +           /* don't do the read, it's not guaranteed to return an EOF,
    +            * just force an EOF
    +            */
    +           YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
    +
    +   else
    +           {
    +                   int num_to_read =
    +                   YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move 
- 1;
    +
    +           while ( num_to_read <= 0 )
    +                   { /* Not enough room in the buffer - grow it. */
    +
    +                   /* just a shorter name for the current buffer */
    +                   YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
    +
    +                   int yy_c_buf_p_offset =
    +                           (int) ((yy_c_buf_p) - b->yy_ch_buf);
    +
    +                   if ( b->yy_is_our_buffer )
    +                           {
    +                           int new_size = b->yy_buf_size * 2;
    +
    +                           if ( new_size <= 0 )
    +                                   b->yy_buf_size += b->yy_buf_size / 8;
    +                           else
    +                                   b->yy_buf_size *= 2;
    +
    +                           b->yy_ch_buf = (char *)
    +                                   /* Include room in for 2 EOB chars. */
    +                                   yyrealloc((void *) 
b->yy_ch_buf,b->yy_buf_size + 2  );
    +                           }
    +                   else
    +                           /* Can't grow it, we don't own it. */
    +                           b->yy_ch_buf = NULL;
    +
    +                   if ( ! b->yy_ch_buf )
    +                           YY_FATAL_ERROR(
    +                           "fatal error - scanner input buffer overflow" );
    +
    +                   (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
    +
    +                   num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
    +                                           number_to_move - 1;
    +
    +                   }
    +
    +           if ( num_to_read > YY_READ_BUF_SIZE )
    +                   num_to_read = YY_READ_BUF_SIZE;
    +
    +           /* Read in more data. */
    +           YY_INPUT( 
(&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
    +                   (yy_n_chars), num_to_read );
    +
    +           YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
    +           }
    +
    +   if ( (yy_n_chars) == 0 )
    +           {
    +           if ( number_to_move == YY_MORE_ADJ )
    +                   {
    +                   ret_val = EOB_ACT_END_OF_FILE;
    +                   yyrestart(yyin  );
    +                   }
    +
    +           else
    +                   {
    +                   ret_val = EOB_ACT_LAST_MATCH;
    +                   YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
    +                           YY_BUFFER_EOF_PENDING;
    +                   }
    +           }
    +
    +   else
    +           ret_val = EOB_ACT_CONTINUE_SCAN;
    +
    +   if (((yy_n_chars) + number_to_move) > 
YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
    +           /* Extend the array by 50%, plus the number we really need. */
    +           int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 
1);
    +           YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void 
*) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
    +           if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
    +                   YY_FATAL_ERROR( "out of dynamic memory in 
yy_get_next_buffer()" );
    +   }
    +
    +   (yy_n_chars) += number_to_move;
    +   YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = 
YY_END_OF_BUFFER_CHAR;
    +   YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = 
YY_END_OF_BUFFER_CHAR;
    +
    +   (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
    +
    +   return ret_val;
    +}
    +
    +/* yy_get_previous_state - get the state just before the EOB char was 
reached */
    +
    +    static yy_state_type yy_get_previous_state (void)
    +{
    +   yy_state_type yy_current_state;
    +   char *yy_cp;
    +    
    +   yy_current_state = (yy_start);
    +
    +   for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp 
)
    +           {
    +           yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? 
yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
    +           }
    +
    +   return yy_current_state;
    +}
    +
    +/* yy_try_NUL_trans - try to make a transition on the NUL character
    + *
    + * synopsis
    + * next_state = yy_try_NUL_trans( current_state );
    + */
    +    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state 
)
    +{
    +   int yy_is_jam;
    +    
    +   yy_current_state = yy_nxt[yy_current_state][1];
    +   yy_is_jam = (yy_current_state <= 0);
    +
    +           return yy_is_jam ? 0 : yy_current_state;
    +}
    +
    +#ifndef YY_NO_UNPUT
    +
    +    static void yyunput (int c, char * yy_bp )
    +{
    +   char *yy_cp;
    +    
    +    yy_cp = (yy_c_buf_p);
    +
    +   /* undo effects of setting up yytext */
    +   *yy_cp = (yy_hold_char);
    +
    +   if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
    +           { /* need to shift things up to make room */
    +           /* +2 for EOB chars. */
    +           int number_to_move = (yy_n_chars) + 2;
    +           char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
    +                                   YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 
2];
    +           char *source =
    +                           
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
    +
    +           while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
    +                   *--dest = *--source;
    +
    +           yy_cp += (int) (dest - source);
    +           yy_bp += (int) (dest - source);
    +           YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
    +                   (yy_n_chars) = (int) 
YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
    +
    +           if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
    +                   YY_FATAL_ERROR( "flex scanner push-back overflow" );
    +           }
    +
    +   *--yy_cp = (char) c;
    +
    +    if ( c == '\n' ){
    +        --yylineno;
    +    }
    +
    +   (yytext_ptr) = yy_bp;
    +   (yy_hold_char) = *yy_cp;
    +   (yy_c_buf_p) = yy_cp;
    +}
    +
    +#endif
    +
    +#ifndef YY_NO_INPUT
    +#ifdef __cplusplus
    +    static int yyinput (void)
    +#else
    +    static int input  (void)
    +#endif
    +
    +{
    +   int c;
    +    
    +   *(yy_c_buf_p) = (yy_hold_char);
    +
    +   if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
    +           {
    +           /* yy_c_buf_p now points to the character we want to return.
    +            * If this occurs *before* the EOB characters, then it's a
    +            * valid NUL; if not, then we've hit the end of the buffer.
    +            */
    +           if ( (yy_c_buf_p) < 
&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
    +                   /* This was really a NUL. */
    +                   *(yy_c_buf_p) = '\0';
    +
    +           else
    +                   { /* need more input */
    +                   int offset = (yy_c_buf_p) - (yytext_ptr);
    +                   ++(yy_c_buf_p);
    +
    +                   switch ( yy_get_next_buffer(  ) )
    +                           {
    +                           case EOB_ACT_LAST_MATCH:
    +                                   /* This happens because yy_g_n_b()
    +                                    * sees that we've accumulated a
    +                                    * token and flags that we need to
    +                                    * try matching the token before
    +                                    * proceeding.  But for input(),
    +                                    * there's no matching to consider.
    +                                    * So convert the EOB_ACT_LAST_MATCH
    +                                    * to EOB_ACT_END_OF_FILE.
    +                                    */
    +
    +                                   /* Reset buffer status. */
    +                                   yyrestart(yyin );
    +
    +                                   /*FALLTHROUGH*/
    +
    +                           case EOB_ACT_END_OF_FILE:
    +                                   {
    +                                   if ( yywrap( ) )
    +                                           return 0;
    +
    +                                   if ( ! (yy_did_buffer_switch_on_eof) )
    +                                           YY_NEW_FILE;
    +#ifdef __cplusplus
    +                                   return yyinput();
    +#else
    +                                   return input();
    +#endif
    +                                   }
    +
    +                           case EOB_ACT_CONTINUE_SCAN:
    +                                   (yy_c_buf_p) = (yytext_ptr) + offset;
    +                                   break;
    +                           }
    +                   }
    +           }
    +
    +   c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
    +   *(yy_c_buf_p) = '\0';   /* preserve yytext */
    +   (yy_hold_char) = *++(yy_c_buf_p);
    +
    +   if ( c == '\n' )
    +           
    +    yylineno++;
    +;
    +
    +   return c;
    +}
    +#endif     /* ifndef YY_NO_INPUT */
    +
    +/** Immediately switch to a different input stream.
    + * @param input_file A readable stream.
    + * 
    + * @note This function does not reset the start condition to @c INITIAL .
    + */
    +    void yyrestart  (FILE * input_file )
    +{
    +    
    +   if ( ! YY_CURRENT_BUFFER ){
    +        yyensure_buffer_stack ();
    +           YY_CURRENT_BUFFER_LVALUE =
    +            yy_create_buffer(yyin,YY_BUF_SIZE );
    +   }
    +
    +   yy_init_buffer(YY_CURRENT_BUFFER,input_file );
    +   yy_load_buffer_state( );
    +}
    +
    +/** Switch to a different input buffer.
    + * @param new_buffer The new input buffer.
    + * 
    + */
    +    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
    +{
    +    
    +   /* TODO. We should be able to replace this entire function body
    +    * with
    +    *              yypop_buffer_state();
    +    *              yypush_buffer_state(new_buffer);
    +     */
    +   yyensure_buffer_stack ();
    +   if ( YY_CURRENT_BUFFER == new_buffer )
    +           return;
    +
    +   if ( YY_CURRENT_BUFFER )
    +           {
    +           /* Flush out information for old buffer. */
    +           *(yy_c_buf_p) = (yy_hold_char);
    +           YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
    +           YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
    +           }
    +
    +   YY_CURRENT_BUFFER_LVALUE = new_buffer;
    +   yy_load_buffer_state( );
    +
    +   /* We don't actually know whether we did this switch during
    +    * EOF (yywrap()) processing, but the only time this flag
    +    * is looked at is after yywrap() is called, so it's safe
    +    * to go ahead and always set it.
    +    */
    +   (yy_did_buffer_switch_on_eof) = 1;
    +}
    +
    +static void yy_load_buffer_state  (void)
    +{
    +           (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
    +   (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
    +   yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
    +   (yy_hold_char) = *(yy_c_buf_p);
    +}
    +
    +/** Allocate and initialize an input buffer state.
    + * @param file A readable stream.
    + * @param size The character buffer size in bytes. When in doubt, use @c 
YY_BUF_SIZE.
    + * 
    + * @return the allocated buffer state.
    + */
    +    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
    +{
    +   YY_BUFFER_STATE b;
    +    
    +   b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
    +   if ( ! b )
    +           YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
    +
    +   b->yy_buf_size = (yy_size_t)size;
    +
    +   /* yy_ch_buf has to be 2 characters longer than the size given because
    +    * we need to put in 2 end-of-buffer characters.
    +    */
    +   b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
    +   if ( ! b->yy_ch_buf )
    +           YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
    +
    +   b->yy_is_our_buffer = 1;
    +
    +   yy_init_buffer(b,file );
    +
    +   return b;
    +}
    +
    +/** Destroy the buffer.
    + * @param b a buffer created with yy_create_buffer()
    + * 
    + */
    +    void yy_delete_buffer (YY_BUFFER_STATE  b )
    +{
    +    
    +   if ( ! b )
    +           return;
    +
    +   if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
    +           YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
    +
    +   if ( b->yy_is_our_buffer )
    +           yyfree((void *) b->yy_ch_buf  );
    +
    +   yyfree((void *) b  );
    +}
    +
    +/* Initializes or reinitializes a buffer.
    + * This function is sometimes called more than once on the same buffer,
    + * such as during a yyrestart() or at EOF.
    + */
    +    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
    +
    +{
    +   int oerrno = errno;
    +    
    +   yy_flush_buffer(b );
    +
    +   b->yy_input_file = file;
    +   b->yy_fill_buffer = 1;
    +
    +    /* If b is the current buffer, then yy_init_buffer was _probably_
    +     * called from yyrestart() or through yy_get_next_buffer.
    +     * In that case, we don't want to reset the lineno or column.
    +     */
    +    if (b != YY_CURRENT_BUFFER){
    +        b->yy_bs_lineno = 1;
    +        b->yy_bs_column = 0;
    +    }
    +
    +        b->yy_is_interactive = 0;
    +    
    +   errno = oerrno;
    +}
    +
    +/** Discard all buffered characters. On the next scan, YY_INPUT will be 
called.
    + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
    + * 
    + */
    +    void yy_flush_buffer (YY_BUFFER_STATE  b )
    +{
    +           if ( ! b )
    +           return;
    +
    +   b->yy_n_chars = 0;
    +
    +   /* We always need two end-of-buffer characters.  The first causes
    +    * a transition to the end-of-buffer state.  The second causes
    +    * a jam in that state.
    +    */
    +   b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
    +   b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
    +
    +   b->yy_buf_pos = &b->yy_ch_buf[0];
    +
    +   b->yy_at_bol = 1;
    +   b->yy_buffer_status = YY_BUFFER_NEW;
    +
    +   if ( b == YY_CURRENT_BUFFER )
    +           yy_load_buffer_state( );
    +}
    +
    +/** Pushes the new state onto the stack. The new state becomes
    + *  the current state. This function will allocate the stack
    + *  if necessary.
    + *  @param new_buffer The new state.
    + *  
    + */
    +void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
    +{
    +           if (new_buffer == NULL)
    +           return;
    +
    +   yyensure_buffer_stack();
    +
    +   /* This block is copied from yy_switch_to_buffer. */
    +   if ( YY_CURRENT_BUFFER )
    +           {
    +           /* Flush out information for old buffer. */
    +           *(yy_c_buf_p) = (yy_hold_char);
    +           YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
    +           YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
    +           }
    +
    +   /* Only push if top exists. Otherwise, replace top. */
    +   if (YY_CURRENT_BUFFER)
    +           (yy_buffer_stack_top)++;
    +   YY_CURRENT_BUFFER_LVALUE = new_buffer;
    +
    +   /* copied from yy_switch_to_buffer. */
    +   yy_load_buffer_state( );
    +   (yy_did_buffer_switch_on_eof) = 1;
    +}
    +
    +/** Removes and deletes the top of the stack, if present.
    + *  The next element becomes the new top.
    + *  
    + */
    +void yypop_buffer_state (void)
    +{
    +           if (!YY_CURRENT_BUFFER)
    +           return;
    +
    +   yy_delete_buffer(YY_CURRENT_BUFFER );
    +   YY_CURRENT_BUFFER_LVALUE = NULL;
    +   if ((yy_buffer_stack_top) > 0)
    +           --(yy_buffer_stack_top);
    +
    +   if (YY_CURRENT_BUFFER) {
    +           yy_load_buffer_state( );
    +           (yy_did_buffer_switch_on_eof) = 1;
    +   }
    +}
    +
    +/* Allocates the stack if it does not exist.
    + *  Guarantees space for at least one push.
    + */
    +static void yyensure_buffer_stack (void)
    +{
    +   int num_to_alloc;
    +    
    +   if (!(yy_buffer_stack)) {
    +
    +           /* First allocation is just for 2 elements, since we don't know 
if this
    +            * scanner will even need a stack. We use 2 instead of 1 to 
avoid an
    +            * immediate realloc on the next call.
    +         */
    +      num_to_alloc = 1; /* After all that talk, this was set to 1 
anyways... */
    +           (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
    +                                                           (num_to_alloc * 
sizeof(struct yy_buffer_state*)
    +                                                           );
    +           if ( ! (yy_buffer_stack) )
    +                   YY_FATAL_ERROR( "out of dynamic memory in 
yyensure_buffer_stack()" );
    +
    +           memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct 
yy_buffer_state*));
    +
    +           (yy_buffer_stack_max) = num_to_alloc;
    +           (yy_buffer_stack_top) = 0;
    +           return;
    +   }
    +
    +   if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
    +
    +           /* Increase the buffer to prepare for a possible push. */
    +           yy_size_t grow_size = 8 /* arbitrary grow size */;
    +
    +           num_to_alloc = (yy_buffer_stack_max) + grow_size;
    +           (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
    +                                                           
((yy_buffer_stack),
    +                                                           num_to_alloc * 
sizeof(struct yy_buffer_state*)
    +                                                           );
    +           if ( ! (yy_buffer_stack) )
    +                   YY_FATAL_ERROR( "out of dynamic memory in 
yyensure_buffer_stack()" );
    +
    +           /* zero only the new slots.*/
    +           memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size 
* sizeof(struct yy_buffer_state*));
    +           (yy_buffer_stack_max) = num_to_alloc;
    +   }
    +}
    +
    +/** Setup the input buffer state to scan directly from a user-specified 
character buffer.
    + * @param base the character buffer
    + * @param size the size in bytes of the character buffer
    + * 
    + * @return the newly allocated buffer state object.
    + */
    +YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
    +{
    +   YY_BUFFER_STATE b;
    +    
    +   if ( size < 2 ||
    +        base[size-2] != YY_END_OF_BUFFER_CHAR ||
    +        base[size-1] != YY_END_OF_BUFFER_CHAR )
    +           /* They forgot to leave room for the EOB's. */
    +           return NULL;
    +
    +   b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
    +   if ( ! b )
    +           YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
    +
    +   b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
    +   b->yy_buf_pos = b->yy_ch_buf = base;
    +   b->yy_is_our_buffer = 0;
    +   b->yy_input_file = NULL;
    +   b->yy_n_chars = b->yy_buf_size;
    +   b->yy_is_interactive = 0;
    +   b->yy_at_bol = 1;
    +   b->yy_fill_buffer = 0;
    +   b->yy_buffer_status = YY_BUFFER_NEW;
    +
    +   yy_switch_to_buffer(b  );
    +
    +   return b;
    +}
    +
    +/** Setup the input buffer state to scan a string. The next call to 
yylex() will
    + * scan from a @e copy of @a str.
    + * @param yystr a NUL-terminated string to scan
    + * 
    + * @return the newly allocated buffer state object.
    + * @note If you want to scan bytes that may contain NUL values, then use
    + *       yy_scan_bytes() instead.
    + */
    +YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
    +{
    +    
    +   return yy_scan_bytes(yystr,(int) strlen(yystr) );
    +}
    +
    +/** Setup the input buffer state to scan the given bytes. The next call to 
yylex() will
    + * scan from a @e copy of @a bytes.
    + * @param yybytes the byte buffer to scan
    + * @param _yybytes_len the number of bytes in the buffer pointed to by @a 
bytes.
    + * 
    + * @return the newly allocated buffer state object.
    + */
    +YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
    +{
    +   YY_BUFFER_STATE b;
    +   char *buf;
    +   yy_size_t n;
    +   int i;
    +    
    +   /* Get memory for full buffer, including space for trailing EOB's. */
    +   n = (yy_size_t) (_yybytes_len + 2);
    +   buf = (char *) yyalloc(n  );
    +   if ( ! buf )
    +           YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
    +
    +   for ( i = 0; i < _yybytes_len; ++i )
    +           buf[i] = yybytes[i];
    +
    +   buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
    +
    +   b = yy_scan_buffer(buf,n );
    +   if ( ! b )
    +           YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
    +
    +   /* It's okay to grow etc. this buffer, and we should throw it
    +    * away when we're done.
    +    */
    +   b->yy_is_our_buffer = 1;
    +
    +   return b;
    +}
    +
    +#ifndef YY_EXIT_FAILURE
    +#define YY_EXIT_FAILURE 2
    +#endif
    +
    +static void yynoreturn yy_fatal_error (yyconst char* msg )
    +{
    +                   (void) fprintf( stderr, "%s\n", msg );
    +   exit( YY_EXIT_FAILURE );
    +}
    +
    +/* Redefine yyless() so it works in section 3 code. */
    +
    +#undef yyless
    +#define yyless(n) \
    +   do \
    +           { \
    +           /* Undo effects of setting up yytext. */ \
    +        int yyless_macro_arg = (n); \
    +        YY_LESS_LINENO(yyless_macro_arg);\
    +           yytext[yyleng] = (yy_hold_char); \
    +           (yy_c_buf_p) = yytext + yyless_macro_arg; \
    +           (yy_hold_char) = *(yy_c_buf_p); \
    +           *(yy_c_buf_p) = '\0'; \
    +           yyleng = yyless_macro_arg; \
    +           } \
    +   while ( 0 )
    +
    +/* Accessor  methods (get/set functions) to struct members. */
    +
    +/** Get the current line number.
    + * 
    + */
    +int yyget_lineno  (void)
    +{
    +    
    +    return yylineno;
    +}
    +
    +/** Get the input stream.
    + * 
    + */
    +FILE *yyget_in  (void)
    +{
    +        return yyin;
    +}
    +
    +/** Get the output stream.
    + * 
    + */
    +FILE *yyget_out  (void)
    +{
    +        return yyout;
    +}
    +
    +/** Get the length of the current token.
    + * 
    + */
    +int yyget_leng  (void)
    +{
    +        return yyleng;
    +}
    +
    +/** Get the current token.
    + * 
    + */
    +
    +char *yyget_text  (void)
    +{
    +        return yytext;
    +}
    +
    +/** Set the current line number.
    + * @param _line_number line number
    + * 
    + */
    +void yyset_lineno (int  _line_number )
    +{
    +    
    +    yylineno = _line_number;
    +}
    +
    +/** Set the input stream. This does not discard the current
    + * input buffer.
    + * @param _in_str A readable stream.
    + * 
    + * @see yy_switch_to_buffer
    + */
    +void yyset_in (FILE *  _in_str )
    +{
    +        yyin = _in_str ;
    +}
    +
    +void yyset_out (FILE *  _out_str )
    +{
    +        yyout = _out_str ;
    +}
    +
    +int yyget_debug  (void)
    +{
    +        return yy_flex_debug;
    +}
    +
    +void yyset_debug (int  _bdebug )
    +{
    +        yy_flex_debug = _bdebug ;
    +}
    +
    +static int yy_init_globals (void)
    +{
    +        /* Initialization is the same as for the non-reentrant scanner.
    +     * This function is called from yylex_destroy(), so don't allocate 
here.
    +     */
    +
    +    /* We do not touch yylineno unless the option is enabled. */
    +    yylineno =  1;
    +    
    +    (yy_buffer_stack) = NULL;
    +    (yy_buffer_stack_top) = 0;
    +    (yy_buffer_stack_max) = 0;
    +    (yy_c_buf_p) = NULL;
    +    (yy_init) = 0;
    +    (yy_start) = 0;
    +
    +/* Defined in main.c */
    +#ifdef YY_STDINIT
    +    yyin = stdin;
    +    yyout = stdout;
    +#else
    +    yyin = NULL;
    +    yyout = NULL;
    +#endif
    +
    +    /* For future reference: Set errno on error, since we are called by
    +     * yylex_init()
    +     */
    +    return 0;
    +}
    +
    +/* yylex_destroy is for both reentrant and non-reentrant scanners. */
    +int yylex_destroy  (void)
    +{
    +    
    +    /* Pop the buffer stack, destroying each element. */
    +   while(YY_CURRENT_BUFFER){
    +           yy_delete_buffer(YY_CURRENT_BUFFER  );
    +           YY_CURRENT_BUFFER_LVALUE = NULL;
    +           yypop_buffer_state();
    +   }
    +
    +   /* Destroy the stack itself. */
    +   yyfree((yy_buffer_stack) );
    +   (yy_buffer_stack) = NULL;
    +
    +    /* Reset the globals. This is important in a non-reentrant scanner so 
the next time
    +     * yylex() is called, initialization will occur. */
    +    yy_init_globals( );
    +
    +    return 0;
    +}
    +
    +/*
    + * Internal utility routines.
    + */
    +
    +#ifndef yytext_ptr
    +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
    +{
    +           
    +   int i;
    +   for ( i = 0; i < n; ++i )
    +           s1[i] = s2[i];
    +}
    +#endif
    +
    +#ifdef YY_NEED_STRLEN
    +static int yy_flex_strlen (yyconst char * s )
    +{
    +   int n;
    +   for ( n = 0; s[n]; ++n )
    +           ;
    +
    +   return n;
    +}
    +#endif
    +
    +void *yyalloc (yy_size_t  size )
    +{
    +                   return malloc(size);
    +}
    +
    +void *yyrealloc  (void * ptr, yy_size_t  size )
    +{
    +           
    +   /* The cast to (char *) in the following accommodates both
    +    * implementations that use char* generic pointers, and those
    +    * that use void* generic pointers.  It works with the latter
    +    * because both ANSI C and C++ allow castless assignment from
    +    * any pointer type to void*, and deal with argument conversions
    +    * as though doing an assignment.
    +    */
    +   return realloc(ptr, size);
    +}
    +
    +void yyfree (void * ptr )
    +{
    +                   free( (char *) ptr );   /* see yyrealloc() for (char *) 
cast */
    +}
    +
    +#define YYTABLES_NAME "yytables"
    +
    +static char *expand_token(const char *in, size_t n)
    +{
    +   char *out;
    +   int c;
    +   char c2;
    +   const char *rest, *end;
    +
    +   new_string();
    +   append_string(in, n);
    +
    +   /* get the whole line because we do not know the end of token. */
    +   while ((c = input()) != EOF) {
    +           if (c == '\n') {
    +                   unput(c);
    +                   break;
    +           }
    +           c2 = c;
    +           append_string(&c2, 1);
    +   }
    +
    +   rest = text;
    +   out = expand_one_token(&rest);
    +
    +   /* push back unused characters to the input stream */
    +   end = rest + strlen(rest);
    +   while (end > rest)
    +           unput(*--end);
    +
    +   free(text);
    +
    +   return out;
    +}
    +
    +static void append_expanded_string(const char *str)
    +{
    +   const char *end;
    +   char *res;
    +
    +   str++;
    +
    +   res = expand_dollar(&str);
    +
    +   /* push back unused characters to the input stream */
    +   end = str + strlen(str);
    +   while (end > str)
    +           unput(*--end);
    +
    +   append_string(res, strlen(res));
    +
    +   free(res);
    +}
    +
    +void zconf_starthelp(void)
    +{
    +   new_string();
    +   last_ts = first_ts = 0;
    +   BEGIN(HELP);
    +}
    +
    +static void zconf_endhelp(void)
    +{
    +   yylval.string = text;
    +   BEGIN(INITIAL);
    +}
    +
    +/*
    + * Try to open specified file with following names:
    + * ./name
    + * $(srctree)/name
    + * The latter is used when srctree is separate from objtree
    + * when compiling the kernel.
    + * Return NULL if file is not found.
    + */
    +FILE *zconf_fopen(const char *name)
    +{
    +   char *env, fullname[PATH_MAX+1];
    +   FILE *f;
    +
    +   f = fopen(name, "r");
    +   if (!f && name != NULL && name[0] != '/') {
    +           env = getenv(SRCTREE);
    +           if (env) {
    +                   sprintf(fullname, "%s/%s", env, name);
    +                   f = fopen(fullname, "r");
    +           }
    +   }
    +   return f;
    +}
    +
    +void zconf_initscan(const char *name)
    +{
    +   yyin = zconf_fopen(name);
    +   if (!yyin) {
    +           fprintf(stderr, "can't find file %s\n", name);
    +           exit(1);
    +   }
    +
    +   current_buf = xmalloc(sizeof(*current_buf));
    +   memset(current_buf, 0, sizeof(*current_buf));
    +
    +   current_file = file_lookup(name);
    +   yylineno = 1;
    +}
    +
    +void zconf_nextfile(const char *name)
    +{
    +   struct file *iter;
    +   struct file *file = file_lookup(name);
    +   struct buffer *buf = xmalloc(sizeof(*buf));
    +   memset(buf, 0, sizeof(*buf));
    +
    +   current_buf->state = YY_CURRENT_BUFFER;
    +   yyin = zconf_fopen(file->name);
    +   if (!yyin) {
    +           fprintf(stderr, "%s:%d: can't open file \"%s\"\n",
    +                   zconf_curname(), zconf_lineno(), file->name);
    +           exit(1);
    +   }
    +   yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
    +   buf->parent = current_buf;
    +   current_buf = buf;
    +
    +   current_file->lineno = yylineno;
    +   file->parent = current_file;
    +
    +   for (iter = current_file; iter; iter = iter->parent) {
    +           if (!strcmp(iter->name, file->name)) {
    +                   fprintf(stderr,
    +                           "Recursive inclusion detected.\n"
    +                           "Inclusion path:\n"
    +                           "  current file : %s\n", file->name);
    +                   iter = file;
    +                   do {
    +                           iter = iter->parent;
    +                           fprintf(stderr, "  included from: %s:%d\n",
    +                                   iter->name, iter->lineno - 1);
    +                   } while (strcmp(iter->name, file->name));
    +                   exit(1);
    +           }
    +   }
    +
    +   yylineno = 1;
    +   current_file = file;
    +}
    +
    +static void zconf_endfile(void)
    +{
    +   struct buffer *parent;
    +
    +   current_file = current_file->parent;
    +   if (current_file)
    +           yylineno = current_file->lineno;
    +
    +   parent = current_buf->parent;
    +   if (parent) {
    +           fclose(yyin);
    +           yy_delete_buffer(YY_CURRENT_BUFFER);
    +           yy_switch_to_buffer(parent->state);
    +   }
    +   free(current_buf);
    +   current_buf = parent;
    +}
    +
    +int zconf_lineno(void)
    +{
    +   return current_pos.lineno;
    +}
    +
    +const char *zconf_curname(void)
    +{
    +   return current_pos.file ? current_pos.file->name : "<none>";
    +}
    +
    diff --git a/support/kconfig.new/zconf.tab.c 
b/support/kconfig.new/zconf.tab.c
    new file mode 100644
    index 0000000..d1cfbcb
    --- /dev/null
    +++ b/support/kconfig.new/zconf.tab.c
    @@ -0,0 +1,2504 @@
    +/* A Bison parser, made by GNU Bison 3.0.4.  */
    +
    +/* Bison implementation for Yacc-like parsers in C
    +
    +   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
    +
    +   This program is free software: you can redistribute it and/or modify
    +   it under the terms of the GNU General Public License as published by
    +   the Free Software Foundation, either version 3 of the License, or
    +   (at your option) any later version.
    +
    +   This program is distributed in the hope that it will be useful,
    +   but WITHOUT ANY WARRANTY; without even the implied warranty of
    +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    +   GNU General Public License for more details.
    +
    +   You should have received a copy of the GNU General Public License
    +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  
*/
    +
    +/* As a special exception, you may create a larger work that contains
    +   part or all of the Bison parser skeleton and distribute that work
    +   under terms of your choice, so long as that work isn't itself a
    +   parser generator using the skeleton or a modified version thereof
    +   as a parser skeleton.  Alternatively, if you modify or redistribute
    +   the parser skeleton itself, you may (at your option) remove this
    +   special exception, which will cause the skeleton and the resulting
    +   Bison output files to be licensed under the GNU General Public
    +   License without this special exception.
    +
    +   This special exception was added by the Free Software Foundation in
    +   version 2.2 of Bison.  */
    +
    +/* C LALR(1) parser skeleton written by Richard Stallman, by
    +   simplifying the original so-called "semantic" parser.  */
    +
    +/* All symbols defined below should begin with yy or YY, to avoid
    +   infringing on user name space.  This should be done even for local
    +   variables, as they might otherwise be expanded by user macros.
    +   There are some unavoidable exceptions within include files to
    +   define necessary library symbols; they are noted "INFRINGES ON
    +   USER NAME SPACE" below.  */
    +
    +/* Identify Bison output.  */
    +#define YYBISON 1
    +
    +/* Bison version.  */
    +#define YYBISON_VERSION "3.0.4"
    +
    +/* Skeleton name.  */
    +#define YYSKELETON_NAME "yacc.c"
    +
    +/* Pure parsers.  */
    +#define YYPURE 0
    +
    +/* Push parsers.  */
    +#define YYPUSH 0
    +
    +/* Pull parsers.  */
    +#define YYPULL 1
    +
    +
    +
    +
    +/* Copy the first part of user declarations.  */
    +
    +
    +/*
    + * Copyright (C) 2002 Roman Zippel <zippel@xxxxxxxxxxxxxx>
    + * Released under the terms of the GNU GPL v2.0.
    + */
    +
    +#include <ctype.h>
    +#include <stdarg.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <stdbool.h>
    +
    +#include "lkc.h"
    +
    +#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt)
    +
    +#define PRINTD             0x0001
    +#define DEBUG_PARSE        0x0002
    +
    +int cdebug = PRINTD;
    +
    +int yylex(void);
    +static void yyerror(const char *err);
    +static void zconfprint(const char *err, ...);
    +static void zconf_error(const char *err, ...);
    +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int 
endtoken);
    +
    +struct symbol *symbol_hash[SYMBOL_HASHSIZE];
    +
    +static struct menu *current_menu, *current_entry;
    +
    +
    +
    +
    +# ifndef YY_NULLPTR
    +#  if defined __cplusplus && 201103L <= __cplusplus
    +#   define YY_NULLPTR nullptr
    +#  else
    +#   define YY_NULLPTR 0
    +#  endif
    +# endif
    +
    +/* Enabling verbose error messages.  */
    +#ifdef YYERROR_VERBOSE
    +# undef YYERROR_VERBOSE
    +# define YYERROR_VERBOSE 1
    +#else
    +# define YYERROR_VERBOSE 0
    +#endif
    +
    +
    +/* Debug traces.  */
    +#ifndef YYDEBUG
    +# define YYDEBUG 1
    +#endif
    +#if YYDEBUG
    +extern int yydebug;
    +#endif
    +
    +/* Token type.  */
    +#ifndef YYTOKENTYPE
    +# define YYTOKENTYPE
    +  enum yytokentype
    +  {
    +    T_MAINMENU = 258,
    +    T_MENU = 259,
    +    T_ENDMENU = 260,
    +    T_SOURCE = 261,
    +    T_CHOICE = 262,
    +    T_ENDCHOICE = 263,
    +    T_COMMENT = 264,
    +    T_CONFIG = 265,
    +    T_MENUCONFIG = 266,
    +    T_HELP = 267,
    +    T_HELPTEXT = 268,
    +    T_IF = 269,
    +    T_ENDIF = 270,
    +    T_DEPENDS = 271,
    +    T_OPTIONAL = 272,
    +    T_PROMPT = 273,
    +    T_TYPE = 274,
    +    T_DEFAULT = 275,
    +    T_SELECT = 276,
    +    T_IMPLY = 277,
    +    T_RANGE = 278,
    +    T_VISIBLE = 279,
    +    T_OPTION = 280,
    +    T_ON = 281,
    +    T_WORD = 282,
    +    T_WORD_QUOTE = 283,
    +    T_UNEQUAL = 284,
    +    T_LESS = 285,
    +    T_LESS_EQUAL = 286,
    +    T_GREATER = 287,
    +    T_GREATER_EQUAL = 288,
    +    T_CLOSE_PAREN = 289,
    +    T_OPEN_PAREN = 290,
    +    T_EOL = 291,
    +    T_VARIABLE = 292,
    +    T_ASSIGN = 293,
    +    T_ASSIGN_VAL = 294,
    +    T_OR = 295,
    +    T_AND = 296,
    +    T_EQUAL = 297,
    +    T_NOT = 298
    +  };
    +#endif
    +
    +/* Value type.  */
    +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
    +
    +union YYSTYPE
    +{
    +
    +
    +   char *string;
    +   struct file *file;
    +   struct symbol *symbol;
    +   struct expr *expr;
    +   struct menu *menu;
    +   const struct kconf_id *id;
    +   enum variable_flavor flavor;
    +
    +
    +};
    +
    +typedef union YYSTYPE YYSTYPE;
    +# define YYSTYPE_IS_TRIVIAL 1
    +# define YYSTYPE_IS_DECLARED 1
    +#endif
    +
    +
    +extern YYSTYPE yylval;
    +
    +int yyparse (void);
    +
    +
    +
    +/* Copy the second part of user declarations.  */
    +
    +
    +/* Include kconf_id.c here so it can see the token constants. */
    +#include "kconf_id.c"
    +
    +
    +
    +#ifdef short
    +# undef short
    +#endif
    +
    +#ifdef YYTYPE_UINT8
    +typedef YYTYPE_UINT8 yytype_uint8;
    +#else
    +typedef unsigned char yytype_uint8;
    +#endif
    +
    +#ifdef YYTYPE_INT8
    +typedef YYTYPE_INT8 yytype_int8;
    +#else
    +typedef signed char yytype_int8;
    +#endif
    +
    +#ifdef YYTYPE_UINT16
    +typedef YYTYPE_UINT16 yytype_uint16;
    +#else
    +typedef unsigned short int yytype_uint16;
    +#endif
    +
    +#ifdef YYTYPE_INT16
    +typedef YYTYPE_INT16 yytype_int16;
    +#else
    +typedef short int yytype_int16;
    +#endif
    +
    +#ifndef YYSIZE_T
    +# ifdef __SIZE_TYPE__
    +#  define YYSIZE_T __SIZE_TYPE__
    +# elif defined size_t
    +#  define YYSIZE_T size_t
    +# elif ! defined YYSIZE_T
    +#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
    +#  define YYSIZE_T size_t
    +# else
    +#  define YYSIZE_T unsigned int
    +# endif
    +#endif
    +
    +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
    +
    +#ifndef YY_
    +# if defined YYENABLE_NLS && YYENABLE_NLS
    +#  if ENABLE_NLS
    +#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
    +#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
    +#  endif
    +# endif
    +# ifndef YY_
    +#  define YY_(Msgid) Msgid
    +# endif
    +#endif
    +
    +#ifndef YY_ATTRIBUTE
    +# if (defined __GNUC__                                               \
    +      && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__)))  \
    +     || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
    +#  define YY_ATTRIBUTE(Spec) __attribute__(Spec)
    +# else
    +#  define YY_ATTRIBUTE(Spec) /* empty */
    +# endif
    +#endif
    +
    +#ifndef YY_ATTRIBUTE_PURE
    +# define YY_ATTRIBUTE_PURE   YY_ATTRIBUTE ((__pure__))
    +#endif
    +
    +#ifndef YY_ATTRIBUTE_UNUSED
    +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
    +#endif
    +
    +#if !defined _Noreturn \
    +     && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
    +# if defined _MSC_VER && 1200 <= _MSC_VER
    +#  define _Noreturn __declspec (noreturn)
    +# else
    +#  define _Noreturn YY_ATTRIBUTE ((__noreturn__))
    +# endif
    +#endif
    +
    +/* Suppress unused-variable warnings by "using" E.  */
    +#if ! defined lint || defined __GNUC__
    +# define YYUSE(E) ((void) (E))
    +#else
    +# define YYUSE(E) /* empty */
    +#endif
    +
    +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
    +/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
    +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
    +    _Pragma ("GCC diagnostic push") \
    +    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
    +    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
    +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
    +    _Pragma ("GCC diagnostic pop")
    +#else
    +# define YY_INITIAL_VALUE(Value) Value
    +#endif
    +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
    +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
    +# define YY_IGNORE_MAYBE_UNINITIALIZED_END
    +#endif
    +#ifndef YY_INITIAL_VALUE
    +# define YY_INITIAL_VALUE(Value) /* Nothing. */
    +#endif
    +
    +
    +#if ! defined yyoverflow || YYERROR_VERBOSE
    +
    +/* The parser invokes alloca or malloc; define the necessary symbols.  */
    +
    +# ifdef YYSTACK_USE_ALLOCA
    +#  if YYSTACK_USE_ALLOCA
    +#   ifdef __GNUC__
    +#    define YYSTACK_ALLOC __builtin_alloca
    +#   elif defined __BUILTIN_VA_ARG_INCR
    +#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
    +#   elif defined _AIX
    +#    define YYSTACK_ALLOC __alloca
    +#   elif defined _MSC_VER
    +#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
    +#    define alloca _alloca
    +#   else
    +#    define YYSTACK_ALLOC alloca
    +#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
    +#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
    +      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
    +#     ifndef EXIT_SUCCESS
    +#      define EXIT_SUCCESS 0
    +#     endif
    +#    endif
    +#   endif
    +#  endif
    +# endif
    +
    +# ifdef YYSTACK_ALLOC
    +   /* Pacify GCC's 'empty if-body' warning.  */
    +#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
    +#  ifndef YYSTACK_ALLOC_MAXIMUM
    +    /* The OS might guarantee only one guard page at the bottom of the 
stack,
    +       and a page size can be as small as 4096 bytes.  So we cannot safely
    +       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
    +       to allow for a few compiler-allocated temporary stack slots.  */
    +#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
    +#  endif
    +# else
    +#  define YYSTACK_ALLOC YYMALLOC
    +#  define YYSTACK_FREE YYFREE
    +#  ifndef YYSTACK_ALLOC_MAXIMUM
    +#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
    +#  endif
    +#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
    +       && ! ((defined YYMALLOC || defined malloc) \
    +             && (defined YYFREE || defined free)))
    +#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
    +#   ifndef EXIT_SUCCESS
    +#    define EXIT_SUCCESS 0
    +#   endif
    +#  endif
    +#  ifndef YYMALLOC
    +#   define YYMALLOC malloc
    +#   if ! defined malloc && ! defined EXIT_SUCCESS
    +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
    +#   endif
    +#  endif
    +#  ifndef YYFREE
    +#   define YYFREE free
    +#   if ! defined free && ! defined EXIT_SUCCESS
    +void free (void *); /* INFRINGES ON USER NAME SPACE */
    +#   endif
    +#  endif
    +# endif
    +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
    +
    +
    +#if (! defined yyoverflow \
    +     && (! defined __cplusplus \
    +         || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
    +
    +/* A type that is properly aligned for any stack member.  */
    +union yyalloc
    +{
    +  yytype_int16 yyss_alloc;
    +  YYSTYPE yyvs_alloc;
    +};
    +
    +/* The size of the maximum gap between one aligned stack and the next.  */
    +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
    +
    +/* The size of an array large to enough to hold all stacks, each with
    +   N elements.  */
    +# define YYSTACK_BYTES(N) \
    +     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
    +      + YYSTACK_GAP_MAXIMUM)
    +
    +# define YYCOPY_NEEDED 1
    +
    +/* Relocate STACK from its old location to the new one.  The
    +   local variables YYSIZE and YYSTACKSIZE give the old and new number of
    +   elements in the stack, and YYPTR gives the new location of the
    +   stack.  Advance YYPTR to a properly aligned location for the next
    +   stack.  */
    +# define YYSTACK_RELOCATE(Stack_alloc, Stack)                           \
    +    do                                                                  \
    +      {                                                                 \
    +        YYSIZE_T yynewbytes;                                            \
    +        YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
    +        Stack = &yyptr->Stack_alloc;                                    \
    +        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
    +        yyptr += yynewbytes / sizeof (*yyptr);                          \
    +      }                                                                 \
    +    while (0)
    +
    +#endif
    +
    +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
    +/* Copy COUNT objects from SRC to DST.  The source and destination do
    +   not overlap.  */
    +# ifndef YYCOPY
    +#  if defined __GNUC__ && 1 < __GNUC__
    +#   define YYCOPY(Dst, Src, Count) \
    +      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
    +#  else
    +#   define YYCOPY(Dst, Src, Count)              \
    +      do                                        \
    +        {                                       \
    +          YYSIZE_T yyi;                         \
    +          for (yyi = 0; yyi < (Count); yyi++)   \
    +            (Dst)[yyi] = (Src)[yyi];            \
    +        }                                       \
    +      while (0)
    +#  endif
    +# endif
    +#endif /* !YYCOPY_NEEDED */
    +
    +/* YYFINAL -- State number of the termination state.  */
    +#define YYFINAL  11
    +/* YYLAST -- Last index in YYTABLE.  */
    +#define YYLAST   332
    +
    +/* YYNTOKENS -- Number of terminals.  */
    +#define YYNTOKENS  44
    +/* YYNNTS -- Number of nonterminals.  */
    +#define YYNNTS  53
    +/* YYNRULES -- Number of rules.  */
    +#define YYNRULES  129
    +/* YYNSTATES -- Number of states.  */
    +#define YYNSTATES  211
    +
    +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
    +   by yylex, with out-of-bounds checking.  */
    +#define YYUNDEFTOK  2
    +#define YYMAXUTOK   298
    +
    +#define YYTRANSLATE(YYX)                                                \
    +  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
    +
    +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
    +   as returned by yylex, without out-of-bounds checking.  */
    +static const yytype_uint8 yytranslate[] =
    +{
    +       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
    +       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
    +       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
    +      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
    +      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
    +      35,    36,    37,    38,    39,    40,    41,    42,    43
    +};
    +
    +#if YYDEBUG
    +  /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
    +static const yytype_uint16 yyrline[] =
    +{
    +       0,   114,   114,   114,   116,   116,   120,   125,   127,   128,
    +     129,   130,   131,   132,   136,   140,   140,   140,   140,   140,
    +     140,   140,   140,   140,   144,   145,   146,   147,   148,   149,
    +     150,   154,   155,   161,   168,   173,   180,   189,   191,   192,
    +     193,   194,   195,   196,   199,   207,   213,   223,   229,   235,
    +     241,   244,   246,   259,   260,   265,   275,   280,   288,   291,
    +     293,   294,   295,   296,   297,   300,   306,   317,   323,   333,
    +     335,   340,   348,   356,   359,   361,   362,   363,   368,   375,
    +     380,   388,   391,   393,   394,   395,   398,   407,   414,   419,
    +     425,   443,   445,   446,   447,   450,   458,   460,   461,   464,
    +     471,   473,   478,   479,   482,   483,   484,   488,   489,   492,
    +     493,   496,   497,   498,   499,   500,   501,   502,   503,   504,
    +     505,   506,   510,   512,   513,   516,   517,   521,   524,   525
    +};
    +#endif
    +
    +#if YYDEBUG || YYERROR_VERBOSE || 0
    +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
    +   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
    +static const char *const yytname[] =
    +{
    +  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU",
    +  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG",
    +  "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS",
    +  "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_IMPLY",
    +  "T_RANGE", "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE",
    +  "T_UNEQUAL", "T_LESS", "T_LESS_EQUAL", "T_GREATER", "T_GREATER_EQUAL",
    +  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_VARIABLE", "T_ASSIGN",
    +  "T_ASSIGN_VAL", "T_OR", "T_AND", "T_EQUAL", "T_NOT", "$accept", "input",
    +  "start", "mainmenu_stmt", "stmt_list", "option_name", "common_stmt",
    +  "option_error", "config_entry_start", "config_stmt",
    +  "menuconfig_entry_start", "menuconfig_stmt", "config_option_list",
    +  "config_option", "symbol_option", "symbol_option_list",
    +  "symbol_option_arg", "choice", "choice_entry", "choice_end",
    +  "choice_stmt", "choice_option_list", "choice_option", "choice_block",
    +  "if_entry", "if_end", "if_stmt", "if_block", "menu", "menu_entry",
    +  "menu_end", "menu_stmt", "menu_block", "source_stmt", "comment",
    +  "comment_stmt", "help_start", "help", "depends_list", "depends",
    +  "visibility_list", "visible", "prompt_stmt_opt", "prompt", "end", "nl",
    +  "if_expr", "expr", "nonconst_symbol", "symbol", "word_opt",
    +  "assignment_stmt", "assign_val", YY_NULLPTR
    +};
    +#endif
    +
    +# ifdef YYPRINT
    +/* YYTOKNUM[NUM] -- (External) token number corresponding to the
    +   (internal) symbol number NUM (which must be that of a token).  */
    +static const yytype_uint16 yytoknum[] =
    +{
    +       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
    +     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
    +     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
    +     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
    +     295,   296,   297,   298
    +};
    +# endif
    +
    +#define YYPACT_NINF -92
    +
    +#define yypact_value_is_default(Yystate) \
    +  (!!((Yystate) == (-92)))
    +
    +#define YYTABLE_NINF -89
    +
    +#define yytable_value_is_error(Yytable_value) \
    +  0
    +
    +  /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
    +     STATE-NUM.  */
    +static const yytype_int16 yypact[] =
    +{
    +      21,    38,   -92,     4,   -92,   -92,   157,    23,   -92,   -92,
    +     -19,   -92,   191,   -16,    38,   -13,    38,     6,    24,    38,
    +      48,    48,    34,    43,   -92,   -92,   -92,   -92,   -92,   -92,
    +     -92,   -92,   -92,    96,   -92,    44,   111,   -92,   -92,   -92,
    +     -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,
    +     -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,    83,
    +     -92,    89,   -92,   116,   -92,   133,   -92,   134,   146,   -92,
    +      34,    34,   113,   -92,    73,   -92,   150,    62,   151,    31,
    +     123,   258,   293,   282,    -2,   282,   225,   -92,   -92,   -92,
    +     -92,   -92,   -92,    30,   -92,   -92,    34,    34,    65,    65,
    +      65,    65,    65,    65,   -92,   -92,   152,   -92,   153,   154,
    +     110,    38,    38,    34,    48,    48,    65,   -92,   202,   -92,
    +     -92,   -92,   -92,   203,   -92,   -92,   181,    38,    38,    48,
    +     -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,
    +     -92,   -92,   -92,   205,   -92,    80,   -92,   -92,   -92,   -92,
    +     -92,   -92,   -92,   -92,   -92,   -92,   179,   -92,   -92,   -92,
    +     -92,   -92,   -92,   -92,   -92,   -92,   -92,    34,   205,   185,
    +     205,   -11,   205,   205,    65,    36,   186,   -92,   -92,   205,
    +     187,   205,    34,   -92,   115,   188,   -92,   -92,   201,   214,
    +     215,   205,   196,   -92,   -92,   217,   -92,   218,    81,   -92,
    +     -92,   -92,   -92,   -92,   219,    38,   -92,   -92,   -92,   -92,
    +     -92
    +};
    +
    +  /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
    +     Performed when YYTABLE does not specify something else to do.  Zero
    +     means the default is an error.  */
    +static const yytype_uint8 yydefact[] =
    +{
    +       7,     0,   107,     0,     3,     7,     0,     7,   102,   103,
    +       0,     1,     0,     0,     0,     0,     0,   125,     0,     0,
    +       0,     0,     0,     0,    15,    20,    16,    17,    22,    18,
    +      19,    21,    23,     0,    24,     0,     0,     8,    37,    27,
    +      37,    28,    59,    69,     9,    74,    25,    96,    82,    10,
    +      29,    91,    26,    11,    30,   108,     2,     6,    14,     0,
    +     104,     0,   126,     0,   105,     0,   122,     0,     0,   124,
    +       0,     0,     0,   123,   111,   106,     0,   128,     0,     0,
    +       0,     0,     0,     0,    91,     0,     0,    78,    86,    55,
    +      87,    33,    35,     0,   119,    71,     0,     0,     0,     0,
    +       0,     0,     0,     0,    12,   129,     0,    13,     0,     0,
    +       0,     0,   100,     0,     0,     0,     0,    51,     0,    43,
    +      42,    38,    39,     0,    41,    40,     0,     0,   100,     0,
    +      63,    64,    60,    62,    61,    70,    58,    57,    75,    77,
    +      73,    76,    72,   109,    98,     0,    97,    83,    85,    81,
    +      84,    80,    93,    94,    92,   118,   120,   121,   117,   112,
    +     113,   114,   115,   116,   127,    32,    89,     0,   109,     0,
    +     109,   109,   109,   109,     0,     0,     0,    90,    67,   109,
    +       0,   109,     0,    99,     0,     0,    44,   101,     0,     0,
    +       0,   109,    53,    50,    31,     0,    66,     0,   110,    95,
    +      45,    46,    47,    48,     0,     0,    52,    65,    68,    49,
    +      54
    +};
    +
    +  /* YYPGOTO[NTERM-NUM].  */
    +static const yytype_int16 yypgoto[] =
    +{
    +     -92,   -92,   249,   -92,   252,   -92,    -9,   -67,   -92,   -92,
    +     -92,   -92,   220,   -92,   -92,   -92,   -92,   -92,   -92,   -92,
    +      35,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,   -92,
    +     -92,   100,   -92,   -92,   -92,   -92,   -92,   177,   195,   -65,
    +     -92,   -92,   137,    -1,    26,   -92,   141,   -69,   -15,   -91,
    +     -92,   -92,   -92
    +};
    +
    +  /* YYDEFGOTO[NTERM-NUM].  */
    +static const yytype_int16 yydefgoto[] =
    +{
    +      -1,     3,     4,     5,     6,    36,    37,   120,    38,    39,
    +      40,    41,    79,   121,   122,   175,   206,    42,    43,   136,
    +      44,    81,   132,    82,    45,   140,    46,    83,    47,    48,
    +     149,    49,    85,    50,    51,    52,   123,   124,    86,   125,
    +      84,   146,   169,   170,    53,     7,   183,    72,    73,    74,
    +      63,    54,   106
    +};
    +
    +  /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
    +     positive, shift that token.  If negative, reduce the rule whose
    +     number is the opposite.  If YYTABLE_NINF, syntax error.  */
    +static const yytype_int16 yytable[] =
    +{
    +      10,    93,    94,   182,    11,    67,    68,   158,   159,   160,
    +     161,   162,   163,    59,   131,    61,   134,    57,    65,   153,
    +      58,   154,   143,    60,     1,   174,     1,   156,   157,    96,
    +      97,   -34,   108,    62,   144,   -34,   -34,   -34,   -34,   -34,
    +     -34,   -34,   -34,   109,   171,   -34,   -34,   110,   -34,   111,
    +     112,   113,   114,   115,   116,   -34,   117,     2,   118,    55,
    +      64,    66,    69,   192,   155,     8,     9,   119,   -34,    70,
    +      96,    97,   193,   135,   138,    66,   147,    71,   153,    75,
    +     154,   108,    77,   191,   -79,   -79,   -79,   -79,   -79,   -79,
    +     -79,   -79,    66,    69,   -79,   -79,   110,    76,   184,   172,
    +     173,   105,    98,    99,   100,   101,   102,   118,   137,   142,
    +     168,   151,    78,   198,   181,   103,   152,   -79,   139,    87,
    +     148,    96,    97,   -36,   108,    88,   179,   -36,   -36,   -36,
    +     -36,   -36,   -36,   -36,   -36,   109,   167,   -36,   -36,   110,
    +     -36,   111,   112,   113,   114,   115,   116,   -36,   117,    95,
    +     118,   199,    89,    96,    97,    96,    97,    -5,    13,   119,
    +     -36,    14,    15,    16,    17,    18,    19,    20,    21,    90,
    +      91,    22,    23,    24,    25,    26,    27,    28,    29,    30,
    +      31,    32,    92,   141,    33,   150,   104,   107,   164,   165,
    +     166,    -4,    13,    34,    35,    14,    15,    16,    17,    18,
    +      19,    20,    21,   176,   210,    22,    23,    24,    25,    26,
    +      27,    28,    29,    30,    31,    32,   177,   178,    33,   182,
    +      97,   186,   194,   196,   200,   -88,   108,    34,    35,   -88,
    +     -88,   -88,   -88,   -88,   -88,   -88,   -88,   201,   205,   -88,
    +     -88,   110,   -88,   -88,   -88,   -88,   -88,   -88,   -88,   -88,
    +     202,   203,   118,   207,   208,   209,    56,    12,   133,   108,
    +      80,   152,   -88,   -56,   -56,   180,   -56,   -56,   -56,   -56,
    +     109,     0,   -56,   -56,   110,   126,   127,   128,   129,   145,
    +       0,     0,     0,     0,     0,   118,    14,    15,    16,    17,
    +      18,    19,    20,    21,   130,   -56,    22,    23,    15,    16,
    +       0,    18,    19,    20,    21,     0,     0,    22,    23,   185,
    +       0,   187,   188,   189,   190,     0,     0,     0,    34,    35,
    +     195,     0,   197,     0,     0,     0,     0,     0,     0,    34,
    +      35,     0,   204
    +};
    +
    +static const yytype_int16 yycheck[] =
    +{
    +       1,    70,    71,    14,     0,    20,    21,    98,    99,   100,
    +     101,   102,   103,    14,    81,    16,    81,    36,    19,    86,
    +      36,    86,    24,    36,     3,   116,     3,    96,    97,    40,
    +      41,     0,     1,    27,    36,     4,     5,     6,     7,     8,
    +       9,    10,    11,    12,   113,    14,    15,    16,    17,    18,
    +      19,    20,    21,    22,    23,    24,    25,    36,    27,    36,
    +      36,    27,    28,    27,    34,    27,    28,    36,    37,    35,
    +      40,    41,    36,    82,    83,    27,    85,    43,   145,    36,
    +     145,     1,    38,   174,     4,     5,     6,     7,     8,     9,
    +      10,    11,    27,    28,    14,    15,    16,     1,   167,   114,
    +     115,    39,    29,    30,    31,    32,    33,    27,    82,    83,
    +     111,    85,     1,   182,   129,    42,    36,    37,    83,    36,
    +      85,    40,    41,     0,     1,    36,   127,     4,     5,     6,
    +       7,     8,     9,    10,    11,    12,    26,    14,    15,    16,
    +      17,    18,    19,    20,    21,    22,    23,    24,    25,    36,
    +      27,    36,    36,    40,    41,    40,    41,     0,     1,    36,
    +      37,     4,     5,     6,     7,     8,     9,    10,    11,    36,
    +      36,    14,    15,    16,    17,    18,    19,    20,    21,    22,
    +      23,    24,    36,    83,    27,    85,    36,    36,    36,    36,
    +      36,     0,     1,    36,    37,     4,     5,     6,     7,     8,
    +       9,    10,    11,     1,   205,    14,    15,    16,    17,    18,
    +      19,    20,    21,    22,    23,    24,    13,    36,    27,    14,
    +      41,    36,    36,    36,    36,     0,     1,    36,    37,     4,
    +       5,     6,     7,     8,     9,    10,    11,    36,    42,    14,
    +      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
    +      36,    36,    27,    36,    36,    36,     7,     5,    81,     1,
    +      40,    36,    37,     5,     6,   128,     8,     9,    10,    11,
    +      12,    -1,    14,    15,    16,    17,    18,    19,    20,    84,
    +      -1,    -1,    -1,    -1,    -1,    27,     4,     5,     6,     7,
    +       8,     9,    10,    11,    36,    37,    14,    15,     5,     6,
    +      -1,     8,     9,    10,    11,    -1,    -1,    14,    15,   168,
    +      -1,   170,   171,   172,   173,    -1,    -1,    -1,    36,    37,
    +     179,    -1,   181,    -1,    -1,    -1,    -1,    -1,    -1,    36,
    +      37,    -1,   191
    +};
    +
    +  /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
    +     symbol of state STATE-NUM.  */
    +static const yytype_uint8 yystos[] =
    +{
    +       0,     3,    36,    45,    46,    47,    48,    89,    27,    28,
    +      87,     0,    48,     1,     4,     5,     6,     7,     8,     9,
    +      10,    11,    14,    15,    16,    17,    18,    19,    20,    21,
    +      22,    23,    24,    27,    36,    37,    49,    50,    52,    53,
    +      54,    55,    61,    62,    64,    68,    70,    72,    73,    75,
    +      77,    78,    79,    88,    95,    36,    46,    36,    36,    87,
    +      36,    87,    27,    94,    36,    87,    27,    92,    92,    28,
    +      35,    43,    91,    92,    93,    36,     1,    38,     1,    56,
    +      56,    65,    67,    71,    84,    76,    82,    36,    36,    36,
    +      36,    36,    36,    91,    91,    36,    40,    41,    29,    30,
    +      31,    32,    33,    42,    36,    39,    96,    36,     1,    12,
    +      16,    18,    19,    20,    21,    22,    23,    25,    27,    36,
    +      51,    57,    58,    80,    81,    83,    17,    18,    19,    20,
    +      36,    51,    66,    81,    83,    50,    63,    88,    50,    64,
    +      69,    75,    88,    24,    36,    82,    85,    50,    64,    74,
    +      75,    88,    36,    51,    83,    34,    91,    91,    93,    93,
    +      93,    93,    93,    93,    36,    36,    36,    26,    87,    86,
    +      87,    91,    92,    92,    93,    59,     1,    13,    36,    87,
    +      86,    92,    14,    90,    91,    90,    36,    90,    90,    90,
    +      90,    93,    27,    36,    36,    90,    36,    90,    91,    36,
    +      36,    36,    36,    36,    90,    42,    60,    36,    36,    36,
    +      87
    +};
    +
    +  /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
    +static const yytype_uint8 yyr1[] =
    +{
    +       0,    44,    45,    45,    46,    46,    47,    48,    48,    48,
    +      48,    48,    48,    48,    48,    49,    49,    49,    49,    49,
    +      49,    49,    49,    49,    50,    50,    50,    50,    50,    50,
    +      50,    51,    51,    52,    53,    54,    55,    56,    56,    56,
    +      56,    56,    56,    56,    57,    57,    57,    57,    57,    57,
    +      58,    59,    59,    60,    60,    61,    62,    63,    64,    65,
    +      65,    65,    65,    65,    65,    66,    66,    66,    66,    67,
    +      67,    68,    69,    70,    71,    71,    71,    71,    72,    73,
    +      74,    75,    76,    76,    76,    76,    77,    78,    79,    80,
    +      81,    82,    82,    82,    82,    83,    84,    84,    84,    85,
    +      86,    86,    87,    87,    88,    88,    88,    89,    89,    90,
    +      90,    91,    91,    91,    91,    91,    91,    91,    91,    91,
    +      91,    91,    92,    93,    93,    94,    94,    95,    96,    96
    +};
    +
    +  /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.  */
    +static const yytype_uint8 yyr2[] =
    +{
    +       0,     2,     2,     1,     2,     1,     3,     0,     2,     2,
    +       2,     2,     4,     4,     3,     1,     1,     1,     1,     1,
    +       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
    +       1,     3,     2,     3,     2,     3,     2,     0,     2,     2,
    +       2,     2,     2,     2,     3,     4,     4,     4,     4,     5,
    +       3,     0,     3,     0,     2,     3,     2,     1,     3,     0,
    +       2,     2,     2,     2,     2,     4,     3,     2,     4,     0,
    +       2,     3,     1,     3,     0,     2,     2,     2,     3,     3,
    +       1,     3,     0,     2,     2,     2,     3,     3,     2,     2,
    +       2,     0,     2,     2,     2,     4,     0,     2,     2,     2,
    +       0,     2,     1,     1,     2,     2,     2,     1,     2,     0,
    +       2,     1,     3,     3,     3,     3,     3,     3,     3,     2,
    +       3,     3,     1,     1,     1,     0,     1,     4,     0,     1
    +};
    +
    +
    +#define yyerrok         (yyerrstatus = 0)
    +#define yyclearin       (yychar = YYEMPTY)
    +#define YYEMPTY         (-2)
    +#define YYEOF           0
    +
    +#define YYACCEPT        goto yyacceptlab
    +#define YYABORT         goto yyabortlab
    +#define YYERROR         goto yyerrorlab
    +
    +
    +#define YYRECOVERING()  (!!yyerrstatus)
    +
    +#define YYBACKUP(Token, Value)                                  \
    +do                                                              \
    +  if (yychar == YYEMPTY)                                        \
    +    {                                                           \
    +      yychar = (Token);                                         \
    +      yylval = (Value);                                         \
    +      YYPOPSTACK (yylen);                                       \
    +      yystate = *yyssp;                                         \
    +      goto yybackup;                                            \
    +    }                                                           \
    +  else                                                          \
    +    {                                                           \
    +      yyerror (YY_("syntax error: cannot back up")); \
    +      YYERROR;                                                  \
    +    }                                                           \
    +while (0)
    +
    +/* Error token number */
    +#define YYTERROR        1
    +#define YYERRCODE       256
    +
    +
    +
    +/* Enable debugging if requested.  */
    +#if YYDEBUG
    +
    +# ifndef YYFPRINTF
    +#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
    +#  define YYFPRINTF fprintf
    +# endif
    +
    +# define YYDPRINTF(Args)                        \
    +do {                                            \
    +  if (yydebug)                                  \
    +    YYFPRINTF Args;                             \
    +} while (0)
    +
    +/* This macro is provided for backward compatibility. */
    +#ifndef YY_LOCATION_PRINT
    +# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
    +#endif
    +
    +
    +# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                    \
    +do {                                                                      \
    +  if (yydebug)                                                            \
    +    {                                                                     \
    +      YYFPRINTF (stderr, "%s ", Title);                                   \
    +      yy_symbol_print (stderr,                                            \
    +                  Type, Value); \
    +      YYFPRINTF (stderr, "\n");                                           \
    +    }                                                                     \
    +} while (0)
    +
    +
    +/*----------------------------------------.
    +| Print this symbol's value on YYOUTPUT.  |
    +`----------------------------------------*/
    +
    +static void
    +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const 
yyvaluep)
    +{
    +  FILE *yyo = yyoutput;
    +  YYUSE (yyo);
    +  if (!yyvaluep)
    +    return;
    +# ifdef YYPRINT
    +  if (yytype < YYNTOKENS)
    +    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
    +# endif
    +  YYUSE (yytype);
    +}
    +
    +
    +/*--------------------------------.
    +| Print this symbol on YYOUTPUT.  |
    +`--------------------------------*/
    +
    +static void
    +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const 
yyvaluep)
    +{
    +  YYFPRINTF (yyoutput, "%s %s (",
    +             yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
    +
    +  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
    +  YYFPRINTF (yyoutput, ")");
    +}
    +
    +/*------------------------------------------------------------------.
    +| yy_stack_print -- Print the state stack from its BOTTOM up to its |
    +| TOP (included).                                                   |
    +`------------------------------------------------------------------*/
    +
    +static void
    +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
    +{
    +  YYFPRINTF (stderr, "Stack now");
    +  for (; yybottom <= yytop; yybottom++)
    +    {
    +      int yybot = *yybottom;
    +      YYFPRINTF (stderr, " %d", yybot);
    +    }
    +  YYFPRINTF (stderr, "\n");
    +}
    +
    +# define YY_STACK_PRINT(Bottom, Top)                            \
    +do {                                                            \
    +  if (yydebug)                                                  \
    +    yy_stack_print ((Bottom), (Top));                           \
    +} while (0)
    +
    +
    +/*------------------------------------------------.
    +| Report that the YYRULE is going to be reduced.  |
    +`------------------------------------------------*/
    +
    +static void
    +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
    +{
    +  unsigned long int yylno = yyrline[yyrule];
    +  int yynrhs = yyr2[yyrule];
    +  int yyi;
    +  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
    +             yyrule - 1, yylno);
    +  /* The symbols being reduced.  */
    +  for (yyi = 0; yyi < yynrhs; yyi++)
    +    {
    +      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
    +      yy_symbol_print (stderr,
    +                       yystos[yyssp[yyi + 1 - yynrhs]],
    +                       &(yyvsp[(yyi + 1) - (yynrhs)])
    +                                              );
    +      YYFPRINTF (stderr, "\n");
    +    }
    +}
    +
    +# define YY_REDUCE_PRINT(Rule)          \
    +do {                                    \
    +  if (yydebug)                          \
    +    yy_reduce_print (yyssp, yyvsp, Rule); \
    +} while (0)
    +
    +/* Nonzero means print parse trace.  It is left uninitialized so that
    +   multiple parsers can coexist.  */
    +int yydebug;
    +#else /* !YYDEBUG */
    +# define YYDPRINTF(Args)
    +# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
    +# define YY_STACK_PRINT(Bottom, Top)
    +# define YY_REDUCE_PRINT(Rule)
    +#endif /* !YYDEBUG */
    +
    +
    +/* YYINITDEPTH -- initial size of the parser's stacks.  */
    +#ifndef YYINITDEPTH
    +# define YYINITDEPTH 200
    +#endif
    +
    +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
    +   if the built-in stack extension method is used).
    +
    +   Do not make this value too large; the results are undefined if
    +   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
    +   evaluated with infinite-precision integer arithmetic.  */
    +
    +#ifndef YYMAXDEPTH
    +# define YYMAXDEPTH 10000
    +#endif
    +
    +
    +#if YYERROR_VERBOSE
    +
    +# ifndef yystrlen
    +#  if defined __GLIBC__ && defined _STRING_H
    +#   define yystrlen strlen
    +#  else
    +/* Return the length of YYSTR.  */
    +static YYSIZE_T
    +yystrlen (const char *yystr)
    +{
    +  YYSIZE_T yylen;
    +  for (yylen = 0; yystr[yylen]; yylen++)
    +    continue;
    +  return yylen;
    +}
    +#  endif
    +# endif
    +
    +# ifndef yystpcpy
    +#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
    +#   define yystpcpy stpcpy
    +#  else
    +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
    +   YYDEST.  */
    +static char *
    +yystpcpy (char *yydest, const char *yysrc)
    +{
    +  char *yyd = yydest;
    +  const char *yys = yysrc;
    +
    +  while ((*yyd++ = *yys++) != '\0')
    +    continue;
    +
    +  return yyd - 1;
    +}
    +#  endif
    +# endif
    +
    +# ifndef yytnamerr
    +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
    +   quotes and backslashes, so that it's suitable for yyerror.  The
    +   heuristic is that double-quoting is unnecessary unless the string
    +   contains an apostrophe, a comma, or backslash (other than
    +   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
    +   null, do not copy; instead, return the length of what the result
    +   would have been.  */
    +static YYSIZE_T
    +yytnamerr (char *yyres, const char *yystr)
    +{
    +  if (*yystr == '"')
    +    {
    +      YYSIZE_T yyn = 0;
    +      char const *yyp = yystr;
    +
    +      for (;;)
    +        switch (*++yyp)
    +          {
    +          case '\'':
    +          case ',':
    +            goto do_not_strip_quotes;
    +
    +          case '\\':
    +            if (*++yyp != '\\')
    +              goto do_not_strip_quotes;
    +            /* Fall through.  */
    +          default:
    +            if (yyres)
    +              yyres[yyn] = *yyp;
    +            yyn++;
    +            break;
    +
    +          case '"':
    +            if (yyres)
    +              yyres[yyn] = '\0';
    +            return yyn;
    +          }
    +    do_not_strip_quotes: ;
    +    }
    +
    +  if (! yyres)
    +    return yystrlen (yystr);
    +
    +  return yystpcpy (yyres, yystr) - yyres;
    +}
    +# endif
    +
    +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
    +   about the unexpected token YYTOKEN for the state stack whose top is
    +   YYSSP.
    +
    +   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
    +   not large enough to hold the message.  In that case, also set
    +   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
    +   required number of bytes is too large to store.  */
    +static int
    +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
    +                yytype_int16 *yyssp, int yytoken)
    +{
    +  YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
    +  YYSIZE_T yysize = yysize0;
    +  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
    +  /* Internationalized format string. */
    +  const char *yyformat = YY_NULLPTR;
    +  /* Arguments of yyformat. */
    +  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
    +  /* Number of reported tokens (one for the "unexpected", one per
    +     "expected"). */
    +  int yycount = 0;
    +
    +  /* There are many possibilities here to consider:
    +     - If this state is a consistent state with a default action, then
    +       the only way this function was invoked is if the default action
    +       is an error action.  In that case, don't check for expected
    +       tokens because there are none.
    +     - The only way there can be no lookahead present (in yychar) is if
    +       this state is a consistent state with a default action.  Thus,
    +       detecting the absence of a lookahead is sufficient to determine
    +       that there is no unexpected or expected token to report.  In that
    +       case, just report a simple "syntax error".
    +     - Don't assume there isn't a lookahead just because this state is a
    +       consistent state with a default action.  There might have been a
    +       previous inconsistent state, consistent state with a non-default
    +       action, or user semantic action that manipulated yychar.
    +     - Of course, the expected token list depends on states to have
    +       correct lookahead information, and it depends on the parser not
    +       to perform extra reductions after fetching a lookahead from the
    +       scanner and before detecting a syntax error.  Thus, state merging
    +       (from LALR or IELR) and default reductions corrupt the expected
    +       token list.  However, the list is correct for canonical LR with
    +       one exception: it will still contain any token that will not be
    +       accepted due to an error action in a later state.
    +  */
    +  if (yytoken != YYEMPTY)
    +    {
    +      int yyn = yypact[*yyssp];
    +      yyarg[yycount++] = yytname[yytoken];
    +      if (!yypact_value_is_default (yyn))
    +        {
    +          /* Start YYX at -YYN if negative to avoid negative indexes in
    +             YYCHECK.  In other words, skip the first -YYN actions for
    +             this state because they are default actions.  */
    +          int yyxbegin = yyn < 0 ? -yyn : 0;
    +          /* Stay within bounds of both yycheck and yytname.  */
    +          int yychecklim = YYLAST - yyn + 1;
    +          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
    +          int yyx;
    +
    +          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
    +            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
    +                && !yytable_value_is_error (yytable[yyx + yyn]))
    +              {
    +                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
    +                  {
    +                    yycount = 1;
    +                    yysize = yysize0;
    +                    break;
    +                  }
    +                yyarg[yycount++] = yytname[yyx];
    +                {
    +                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, 
yytname[yyx]);
    +                  if (! (yysize <= yysize1
    +                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
    +                    return 2;
    +                  yysize = yysize1;
    +                }
    +              }
    +        }
    +    }
    +
    +  switch (yycount)
    +    {
    +# define YYCASE_(N, S)                      \
    +      case N:                               \
    +        yyformat = S;                       \
    +      break
    +      YYCASE_(0, YY_("syntax error"));
    +      YYCASE_(1, YY_("syntax error, unexpected %s"));
    +      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
    +      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
    +      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or 
%s"));
    +      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or 
%s or %s"));
    +# undef YYCASE_
    +    }
    +
    +  {
    +    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
    +    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
    +      return 2;
    +    yysize = yysize1;
    +  }
    +
    +  if (*yymsg_alloc < yysize)
    +    {
    +      *yymsg_alloc = 2 * yysize;
    +      if (! (yysize <= *yymsg_alloc
    +             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
    +        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
    +      return 1;
    +    }
    +
    +  /* Avoid sprintf, as that infringes on the user's name space.
    +     Don't have undefined behavior even if the translation
    +     produced a string with the wrong number of "%s"s.  */
    +  {
    +    char *yyp = *yymsg;
    +    int yyi = 0;
    +    while ((*yyp = *yyformat) != '\0')
    +      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
    +        {
    +          yyp += yytnamerr (yyp, yyarg[yyi++]);
    +          yyformat += 2;
    +        }
    +      else
    +        {
    +          yyp++;
    +          yyformat++;
    +        }
    +  }
    +  return 0;
    +}
    +#endif /* YYERROR_VERBOSE */
    +
    +/*-----------------------------------------------.
    +| Release the memory associated to this symbol.  |
    +`-----------------------------------------------*/
    +
    +static void
    +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
    +{
    +  YYUSE (yyvaluep);
    +  if (!yymsg)
    +    yymsg = "Deleting";
    +  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
    +
    +  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
    +  switch (yytype)
    +    {
    +          case 62: /* choice_entry  */
    +
    +      {
    +   fprintf(stderr, "%s:%d: missing end statement for this entry\n",
    +           ((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
    +   if (current_menu == ((*yyvaluep).menu))
    +           menu_end_menu();
    +}
    +
    +        break;
    +
    +    case 68: /* if_entry  */
    +
    +      {
    +   fprintf(stderr, "%s:%d: missing end statement for this entry\n",
    +           ((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
    +   if (current_menu == ((*yyvaluep).menu))
    +           menu_end_menu();
    +}
    +
    +        break;
    +
    +    case 73: /* menu_entry  */
    +
    +      {
    +   fprintf(stderr, "%s:%d: missing end statement for this entry\n",
    +           ((*yyvaluep).menu)->file->name, ((*yyvaluep).menu)->lineno);
    +   if (current_menu == ((*yyvaluep).menu))
    +           menu_end_menu();
    +}
    +
    +        break;
    +
    +
    +      default:
    +        break;
    +    }
    +  YY_IGNORE_MAYBE_UNINITIALIZED_END
    +}
    +
    +
    +
    +
    +/* The lookahead symbol.  */
    +int yychar;
    +
    +/* The semantic value of the lookahead symbol.  */
    +YYSTYPE yylval;
    +/* Number of syntax errors so far.  */
    +int yynerrs;
    +
    +
    +/*----------.
    +| yyparse.  |
    +`----------*/
    +
    +int
    +yyparse (void)
    +{
    +    int yystate;
    +    /* Number of tokens to shift before error messages enabled.  */
    +    int yyerrstatus;
    +
    +    /* The stacks and their tools:
    +       'yyss': related to states.
    +       'yyvs': related to semantic values.
    +
    +       Refer to the stacks through separate pointers, to allow yyoverflow
    +       to reallocate them elsewhere.  */
    +
    +    /* The state stack.  */
    +    yytype_int16 yyssa[YYINITDEPTH];
    +    yytype_int16 *yyss;
    +    yytype_int16 *yyssp;
    +
    +    /* The semantic value stack.  */
    +    YYSTYPE yyvsa[YYINITDEPTH];
    +    YYSTYPE *yyvs;
    +    YYSTYPE *yyvsp;
    +
    +    YYSIZE_T yystacksize;
    +
    +  int yyn;
    +  int yyresult;
    +  /* Lookahead token as an internal (translated) token number.  */
    +  int yytoken = 0;
    +  /* The variables used to return semantic value and location from the
    +     action routines.  */
    +  YYSTYPE yyval;
    +
    +#if YYERROR_VERBOSE
    +  /* Buffer for error messages, and its allocated size.  */
    +  char yymsgbuf[128];
    +  char *yymsg = yymsgbuf;
    +  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
    +#endif
    +
    +#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
    +
    +  /* The number of symbols on the RHS of the reduced rule.
    +     Keep to zero when no symbol should be popped.  */
    +  int yylen = 0;
    +
    +  yyssp = yyss = yyssa;
    +  yyvsp = yyvs = yyvsa;
    +  yystacksize = YYINITDEPTH;
    +
    +  YYDPRINTF ((stderr, "Starting parse\n"));
    +
    +  yystate = 0;
    +  yyerrstatus = 0;
    +  yynerrs = 0;
    +  yychar = YYEMPTY; /* Cause a token to be read.  */
    +  goto yysetstate;
    +
    +/*------------------------------------------------------------.
    +| yynewstate -- Push a new state, which is found in yystate.  |
    +`------------------------------------------------------------*/
    + yynewstate:
    +  /* In all cases, when you get here, the value and location stacks
    +     have just been pushed.  So pushing a state here evens the stacks.  */
    +  yyssp++;
    +
    + yysetstate:
    +  *yyssp = yystate;
    +
    +  if (yyss + yystacksize - 1 <= yyssp)
    +    {
    +      /* Get the current used size of the three stacks, in elements.  */
    +      YYSIZE_T yysize = yyssp - yyss + 1;
    +
    +#ifdef yyoverflow
    +      {
    +        /* Give user a chance to reallocate the stack.  Use copies of
    +           these so that the &'s don't force the real ones into
    +           memory.  */
    +        YYSTYPE *yyvs1 = yyvs;
    +        yytype_int16 *yyss1 = yyss;
    +
    +        /* Each stack pointer address is followed by the size of the
    +           data in use in that stack, in bytes.  This used to be a
    +           conditional around just the two extra args, but that might
    +           be undefined if yyoverflow is a macro.  */
    +        yyoverflow (YY_("memory exhausted"),
    +                    &yyss1, yysize * sizeof (*yyssp),
    +                    &yyvs1, yysize * sizeof (*yyvsp),
    +                    &yystacksize);
    +
    +        yyss = yyss1;
    +        yyvs = yyvs1;
    +      }
    +#else /* no yyoverflow */
    +# ifndef YYSTACK_RELOCATE
    +      goto yyexhaustedlab;
    +# else
    +      /* Extend the stack our own way.  */
    +      if (YYMAXDEPTH <= yystacksize)
    +        goto yyexhaustedlab;
    +      yystacksize *= 2;
    +      if (YYMAXDEPTH < yystacksize)
    +        yystacksize = YYMAXDEPTH;
    +
    +      {
    +        yytype_int16 *yyss1 = yyss;
    +        union yyalloc *yyptr =
    +          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
    +        if (! yyptr)
    +          goto yyexhaustedlab;
    +        YYSTACK_RELOCATE (yyss_alloc, yyss);
    +        YYSTACK_RELOCATE (yyvs_alloc, yyvs);
    +#  undef YYSTACK_RELOCATE
    +        if (yyss1 != yyssa)
    +          YYSTACK_FREE (yyss1);
    +      }
    +# endif
    +#endif /* no yyoverflow */
    +
    +      yyssp = yyss + yysize - 1;
    +      yyvsp = yyvs + yysize - 1;
    +
    +      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
    +                  (unsigned long int) yystacksize));
    +
    +      if (yyss + yystacksize - 1 <= yyssp)
    +        YYABORT;
    +    }
    +
    +  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
    +
    +  if (yystate == YYFINAL)
    +    YYACCEPT;
    +
    +  goto yybackup;
    +
    +/*-----------.
    +| yybackup.  |
    +`-----------*/
    +yybackup:
    +
    +  /* Do appropriate processing given the current state.  Read a
    +     lookahead token if we need one and don't already have one.  */
    +
    +  /* First try to decide what to do without reference to lookahead token.  
*/
    +  yyn = yypact[yystate];
    +  if (yypact_value_is_default (yyn))
    +    goto yydefault;
    +
    +  /* Not known => get a lookahead token if don't already have one.  */
    +
    +  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
    +  if (yychar == YYEMPTY)
    +    {
    +      YYDPRINTF ((stderr, "Reading a token: "));
    +      yychar = yylex ();
    +    }
    +
    +  if (yychar <= YYEOF)
    +    {
    +      yychar = yytoken = YYEOF;
    +      YYDPRINTF ((stderr, "Now at end of input.\n"));
    +    }
    +  else
    +    {
    +      yytoken = YYTRANSLATE (yychar);
    +      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
    +    }
    +
    +  /* If the proper action on seeing token YYTOKEN is to reduce or to
    +     detect an error, take that action.  */
    +  yyn += yytoken;
    +  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
    +    goto yydefault;
    +  yyn = yytable[yyn];
    +  if (yyn <= 0)
    +    {
    +      if (yytable_value_is_error (yyn))
    +        goto yyerrlab;
    +      yyn = -yyn;
    +      goto yyreduce;
    +    }
    +
    +  /* Count tokens shifted since error; after three, turn off error
    +     status.  */
    +  if (yyerrstatus)
    +    yyerrstatus--;
    +
    +  /* Shift the lookahead token.  */
    +  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
    +
    +  /* Discard the shifted token.  */
    +  yychar = YYEMPTY;
    +
    +  yystate = yyn;
    +  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
    +  *++yyvsp = yylval;
    +  YY_IGNORE_MAYBE_UNINITIALIZED_END
    +
    +  goto yynewstate;
    +
    +
    +/*-----------------------------------------------------------.
    +| yydefault -- do the default action for the current state.  |
    +`-----------------------------------------------------------*/
    +yydefault:
    +  yyn = yydefact[yystate];
    +  if (yyn == 0)
    +    goto yyerrlab;
    +  goto yyreduce;
    +
    +
    +/*-----------------------------.
    +| yyreduce -- Do a reduction.  |
    +`-----------------------------*/
    +yyreduce:
    +  /* yyn is the number of a rule to reduce with.  */
    +  yylen = yyr2[yyn];
    +
    +  /* If YYLEN is nonzero, implement the default value of the action:
    +     '$$ = $1'.
    +
    +     Otherwise, the following line sets YYVAL to garbage.
    +     This behavior is undocumented and Bison
    +     users should not rely upon it.  Assigning to YYVAL
    +     unconditionally makes the parser a bit smaller, and it avoids a
    +     GCC warning that YYVAL may be used uninitialized.  */
    +  yyval = yyvsp[1-yylen];
    +
    +
    +  YY_REDUCE_PRINT (yyn);
    +  switch (yyn)
    +    {
    +        case 6:
    +
    +    {
    +   menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
    +}
    +
    +    break;
    +
    +  case 11:
    +
    +    { zconf_error("unexpected end statement"); }
    +
    +    break;
    +
    +  case 12:
    +
    +    { zconf_error("unknown statement \"%s\"", (yyvsp[-2].string)); }
    +
    +    break;
    +
    +  case 13:
    +
    +    {
    +   zconf_error("unexpected option \"%s\"", (yyvsp[-2].id)->name);
    +}
    +
    +    break;
    +
    +  case 14:
    +
    +    { zconf_error("invalid statement"); }
    +
    +    break;
    +
    +  case 31:
    +
    +    { zconf_error("unknown option \"%s\"", (yyvsp[-2].string)); }
    +
    +    break;
    +
    +  case 32:
    +
    +    { zconf_error("invalid option"); }
    +
    +    break;
    +
    +  case 33:
    +
    +    {
    +   (yyvsp[-1].symbol)->flags |= SYMBOL_OPTIONAL;
    +   menu_add_entry((yyvsp[-1].symbol));
    +   printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), 
zconf_lineno(), (yyvsp[-1].symbol)->name);
    +}
    +
    +    break;
    +
    +  case 34:
    +
    +    {
    +   printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), 
zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 35:
    +
    +    {
    +   (yyvsp[-1].symbol)->flags |= SYMBOL_OPTIONAL;
    +   menu_add_entry((yyvsp[-1].symbol));
    +   printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), 
zconf_lineno(), (yyvsp[-1].symbol)->name);
    +}
    +
    +    break;
    +
    +  case 36:
    +
    +    {
    +   if (current_entry->prompt)
    +           current_entry->prompt->type = P_MENU;
    +   else
    +           zconfprint("warning: menuconfig statement without prompt");
    +   printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), 
zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 44:
    +
    +    {
    +   menu_set_type((yyvsp[-2].id)->stype);
    +   printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
    +           zconf_curname(), zconf_lineno(),
    +           (yyvsp[-2].id)->stype);
    +}
    +
    +    break;
    +
    +  case 45:
    +
    +    {
    +   menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
    +   printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 46:
    +
    +    {
    +   menu_add_expr(P_DEFAULT, (yyvsp[-2].expr), (yyvsp[-1].expr));
    +   if ((yyvsp[-3].id)->stype != S_UNKNOWN)
    +           menu_set_type((yyvsp[-3].id)->stype);
    +   printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
    +           zconf_curname(), zconf_lineno(),
    +           (yyvsp[-3].id)->stype);
    +}
    +
    +    break;
    +
    +  case 47:
    +
    +    {
    +   menu_add_symbol(P_SELECT, (yyvsp[-2].symbol), (yyvsp[-1].expr));
    +   printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 48:
    +
    +    {
    +   menu_add_symbol(P_IMPLY, (yyvsp[-2].symbol), (yyvsp[-1].expr));
    +   printd(DEBUG_PARSE, "%s:%d:imply\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 49:
    +
    +    {
    +   menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[-3].symbol), 
(yyvsp[-2].symbol)), (yyvsp[-1].expr));
    +   printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 52:
    +
    +    {
    +   const struct kconf_id *id = kconf_id_lookup((yyvsp[-1].string), 
strlen((yyvsp[-1].string)));
    +   if (id && id->flags & TF_OPTION) {
    +           menu_add_option(id->token, (yyvsp[0].string));
    +           free((yyvsp[0].string));
    +   }
    +   else
    +           zconfprint("warning: ignoring unknown option %s", 
(yyvsp[-1].string));
    +   free((yyvsp[-1].string));
    +}
    +
    +    break;
    +
    +  case 53:
    +
    +    { (yyval.string) = NULL; }
    +
    +    break;
    +
    +  case 54:
    +
    +    { (yyval.string) = (yyvsp[0].string); }
    +
    +    break;
    +
    +  case 55:
    +
    +    {
    +   struct symbol *sym = sym_lookup((yyvsp[-1].string), SYMBOL_CHOICE);
    +   sym->flags |= SYMBOL_NO_WRITE;
    +   menu_add_entry(sym);
    +   menu_add_expr(P_CHOICE, NULL, NULL);
    +   free((yyvsp[-1].string));
    +   printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 56:
    +
    +    {
    +   (yyval.menu) = menu_add_menu();
    +}
    +
    +    break;
    +
    +  case 57:
    +
    +    {
    +   if (zconf_endtoken((yyvsp[0].id), T_CHOICE, T_ENDCHOICE)) {
    +           menu_end_menu();
    +           printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), 
zconf_lineno());
    +   }
    +}
    +
    +    break;
    +
    +  case 65:
    +
    +    {
    +   menu_add_prompt(P_PROMPT, (yyvsp[-2].string), (yyvsp[-1].expr));
    +   printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 66:
    +
    +    {
    +   if ((yyvsp[-2].id)->stype == S_BOOLEAN || (yyvsp[-2].id)->stype == 
S_TRISTATE) {
    +           menu_set_type((yyvsp[-2].id)->stype);
    +           printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
    +                   zconf_curname(), zconf_lineno(),
    +                   (yyvsp[-2].id)->stype);
    +   } else
    +           YYERROR;
    +}
    +
    +    break;
    +
    +  case 67:
    +
    +    {
    +   current_entry->sym->flags |= SYMBOL_OPTIONAL;
    +   printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), 
zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 68:
    +
    +    {
    +   if ((yyvsp[-3].id)->stype == S_UNKNOWN) {
    +           menu_add_symbol(P_DEFAULT, (yyvsp[-2].symbol), 
(yyvsp[-1].expr));
    +           printd(DEBUG_PARSE, "%s:%d:default\n",
    +                   zconf_curname(), zconf_lineno());
    +   } else
    +           YYERROR;
    +}
    +
    +    break;
    +
    +  case 71:
    +
    +    {
    +   printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
    +   menu_add_entry(NULL);
    +   menu_add_dep((yyvsp[-1].expr));
    +   (yyval.menu) = menu_add_menu();
    +}
    +
    +    break;
    +
    +  case 72:
    +
    +    {
    +   if (zconf_endtoken((yyvsp[0].id), T_IF, T_ENDIF)) {
    +           menu_end_menu();
    +           printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), 
zconf_lineno());
    +   }
    +}
    +
    +    break;
    +
    +  case 78:
    +
    +    {
    +   menu_add_entry(NULL);
    +   menu_add_prompt(P_MENU, (yyvsp[-1].string), NULL);
    +   printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 79:
    +
    +    {
    +   (yyval.menu) = menu_add_menu();
    +}
    +
    +    break;
    +
    +  case 80:
    +
    +    {
    +   if (zconf_endtoken((yyvsp[0].id), T_MENU, T_ENDMENU)) {
    +           menu_end_menu();
    +           printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), 
zconf_lineno());
    +   }
    +}
    +
    +    break;
    +
    +  case 86:
    +
    +    {
    +   printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), 
zconf_lineno(), (yyvsp[-1].string));
    +   zconf_nextfile((yyvsp[-1].string));
    +   free((yyvsp[-1].string));
    +}
    +
    +    break;
    +
    +  case 87:
    +
    +    {
    +   menu_add_entry(NULL);
    +   menu_add_prompt(P_COMMENT, (yyvsp[-1].string), NULL);
    +   printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 89:
    +
    +    {
    +   printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
    +   zconf_starthelp();
    +}
    +
    +    break;
    +
    +  case 90:
    +
    +    {
    +   if (current_entry->help) {
    +           free(current_entry->help);
    +           zconfprint("warning: '%s' defined with more than one help text 
-- only the last one will be used",
    +                      current_entry->sym->name ?: "<choice>");
    +   }
    +
    +   /* Is the help text empty or all whitespace? */
    +   if ((yyvsp[0].string)[strspn((yyvsp[0].string), " \f\n\r\t\v")] == '\0')
    +           zconfprint("warning: '%s' defined with blank help text",
    +                      current_entry->sym->name ?: "<choice>");
    +
    +   current_entry->help = (yyvsp[0].string);
    +}
    +
    +    break;
    +
    +  case 95:
    +
    +    {
    +   menu_add_dep((yyvsp[-1].expr));
    +   printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), 
zconf_lineno());
    +}
    +
    +    break;
    +
    +  case 99:
    +
    +    {
    +   menu_add_visibility((yyvsp[0].expr));
    +}
    +
    +    break;
    +
    +  case 101:
    +
    +    {
    +   menu_add_prompt(P_PROMPT, (yyvsp[-1].string), (yyvsp[0].expr));
    +}
    +
    +    break;
    +
    +  case 104:
    +
    +    { (yyval.id) = (yyvsp[-1].id); }
    +
    +    break;
    +
    +  case 105:
    +
    +    { (yyval.id) = (yyvsp[-1].id); }
    +
    +    break;
    +
    +  case 106:
    +
    +    { (yyval.id) = (yyvsp[-1].id); }
    +
    +    break;
    +
    +  case 109:
    +
    +    { (yyval.expr) = NULL; }
    +
    +    break;
    +
    +  case 110:
    +
    +    { (yyval.expr) = (yyvsp[0].expr); }
    +
    +    break;
    +
    +  case 111:
    +
    +    { (yyval.expr) = expr_alloc_symbol((yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 112:
    +
    +    { (yyval.expr) = expr_alloc_comp(E_LTH, (yyvsp[-2].symbol), 
(yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 113:
    +
    +    { (yyval.expr) = expr_alloc_comp(E_LEQ, (yyvsp[-2].symbol), 
(yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 114:
    +
    +    { (yyval.expr) = expr_alloc_comp(E_GTH, (yyvsp[-2].symbol), 
(yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 115:
    +
    +    { (yyval.expr) = expr_alloc_comp(E_GEQ, (yyvsp[-2].symbol), 
(yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 116:
    +
    +    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[-2].symbol), 
(yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 117:
    +
    +    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[-2].symbol), 
(yyvsp[0].symbol)); }
    +
    +    break;
    +
    +  case 118:
    +
    +    { (yyval.expr) = (yyvsp[-1].expr); }
    +
    +    break;
    +
    +  case 119:
    +
    +    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[0].expr)); }
    +
    +    break;
    +
    +  case 120:
    +
    +    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[-2].expr), 
(yyvsp[0].expr)); }
    +
    +    break;
    +
    +  case 121:
    +
    +    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[-2].expr), 
(yyvsp[0].expr)); }
    +
    +    break;
    +
    +  case 122:
    +
    +    { (yyval.symbol) = sym_lookup((yyvsp[0].string), 0); 
free((yyvsp[0].string)); }
    +
    +    break;
    +
    +  case 124:
    +
    +    { (yyval.symbol) = sym_lookup((yyvsp[0].string), SYMBOL_CONST); 
free((yyvsp[0].string)); }
    +
    +    break;
    +
    +  case 125:
    +
    +    { (yyval.string) = NULL; }
    +
    +    break;
    +
    +  case 127:
    +
    +    { variable_add((yyvsp[-3].string), (yyvsp[-1].string), 
(yyvsp[-2].flavor)); free((yyvsp[-3].string)); free((yyvsp[-1].string)); }
    +
    +    break;
    +
    +  case 128:
    +
    +    { (yyval.string) = xstrdup(""); }
    +
    +    break;
    +
    +
    +
    +      default: break;
    +    }
    +  /* User semantic actions sometimes alter yychar, and that requires
    +     that yytoken be updated with the new translation.  We take the
    +     approach of translating immediately before every use of yytoken.
    +     One alternative is translating here after every semantic action,
    +     but that translation would be missed if the semantic action invokes
    +     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
    +     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
    +     incorrect destructor might then be invoked immediately.  In the
    +     case of YYERROR or YYBACKUP, subsequent parser actions might lead
    +     to an incorrect destructor call or verbose syntax error message
    +     before the lookahead is translated.  */
    +  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
    +
    +  YYPOPSTACK (yylen);
    +  yylen = 0;
    +  YY_STACK_PRINT (yyss, yyssp);
    +
    +  *++yyvsp = yyval;
    +
    +  /* Now 'shift' the result of the reduction.  Determine what state
    +     that goes to, based on the state we popped back to and the rule
    +     number reduced by.  */
    +
    +  yyn = yyr1[yyn];
    +
    +  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
    +  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
    +    yystate = yytable[yystate];
    +  else
    +    yystate = yydefgoto[yyn - YYNTOKENS];
    +
    +  goto yynewstate;
    +
    +
    +/*--------------------------------------.
    +| yyerrlab -- here on detecting error.  |
    +`--------------------------------------*/
    +yyerrlab:
    +  /* Make sure we have latest lookahead translation.  See comments at
    +     user semantic actions for why this is necessary.  */
    +  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
    +
    +  /* If not already recovering from an error, report this error.  */
    +  if (!yyerrstatus)
    +    {
    +      ++yynerrs;
    +#if ! YYERROR_VERBOSE
    +      yyerror (YY_("syntax error"));
    +#else
    +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
    +                                        yyssp, yytoken)
    +      {
    +        char const *yymsgp = YY_("syntax error");
    +        int yysyntax_error_status;
    +        yysyntax_error_status = YYSYNTAX_ERROR;
    +        if (yysyntax_error_status == 0)
    +          yymsgp = yymsg;
    +        else if (yysyntax_error_status == 1)
    +          {
    +            if (yymsg != yymsgbuf)
    +              YYSTACK_FREE (yymsg);
    +            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
    +            if (!yymsg)
    +              {
    +                yymsg = yymsgbuf;
    +                yymsg_alloc = sizeof yymsgbuf;
    +                yysyntax_error_status = 2;
    +              }
    +            else
    +              {
    +                yysyntax_error_status = YYSYNTAX_ERROR;
    +                yymsgp = yymsg;
    +              }
    +          }
    +        yyerror (yymsgp);
    +        if (yysyntax_error_status == 2)
    +          goto yyexhaustedlab;
    +      }
    +# undef YYSYNTAX_ERROR
    +#endif
    +    }
    +
    +
    +
    +  if (yyerrstatus == 3)
    +    {
    +      /* If just tried and failed to reuse lookahead token after an
    +         error, discard it.  */
    +
    +      if (yychar <= YYEOF)
    +        {
    +          /* Return failure if at end of input.  */
    +          if (yychar == YYEOF)
    +            YYABORT;
    +        }
    +      else
    +        {
    +          yydestruct ("Error: discarding",
    +                      yytoken, &yylval);
    +          yychar = YYEMPTY;
    +        }
    +    }
    +
    +  /* Else will try to reuse lookahead token after shifting the error
    +     token.  */
    +  goto yyerrlab1;
    +
    +
    +/*---------------------------------------------------.
    +| yyerrorlab -- error raised explicitly by YYERROR.  |
    +`---------------------------------------------------*/
    +yyerrorlab:
    +
    +  /* Pacify compilers like GCC when the user code never invokes
    +     YYERROR and the label yyerrorlab therefore never appears in user
    +     code.  */
    +  if (/*CONSTCOND*/ 0)
    +     goto yyerrorlab;
    +
    +  /* Do not reclaim the symbols of the rule whose action triggered
    +     this YYERROR.  */
    +  YYPOPSTACK (yylen);
    +  yylen = 0;
    +  YY_STACK_PRINT (yyss, yyssp);
    +  yystate = *yyssp;
    +  goto yyerrlab1;
    +
    +
    +/*-------------------------------------------------------------.
    +| yyerrlab1 -- common code for both syntax error and YYERROR.  |
    +`-------------------------------------------------------------*/
    +yyerrlab1:
    +  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
    +
    +  for (;;)
    +    {
    +      yyn = yypact[yystate];
    +      if (!yypact_value_is_default (yyn))
    +        {
    +          yyn += YYTERROR;
    +          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
    +            {
    +              yyn = yytable[yyn];
    +              if (0 < yyn)
    +                break;
    +            }
    +        }
    +
    +      /* Pop the current state because it cannot handle the error token.  
*/
    +      if (yyssp == yyss)
    +        YYABORT;
    +
    +
    +      yydestruct ("Error: popping",
    +                  yystos[yystate], yyvsp);
    +      YYPOPSTACK (1);
    +      yystate = *yyssp;
    +      YY_STACK_PRINT (yyss, yyssp);
    +    }
    +
    +  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
    +  *++yyvsp = yylval;
    +  YY_IGNORE_MAYBE_UNINITIALIZED_END
    +
    +
    +  /* Shift the error token.  */
    +  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
    +
    +  yystate = yyn;
    +  goto yynewstate;
    +
    +
    +/*-------------------------------------.
    +| yyacceptlab -- YYACCEPT comes here.  |
    +`-------------------------------------*/
    +yyacceptlab:
    +  yyresult = 0;
    +  goto yyreturn;
    +
    +/*-----------------------------------.
    +| yyabortlab -- YYABORT comes here.  |
    +`-----------------------------------*/
    +yyabortlab:
    +  yyresult = 1;
    +  goto yyreturn;
    +
    +#if !defined yyoverflow || YYERROR_VERBOSE
    +/*-------------------------------------------------.
    +| yyexhaustedlab -- memory exhaustion comes here.  |
    +`-------------------------------------------------*/
    +yyexhaustedlab:
    +  yyerror (YY_("memory exhausted"));
    +  yyresult = 2;
    +  /* Fall through.  */
    +#endif
    +
    +yyreturn:
    +  if (yychar != YYEMPTY)
    +    {
    +      /* Make sure we have latest lookahead translation.  See comments at
    +         user semantic actions for why this is necessary.  */
    +      yytoken = YYTRANSLATE (yychar);
    +      yydestruct ("Cleanup: discarding lookahead",
    +                  yytoken, &yylval);
    +    }
    +  /* Do not reclaim the symbols of the rule whose action triggered
    +     this YYABORT or YYACCEPT.  */
    +  YYPOPSTACK (yylen);
    +  YY_STACK_PRINT (yyss, yyssp);
    +  while (yyssp != yyss)
    +    {
    +      yydestruct ("Cleanup: popping",
    +                  yystos[*yyssp], yyvsp);
    +      YYPOPSTACK (1);
    +    }
    +#ifndef yyoverflow
    +  if (yyss != yyssa)
    +    YYSTACK_FREE (yyss);
    +#endif
    +#if YYERROR_VERBOSE
    +  if (yymsg != yymsgbuf)
    +    YYSTACK_FREE (yymsg);
    +#endif
    +  return yyresult;
    +}
    +
    +
    +
    +void conf_parse(const char *name)
    +{
    +   struct symbol *sym;
    +   int i;
    +
    +   zconf_initscan(name);
    +
    +   _menu_init();
    +
    +   if (getenv("ZCONF_DEBUG"))
    +           yydebug = 1;
    +   yyparse();
    +
    +   /* Variables are expanded in the parse phase. We can free them here. */
    +   variable_all_del();
    +
    +   if (yynerrs)
    +           exit(1);
    +   if (!modules_sym)
    +           modules_sym = sym_find( "n" );
    +
    +   if (!menu_has_prompt(&rootmenu)) {
    +           current_entry = &rootmenu;
    +           menu_add_prompt(P_MENU, "Main menu", NULL);
    +   }
    +
    +   menu_finalize(&rootmenu);
    +   for_all_symbols(i, sym) {
    +           if (sym_check_deps(sym))
    +                   yynerrs++;
    +   }
    +   if (yynerrs)
    +           exit(1);
    +   sym_set_change_count(1);
    +}
    +
    +static const char *zconf_tokenname(int token)
    +{
    +   switch (token) {
    +   case T_MENU:            return "menu";
    +   case T_ENDMENU:         return "endmenu";
    +   case T_CHOICE:          return "choice";
    +   case T_ENDCHOICE:       return "endchoice";
    +   case T_IF:              return "if";
    +   case T_ENDIF:           return "endif";
    +   case T_DEPENDS:         return "depends";
    +   case T_VISIBLE:         return "visible";
    +   }
    +   return "<token>";
    +}
    +
    +static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int 
endtoken)
    +{
    +   if (id->token != endtoken) {
    +           zconf_error("unexpected '%s' within %s block",
    +                   id->name, zconf_tokenname(starttoken));
    +           yynerrs++;
    +           return false;
    +   }
    +   if (current_menu->file != current_file) {
    +           zconf_error("'%s' in different file than '%s'",
    +                   id->name, zconf_tokenname(starttoken));
    +           fprintf(stderr, "%s:%d: location of the '%s'\n",
    +                   current_menu->file->name, current_menu->lineno,
    +                   zconf_tokenname(starttoken));
    +           yynerrs++;
    +           return false;
    +   }
    +   return true;
    +}
    +
    +static void zconfprint(const char *err, ...)
    +{
    +   va_list ap;
    +
    +   fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
    +   va_start(ap, err);
    +   vfprintf(stderr, err, ap);
    +   va_end(ap);
    +   fprintf(stderr, "\n");
    +}
    +
    +static void zconf_error(const char *err, ...)
    +{
    +   va_list ap;
    +
    +   yynerrs++;
    +   fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno());
    +   va_start(ap, err);
    +   vfprintf(stderr, err, ap);
    +   va_end(ap);
    +   fprintf(stderr, "\n");
    +}
    +
    +static void yyerror(const char *err)
    +{
    +   fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, 
err);
    +}
    +
    +static void print_quoted_string(FILE *out, const char *str)
    +{
    +   const char *p;
    +   int len;
    +
    +   putc('"', out);
    +   while ((p = strchr(str, '"'))) {
    +           len = p - str;
    +           if (len)
    +                   fprintf(out, "%.*s", len, str);
    +           fputs("\\\"", out);
    +           str = p + 1;
    +   }
    +   fputs(str, out);
    +   putc('"', out);
    +}
    +
    +static void print_symbol(FILE *out, struct menu *menu)
    +{
    +   struct symbol *sym = menu->sym;
    +   struct property *prop;
    +
    +   if (sym_is_choice(sym))
    +           fprintf(out, "\nchoice\n");
    +   else
    +           fprintf(out, "\nconfig %s\n", sym->name);
    +   switch (sym->type) {
    +   case S_BOOLEAN:
    +           fputs("  bool\n", out);
    +           break;
    +   case S_TRISTATE:
    +           fputs("  tristate\n", out);
    +           break;
    +   case S_STRING:
    +           fputs("  string\n", out);
    +           break;
    +   case S_INT:
    +           fputs("  integer\n", out);
    +           break;
    +   case S_HEX:
    +           fputs("  hex\n", out);
    +           break;
    +   default:
    +           fputs("  ???\n", out);
    +           break;
    +   }
    +   for (prop = sym->prop; prop; prop = prop->next) {
    +           if (prop->menu != menu)
    +                   continue;
    +           switch (prop->type) {
    +           case P_PROMPT:
    +                   fputs("  prompt ", out);
    +                   print_quoted_string(out, prop->text);
    +                   if (!expr_is_yes(prop->visible.expr)) {
    +                           fputs(" if ", out);
    +                           expr_fprint(prop->visible.expr, out);
    +                   }
    +                   fputc('\n', out);
    +                   break;
    +           case P_DEFAULT:
    +                   fputs( "  default ", out);
    +                   expr_fprint(prop->expr, out);
    +                   if (!expr_is_yes(prop->visible.expr)) {
    +                           fputs(" if ", out);
    +                           expr_fprint(prop->visible.expr, out);
    +                   }
    +                   fputc('\n', out);
    +                   break;
    +           case P_CHOICE:
    +                   fputs("  #choice value\n", out);
    +                   break;
    +           case P_SELECT:
    +                   fputs( "  select ", out);
    +                   expr_fprint(prop->expr, out);
    +                   fputc('\n', out);
    +                   break;
    +           case P_IMPLY:
    +                   fputs( "  imply ", out);
    +                   expr_fprint(prop->expr, out);
    +                   fputc('\n', out);
    +                   break;
    +           case P_RANGE:
    +                   fputs( "  range ", out);
    +                   expr_fprint(prop->expr, out);
    +                   fputc('\n', out);
    +                   break;
    +           case P_MENU:
    +                   fputs( "  menu ", out);
    +                   print_quoted_string(out, prop->text);
    +                   fputc('\n', out);
    +                   break;
    +           case P_SYMBOL:
    +                   fputs( "  symbol ", out);
    +                   fprintf(out, "%s\n", prop->sym->name);
    +                   break;
    +           default:
    +                   fprintf(out, "  unknown prop %d!\n", prop->type);
    +                   break;
    +           }
    +   }
    +   if (menu->help) {
    +           int len = strlen(menu->help);
    +           while (menu->help[--len] == '\n')
    +                   menu->help[len] = 0;
    +           fprintf(out, "  help\n%s\n", menu->help);
    +   }
    +}
    +
    +void zconfdump(FILE *out)
    +{
    +   struct property *prop;
    +   struct symbol *sym;
    +   struct menu *menu;
    +
    +   menu = rootmenu.list;
    +   while (menu) {
    +           if ((sym = menu->sym))
    +                   print_symbol(out, menu);
    +           else if ((prop = menu->prompt)) {
    +                   switch (prop->type) {
    +                   case P_COMMENT:
    +                           fputs("\ncomment ", out);
    +                           print_quoted_string(out, prop->text);
    +                           fputs("\n", out);
    +                           break;
    +                   case P_MENU:
    +                           fputs("\nmenu ", out);
    +                           print_quoted_string(out, prop->text);
    +                           fputs("\n", out);
    +                           break;
    +                   default:
    +                           ;
    +                   }
    +                   if (!expr_is_yes(prop->visible.expr)) {
    +                           fputs("  depends ", out);
    +                           expr_fprint(prop->visible.expr, out);
    +                           fputc('\n', out);
    +                   }
    +           }
    +
    +           if (menu->list)
    +                   menu = menu->list;
    +           else if (menu->next)
    +                   menu = menu->next;
    +           else while ((menu = menu->parent)) {
    +                   if (menu->prompt && menu->prompt->type == P_MENU)
    +                           fputs("\nendmenu\n", out);
    +                   if (menu->next) {
    +                           menu = menu->next;
    +                           break;
    +                   }
    +           }
    +   }
    +}
    +
    +#include "zconf.lex.c"
    +#include "util.c"
    +#include "confdata.c"
    +#include "expr.c"
    +#include "symbol.c"
    +#include "menu.c"
    +#include "preprocess.c"
    -- 
    2.7.4
    
    
    _______________________________________________
    Minios-devel mailing list
    Minios-devel@xxxxxxxxxxxxxxxxxxxx
    https://lists.xenproject.org/mailman/listinfo/minios-devel

_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.