From 65a3eb28d5ec276c960e992fc99d0d042f5c863f Mon Sep 17 00:00:00 2001 From: Eneas U de Queiroz Date: Fri, 16 Feb 2024 14:32:07 -0300 Subject: [PATCH] build: scripts/config - update to kconfig-v6.6.16 The main goal here is to keep this close to upstream. Changes include: - allow symbols implied by y to become m - make 'imply' obey the direct dependency - allow only 'config', 'comment', and 'if' inside 'choice' - qconf: make search fully work again on split mode - qconf: navigate menus on hyperlinks - remove '---help---' support - qconf: allow to edit "int", "hex", "string" menus in-place - qconf: drop Qt4 support - nconf: fix core dump when searching in empty menu - nconf: stop endless search loops - Create links to main menu items in search - fix segmentation fault in menuconfig search - nconf: Add search jump feature - port qconf to work with Qt6 in addition to Qt5 - fix possible buffer overflow - fix memory leak from range properties Signed-off-by: Eneas U de Queiroz --- scripts/config/.gitignore | 18 +- scripts/config/Kbuild.include | 279 ++++++++++++++ scripts/config/Makefile | 111 ++---- scripts/config/README | 9 +- scripts/config/conf.c | 58 ++- scripts/config/confdata.c | 620 ++++++++++++++++++------------ scripts/config/expr.h | 1 - scripts/config/lexer.l | 9 +- scripts/config/lexer.lex.c | 14 +- scripts/config/lkc.h | 9 +- scripts/config/lkc_proto.h | 2 +- scripts/config/lxdialog/dialog.h | 37 +- scripts/config/lxdialog/menubox.c | 8 - scripts/config/lxdialog/textbox.c | 311 +++++++-------- scripts/config/mconf-cfg.sh | 31 +- scripts/config/mconf.c | 398 +++++++++---------- scripts/config/menu.c | 71 ++-- scripts/config/nconf-cfg.sh | 31 +- scripts/config/nconf.c | 121 +++++- scripts/config/nconf.gui.c | 37 +- scripts/config/nconf.h | 5 + scripts/config/parser.tab.c | 101 +++-- scripts/config/parser.tab.h | 4 +- scripts/config/preprocess.c | 5 +- scripts/config/qconf-cfg.sh | 34 +- scripts/config/qconf.cc | 40 +- scripts/config/symbol.c | 57 +-- scripts/config/util.c | 2 +- 28 files changed, 1411 insertions(+), 1012 deletions(-) create mode 100644 scripts/config/Kbuild.include diff --git a/scripts/config/.gitignore b/scripts/config/.gitignore index 05c55c3c8e..1cef9de10f 100644 --- a/scripts/config/.gitignore +++ b/scripts/config/.gitignore @@ -1,16 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only /conf /[gmnq]conf -/[gmnq]conf-cfg +/[gmnq]conf-bin +/[gmnq]conf-cflags +/[gmnq]conf-libs /qconf-moc.cc -# From linux kconfig parent directories -.* - -# OpenWrt-generated files +# +# Added by openwrt +# mconf_check - -# Temporary files from older versions. They should be removed after the -# end of support for OpenWrt 19.07. -zconf.???.c -zconf.hash.c +# The next line should be removed after 23.05 is EOL +*conf-cfg diff --git a/scripts/config/Kbuild.include b/scripts/config/Kbuild.include new file mode 100644 index 0000000000..7778cc97a4 --- /dev/null +++ b/scripts/config/Kbuild.include @@ -0,0 +1,279 @@ +# SPDX-License-Identifier: GPL-2.0 +#### +# kbuild: Generic definitions + +# Convenient variables +comma := , +quote := " +squote := ' +empty := +space := $(empty) $(empty) +space_escape := _-_SPACE_-_ +pound := \# +define newline + + +endef + +### +# Comparison macros. +# Usage: $(call test-lt, $(CONFIG_LLD_VERSION), 150000) +# +# Use $(intcmp ...) if supported. (Make >= 4.4) +# Otherwise, fall back to the 'test' shell command. +ifeq ($(intcmp 1,0,,,y),y) +test-ge = $(intcmp $(strip $1)0, $(strip $2)0,,y,y) +test-gt = $(intcmp $(strip $1)0, $(strip $2)0,,,y) +else +test-ge = $(shell test $(strip $1)0 -ge $(strip $2)0 && echo y) +test-gt = $(shell test $(strip $1)0 -gt $(strip $2)0 && echo y) +endif +test-le = $(call test-ge, $2, $1) +test-lt = $(call test-gt, $2, $1) + +### +# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o +dot-target = $(dir $@).$(notdir $@) + +### +# Name of target with a '.tmp_' as filename prefix. foo/bar.o => foo/.tmp_bar.o +tmp-target = $(dir $@).tmp_$(notdir $@) + +### +# The temporary file to save gcc -MMD generated dependencies must not +# contain a comma +depfile = $(subst $(comma),_,$(dot-target).d) + +### +# filename of target with directory and extension stripped +basetarget = $(basename $(notdir $@)) + +### +# real prerequisites without phony targets +real-prereqs = $(filter-out $(PHONY), $^) + +### +# Escape single quote for use in echo statements +escsq = $(subst $(squote),'\$(squote)',$1) + +### +# Quote a string to pass it to C files. foo => '"foo"' +stringify = $(squote)$(quote)$1$(quote)$(squote) + +### +# The path to Kbuild or Makefile. Kbuild has precedence over Makefile. +kbuild-dir = $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) +kbuild-file = $(or $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Makefile) + +### +# Read a file, replacing newlines with spaces +# +# Make 4.2 or later can read a file by using its builtin function. +ifneq ($(filter-out 3.% 4.0 4.1, $(MAKE_VERSION)),) +read-file = $(subst $(newline),$(space),$(file < $1)) +else +read-file = $(shell cat $1 2>/dev/null) +endif + +### +# Easy method for doing a status message + kecho := : + quiet_kecho := echo +silent_kecho := : +kecho := $($(quiet)kecho) + +### +# filechk is used to check if the content of a generated file is updated. +# Sample usage: +# +# filechk_sample = echo $(KERNELRELEASE) +# version.h: FORCE +# $(call filechk,sample) +# +# The rule defined shall write to stdout the content of the new file. +# The existing file will be compared with the new one. +# - If no file exist it is created +# - If the content differ the new file is used +# - If they are equal no change, and no timestamp update +define filechk + $(check-FORCE) + $(Q)set -e; \ + mkdir -p $(dir $@); \ + trap "rm -f $(tmp-target)" EXIT; \ + { $(filechk_$(1)); } > $(tmp-target); \ + if [ ! -r $@ ] || ! cmp -s $@ $(tmp-target); then \ + $(kecho) ' UPD $@'; \ + mv -f $(tmp-target) $@; \ + fi +endef + +### +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= +# Usage: +# $(Q)$(MAKE) $(build)=dir +build := -f $(srctree)/scripts/Makefile.build obj + +### +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= +# Usage: +# $(Q)$(MAKE) $(dtbinst)=dir +dtbinst := -f $(srctree)/scripts/Makefile.dtbinst obj + +### +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= +# Usage: +# $(Q)$(MAKE) $(clean)=dir +clean := -f $(srctree)/scripts/Makefile.clean obj + +# pring log +# +# If quiet is "silent_", print nothing and sink stdout +# If quiet is "quiet_", print short log +# If quiet is empty, print short log and whole command +silent_log_print = exec >/dev/null; + quiet_log_print = $(if $(quiet_cmd_$1), echo ' $(call escsq,$(quiet_cmd_$1)$(why))';) + log_print = echo '$(pound) $(call escsq,$(or $(quiet_cmd_$1),cmd_$1 $@)$(why))'; \ + echo ' $(call escsq,$(cmd_$1))'; + +# Delete the target on interruption +# +# GNU Make automatically deletes the target if it has already been changed by +# the interrupted recipe. So, you can safely stop the build by Ctrl-C (Make +# will delete incomplete targets), and resume it later. +# +# However, this does not work when the stderr is piped to another program, like +# $ make >&2 | tee log +# Make dies with SIGPIPE before cleaning the targets. +# +# To address it, we clean the target in signal traps. +# +# Make deletes the target when it catches SIGHUP, SIGINT, SIGQUIT, SIGTERM. +# So, we cover them, and also SIGPIPE just in case. +# +# Of course, this is unneeded for phony targets. +delete-on-interrupt = \ + $(if $(filter-out $(PHONY), $@), \ + $(foreach sig, HUP INT QUIT TERM PIPE, \ + trap 'rm -f $@; trap - $(sig); kill -s $(sig) $$$$' $(sig);)) + +# print and execute commands +cmd = @$(if $(cmd_$(1)),set -e; $($(quiet)log_print) $(delete-on-interrupt) $(cmd_$(1)),:) + +### +# if_changed - execute command if any prerequisite is newer than +# target, or command line has changed +# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies +# including used config symbols +# if_changed_rule - as if_changed but execute rule instead +# See Documentation/kbuild/makefiles.rst for more info + +ifneq ($(KBUILD_NOCMDDEP),1) +# Check if both commands are the same including their order. Result is empty +# string if equal. User may override this check using make KBUILD_NOCMDDEP=1 +# If the target does not exist, the *.cmd file should not be included so +# $(savedcmd_$@) gets empty. Then, target will be built even if $(newer-prereqs) +# happens to become empty. +cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(savedcmd_$@))), \ + $(subst $(space),$(space_escape),$(strip $(cmd_$1)))) +else +# We still need to detect missing targets. +cmd-check = $(if $(strip $(savedcmd_$@)),,1) +endif + +# Replace >$< with >$$< to preserve $ when reloading the .cmd file +# (needed for make) +# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file +# (needed for make) +# Replace >'< with >'\''< to be able to enclose the whole string in '...' +# (needed for the shell) +make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) + +# Find any prerequisites that are newer than target or that do not exist. +# PHONY targets skipped in both cases. +# If there is no prerequisite other than phony targets, $(newer-prereqs) becomes +# empty even if the target does not exist. cmd-check saves this corner case. +newer-prereqs = $(filter-out $(PHONY),$?) + +# It is a typical mistake to forget the FORCE prerequisite. Check it here so +# no more breakage will slip in. +check-FORCE = $(if $(filter FORCE, $^),,$(warning FORCE prerequisite is missing)) + +if-changed-cond = $(newer-prereqs)$(cmd-check)$(check-FORCE) + +# Execute command if command has changed or prerequisite(s) are updated. +if_changed = $(if $(if-changed-cond),$(cmd_and_savecmd),@:) + +cmd_and_savecmd = \ + $(cmd); \ + printf '%s\n' 'savedcmd_$@ := $(make-cmd)' > $(dot-target).cmd + +# Execute the command and also postprocess generated .d dependencies file. +if_changed_dep = $(if $(if-changed-cond),$(cmd_and_fixdep),@:) + +cmd_and_fixdep = \ + $(cmd); \ + scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\ + rm -f $(depfile) + +# Usage: $(call if_changed_rule,foo) +# Will check if $(cmd_foo) or any of the prerequisites changed, +# and if so will execute $(rule_foo). +if_changed_rule = $(if $(if-changed-cond),$(rule_$(1)),@:) + +### +# why - tell why a target got built +# enabled by make V=2 +# Output (listed in the order they are checked): +# (1) - due to target is PHONY +# (2) - due to target missing +# (3) - due to: file1.h file2.h +# (4) - due to command line change +# (5) - due to missing .cmd file +# (6) - due to target not in $(targets) +# (1) PHONY targets are always build +# (2) No target, so we better build it +# (3) Prerequisite is newer than target +# (4) The command line stored in the file named dir/.target.cmd +# differed from actual command line. This happens when compiler +# options changes +# (5) No dir/.target.cmd file (used to store command line) +# (6) No dir/.target.cmd file and target not listed in $(targets) +# This is a good hint that there is a bug in the kbuild file +ifneq ($(findstring 2, $(KBUILD_VERBOSE)),) +_why = \ + $(if $(filter $@, $(PHONY)),- due to target is PHONY, \ + $(if $(wildcard $@), \ + $(if $(newer-prereqs),- due to: $(newer-prereqs), \ + $(if $(cmd-check), \ + $(if $(savedcmd_$@),- due to command line change, \ + $(if $(filter $@, $(targets)), \ + - due to missing .cmd file, \ + - due to $(notdir $@) not in $$(targets) \ + ) \ + ) \ + ) \ + ), \ + - due to target missing \ + ) \ + ) + +why = $(space)$(strip $(_why)) +endif + +############################################################################### + +# delete partially updated (i.e. corrupted) files on error +.DELETE_ON_ERROR: + +# do not delete intermediate files automatically +# +# .NOTINTERMEDIATE is more correct, but only available on newer Make versions. +# Make 4.4 introduced .NOTINTERMEDIATE, and it appears in .FEATURES, but the +# global .NOTINTERMEDIATE does not work. We can use it on Make > 4.4. +# Use .SECONDARY for older Make versions, but "newer-prereq" cannot detect +# deleted files. +ifneq ($(and $(filter notintermediate, $(.FEATURES)),$(filter-out 4.4,$(MAKE_VERSION))),) +.NOTINTERMEDIATE: +else +.SECONDARY: +endif diff --git a/scripts/config/Makefile b/scripts/config/Makefile index 5976a91b9a..5e7dd9578e 100644 --- a/scripts/config/Makefile +++ b/scripts/config/Makefile @@ -5,46 +5,21 @@ .PHONY: clean all all: conf mconf clean: - rm -f *.o lxdialog/*.o *.moc .*.cmd $(clean-files) + rm -f $(clean-files) $(hostprogs) -# This clean-files definition is here to ensure that temporary files from the -# previous version are removed by make config-clean. -# It should be emptied after the end of support for OpenWrt 19.07. -clean-files := zconf.tab.c zconf.lex.c zconf.hash.c .tmp_qtcheck +clean-files := *.o lxdialog/*.o *.moc qconf-moc.cc \ + *conf-cfg # <- This should be removed after 23.05 is EOL # =========================================================================== # Variables needed by the upstream Makefile -# Avoids displaying 'UPD mconf-cfg' in an otherwise quiet make menuconfig -kecho:=true - +export HOSTPKG_CONFIG=pkg-config CONFIG_SHELL:=$(SHELL) -srctree:=. -src:=. +src:=$(CURDIR) obj:=. Q:=$(if $V,,@) -cmd = $(cmd_$(1)) - -# some definitions taken from ../Kbuild.include -dot-target = $(dir $@).$(notdir $@) -squote := ' -escsq = $(subst $(squote),'\$(squote)',$1) -define filechk - $(Q)set -e; \ - mkdir -p $(dir $@); \ - trap "rm -f $(dot-target).tmp" EXIT; \ - { $(filechk_$(1)); } > $(dot-target).tmp; \ - if [ ! -r $@ ] || ! cmp -s $@ $(dot-target).tmp; then \ - $(kecho) ' UPD $@'; \ - mv -f $(dot-target).tmp $@; \ - fi -endef -cmd-check = $(if $(strip $(cmd_$@)),,1) -make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) -newer-prereqs = $(filter-out $(PHONY),$?) -if_changed = $(if $(newer-prereqs)$(cmd-check), \ - $(cmd); \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) +quiet:=$(if $V,,_silent) +include Kbuild.include ### Stripped down upstream Makefile follows: # =========================================================================== @@ -64,11 +39,12 @@ conf-objs := conf.o $(common-objs) hostprogs += 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) +HOSTLDLIBS_nconf = $(call read-file, $(obj)/nconf-libs) +HOSTCFLAGS_nconf.o = $(call read-file, $(obj)/nconf-cflags) +HOSTCFLAGS_nconf.gui.o = $(call read-file, $(obj)/nconf-cflags) -$(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/nconf-cfg +$(obj)/nconf: | $(obj)/nconf-libs +$(obj)/nconf.o $(obj)/nconf.gui.o: | $(obj)/nconf-cflags # mconf: Used for the menuconfig target based on lxdialog hostprogs += mconf @@ -76,45 +52,44 @@ lxdialog := $(addprefix lxdialog/, \ checklist.o inputbox.o menubox.o textbox.o util.o yesno.o) mconf-objs := mconf.o $(lxdialog) $(common-objs) -HOSTLDLIBS_mconf = $(shell . $(obj)/mconf-cfg && echo $$libs) +HOSTLDLIBS_mconf = $(call read-file, $(obj)/mconf-libs) $(foreach f, mconf.o $(lxdialog), \ - $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/mconf-cfg && echo $$$$cflags))) + $(eval HOSTCFLAGS_$f = $$(call read-file, $(obj)/mconf-cflags))) -$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/mconf-cfg +$(obj)/mconf: | $(obj)/mconf-libs +$(addprefix $(obj)/, mconf.o $(lxdialog)): | $(obj)/mconf-cflags # qconf: Used for the xconfig target based on Qt hostprogs += qconf qconf-cxxobjs := qconf.o qconf-moc.o qconf-objs := images.o $(common-objs) -HOSTLDLIBS_qconf = $(shell . $(obj)/qconf-cfg && echo $$libs) -HOSTCXXFLAGS_qconf.o = $(shell . $(obj)/qconf-cfg && echo $$cflags) -HOSTCXXFLAGS_qconf-moc.o = $(shell . $(obj)/qconf-cfg && echo $$cflags) - -$(obj)/qconf.o: $(obj)/qconf-cfg +HOSTLDLIBS_qconf = $(call read-file, $(obj)/qconf-libs) +HOSTCXXFLAGS_qconf.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags) +HOSTCXXFLAGS_qconf-moc.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags) +$(obj)/qconf: | $(obj)/qconf-libs +$(obj)/qconf.o $(obj)/qconf-moc.o: | $(obj)/qconf-cflags quiet_cmd_moc = MOC $@ - cmd_moc = $(shell . $(obj)/qconf-cfg && echo $$moc) $< -o $@ + cmd_moc = $(call read-file, $(obj)/qconf-bin)/moc $< -o $@ -$(obj)/qconf-moc.cc: $(src)/qconf.h $(obj)/qconf-cfg FORCE +$(obj)/qconf-moc.cc: $(src)/qconf.h FORCE | $(obj)/qconf-bin $(call if_changed,moc) targets += qconf-moc.cc # check if necessary packages are available, and configure build flags -filechk_conf_cfg = $(CONFIG_SHELL) $< +cmd_conf_cfg = $< $(addprefix $(obj)/$*conf-, cflags libs bin); touch $(obj)/$*conf-bin -$(obj)/%conf-cfg: $(src)/%conf-cfg.sh FORCE - $(call filechk,conf_cfg) +$(obj)/%conf-cflags $(obj)/%conf-libs $(obj)/%conf-bin: $(src)/%conf-cfg.sh + $(call cmd,conf_cfg) -clean-files += *conf-cfg +clean-files += *conf-cflags *conf-libs *conf-bin # =========================================================================== # OpenWrt rules and final adjustments that need to be made after reading the # full upstream Makefile -clean-files += $(targets) $(hostprogs) - FORCE: ifdef BUILD_SHIPPED_FILES @@ -130,25 +105,21 @@ clean-files += $(shipped-files) flex -L -o$@ $< endif -$(foreach f,$(conf-objs) $(filter-out $(common-objs),$(mconf-objs) \ - $(qconf-objs) \ - $(nconf-objs)), \ - $(eval $(obj)/$f: CFLAGS+=$$(HOSTCFLAGS_$f))) +define link_rule +$(1): LDLIBS+=$$(HOSTLDLIBS_$(1)) +$(1): $($(1)-objs) $$($(1)-cxxobjs) +$(if $($(1)-cxxobjs), $(CXX) $$(LDFLAGS) -o $$@ $$^ $$(LDLIBS)) +all-objs += $($(1)-objs) +all-cxxobjs += $($(1)-cxxobjs) +endef -$(foreach f,$(qconf-cxxobjs), \ - $(eval $(obj)/$f: CXXFLAGS+=$$(HOSTCXXFLAGS_$f))) +all-objs:= +all-cxxobjs:= +$(foreach f,$(hostprogs),$(eval $(call link_rule,$f))) -$(obj)/conf: $(addprefix $(obj)/,$(conf-objs)) -# The *conf-cfg file is used (then filtered out) as the first prerequisite to -# avoid sourcing it before the script is built, when trying to compute CFLAGS -# for the actual first prerequisite. This avoids errors like: -# '/bin/sh: ./mconf-cfg: No such file or directory' -$(obj)/mconf: mconf-cfg $(addprefix $(obj)/,$(mconf-objs)) - $(CC) -o $@ $(filter-out mconf-cfg,$^) $(HOSTLDLIBS_mconf) +$(foreach f,$(sort $(all-objs)), \ + $(eval $f: CFLAGS+=$$(HOSTCFLAGS_$f))) -$(obj)/nconf: nconf-cfg $(addprefix $(obj)/,$(nconf-objs)) - $(CC) -o $@ $(filter-out nconf-cfg,$^) $(HOSTLDLIBS_nconf) - -$(obj)/qconf: qconf-cfg $(addprefix $(obj)/,$(qconf-cxxobjs) $(qconf-objs)) - $(CXX) -o $@ $(filter-out qconf-cfg,$^) $(HOSTLDLIBS_qconf) +$(foreach f,$(sort $(all-cxxobjs)), \ + $(eval $f: CXXFLAGS+=$$(HOSTCXXFLAGS_$f))) diff --git a/scripts/config/README b/scripts/config/README index 99a7d535ab..e1ebf89cbf 100644 --- a/scripts/config/README +++ b/scripts/config/README @@ -1,6 +1,7 @@ -These files were taken from the Linux 5.14 Kernel Configuration System and -modified for the OpenWrt Buildroot: - - Removed nconf, gconf, tests and kernel configuration targets. +These files were taken from the Linux Kernel Configuration System v6.6.16, +at commit eb3e299184cc4f40d4bd84fda269b3a20ddcff80 (Feb 5, 2024), and modified +for the OpenWrt Buildroot: + - Removed gconf, tests and kernel configuration targets. - Adjusted the Makefile to compile outside the kernel. - Always use default file when running make all{no,mod,yes}config. - Added a 'reset' command to reset config when the target changes. @@ -23,4 +24,4 @@ modified for the OpenWrt Buildroot: BUILD_SHIPPED_FILES defined For a full list of changes, see the repository at: -https://github.com/cotequeiroz/linux/commits/openwrt-5.14/scripts/kconfig +https://github.com/cotequeiroz/linux/commits/openwrt-v6.6.16/scripts/kconfig diff --git a/scripts/config/conf.c b/scripts/config/conf.c index 978abebe65..1bd6f4fa8b 100644 --- a/scripts/config/conf.c +++ b/scripts/config/conf.c @@ -35,6 +35,7 @@ enum input_mode { olddefconfig, yes2modconfig, mod2yesconfig, + mod2noconfig, fatalrecursive, }; static enum input_mode input_mode = oldaskconfig; @@ -164,8 +165,6 @@ enum conf_def_mode { def_default, def_yes, def_mod, - def_y2m, - def_m2y, def_no, def_random }; @@ -303,12 +302,10 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode) return has_changed; } -static void conf_rewrite_mod_or_yes(enum conf_def_mode mode) +static void conf_rewrite_tristates(tristate old_val, tristate new_val) { struct symbol *sym; int i; - tristate old_val = (mode == def_y2m) ? yes : mod; - tristate new_val = (mode == def_y2m) ? mod : yes; for_all_symbols(i, sym) { if (sym_get_type(sym) == S_TRISTATE && @@ -555,7 +552,7 @@ static int conf_choice(struct menu *menu) print_help(child); continue; } - sym_set_choice_value(sym, child->sym); + sym_set_tristate_value(child->sym, yes); for (child = child->list; child; child = child->next) { indent += 2; conf(child); @@ -647,19 +644,8 @@ static void check_conf(struct menu *menu) switch (input_mode) { case 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); - } - } + if (sym->name) + print_symbol_for_listconfig(sym); break; case helpnewconfig: printf("-----\n"); @@ -697,7 +683,8 @@ static const struct option long_opts[] = { {"olddefconfig", no_argument, &input_mode_opt, olddefconfig}, {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig}, {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig}, - {"fatalrecursive",no_argument, NULL, fatalrecursive}, + {"mod2noconfig", no_argument, &input_mode_opt, mod2noconfig}, + {"fatalrecursive",no_argument, &input_mode_opt, fatalrecursive}, {NULL, 0, NULL, 0} }; @@ -707,8 +694,10 @@ static void conf_usage(const char *progname) printf("\n"); printf("Generic options:\n"); printf(" -h, --help Print this message and exit.\n"); + printf(" -r Read as input.\n"); printf(" -s, --silent Do not print log.\n"); - printf(" --fatalrecursive Treat recursive depenendencies as a fatal error\n"); + printf(" -w Write config to .\n"); + printf(" --fatalrecursive Treat recursive dependency as error.\n"); printf("\n"); printf("Mode options:\n"); printf(" --listnewconfig List new options\n"); @@ -727,6 +716,7 @@ static void conf_usage(const char *progname) printf(" --randconfig New config with random answer to all options\n"); printf(" --yes2modconfig Change answers from yes to mod if possible\n"); printf(" --mod2yesconfig Change answers from mod to yes if possible\n"); + printf(" --mod2noconfig Change answers from mod to no if possible\n"); printf(" (If none of the above is given, --oldaskconfig is the default)\n"); } @@ -740,27 +730,23 @@ int main(int ac, char **av) tty_stdio = isatty(0) && isatty(1); - while ((opt = getopt_long(ac, av, "hr:sw:", long_opts, NULL)) != -1) { + while ((opt = getopt_long(ac, av, "hr:w:s", long_opts, NULL)) != -1) { switch (opt) { case 'h': conf_usage(progname); exit(1); break; - case 's': - conf_set_message_callback(NULL); - break; - case fatalrecursive: - recursive_is_error = 1; - continue; case 'r': input_file = optarg; break; + case 's': + conf_set_message_callback(NULL); + break; case 'w': output_file = optarg; break; case 0: - input_mode = input_mode_opt; - switch (input_mode) { + switch (input_mode_opt) { case syncconfig: /* * syncconfig is invoked during the build stage. @@ -777,9 +763,13 @@ int main(int ac, char **av) case randconfig: set_randconfig_seed(); break; + case fatalrecursive: + recursive_is_error = 1; + continue; default: break; } + input_mode = input_mode_opt; default: break; } @@ -812,6 +802,7 @@ int main(int ac, char **av) case olddefconfig: case yes2modconfig: case mod2yesconfig: + case mod2noconfig: case allnoconfig: case allyesconfig: case allmodconfig: @@ -858,10 +849,13 @@ int main(int ac, char **av) case savedefconfig: break; case yes2modconfig: - conf_rewrite_mod_or_yes(def_y2m); + conf_rewrite_tristates(yes, mod); break; case mod2yesconfig: - conf_rewrite_mod_or_yes(def_m2y); + conf_rewrite_tristates(mod, yes); + break; + case mod2noconfig: + conf_rewrite_tristates(mod, no); break; case oldaskconfig: rootEntry = &rootmenu; diff --git a/scripts/config/confdata.c b/scripts/config/confdata.c index dad0b471c7..e3f6fdfeb3 100644 --- a/scripts/config/confdata.c +++ b/scripts/config/confdata.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -129,41 +130,22 @@ static size_t depfile_prefix_len; /* touch depfile for symbol 'name' */ static int conf_touch_dep(const char *name) { - int fd, ret; - char *d; + int fd; /* check overflow: prefix + name + '\0' must fit in buffer. */ if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path)) return -1; - d = depfile_path + depfile_prefix_len; - strcpy(d, name); + strcpy(depfile_path + depfile_prefix_len, name); - /* 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; - } + 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))); @@ -227,6 +209,20 @@ static const char *conf_get_autoconfig_name(void) return name ? name : "include/config/auto.conf"; } +static const char *conf_get_autoheader_name(void) +{ + char *name = getenv("KCONFIG_AUTOHEADER"); + + return name ? name : "include/generated/autoconf.h"; +} + +static const char *conf_get_rustccfg_name(void) +{ + char *name = getenv("KCONFIG_RUSTCCFG"); + + return name ? name : "include/generated/rustc_cfg"; +} + static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) { char *p2; @@ -255,19 +251,21 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) p, sym->name); return 1; case S_STRING: - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; + /* No escaping for S_DEF_AUTO (include/config/auto.conf) */ + if (def != S_DEF_AUTO) { + if (*p++ != '"') break; + for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { + if (*p2 == '"') { + *p2 = 0; + break; + } + memmove(p2, p2 + 1, strlen(p2)); } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - if (def != S_DEF_AUTO) + if (!p2) { conf_warning("invalid string found"); - return 1; + return 1; + } } /* fall through */ case S_INT: @@ -376,7 +374,11 @@ int conf_read_simple(const char *name, int def) char *p, *p2; struct symbol *sym; int def_flags; + const char *warn_unknown; + const char *werror; + warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS"); + werror = getenv("KCONFIG_WERROR"); if (name) { in = zconf_fopen(name); } else { @@ -448,6 +450,10 @@ load: if (def == S_DEF_USER) { sym = sym_find(line + 2 + strlen(CONFIG_)); if (!sym) { + if (warn_unknown) + conf_warning("unknown symbol: %s", + line + 2 + strlen(CONFIG_)); + conf_set_changed(true); continue; } @@ -479,7 +485,7 @@ load: sym = sym_find(line + strlen(CONFIG_)); if (!sym) { - if (def == S_DEF_AUTO) + if (def == S_DEF_AUTO) { /* * Reading from include/config/auto.conf * If CONFIG_FOO previously existed in @@ -487,8 +493,13 @@ load: * include/config/FOO must be touched. */ conf_touch_dep(line + strlen(CONFIG_)); - else + } else { + if (warn_unknown) + conf_warning("unknown symbol: %s", + line + strlen(CONFIG_)); + conf_set_changed(true); + } continue; } @@ -524,6 +535,10 @@ load: } free(line); fclose(in); + + if (conf_warnings && werror) + exit(1); + return 0; } @@ -597,169 +612,226 @@ int conf_read(const char *name) 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) +struct comment_style { + const char *decoration; + const char *prefix; + const char *postfix; +}; + +static const struct comment_style comment_style_pound = { + .decoration = "#", + .prefix = "#", + .postfix = "#", +}; + +static const struct comment_style comment_style_c = { + .decoration = " *", + .prefix = "/*", + .postfix = " */", +}; + +static void conf_write_heading(FILE *fp, const struct comment_style *cs) { + if (!cs) + return; + + fprintf(fp, "%s\n", cs->prefix); + + fprintf(fp, "%s Automatically generated file; DO NOT EDIT.\n", + cs->decoration); + + fprintf(fp, "%s %s\n", cs->decoration, rootmenu.prompt->text); + + fprintf(fp, "%s\n", cs->postfix); +} + +/* The returned pointer must be freed on the caller side */ +static char *escape_string_value(const char *in) +{ + const char *p; + char *out; + size_t len; + + len = strlen(in) + strlen("\"\"") + 1; + + p = in; + while (1) { + p += strcspn(p, "\"\\"); + + if (p[0] == '\0') + break; + + len++; + p++; + } + + out = xmalloc(len); + out[0] = '\0'; + + strcat(out, "\""); + + p = in; + while (1) { + len = strcspn(p, "\"\\"); + strncat(out, p, len); + p += len; + + if (p[0] == '\0') + break; + + strcat(out, "\\"); + strncat(out, p++, 1); + } + + strcat(out, "\""); + + return out; +} + +enum output_n { OUTPUT_N, OUTPUT_N_AS_UNSET, OUTPUT_N_NONE }; + +static void __print_symbol(FILE *fp, struct symbol *sym, enum output_n output_n, + bool escape_string) +{ + const char *val; + char *escaped = NULL; + + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); + + if ((sym->type == S_BOOLEAN || sym->type == S_TRISTATE) && + output_n != OUTPUT_N && *val == 'n') { + if (output_n == OUTPUT_N_AS_UNSET) + fprintf(fp, "# %s%s is not set\n", CONFIG_, sym->name); + return; + } + + if (sym->type == S_STRING && escape_string) { + escaped = escape_string_value(val); + val = escaped; + } + + fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, val); + + free(escaped); +} + +static void print_symbol_for_dotconfig(FILE *fp, struct symbol *sym) +{ + __print_symbol(fp, sym, OUTPUT_N_AS_UNSET, true); +} + +static void print_symbol_for_autoconf(FILE *fp, struct symbol *sym) +{ + __print_symbol(fp, sym, OUTPUT_N_NONE, false); +} + +void print_symbol_for_listconfig(struct symbol *sym) +{ + __print_symbol(stdout, sym, OUTPUT_N, true); +} + +static void print_symbol_for_c(FILE *fp, struct symbol *sym) +{ + const char *val; + const char *sym_suffix = ""; + const char *val_prefix = ""; + char *escaped = NULL; + + if (sym->type == S_UNKNOWN) + return; + + val = sym_get_string_value(sym); 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); + switch (*val) { + case 'n': return; + case 'm': + sym_suffix = "_MODULE"; + /* fall through */ + default: + val = "1"; } break; + case S_HEX: + if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) + val_prefix = "0x"; + break; + case S_STRING: + escaped = escape_string_value(val); + val = escaped; default: break; } - fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); + fprintf(fp, "#define %s%s%s %s%s\n", CONFIG_, sym->name, sym_suffix, + val_prefix, val); + + free(escaped); } -static void -kconfig_print_comment(FILE *fp, const char *value, void *arg) +static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym) { - const char *p = value; - size_t l; + const char *val; + const char *val_prefix = ""; + char *val_prefixed = NULL; + size_t val_prefixed_len; + char *escaped = NULL; - 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; - } -} + if (sym->type == S_UNKNOWN) + return; -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) -{ + val = sym_get_string_value(sym); switch (sym->type) { case S_BOOLEAN: - case S_TRISTATE: { - const char *suffix = ""; + case S_TRISTATE: + /* + * We do not care about disabled ones, i.e. no need for + * what otherwise are "comments" in other printers. + */ + if (*val == 'n') + return; - switch (*value) { - case 'n': - break; - case 'm': - suffix = "_MODULE"; - /* fall through */ - default: - fprintf(fp, "#define %s%s%s 1\n", - CONFIG_, sym->name, suffix); - } + /* + * To have similar functionality to the C macro `IS_ENABLED()` + * we provide an empty `--cfg CONFIG_X` here in both `y` + * and `m` cases. + * + * Then, the common `fprintf()` below will also give us + * a `--cfg CONFIG_X="y"` or `--cfg CONFIG_X="m"`, which can + * be used as the equivalent of `IS_BUILTIN()`/`IS_MODULE()`. + */ + fprintf(fp, "--cfg=%s%s\n", CONFIG_, sym->name); 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); + case S_HEX: + if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X')) + val_prefix = "0x"; 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; + if (strlen(val_prefix) > 0) { + val_prefixed_len = strlen(val) + strlen(val_prefix) + 1; + val_prefixed = xmalloc(val_prefixed_len); + snprintf(val_prefixed, val_prefixed_len, "%s%s", val_prefix, val); + val = val_prefixed; } - fprintf(fp, " */\n"); -} -static struct conf_printer header_printer_cb = -{ - .print_symbol = header_print_symbol, - .print_comment = header_print_comment, -}; + /* All values get escaped: the `--cfg` option only takes strings */ + escaped = escape_string_value(val); + val = escaped; -static void conf_write_symbol(FILE *fp, struct symbol *sym, - struct conf_printer *printer, void *printer_arg) -{ - const char *str; + fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val); - 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); + free(escaped); + free(val_prefixed); } /* @@ -818,7 +890,7 @@ int conf_write_defconfig(const char *filename) goto next_menu; } } - conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + print_symbol_for_dotconfig(out, sym); } next_menu: if (menu->list != NULL) { @@ -878,7 +950,7 @@ int conf_write(const char *name) if (!out) return 1; - conf_write_heading(out, &kconfig_printer_cb, NULL); + conf_write_heading(out, &comment_style_pound); if (!conf_get_changed()) sym_clear_all_valid(); @@ -905,7 +977,7 @@ int conf_write(const char *name) need_newline = false; } sym->flags |= SYMBOL_WRITTEN; - conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); + print_symbol_for_dotconfig(out, sym); } next: @@ -913,19 +985,20 @@ next: menu = menu->list; continue; } - if (menu->next) + +end_check: + if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu && + menu->prompt->type == P_MENU) { + fprintf(out, "# end of %s\n", menu_get_prompt(menu)); + need_newline = true; + } + + 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; - } + } else { + menu = menu->parent; + if (menu) + goto end_check; } } fclose(out); @@ -955,45 +1028,69 @@ next: } /* write a dependency file as used by kbuild to track dependencies */ -static int conf_write_dep(const char *name) +static int conf_write_autoconf_cmd(const char *autoconf_name) { + char name[PATH_MAX], tmp[PATH_MAX]; struct file *file; FILE *out; + int ret; - 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); + ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name); + if (ret >= sizeof(name)) /* check truncation */ + return -1; if (make_parent_dir(name)) - return 1; - rename("..config.tmp", name); + return -1; + + ret = snprintf(tmp, sizeof(tmp), "%s.cmd.tmp", autoconf_name); + if (ret >= sizeof(tmp)) /* check truncation */ + return -1; + + out = fopen(tmp, "w"); + if (!out) { + perror("fopen"); + return -1; + } + + fprintf(out, "deps_config := \\\n"); + for (file = file_list; file; file = file->next) + fprintf(out, "\t%s \\\n", file->name); + + fprintf(out, "\n%s: $(deps_config)\n\n", autoconf_name); + + env_write_dep(out, autoconf_name); + + fprintf(out, "\n$(deps_config): ;\n"); + + fflush(out); + ret = ferror(out); /* error check for all fprintf() calls */ + fclose(out); + if (ret) + return -1; + + if (rename(tmp, name)) { + perror("rename"); + return -1; + } + return 0; } static int conf_touch_deps(void) { - const char *name; + const char *name, *tmp; struct symbol *sym; int res, i; - strcpy(depfile_path, "include/config/"); - depfile_prefix_len = strlen(depfile_path); - name = conf_get_autoconfig_name(); + tmp = strrchr(name, '/'); + depfile_prefix_len = tmp ? tmp - name + 1 : 0; + if (depfile_prefix_len + 1 > sizeof(depfile_path)) + return -1; + + strncpy(depfile_path, name, depfile_prefix_len); + depfile_path[depfile_prefix_len] = 0; + conf_read_simple(name, S_DEF_AUTO); sym_calc_value(modules_sym); @@ -1056,13 +1153,54 @@ static int conf_touch_deps(void) return 0; } +static int __conf_write_autoconf(const char *filename, + void (*print_symbol)(FILE *, struct symbol *), + const struct comment_style *comment_style) +{ + char tmp[PATH_MAX]; + FILE *file; + struct symbol *sym; + int ret, i; + + if (make_parent_dir(filename)) + return -1; + + ret = snprintf(tmp, sizeof(tmp), "%s.tmp", filename); + if (ret >= sizeof(tmp)) /* check truncation */ + return -1; + + file = fopen(tmp, "w"); + if (!file) { + perror("fopen"); + return -1; + } + + conf_write_heading(file, comment_style); + + for_all_symbols(i, sym) + if ((sym->flags & SYMBOL_WRITE) && sym->name) + print_symbol(file, sym); + + fflush(file); + /* check possible errors in conf_write_heading() and print_symbol() */ + ret = ferror(file); + fclose(file); + if (ret) + return -1; + + if (rename(tmp, filename)) { + perror("rename"); + return -1; + } + + return 0; +} + int conf_write_autoconf(int overwrite) { struct symbol *sym; - const char *name; const char *autoconf_name = conf_get_autoconfig_name(); - FILE *out, *out_h; - int i; + int ret, i; #ifndef OPENWRT_DOES_NOT_WANT_THIS return 0; @@ -1070,52 +1208,38 @@ int conf_write_autoconf(int overwrite) if (!overwrite && is_present(autoconf_name)) return 0; - conf_write_dep("include/config/auto.conf.cmd"); + ret = conf_write_autoconf_cmd(autoconf_name); + if (ret) + return -1; if (conf_touch_deps()) return 1; - out = fopen(".tmpconfig", "w"); - if (!out) - return 1; - - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) { - fclose(out); - return 1; - } - - conf_write_heading(out, &kconfig_printer_cb, NULL); - conf_write_heading(out_h, &header_printer_cb, NULL); - - for_all_symbols(i, sym) { + for_all_symbols(i, sym) sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE) || !sym->name) - continue; - /* write symbols to auto.conf and autoconf.h */ - conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); - conf_write_symbol(out_h, sym, &header_printer_cb, NULL); - } - fclose(out); - fclose(out_h); + ret = __conf_write_autoconf(conf_get_autoheader_name(), + print_symbol_for_c, + &comment_style_c); + if (ret) + return ret; - 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; + ret = __conf_write_autoconf(conf_get_rustccfg_name(), + print_symbol_for_rustccfg, + NULL); + if (ret) + return ret; - 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. + * Create include/config/auto.conf. This must be the last step because + * Kbuild has a dependency on auto.conf and this marks the successful + * completion of the previous steps. */ - if (rename(".tmpconfig", autoconf_name)) - return 1; + ret = __conf_write_autoconf(conf_get_autoconfig_name(), + print_symbol_for_autoconf, + &comment_style_pound); + if (ret) + return ret; return 0; } @@ -1125,10 +1249,12 @@ static void (*conf_changed_callback)(void); void conf_set_changed(bool val) { - if (conf_changed_callback && conf_changed != val) - conf_changed_callback(); + bool changed = conf_changed != val; conf_changed = val; + + if (conf_changed_callback && changed) + conf_changed_callback(); } bool conf_get_changed(void) diff --git a/scripts/config/expr.h b/scripts/config/expr.h index c2fa804fe1..005e27f130 100644 --- a/scripts/config/expr.h +++ b/scripts/config/expr.h @@ -276,7 +276,6 @@ struct jump_key { struct list_head entries; size_t offset; struct menu *target; - int index; }; extern struct file *file_list; diff --git a/scripts/config/lexer.l b/scripts/config/lexer.l index 0df51ec468..e73b262539 100644 --- a/scripts/config/lexer.l +++ b/scripts/config/lexer.l @@ -86,8 +86,7 @@ static void warn_ignored_character(char chr) n [A-Za-z0-9_-] %% - int str = 0; - int ts, i; + char open_quote = 0; #.* /* ignore comment */ [ \t]* /* whitespaces */ @@ -137,7 +136,7 @@ n [A-Za-z0-9_-] ":=" return T_COLON_EQUAL; "+=" return T_PLUS_EQUAL; \"|\' { - str = yytext[0]; + open_quote = yytext[0]; new_string(); BEGIN(STRING); } @@ -174,7 +173,7 @@ n [A-Za-z0-9_-] append_string(yytext + 1, yyleng - 1); } \'|\" { - if (str == yytext[0]) { + if (open_quote == yytext[0]) { BEGIN(INITIAL); yylval.string = text; return T_WORD_QUOTE; @@ -199,6 +198,8 @@ n [A-Za-z0-9_-] { [ \t]+ { + int ts, i; + ts = 0; for (i = 0; i < yyleng; i++) { if (yytext[i] == '\t') diff --git a/scripts/config/lexer.lex.c b/scripts/config/lexer.lex.c index 826c06e4e7..c57119fa23 100644 --- a/scripts/config/lexer.lex.c +++ b/scripts/config/lexer.lex.c @@ -14,6 +14,7 @@ /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ + #include #include #include @@ -30,8 +31,8 @@ #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. +/* C++ systems might need __STDC_LIMIT_MACROS defined before including + * , if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 @@ -2538,8 +2539,7 @@ YY_DECL { - int str = 0; - int ts, i; + char open_quote = 0; while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -2772,7 +2772,7 @@ return T_PLUS_EQUAL; case 48: YY_RULE_SETUP { - str = yytext[0]; + open_quote = yytext[0]; new_string(); BEGIN(STRING); } @@ -2837,7 +2837,7 @@ YY_RULE_SETUP case 58: YY_RULE_SETUP { - if (str == yytext[0]) { + if (open_quote == yytext[0]) { BEGIN(INITIAL); yylval.string = text; return T_WORD_QUOTE; @@ -2869,6 +2869,8 @@ case YY_STATE_EOF(STRING): case 60: YY_RULE_SETUP { + int ts, i; + ts = 0; for (i = 0; i < yyleng; i++) { if (yytext[i] == '\t') diff --git a/scripts/config/lkc.h b/scripts/config/lkc.h index a7b18b2276..1c8717de78 100644 --- a/scripts/config/lkc.h +++ b/scripts/config/lkc.h @@ -77,7 +77,7 @@ 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); +char *str_get(struct gstr *gs); /* menu.c */ void _menu_init(void); @@ -100,10 +100,10 @@ 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); +int get_jump_key_char(void); struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); void menu_get_ext_help(struct menu *menu, struct gstr *help); @@ -126,11 +126,6 @@ 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; diff --git a/scripts/config/lkc_proto.h b/scripts/config/lkc_proto.h index ebedd230b3..4babf6435a 100644 --- a/scripts/config/lkc_proto.h +++ b/scripts/config/lkc_proto.h @@ -19,7 +19,7 @@ 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); +void print_symbol_for_listconfig(struct symbol *sym); struct symbol ** sym_re_search(const char *pattern); const char * sym_type_name(enum symbol_type type); void sym_calc_value(struct symbol *sym); diff --git a/scripts/config/lxdialog/dialog.h b/scripts/config/lxdialog/dialog.h index 3930d93a4a..3128bd6d76 100644 --- a/scripts/config/lxdialog/dialog.h +++ b/scripts/config/lxdialog/dialog.h @@ -18,22 +18,6 @@ #endif #include -/* - * 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 @@ -212,27 +196,12 @@ 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_textbox(const char *title, const char *tbuf, int initial_height, + int initial_width, int *_vscroll, int *_hscroll, + int (*extra_key_cb)(int, size_t, size_t, void *), 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/scripts/config/lxdialog/menubox.c b/scripts/config/lxdialog/menubox.c index 4287745566..bcdf3bbac9 100644 --- a/scripts/config/lxdialog/menubox.c +++ b/scripts/config/lxdialog/menubox.c @@ -63,15 +63,7 @@ static void do_print_item(WINDOW * win, const char *item, int line_y, /* 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) { diff --git a/scripts/config/lxdialog/textbox.c b/scripts/config/lxdialog/textbox.c index b5987735b0..e02acb7493 100644 --- a/scripts/config/lxdialog/textbox.c +++ b/scripts/config/lxdialog/textbox.c @@ -8,41 +8,149 @@ #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; +static const char *buf, *page; +static size_t start, end; + +/* + * 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++; + } +} + +/* + * 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 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 */ + wclrtoeol(win); +} + +/* + * Print a new page of text. + */ +static void print_page(WINDOW *win, int height, int width) +{ + int i, passed_end = 0; + + 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 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); +} /* * 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) + int cur_y, int cur_x) { - print_page(box, boxh, boxw, update_text, data); + start = page - buf; + + print_page(box, boxh, boxw); print_position(dialog); wmove(dialog, cur_y, cur_x); /* Restore cursor position */ wrefresh(dialog); -} + end = page - buf; +} /* * 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 dialog_textbox(const char *title, const char *tbuf, int initial_height, + int initial_width, int *_vscroll, int *_hscroll, + int (*extra_key_cb)(int, size_t, size_t, void *), void *data) { int i, x, y, cur_x, cur_y, key = 0; int height, width, boxh, boxw; @@ -122,8 +230,7 @@ do_resize: /* 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); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); while (!done) { key = wgetch(dialog); @@ -142,8 +249,7 @@ do_resize: begin_reached = 1; page = buf; refresh_text_box(dialog, box, boxh, boxw, - cur_y, cur_x, update_text, - data); + cur_y, cur_x); } break; case 'G': /* Last page */ @@ -153,8 +259,7 @@ do_resize: /* 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); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'K': /* Previous line */ case 'k': @@ -163,8 +268,7 @@ do_resize: break; back_lines(page_length + 1); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'B': /* Previous page */ case 'b': @@ -173,8 +277,7 @@ do_resize: if (begin_reached) break; back_lines(page_length + boxh); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'J': /* Next line */ case 'j': @@ -183,8 +286,7 @@ do_resize: break; back_lines(page_length - 1); - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case KEY_NPAGE: /* Next page */ case ' ': @@ -193,8 +295,7 @@ do_resize: break; begin_reached = 0; - refresh_text_box(dialog, box, boxh, boxw, cur_y, - cur_x, update_text, data); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case '0': /* Beginning of line */ case 'H': /* Scroll left */ @@ -209,8 +310,7 @@ do_resize: 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); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case 'L': /* Scroll right */ case 'l': @@ -220,8 +320,7 @@ do_resize: 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); + refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x); break; case KEY_ESC: if (on_key_esc(dialog) == KEY_ESC) @@ -234,11 +333,9 @@ do_resize: on_key_resize(); goto do_resize; default: - for (i = 0; keys[i]; i++) { - if (key == keys[i]) { - done = true; - break; - } + if (extra_key_cb && extra_key_cb(key, start, end, data)) { + done = true; + break; } } } @@ -259,137 +356,3 @@ do_resize: *_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/scripts/config/mconf-cfg.sh b/scripts/config/mconf-cfg.sh index 3572369288..4e48cc1d57 100755 --- a/scripts/config/mconf-cfg.sh +++ b/scripts/config/mconf-cfg.sh @@ -1,19 +1,22 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-only +cflags=$1 +libs=$2 + 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)\" +if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then + if ${HOSTPKG_CONFIG} --exists $PKG; then + ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs} exit 0 fi - if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" + if ${HOSTPKG_CONFIG} --exists ${PKG2}; then + ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs} exit 0 fi fi @@ -22,22 +25,22 @@ fi # (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\" + echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags} + echo -lncursesw > ${libs} exit 0 fi if [ -f /usr/include/ncurses/ncurses.h ]; then - echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\" - echo libs=\"-lncurses\" + echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags} + echo -lncurses > ${libs} exit 0 fi # As a final fallback before giving up, check if $HOSTCC knows of a default # ncurses installation (e.g. from a vendor-specific sysroot). if echo '#include ' | ${HOSTCC} -E - >/dev/null 2>&1; then - echo cflags=\"-D_GNU_SOURCE\" - echo libs=\"-lncurses\" + echo -D_GNU_SOURCE > ${cflags} + echo -lncurses > ${libs} exit 0 fi @@ -46,7 +49,7 @@ 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 "*" -echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" echo >&2 "* ncurses installed in a non-default location." echo >&2 "*" exit 1 diff --git a/scripts/config/mconf.c b/scripts/config/mconf.c index 81d232b665..d357cf1100 100644 --- a/scripts/config/mconf.c +++ b/scripts/config/mconf.c @@ -22,8 +22,6 @@ #include "lkc.h" #include "lxdialog/dialog.h" -#define JUMP_NB 9 - static const char mconf_readme[] = "OpenWrt config is based on Kernel kconfig\n" "so ipkg packages are referred here as modules.\n" @@ -164,6 +162,12 @@ static const char mconf_readme[] = "(especially with a larger number of unrolled categories) than the\n" "default mode.\n" "\n" + +"Search\n" +"-------\n" +"Pressing the forward-slash (/) anywhere brings up a search dialog box.\n" +"\n" + "Different color themes available\n" "--------------------------------\n" "It is possible to select different color themes using the variable\n" @@ -285,18 +289,9 @@ static int single_menu_mode; static int show_all_options; static int save_and_exit; static int silent; +static int jump_key_char; 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) @@ -355,37 +350,87 @@ static void reset_subtitle(void) set_dialog_subtitles(subtitles); } +static int show_textbox_ext(const char *title, const char *text, int r, int c, + int *vscroll, int *hscroll, + int (*extra_key_cb)(int, size_t, size_t, void *), + void *data) +{ + dialog_clear(); + return dialog_textbox(title, text, r, c, vscroll, hscroll, + extra_key_cb, data); +} + +static void show_textbox(const char *title, const char *text, int r, int c) +{ + show_textbox_ext(title, text, r, c, NULL, NULL, NULL, NULL); +} + +static void show_helptext(const char *title, const char *text) +{ + show_textbox(title, text, 0, 0); +} + +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); +} + struct search_data { struct list_head *head; - struct menu **targets; - int *keys; + struct menu *target; }; -static void update_text(char *buf, size_t start, size_t end, void *_data) +static int next_jump_key(int key) +{ + if (key < '1' || key > '9') + return '1'; + + key++; + + if (key > '9') + key = '1'; + + return key; +} + +static int handle_search_keys(int key, size_t start, size_t end, void *_data) { struct search_data *data = _data; struct jump_key *pos; - int k = 0; + int index = 0; + + if (key < '1' || key > '9') + return 0; list_for_each_entry(pos, data->head, entries) { - if (pos->offset >= start && pos->offset < end) { - char header[4]; + index = next_jump_key(index); - if (k < JUMP_NB) { - int key = '0' + (pos->index % JUMP_NB) + 1; + if (pos->offset < start) + continue; - sprintf(header, "(%c)", key); - data->keys[k] = key; - data->targets[k] = pos->target; - k++; - } else { - sprintf(header, " "); - } + if (pos->offset >= end) + break; - memcpy(buf + pos->offset, header, sizeof(header) - 1); + if (key == index) { + data->target = pos->target; + return 1; } } - data->keys[k] = 0; + + return 0; +} + +int get_jump_key_char(void) +{ + jump_key_char = next_jump_key(jump_key_char); + + return jump_key_char; } static void search_conf(void) @@ -432,27 +477,23 @@ again: 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; + jump_key_char = 0; 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); + dres = show_textbox_ext("Search Results", str_get(&res), 0, 0, + &vscroll, &hscroll, + handle_search_keys, &data); again = false; - for (i = 0; i < JUMP_NB && keys[i]; i++) - if (dres == keys[i]) { - conf(targets[i]->parent, targets[i]); - again = true; - } + if (dres >= '1' && dres <= '9') { + assert(data.target != NULL); + conf(data.target->parent, data.target); + again = true; + } str_free(&res); list_for_each_entry_safe(pos, tmp, &head, entries) free(pos); @@ -641,158 +682,6 @@ conf_childs: 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); @@ -958,6 +847,127 @@ static void conf_save(void) } } +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 void conf_message_callback(const char *s) +{ + if (save_and_exit) { + if (!silent) + printf("%s", s); + } else { + show_textbox(NULL, s, 6, 60); + } +} + static int handle_exit(void) { int res; diff --git a/scripts/config/menu.c b/scripts/config/menu.c index 22fd26a9f7..d41a61a73a 100644 --- a/scripts/config/menu.c +++ b/scripts/config/menu.c @@ -661,11 +661,6 @@ const char *menu_get_prompt(struct menu *menu) 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; @@ -706,6 +701,11 @@ static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) } } +int __attribute__((weak)) get_jump_key_char(void) +{ + return -1; +} + static void get_prompt_str(struct gstr *r, struct property *prop, struct list_head *head) { @@ -727,52 +727,41 @@ static void get_prompt_str(struct gstr *r, struct property *prop, if (!expr_eq(prop->menu->dep, prop->visible.expr)) get_dep_str(r, prop->visible.expr, " Visible if: "); - menu = prop->menu->parent; + menu = prop->menu; for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { - bool accessible = menu_is_visible(menu); - submenu[i++] = menu; - if (location == NULL && accessible) + if (location == NULL && menu_is_visible(menu)) 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; - + jump->target = location; 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 : "", - sym_get_string_value(menu->sym)); - } - str_append(r, "\n"); + str_printf(r, " Location:\n"); + for (j = 0; --i >= 0; j++) { + int jk = -1; + int indent = 2 * j + 4; + + menu = submenu[i]; + if (jump && menu == location) { + jump->offset = strlen(r->s); + jk = get_jump_key_char(); } + + if (jk >= 0) { + str_printf(r, "(%c)", jk); + indent -= 3; + } + + str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu)); + if (menu->sym) { + str_printf(r, " (%s [=%s])", menu->sym->name ? + menu->sym->name : "", + sym_get_string_value(menu->sym)); + } + str_append(r, "\n"); } } diff --git a/scripts/config/nconf-cfg.sh b/scripts/config/nconf-cfg.sh index a227309283..9d40960749 100755 --- a/scripts/config/nconf-cfg.sh +++ b/scripts/config/nconf-cfg.sh @@ -1,19 +1,22 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-only +cflags=$1 +libs=$2 + 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)\" +if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then + if ${HOSTPKG_CONFIG} --exists $PKG; then + ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs} exit 0 fi - if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" + if ${HOSTPKG_CONFIG} --exists $PKG2; then + ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs} exit 0 fi fi @@ -22,20 +25,20 @@ fi # (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\" + echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags} + echo -lncursesw -lmenuw -lpanelw > ${libs} 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\" + echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags} + echo -lncurses -lmenu -lpanel > ${libs} exit 0 fi if [ -f /usr/include/ncurses.h ]; then - echo cflags=\"-D_GNU_SOURCE\" - echo libs=\"-lncurses -lmenu -lpanel\" + echo -D_GNU_SOURCE > ${cflags} + echo -lncurses -lmenu -lpanel > ${libs} exit 0 fi @@ -44,7 +47,7 @@ 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 "*" -echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* You may also need to install ${HOSTPKG_CONFIG} to find the" echo >&2 "* ncurses installed in a non-default location." echo >&2 "*" exit 1 diff --git a/scripts/config/nconf.c b/scripts/config/nconf.c index b75cabe017..ece86726ef 100644 --- a/scripts/config/nconf.c +++ b/scripts/config/nconf.c @@ -55,8 +55,8 @@ static const char nconf_global_help[] = "\n" "Menu navigation keys\n" "----------------------------------------------------------------------\n" -"Linewise up \n" -"Linewise down \n" +"Linewise up \n" +"Linewise down \n" "Pagewise up \n" "Pagewise down \n" "First entry \n" @@ -223,7 +223,7 @@ search_help[] = "Location:\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> PCI support (PCI [ = y])\n" -" -> PCI access mode ( [ = y])\n" +"(1) -> PCI access mode ( [ = y])\n" "Selects: LIBCRC32\n" "Selected by: BAR\n" "-----------------------------------------------------------------\n" @@ -234,9 +234,13 @@ search_help[] = "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" +" is located.\n" +" 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" +" 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 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" @@ -278,7 +282,9 @@ static const char *current_instructions = menu_instructions; static char *dialog_input_result; static int dialog_input_result_len; +static int jump_key_char; +static void selected_conf(struct menu *menu, struct menu *active_menu); static void conf(struct menu *menu); static void conf_choice(struct menu *menu); static void conf_string(struct menu *menu); @@ -688,6 +694,57 @@ static int do_exit(void) return 0; } +struct search_data { + struct list_head *head; + struct menu *target; +}; + +static int next_jump_key(int key) +{ + if (key < '1' || key > '9') + return '1'; + + key++; + + if (key > '9') + key = '1'; + + return key; +} + +static int handle_search_keys(int key, size_t start, size_t end, void *_data) +{ + struct search_data *data = _data; + struct jump_key *pos; + int index = 0; + + if (key < '1' || key > '9') + return 0; + + list_for_each_entry(pos, data->head, entries) { + index = next_jump_key(index); + + if (pos->offset < start) + continue; + + if (pos->offset >= end) + break; + + if (key == index) { + data->target = pos->target; + return 1; + } + } + + return 0; +} + +int get_jump_key_char(void) +{ + jump_key_char = next_jump_key(jump_key_char); + + return jump_key_char; +} static void search_conf(void) { @@ -695,7 +752,8 @@ static void search_conf(void) struct gstr res; struct gstr title; char *dialog_input; - int dres; + int dres, vscroll = 0, hscroll = 0; + bool again; title = str_new(); str_printf( &title, "Enter (sub)string or regexp to search for " @@ -724,11 +782,28 @@ again: dialog_input += strlen(CONFIG_); sym_arr = sym_re_search(dialog_input); - res = get_relations_str(sym_arr, NULL); + + do { + LIST_HEAD(head); + struct search_data data = { + .head = &head, + .target = NULL, + }; + jump_key_char = 0; + res = get_relations_str(sym_arr, &head); + dres = show_scroll_win_ext(main_window, + "Search Results", str_get(&res), + &vscroll, &hscroll, + handle_search_keys, &data); + again = false; + if (dres >= '1' && dres <= '9') { + assert(data.target != NULL); + selected_conf(data.target->parent, data.target); + again = true; + } + str_free(&res); + } while (again); free(sym_arr); - show_scroll_win(main_window, - "Search Results", str_get(&res)); - str_free(&res); str_free(&title); } @@ -1065,10 +1140,15 @@ static int do_match(int key, struct match_state *state, int *ans) } static void conf(struct menu *menu) +{ + selected_conf(menu, NULL); +} + +static void selected_conf(struct menu *menu, struct menu *active_menu) { struct menu *submenu = NULL; struct symbol *sym; - int res; + int i, res; int current_index = 0; int last_top_row = 0; struct match_state match_state = { @@ -1084,6 +1164,19 @@ static void conf(struct menu *menu) if (!child_count) break; + if (active_menu != NULL) { + for (i = 0; i < items_num; i++) { + struct mitem *mcur; + + mcur = (struct mitem *) item_userptr(curses_menu_items[i]); + if ((struct menu *) mcur->usrptr == active_menu) { + current_index = i; + break; + } + } + active_menu = NULL; + } + show_menu(menu_get_prompt(menu), menu_instructions, current_index, &last_top_row); keypad((menu_win(curses_menu)), TRUE); @@ -1108,9 +1201,11 @@ static void conf(struct menu *menu) break; switch (res) { case KEY_DOWN: + case 'j': menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: + case 'k': menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: @@ -1291,9 +1386,11 @@ static void conf_choice(struct menu *menu) break; switch (res) { case KEY_DOWN: + case 'j': menu_driver(curses_menu, REQ_DOWN_ITEM); break; case KEY_UP: + case 'k': menu_driver(curses_menu, REQ_UP_ITEM); break; case KEY_NPAGE: diff --git a/scripts/config/nconf.gui.c b/scripts/config/nconf.gui.c index c72d61a772..48ba1c1a07 100644 --- a/scripts/config/nconf.gui.c +++ b/scripts/config/nconf.gui.c @@ -497,10 +497,17 @@ void refresh_all_windows(WINDOW *main_window) refresh(); } -/* layman's scrollable window... */ void show_scroll_win(WINDOW *main_window, const char *title, const char *text) +{ + (void)show_scroll_win_ext(main_window, title, (char *)text, NULL, NULL, NULL, NULL); +} + +/* layman's scrollable window... */ +int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, + int *vscroll, int *hscroll, + extra_key_cb_fn extra_key_cb, void *data) { int res; int total_lines = get_line_no(text); @@ -514,6 +521,12 @@ void show_scroll_win(WINDOW *main_window, WINDOW *win; WINDOW *pad; PANEL *panel; + bool done = false; + + if (hscroll) + start_x = *hscroll; + if (vscroll) + start_y = *vscroll; getmaxyx(stdscr, lines, columns); @@ -549,8 +562,7 @@ void show_scroll_win(WINDOW *main_window, panel = new_panel(win); /* handle scrolling */ - do { - + while (!done) { copywin(pad, win, start_y, start_x, 2, 2, text_lines, text_cols, 0); print_in_middle(win, @@ -593,8 +605,18 @@ void show_scroll_win(WINDOW *main_window, case 'l': start_x++; break; + default: + if (extra_key_cb) { + size_t start = (get_line(text, start_y) - text); + size_t end = (get_line(text, start_y + text_lines) - text); + + if (extra_key_cb(res, start, end, data)) { + done = true; + break; + } + } } - if (res == 10 || res == 27 || res == 'q' || + if (res == 0 || res == 10 || res == 27 || res == 'q' || res == KEY_F(F_HELP) || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) break; @@ -606,9 +628,14 @@ void show_scroll_win(WINDOW *main_window, start_x = 0; if (start_x >= total_cols-text_cols) start_x = total_cols-text_cols; - } while (res); + } + if (hscroll) + *hscroll = start_x; + if (vscroll) + *vscroll = start_y; del_panel(panel); delwin(win); refresh_all_windows(main_window); + return res; } diff --git a/scripts/config/nconf.h b/scripts/config/nconf.h index 6e127c63d5..174b035fde 100644 --- a/scripts/config/nconf.h +++ b/scripts/config/nconf.h @@ -67,6 +67,8 @@ typedef enum { void set_colors(void); +typedef int (*extra_key_cb_fn)(int, size_t, size_t, void *); + /* this changes the windows attributes !!! */ void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs); int get_line_length(const char *line); @@ -78,6 +80,9 @@ 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); +int show_scroll_win_ext(WINDOW *main_window, const char *title, char *text, + int *vscroll, int *hscroll, + extra_key_cb_fn extra_key_cb, void *data); void show_scroll_win(WINDOW *main_window, const char *title, const char *text); diff --git a/scripts/config/parser.tab.c b/scripts/config/parser.tab.c index 18137050a9..93fdc257a6 100644 --- a/scripts/config/parser.tab.c +++ b/scripts/config/parser.tab.c @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.7.6. */ +/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C @@ -46,10 +46,10 @@ USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ -#define YYBISON 30706 +#define YYBISON 30802 /* Bison version string. */ -#define YYBISON_VERSION "3.7.6" +#define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -379,12 +379,18 @@ typedef int yy_state_fast_t; # define YY_USE(E) /* empty */ #endif -#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else @@ -603,7 +609,7 @@ static const yytype_int8 yytranslate[] = }; #if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { 0, 110, 110, 110, 114, 119, 121, 122, 123, 124, @@ -661,20 +667,6 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #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_int16 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, 299, 300, 301, 302, 303, 304, - 305 -}; -#endif - #define YYPACT_NINF (-105) #define yypact_value_is_default(Yyn) \ @@ -685,8 +677,8 @@ static const yytype_int16 yytoknum[] = #define yytable_value_is_error(Yyn) \ 0 - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ static const yytype_int16 yypact[] = { -5, 17, 37, -105, 57, 8, -105, 91, 39, 15, @@ -710,9 +702,9 @@ static const yytype_int16 yypact[] = -105, 136, -105, -105, -105, -105, -105 }; - /* 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. */ +/* 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_int8 yydefact[] = { 5, 0, 0, 5, 0, 0, 1, 0, 0, 0, @@ -736,7 +728,7 @@ static const yytype_int8 yydefact[] = 30, 0, 32, 31, 48, 44, 34 }; - /* YYPGOTO[NTERM-NUM]. */ +/* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -105, -105, -105, 3, 38, -105, -55, -105, -105, 138, @@ -746,7 +738,7 @@ static const yytype_int16 yypgoto[] = -46, -8, -65, -105, -105, -105, -105 }; - /* YYDEFGOTO[NTERM-NUM]. */ +/* YYDEFGOTO[NTERM-NUM]. */ static const yytype_uint8 yydefgoto[] = { 0, 2, 3, 4, 57, 17, 18, 19, 20, 54, @@ -756,9 +748,9 @@ static const yytype_uint8 yydefgoto[] = 48, 49, 50, 41, 32, 39, 64 }; - /* 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. */ +/* 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[] = { 68, 69, 116, 118, 44, 120, 7, 52, 134, 135, @@ -807,8 +799,8 @@ static const yytype_int16 yycheck[] = 34, -1, -1, -1, 38 }; - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ static const yytype_int8 yystos[] = { 0, 24, 52, 53, 54, 5, 0, 54, 1, 4, @@ -832,7 +824,7 @@ static const yytype_int8 yystos[] = 40, 90, 40, 40, 40, 40, 40 }; - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int8 yyr1[] = { 0, 51, 52, 52, 53, 54, 54, 54, 54, 54, @@ -848,7 +840,7 @@ static const yytype_int8 yyr1[] = 94, 95, 96, 96, 96, 97, 97 }; - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 2, 1, 3, 0, 2, 2, 2, 2, @@ -873,6 +865,7 @@ enum { YYENOMEM = -2 }; #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) @@ -913,10 +906,7 @@ do { \ 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, Kind, Value, Location) \ @@ -943,10 +933,6 @@ yy_symbol_value_print (FILE *yyo, YY_USE (yyoutput); if (!yyvaluep) return; -# ifdef YYPRINT - if (yykind < YYNTOKENS) - YYPRINT (yyo, yytoknum[yykind], *yyvaluep); -# endif YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END @@ -1162,6 +1148,7 @@ yyparse (void) YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; @@ -1187,7 +1174,7 @@ yysetstate: if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE - goto yyexhaustedlab; + YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ @@ -1215,7 +1202,7 @@ yysetstate: # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; @@ -1226,7 +1213,7 @@ yysetstate: YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) - goto yyexhaustedlab; + YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE @@ -1248,6 +1235,7 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + if (yystate == YYFINAL) YYACCEPT; @@ -1832,6 +1820,7 @@ yyerrorlab: label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; + ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ @@ -1892,7 +1881,7 @@ yyerrlab1: `-------------------------------------*/ yyacceptlab: yyresult = 0; - goto yyreturn; + goto yyreturnlab; /*-----------------------------------. @@ -1900,24 +1889,22 @@ yyacceptlab: `-----------------------------------*/ yyabortlab: yyresult = 1; - goto yyreturn; + goto yyreturnlab; -#if !defined yyoverflow -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; - goto yyreturn; -#endif + goto yyreturnlab; -/*-------------------------------------------------------. -| yyreturn -- parsing is finished, clean up and return. | -`-------------------------------------------------------*/ -yyreturn: +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at diff --git a/scripts/config/parser.tab.h b/scripts/config/parser.tab.h index aac457ce39..fa3eb3491b 100644 --- a/scripts/config/parser.tab.h +++ b/scripts/config/parser.tab.h @@ -1,4 +1,4 @@ -/* A Bison parser, made by GNU Bison 3.7.6. */ +/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C @@ -128,6 +128,8 @@ typedef union YYSTYPE YYSTYPE; extern YYSTYPE yylval; + int yyparse (void); + #endif /* !YY_YY_PARSER_TAB_H_INCLUDED */ diff --git a/scripts/config/preprocess.c b/scripts/config/preprocess.c index 3c7a35a724..3c544b775a 100644 --- a/scripts/config/preprocess.c +++ b/scripts/config/preprocess.c @@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[]) static char *do_shell(int argc, char *argv[]) { FILE *p; - char buf[256]; + char buf[4096]; char *cmd; size_t nread; int i; @@ -396,6 +396,9 @@ static char *eval_clause(const char *str, size_t len, int argc, char *argv[]) p++; } + + if (new_argc >= FUNCTION_MAX_ARGS) + pperror("too many function arguments"); new_argv[new_argc++] = prev; /* diff --git a/scripts/config/qconf-cfg.sh b/scripts/config/qconf-cfg.sh index 609bb818e8..203ddf4203 100755 --- a/scripts/config/qconf-cfg.sh +++ b/scripts/config/qconf-cfg.sh @@ -1,24 +1,40 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-only -PKG="Qt5Core Qt5Gui Qt5Widgets" +cflags=$1 +libs=$2 +bin=$3 -if [ -z "$(command -v pkg-config)" ]; then +PKG5="Qt5Core Qt5Gui Qt5Widgets" +PKG6="Qt6Core Qt6Gui Qt6Widgets" + +if [ -z "$(command -v ${HOSTPKG_CONFIG})" ]; then echo >&2 "*" - echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it." + echo >&2 "* 'make xconfig' requires '${HOSTPKG_CONFIG}'. Please install it." echo >&2 "*" exit 1 fi -if pkg-config --exists $PKG; then - echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags $PKG)\" - echo libs=\"$(pkg-config --libs $PKG)\" - echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\" +if ${HOSTPKG_CONFIG} --exists $PKG6; then + ${HOSTPKG_CONFIG} --cflags ${PKG6} > ${cflags} + # Qt6 requires C++17. + echo -std=c++17 >> ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG6} > ${libs} + ${HOSTPKG_CONFIG} --variable=libexecdir Qt6Core > ${bin} + exit 0 +fi + +if ${HOSTPKG_CONFIG} --exists $PKG5; then + ${HOSTPKG_CONFIG} --cflags ${PKG5} > ${cflags} + ${HOSTPKG_CONFIG} --libs ${PKG5} > ${libs} + ${HOSTPKG_CONFIG} --variable=host_bins Qt5Core > ${bin} exit 0 fi echo >&2 "*" -echo >&2 "* Could not find Qt5 via pkg-config." -echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH" +echo >&2 "* Could not find Qt6 or Qt5 via ${HOSTPKG_CONFIG}." +echo >&2 "* Please install Qt6 or Qt5 and make sure it's in PKG_CONFIG_PATH" +echo >&2 "* You need $PKG6 for Qt6" +echo >&2 "* You need $PKG5 for Qt5" echo >&2 "*" exit 1 diff --git a/scripts/config/qconf.cc b/scripts/config/qconf.cc index ed7b3e3e20..abf0d0b392 100644 --- a/scripts/config/qconf.cc +++ b/scripts/config/qconf.cc @@ -5,10 +5,10 @@ */ #include +#include #include #include #include -#include #include #include #include @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -1126,7 +1128,7 @@ QString ConfigInfoView::debug_info(struct symbol *sym) QString ConfigInfoView::print_filter(const QString &str) { - QRegExp re("[<>&\"\\n]"); + QRegularExpression re("[<>&\"\\n]"); QString res = str; for (int i = 0; (i = res.indexOf(re, i)) >= 0;) { switch (res[i].toLatin1()) { @@ -1322,15 +1324,15 @@ ConfigMainWindow::ConfigMainWindow(void) 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(); + QRect g = configApp->primaryScreen()->geometry(); + width = configSettings->value("/window width", g.width() - 64).toInt(); + height = configSettings->value("/window height", g.height() - 64).toInt(); resize(width, height); x = configSettings->value("/window x"); y = configSettings->value("/window y"); @@ -1379,17 +1381,17 @@ ConfigMainWindow::ConfigMainWindow(void) this, &ConfigMainWindow::goBack); QAction *quitAction = new QAction("&Quit", this); - quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); + quitAction->setShortcut(Qt::CTRL | Qt::Key_Q); connect(quitAction, &QAction::triggered, this, &ConfigMainWindow::close); QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); - loadAction->setShortcut(Qt::CTRL + Qt::Key_L); + loadAction->setShortcut(Qt::CTRL | Qt::Key_L); connect(loadAction, &QAction::triggered, this, &ConfigMainWindow::loadConfig); saveAction = new QAction(QPixmap(xpm_save), "&Save", this); - saveAction->setShortcut(Qt::CTRL + Qt::Key_S); + saveAction->setShortcut(Qt::CTRL | Qt::Key_S); connect(saveAction, &QAction::triggered, this, &ConfigMainWindow::saveConfig); @@ -1403,7 +1405,7 @@ ConfigMainWindow::ConfigMainWindow(void) connect(saveAsAction, &QAction::triggered, this, &ConfigMainWindow::saveConfigAs); QAction *searchAction = new QAction("&Find", this); - searchAction->setShortcut(Qt::CTRL + Qt::Key_F); + searchAction->setShortcut(Qt::CTRL | Qt::Key_F); connect(searchAction, &QAction::triggered, this, &ConfigMainWindow::searchConfig); singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); @@ -1750,11 +1752,21 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e) 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"); + + QMessageBox mb(QMessageBox::Icon::Warning, "qconf", + "Save configuration?"); + + QPushButton *yb = mb.addButton(QMessageBox::Yes); + QPushButton *db = mb.addButton(QMessageBox::No); + QPushButton *cb = mb.addButton(QMessageBox::Cancel); + + yb->setText("&Save Changes"); + db->setText("&Discard Changes"); + cb->setText("Cancel Exit"); + + mb.setDefaultButton(yb); + mb.setEscapeButton(cb); + switch (mb.exec()) { case QMessageBox::Yes: if (saveConfig()) diff --git a/scripts/config/symbol.c b/scripts/config/symbol.c index d97b56ab0e..6ef44adc05 100644 --- a/scripts/config/symbol.c +++ b/scripts/config/symbol.c @@ -123,9 +123,9 @@ static long long sym_get_range_val(struct symbol *sym, int base) static void sym_validate_range(struct symbol *sym) { struct property *prop; + struct symbol *range_sym; int base; long long val, val2; - char str[64]; switch (sym->type) { case S_INT: @@ -141,17 +141,15 @@ static void sym_validate_range(struct symbol *sym) if (!prop) return; val = strtoll(sym->curr.val, NULL, base); - val2 = sym_get_range_val(prop->expr->left.sym, base); + range_sym = prop->expr->left.sym; + val2 = sym_get_range_val(range_sym, base); if (val >= val2) { - val2 = sym_get_range_val(prop->expr->right.sym, base); + range_sym = prop->expr->right.sym; + val2 = sym_get_range_val(range_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); + sym->curr.val = range_sym->curr.val; } static void sym_set_changed(struct symbol *sym) @@ -851,49 +849,6 @@ struct symbol *sym_find(const char *name) 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; diff --git a/scripts/config/util.c b/scripts/config/util.c index 0bc415cd73..53e079e2e8 100644 --- a/scripts/config/util.c +++ b/scripts/config/util.c @@ -74,7 +74,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...) } /* Retrieve value of growable string */ -const char *str_get(struct gstr *gs) +char *str_get(struct gstr *gs) { return gs->s; }