|
[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 = ¤t_entry->list;
+ return current_menu = current_entry;
+}
+
+void menu_end_menu(void)
+{
+ last_entry_ptr = ¤t_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, ¤t_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 += " 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 += " 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, "<");
+ i += 4;
+ break;
+ case '>':
+ res.replace(i, 1, ">");
+ i += 4;
+ break;
+ case '&':
+ res.replace(i, 1, "&");
+ i += 5;
+ break;
+ case '"':
+ res.replace(i, 1, """);
+ i += 6;
+ break;
+ case '\n':
+ res.replace(i, 1, "<br>");
+ i += 4;
+ break;
+ }
+ }
+ return res;
+}
+
+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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |