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 <cotequeiroz@gmail.com>
This commit is contained in:
Eneas U de Queiroz 2024-02-16 14:32:07 -03:00 committed by Robert Marko
parent ff6df9ac9f
commit 65a3eb28d5
28 changed files with 1411 additions and 1012 deletions

View File

@ -1,16 +1,14 @@
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
/conf /conf
/[gmnq]conf /[gmnq]conf
/[gmnq]conf-cfg /[gmnq]conf-bin
/[gmnq]conf-cflags
/[gmnq]conf-libs
/qconf-moc.cc /qconf-moc.cc
# From linux kconfig parent directories #
.* # Added by openwrt
#
# OpenWrt-generated files
mconf_check mconf_check
# The next line should be removed after 23.05 is EOL
# Temporary files from older versions. They should be removed after the *conf-cfg
# end of support for OpenWrt 19.07.
zconf.???.c
zconf.hash.c

View File

@ -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

View File

@ -5,46 +5,21 @@
.PHONY: clean all .PHONY: clean all
all: conf mconf all: conf mconf
clean: 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 clean-files := *.o lxdialog/*.o *.moc qconf-moc.cc \
# previous version are removed by make config-clean. *conf-cfg # <- This should be removed after 23.05 is EOL
# 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
# =========================================================================== # ===========================================================================
# Variables needed by the upstream Makefile # Variables needed by the upstream Makefile
# Avoids displaying 'UPD mconf-cfg' in an otherwise quiet make menuconfig export HOSTPKG_CONFIG=pkg-config
kecho:=true
CONFIG_SHELL:=$(SHELL) CONFIG_SHELL:=$(SHELL)
srctree:=. src:=$(CURDIR)
src:=.
obj:=. obj:=.
Q:=$(if $V,,@) Q:=$(if $V,,@)
cmd = $(cmd_$(1)) quiet:=$(if $V,,_silent)
include Kbuild.include
# 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, @:)
### Stripped down upstream Makefile follows: ### Stripped down upstream Makefile follows:
# =========================================================================== # ===========================================================================
@ -64,11 +39,12 @@ conf-objs := conf.o $(common-objs)
hostprogs += nconf hostprogs += nconf
nconf-objs := nconf.o nconf.gui.o $(common-objs) nconf-objs := nconf.o nconf.gui.o $(common-objs)
HOSTLDLIBS_nconf = $(shell . $(obj)/nconf-cfg && echo $$libs) HOSTLDLIBS_nconf = $(call read-file, $(obj)/nconf-libs)
HOSTCFLAGS_nconf.o = $(shell . $(obj)/nconf-cfg && echo $$cflags) HOSTCFLAGS_nconf.o = $(call read-file, $(obj)/nconf-cflags)
HOSTCFLAGS_nconf.gui.o = $(shell . $(obj)/nconf-cfg && echo $$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 # mconf: Used for the menuconfig target based on lxdialog
hostprogs += mconf hostprogs += mconf
@ -76,45 +52,44 @@ lxdialog := $(addprefix lxdialog/, \
checklist.o inputbox.o menubox.o textbox.o util.o yesno.o) checklist.o inputbox.o menubox.o textbox.o util.o yesno.o)
mconf-objs := mconf.o $(lxdialog) $(common-objs) 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), \ $(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 # qconf: Used for the xconfig target based on Qt
hostprogs += qconf hostprogs += qconf
qconf-cxxobjs := qconf.o qconf-moc.o qconf-cxxobjs := qconf.o qconf-moc.o
qconf-objs := images.o $(common-objs) qconf-objs := images.o $(common-objs)
HOSTLDLIBS_qconf = $(shell . $(obj)/qconf-cfg && echo $$libs) HOSTLDLIBS_qconf = $(call read-file, $(obj)/qconf-libs)
HOSTCXXFLAGS_qconf.o = $(shell . $(obj)/qconf-cfg && echo $$cflags) HOSTCXXFLAGS_qconf.o = -std=c++11 -fPIC $(call read-file, $(obj)/qconf-cflags)
HOSTCXXFLAGS_qconf-moc.o = $(shell . $(obj)/qconf-cfg && echo $$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-cfg $(obj)/qconf.o $(obj)/qconf-moc.o: | $(obj)/qconf-cflags
quiet_cmd_moc = MOC $@ 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) $(call if_changed,moc)
targets += qconf-moc.cc targets += qconf-moc.cc
# check if necessary packages are available, and configure build flags # 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 $(obj)/%conf-cflags $(obj)/%conf-libs $(obj)/%conf-bin: $(src)/%conf-cfg.sh
$(call filechk,conf_cfg) $(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 # OpenWrt rules and final adjustments that need to be made after reading the
# full upstream Makefile # full upstream Makefile
clean-files += $(targets) $(hostprogs)
FORCE: FORCE:
ifdef BUILD_SHIPPED_FILES ifdef BUILD_SHIPPED_FILES
@ -130,25 +105,21 @@ clean-files += $(shipped-files)
flex -L -o$@ $< flex -L -o$@ $<
endif endif
$(foreach f,$(conf-objs) $(filter-out $(common-objs),$(mconf-objs) \ define link_rule
$(qconf-objs) \ $(1): LDLIBS+=$$(HOSTLDLIBS_$(1))
$(nconf-objs)), \ $(1): $($(1)-objs) $$($(1)-cxxobjs)
$(eval $(obj)/$f: CFLAGS+=$$(HOSTCFLAGS_$f))) $(if $($(1)-cxxobjs), $(CXX) $$(LDFLAGS) -o $$@ $$^ $$(LDLIBS))
all-objs += $($(1)-objs)
all-cxxobjs += $($(1)-cxxobjs)
endef
$(foreach f,$(qconf-cxxobjs), \ all-objs:=
$(eval $(obj)/$f: CXXFLAGS+=$$(HOSTCXXFLAGS_$f))) 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 $(foreach f,$(sort $(all-objs)), \
# avoid sourcing it before the script is built, when trying to compute CFLAGS $(eval $f: CFLAGS+=$$(HOSTCFLAGS_$f)))
# 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)
$(obj)/nconf: nconf-cfg $(addprefix $(obj)/,$(nconf-objs)) $(foreach f,$(sort $(all-cxxobjs)), \
$(CC) -o $@ $(filter-out nconf-cfg,$^) $(HOSTLDLIBS_nconf) $(eval $f: CXXFLAGS+=$$(HOSTCXXFLAGS_$f)))
$(obj)/qconf: qconf-cfg $(addprefix $(obj)/,$(qconf-cxxobjs) $(qconf-objs))
$(CXX) -o $@ $(filter-out qconf-cfg,$^) $(HOSTLDLIBS_qconf)

View File

@ -1,6 +1,7 @@
These files were taken from the Linux 5.14 Kernel Configuration System and These files were taken from the Linux Kernel Configuration System v6.6.16,
modified for the OpenWrt Buildroot: at commit eb3e299184cc4f40d4bd84fda269b3a20ddcff80 (Feb 5, 2024), and modified
- Removed nconf, gconf, tests and kernel configuration targets. for the OpenWrt Buildroot:
- Removed gconf, tests and kernel configuration targets.
- Adjusted the Makefile to compile outside the kernel. - Adjusted the Makefile to compile outside the kernel.
- Always use default file when running make all{no,mod,yes}config. - Always use default file when running make all{no,mod,yes}config.
- Added a 'reset' command to reset config when the target changes. - Added a 'reset' command to reset config when the target changes.
@ -23,4 +24,4 @@ modified for the OpenWrt Buildroot:
BUILD_SHIPPED_FILES defined BUILD_SHIPPED_FILES defined
For a full list of changes, see the repository at: 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

View File

@ -35,6 +35,7 @@ enum input_mode {
olddefconfig, olddefconfig,
yes2modconfig, yes2modconfig,
mod2yesconfig, mod2yesconfig,
mod2noconfig,
fatalrecursive, fatalrecursive,
}; };
static enum input_mode input_mode = oldaskconfig; static enum input_mode input_mode = oldaskconfig;
@ -164,8 +165,6 @@ enum conf_def_mode {
def_default, def_default,
def_yes, def_yes,
def_mod, def_mod,
def_y2m,
def_m2y,
def_no, def_no,
def_random def_random
}; };
@ -303,12 +302,10 @@ static bool conf_set_all_new_symbols(enum conf_def_mode mode)
return has_changed; 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; struct symbol *sym;
int i; int i;
tristate old_val = (mode == def_y2m) ? yes : mod;
tristate new_val = (mode == def_y2m) ? mod : yes;
for_all_symbols(i, sym) { for_all_symbols(i, sym) {
if (sym_get_type(sym) == S_TRISTATE && if (sym_get_type(sym) == S_TRISTATE &&
@ -555,7 +552,7 @@ static int conf_choice(struct menu *menu)
print_help(child); print_help(child);
continue; continue;
} }
sym_set_choice_value(sym, child->sym); sym_set_tristate_value(child->sym, yes);
for (child = child->list; child; child = child->next) { for (child = child->list; child; child = child->next) {
indent += 2; indent += 2;
conf(child); conf(child);
@ -647,19 +644,8 @@ static void check_conf(struct menu *menu)
switch (input_mode) { switch (input_mode) {
case listnewconfig: case listnewconfig:
if (sym->name) { if (sym->name)
const char *str; print_symbol_for_listconfig(sym);
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);
}
}
break; break;
case helpnewconfig: case helpnewconfig:
printf("-----\n"); printf("-----\n");
@ -697,7 +683,8 @@ static const struct option long_opts[] = {
{"olddefconfig", no_argument, &input_mode_opt, olddefconfig}, {"olddefconfig", no_argument, &input_mode_opt, olddefconfig},
{"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig}, {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig},
{"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig}, {"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} {NULL, 0, NULL, 0}
}; };
@ -707,8 +694,10 @@ static void conf_usage(const char *progname)
printf("\n"); printf("\n");
printf("Generic options:\n"); printf("Generic options:\n");
printf(" -h, --help Print this message and exit.\n"); printf(" -h, --help Print this message and exit.\n");
printf(" -r <file> Read <file> as input.\n");
printf(" -s, --silent Do not print log.\n"); printf(" -s, --silent Do not print log.\n");
printf(" --fatalrecursive Treat recursive depenendencies as a fatal error\n"); printf(" -w <file> Write config to <file>.\n");
printf(" --fatalrecursive Treat recursive dependency as error.\n");
printf("\n"); printf("\n");
printf("Mode options:\n"); printf("Mode options:\n");
printf(" --listnewconfig List new 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(" --randconfig New config with random answer to all options\n");
printf(" --yes2modconfig Change answers from yes to mod if possible\n"); printf(" --yes2modconfig Change answers from yes to mod if possible\n");
printf(" --mod2yesconfig Change answers from mod to yes 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"); 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); 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) { switch (opt) {
case 'h': case 'h':
conf_usage(progname); conf_usage(progname);
exit(1); exit(1);
break; break;
case 's':
conf_set_message_callback(NULL);
break;
case fatalrecursive:
recursive_is_error = 1;
continue;
case 'r': case 'r':
input_file = optarg; input_file = optarg;
break; break;
case 's':
conf_set_message_callback(NULL);
break;
case 'w': case 'w':
output_file = optarg; output_file = optarg;
break; break;
case 0: case 0:
input_mode = input_mode_opt; switch (input_mode_opt) {
switch (input_mode) {
case syncconfig: case syncconfig:
/* /*
* syncconfig is invoked during the build stage. * syncconfig is invoked during the build stage.
@ -777,9 +763,13 @@ int main(int ac, char **av)
case randconfig: case randconfig:
set_randconfig_seed(); set_randconfig_seed();
break; break;
case fatalrecursive:
recursive_is_error = 1;
continue;
default: default:
break; break;
} }
input_mode = input_mode_opt;
default: default:
break; break;
} }
@ -812,6 +802,7 @@ int main(int ac, char **av)
case olddefconfig: case olddefconfig:
case yes2modconfig: case yes2modconfig:
case mod2yesconfig: case mod2yesconfig:
case mod2noconfig:
case allnoconfig: case allnoconfig:
case allyesconfig: case allyesconfig:
case allmodconfig: case allmodconfig:
@ -858,10 +849,13 @@ int main(int ac, char **av)
case savedefconfig: case savedefconfig:
break; break;
case yes2modconfig: case yes2modconfig:
conf_rewrite_mod_or_yes(def_y2m); conf_rewrite_tristates(yes, mod);
break; break;
case mod2yesconfig: case mod2yesconfig:
conf_rewrite_mod_or_yes(def_m2y); conf_rewrite_tristates(mod, yes);
break;
case mod2noconfig:
conf_rewrite_tristates(mod, no);
break; break;
case oldaskconfig: case oldaskconfig:
rootEntry = &rootmenu; rootEntry = &rootmenu;

View File

@ -11,6 +11,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <limits.h> #include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -129,41 +130,22 @@ static size_t depfile_prefix_len;
/* touch depfile for symbol 'name' */ /* touch depfile for symbol 'name' */
static int conf_touch_dep(const char *name) static int conf_touch_dep(const char *name)
{ {
int fd, ret; int fd;
char *d;
/* check overflow: prefix + name + '\0' must fit in buffer. */ /* check overflow: prefix + name + '\0' must fit in buffer. */
if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path)) if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path))
return -1; return -1;
d = depfile_path + depfile_prefix_len; strcpy(depfile_path + depfile_prefix_len, name);
strcpy(d, 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); fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) if (fd == -1)
return -1; return -1;
}
close(fd); close(fd);
return 0; 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, ...) static void conf_warning(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2))); __attribute__ ((format (printf, 1, 2)));
@ -227,6 +209,20 @@ static const char *conf_get_autoconfig_name(void)
return name ? name : "include/config/auto.conf"; 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) static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
{ {
char *p2; char *p2;
@ -255,6 +251,8 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
p, sym->name); p, sym->name);
return 1; return 1;
case S_STRING: case S_STRING:
/* No escaping for S_DEF_AUTO (include/config/auto.conf) */
if (def != S_DEF_AUTO) {
if (*p++ != '"') if (*p++ != '"')
break; break;
for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) {
@ -265,10 +263,10 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
memmove(p2, p2 + 1, strlen(p2)); memmove(p2, p2 + 1, strlen(p2));
} }
if (!p2) { if (!p2) {
if (def != S_DEF_AUTO)
conf_warning("invalid string found"); conf_warning("invalid string found");
return 1; return 1;
} }
}
/* fall through */ /* fall through */
case S_INT: case S_INT:
case S_HEX: case S_HEX:
@ -376,7 +374,11 @@ int conf_read_simple(const char *name, int def)
char *p, *p2; char *p, *p2;
struct symbol *sym; struct symbol *sym;
int def_flags; int def_flags;
const char *warn_unknown;
const char *werror;
warn_unknown = getenv("KCONFIG_WARN_UNKNOWN_SYMBOLS");
werror = getenv("KCONFIG_WERROR");
if (name) { if (name) {
in = zconf_fopen(name); in = zconf_fopen(name);
} else { } else {
@ -448,6 +450,10 @@ load:
if (def == S_DEF_USER) { if (def == S_DEF_USER) {
sym = sym_find(line + 2 + strlen(CONFIG_)); sym = sym_find(line + 2 + strlen(CONFIG_));
if (!sym) { if (!sym) {
if (warn_unknown)
conf_warning("unknown symbol: %s",
line + 2 + strlen(CONFIG_));
conf_set_changed(true); conf_set_changed(true);
continue; continue;
} }
@ -479,7 +485,7 @@ load:
sym = sym_find(line + strlen(CONFIG_)); sym = sym_find(line + strlen(CONFIG_));
if (!sym) { if (!sym) {
if (def == S_DEF_AUTO) if (def == S_DEF_AUTO) {
/* /*
* Reading from include/config/auto.conf * Reading from include/config/auto.conf
* If CONFIG_FOO previously existed in * If CONFIG_FOO previously existed in
@ -487,8 +493,13 @@ load:
* include/config/FOO must be touched. * include/config/FOO must be touched.
*/ */
conf_touch_dep(line + strlen(CONFIG_)); conf_touch_dep(line + strlen(CONFIG_));
else } else {
if (warn_unknown)
conf_warning("unknown symbol: %s",
line + strlen(CONFIG_));
conf_set_changed(true); conf_set_changed(true);
}
continue; continue;
} }
@ -524,6 +535,10 @@ load:
} }
free(line); free(line);
fclose(in); fclose(in);
if (conf_warnings && werror)
exit(1);
return 0; return 0;
} }
@ -597,169 +612,226 @@ int conf_read(const char *name)
return 0; return 0;
} }
/* struct comment_style {
* Kconfig configuration printer const char *decoration;
* const char *prefix;
* This printer is used when generating the resulting configuration after const char *postfix;
* kconfig invocation and `defconfig' files. Unset symbol might be omitted by };
* passing a non-NULL argument to the printer.
* static const struct comment_style comment_style_pound = {
*/ .decoration = "#",
static void .prefix = "#",
kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) .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) { switch (sym->type) {
case S_BOOLEAN: case S_BOOLEAN:
case S_TRISTATE: case S_TRISTATE:
if (*value == 'n') { switch (*val) {
bool skip_unset = (arg != NULL); case 'n':
if (!skip_unset)
fprintf(fp, "# %s%s is not set\n",
CONFIG_, sym->name);
return; return;
case 'm':
sym_suffix = "_MODULE";
/* fall through */
default:
val = "1";
} }
break; 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: default:
break; 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 static void print_symbol_for_rustccfg(FILE *fp, struct symbol *sym)
kconfig_print_comment(FILE *fp, const char *value, void *arg)
{ {
const char *p = value; const char *val;
size_t l; const char *val_prefix = "";
char *val_prefixed = NULL;
size_t val_prefixed_len;
char *escaped = NULL;
for (;;) { if (sym->type == S_UNKNOWN)
l = strcspn(p, "\n"); return;
fprintf(fp, "#");
if (l) {
fprintf(fp, " ");
xfwrite(p, l, 1, fp);
p += l;
}
fprintf(fp, "\n");
if (*p++ == '\0')
break;
}
}
static struct conf_printer kconfig_printer_cb = val = sym_get_string_value(sym);
{
.print_symbol = kconfig_print_symbol,
.print_comment = kconfig_print_comment,
};
/*
* Header printer
*
* This printer is used when generating the `include/generated/autoconf.h' file.
*/
static void
header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg)
{
switch (sym->type) { switch (sym->type) {
case S_BOOLEAN: case S_BOOLEAN:
case S_TRISTATE: { case S_TRISTATE:
const char *suffix = ""; /*
* 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': * 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; break;
case 'm': case S_HEX:
suffix = "_MODULE"; if (val[0] != '0' || (val[1] != 'x' && val[1] != 'X'))
/* fall through */ val_prefix = "0x";
default:
fprintf(fp, "#define %s%s%s 1\n",
CONFIG_, sym->name, suffix);
}
break;
}
case S_HEX: {
const char *prefix = "";
if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X'))
prefix = "0x";
fprintf(fp, "#define %s%s %s%s\n",
CONFIG_, sym->name, prefix, value);
break;
}
case S_STRING:
case S_INT:
fprintf(fp, "#define %s%s %s\n",
CONFIG_, sym->name, value);
break; break;
default: default:
break; 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;
} }
static void /* All values get escaped: the `--cfg` option only takes strings */
header_print_comment(FILE *fp, const char *value, void *arg) escaped = escape_string_value(val);
{ val = escaped;
const char *p = value;
size_t l;
fprintf(fp, "/*\n"); fprintf(fp, "--cfg=%s%s=%s\n", CONFIG_, sym->name, val);
for (;;) {
l = strcspn(p, "\n");
fprintf(fp, " *");
if (l) {
fprintf(fp, " ");
xfwrite(p, l, 1, fp);
p += l;
}
fprintf(fp, "\n");
if (*p++ == '\0')
break;
}
fprintf(fp, " */\n");
}
static struct conf_printer header_printer_cb = free(escaped);
{ free(val_prefixed);
.print_symbol = header_print_symbol,
.print_comment = header_print_comment,
};
static void conf_write_symbol(FILE *fp, struct symbol *sym,
struct conf_printer *printer, void *printer_arg)
{
const char *str;
switch (sym->type) {
case S_UNKNOWN:
break;
case S_STRING:
str = sym_get_string_value(sym);
str = sym_escape_string_value(str);
printer->print_symbol(fp, sym, str, printer_arg);
free((void *)str);
break;
default:
str = sym_get_string_value(sym);
printer->print_symbol(fp, sym, str, printer_arg);
}
}
static void
conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg)
{
char buf[256];
snprintf(buf, sizeof(buf),
"\n"
"Automatically generated file; DO NOT EDIT.\n"
"%s\n",
rootmenu.prompt->text);
printer->print_comment(fp, buf, printer_arg);
} }
/* /*
@ -818,7 +890,7 @@ int conf_write_defconfig(const char *filename)
goto next_menu; goto next_menu;
} }
} }
conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); print_symbol_for_dotconfig(out, sym);
} }
next_menu: next_menu:
if (menu->list != NULL) { if (menu->list != NULL) {
@ -878,7 +950,7 @@ int conf_write(const char *name)
if (!out) if (!out)
return 1; return 1;
conf_write_heading(out, &kconfig_printer_cb, NULL); conf_write_heading(out, &comment_style_pound);
if (!conf_get_changed()) if (!conf_get_changed())
sym_clear_all_valid(); sym_clear_all_valid();
@ -905,7 +977,7 @@ int conf_write(const char *name)
need_newline = false; need_newline = false;
} }
sym->flags |= SYMBOL_WRITTEN; sym->flags |= SYMBOL_WRITTEN;
conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); print_symbol_for_dotconfig(out, sym);
} }
next: next:
@ -913,19 +985,20 @@ next:
menu = menu->list; menu = menu->list;
continue; continue;
} }
if (menu->next)
menu = menu->next; end_check:
else while ((menu = menu->parent)) { if (!menu->sym && menu_is_visible(menu) && menu != &rootmenu &&
if (!menu->sym && menu_is_visible(menu) && menu->prompt->type == P_MENU) {
menu != &rootmenu) { fprintf(out, "# end of %s\n", menu_get_prompt(menu));
str = menu_get_prompt(menu);
fprintf(out, "# end of %s\n", str);
need_newline = true; need_newline = true;
} }
if (menu->next) { if (menu->next) {
menu = menu->next; menu = menu->next;
break; } else {
} menu = menu->parent;
if (menu)
goto end_check;
} }
} }
fclose(out); fclose(out);
@ -955,45 +1028,69 @@ next:
} }
/* write a dependency file as used by kbuild to track dependencies */ /* 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; struct file *file;
FILE *out; FILE *out;
int ret;
out = fopen("..config.tmp", "w"); ret = snprintf(name, sizeof(name), "%s.cmd", autoconf_name);
if (!out) if (ret >= sizeof(name)) /* check truncation */
return 1; return -1;
fprintf(out, "deps_config := \\\n");
for (file = file_list; file; file = file->next) {
if (file->next)
fprintf(out, "\t%s \\\n", file->name);
else
fprintf(out, "\t%s\n", file->name);
}
fprintf(out, "\n%s: \\\n"
"\t$(deps_config)\n\n", conf_get_autoconfig_name());
env_write_dep(out, conf_get_autoconfig_name());
fprintf(out, "\n$(deps_config): ;\n");
fclose(out);
if (make_parent_dir(name)) if (make_parent_dir(name))
return 1; return -1;
rename("..config.tmp", name);
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; return 0;
} }
static int conf_touch_deps(void) static int conf_touch_deps(void)
{ {
const char *name; const char *name, *tmp;
struct symbol *sym; struct symbol *sym;
int res, i; int res, i;
strcpy(depfile_path, "include/config/");
depfile_prefix_len = strlen(depfile_path);
name = conf_get_autoconfig_name(); 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); conf_read_simple(name, S_DEF_AUTO);
sym_calc_value(modules_sym); sym_calc_value(modules_sym);
@ -1056,13 +1153,54 @@ static int conf_touch_deps(void)
return 0; 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) int conf_write_autoconf(int overwrite)
{ {
struct symbol *sym; struct symbol *sym;
const char *name;
const char *autoconf_name = conf_get_autoconfig_name(); const char *autoconf_name = conf_get_autoconfig_name();
FILE *out, *out_h; int ret, i;
int i;
#ifndef OPENWRT_DOES_NOT_WANT_THIS #ifndef OPENWRT_DOES_NOT_WANT_THIS
return 0; return 0;
@ -1070,52 +1208,38 @@ int conf_write_autoconf(int overwrite)
if (!overwrite && is_present(autoconf_name)) if (!overwrite && is_present(autoconf_name))
return 0; 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()) if (conf_touch_deps())
return 1; return 1;
out = fopen(".tmpconfig", "w"); for_all_symbols(i, sym)
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) {
sym_calc_value(sym); sym_calc_value(sym);
if (!(sym->flags & SYMBOL_WRITE) || !sym->name)
continue;
/* write symbols to auto.conf and autoconf.h */ ret = __conf_write_autoconf(conf_get_autoheader_name(),
conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); print_symbol_for_c,
conf_write_symbol(out_h, sym, &header_printer_cb, NULL); &comment_style_c);
} if (ret)
fclose(out); return ret;
fclose(out_h);
name = getenv("KCONFIG_AUTOHEADER"); ret = __conf_write_autoconf(conf_get_rustccfg_name(),
if (!name) print_symbol_for_rustccfg,
name = "include/generated/autoconf.h"; NULL);
if (make_parent_dir(name)) if (ret)
return 1; return ret;
if (rename(".tmpconfig.h", name))
return 1;
if (make_parent_dir(autoconf_name))
return 1;
/* /*
* This must be the last step, kbuild has a dependency on auto.conf * Create include/config/auto.conf. This must be the last step because
* and this marks the successful completion of the previous steps. * Kbuild has a dependency on auto.conf and this marks the successful
* completion of the previous steps.
*/ */
if (rename(".tmpconfig", autoconf_name)) ret = __conf_write_autoconf(conf_get_autoconfig_name(),
return 1; print_symbol_for_autoconf,
&comment_style_pound);
if (ret)
return ret;
return 0; return 0;
} }
@ -1125,10 +1249,12 @@ static void (*conf_changed_callback)(void);
void conf_set_changed(bool val) void conf_set_changed(bool val)
{ {
if (conf_changed_callback && conf_changed != val) bool changed = conf_changed != val;
conf_changed_callback();
conf_changed = val; conf_changed = val;
if (conf_changed_callback && changed)
conf_changed_callback();
} }
bool conf_get_changed(void) bool conf_get_changed(void)

View File

@ -276,7 +276,6 @@ struct jump_key {
struct list_head entries; struct list_head entries;
size_t offset; size_t offset;
struct menu *target; struct menu *target;
int index;
}; };
extern struct file *file_list; extern struct file *file_list;

View File

@ -86,8 +86,7 @@ static void warn_ignored_character(char chr)
n [A-Za-z0-9_-] n [A-Za-z0-9_-]
%% %%
int str = 0; char open_quote = 0;
int ts, i;
#.* /* ignore comment */ #.* /* ignore comment */
[ \t]* /* whitespaces */ [ \t]* /* whitespaces */
@ -137,7 +136,7 @@ n [A-Za-z0-9_-]
":=" return T_COLON_EQUAL; ":=" return T_COLON_EQUAL;
"+=" return T_PLUS_EQUAL; "+=" return T_PLUS_EQUAL;
\"|\' { \"|\' {
str = yytext[0]; open_quote = yytext[0];
new_string(); new_string();
BEGIN(STRING); BEGIN(STRING);
} }
@ -174,7 +173,7 @@ n [A-Za-z0-9_-]
append_string(yytext + 1, yyleng - 1); append_string(yytext + 1, yyleng - 1);
} }
\'|\" { \'|\" {
if (str == yytext[0]) { if (open_quote == yytext[0]) {
BEGIN(INITIAL); BEGIN(INITIAL);
yylval.string = text; yylval.string = text;
return T_WORD_QUOTE; return T_WORD_QUOTE;
@ -199,6 +198,8 @@ n [A-Za-z0-9_-]
<HELP>{ <HELP>{
[ \t]+ { [ \t]+ {
int ts, i;
ts = 0; ts = 0;
for (i = 0; i < yyleng; i++) { for (i = 0; i < yyleng; i++) {
if (yytext[i] == '\t') if (yytext[i] == '\t')

View File

@ -14,6 +14,7 @@
/* First, we deal with platform-specific or compiler-specific issues. */ /* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */ /* begin standard C headers. */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
@ -30,8 +31,8 @@
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, /* C++ systems might need __STDC_LIMIT_MACROS defined before including
* if you want the limit (max/min) macros for int types. * <stdint.h>, if you want the limit (max/min) macros for int types.
*/ */
#ifndef __STDC_LIMIT_MACROS #ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1 #define __STDC_LIMIT_MACROS 1
@ -2538,8 +2539,7 @@ YY_DECL
{ {
int str = 0; char open_quote = 0;
int ts, i;
while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */
{ {
@ -2772,7 +2772,7 @@ return T_PLUS_EQUAL;
case 48: case 48:
YY_RULE_SETUP YY_RULE_SETUP
{ {
str = yytext[0]; open_quote = yytext[0];
new_string(); new_string();
BEGIN(STRING); BEGIN(STRING);
} }
@ -2837,7 +2837,7 @@ YY_RULE_SETUP
case 58: case 58:
YY_RULE_SETUP YY_RULE_SETUP
{ {
if (str == yytext[0]) { if (open_quote == yytext[0]) {
BEGIN(INITIAL); BEGIN(INITIAL);
yylval.string = text; yylval.string = text;
return T_WORD_QUOTE; return T_WORD_QUOTE;
@ -2869,6 +2869,8 @@ case YY_STATE_EOF(STRING):
case 60: case 60:
YY_RULE_SETUP YY_RULE_SETUP
{ {
int ts, i;
ts = 0; ts = 0;
for (i = 0; i < yyleng; i++) { for (i = 0; i < yyleng; i++) {
if (yytext[i] == '\t') if (yytext[i] == '\t')

View File

@ -77,7 +77,7 @@ struct gstr str_new(void);
void str_free(struct gstr *gs); void str_free(struct gstr *gs);
void str_append(struct gstr *gs, const char *s); void str_append(struct gstr *gs, const char *s);
void str_printf(struct gstr *gs, const char *fmt, ...); void str_printf(struct gstr *gs, const char *fmt, ...);
const char *str_get(struct gstr *gs); char *str_get(struct gstr *gs);
/* menu.c */ /* menu.c */
void _menu_init(void); void _menu_init(void);
@ -100,10 +100,10 @@ bool menu_is_empty(struct menu *menu);
bool menu_is_visible(struct menu *menu); bool menu_is_visible(struct menu *menu);
bool menu_has_prompt(struct menu *menu); bool menu_has_prompt(struct menu *menu);
const char *menu_get_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); struct menu *menu_get_parent_menu(struct menu *menu);
bool menu_has_help(struct menu *menu); bool menu_has_help(struct menu *menu);
const char *menu_get_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); struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head);
void menu_get_ext_help(struct menu *menu, struct gstr *help); 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; 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) static inline bool sym_is_choice(struct symbol *sym)
{ {
return sym->flags & SYMBOL_CHOICE ? true : false; return sym->flags & SYMBOL_CHOICE ? true : false;

View File

@ -19,7 +19,7 @@ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE];
struct symbol * sym_lookup(const char *name, int flags); struct symbol * sym_lookup(const char *name, int flags);
struct symbol * sym_find(const char *name); 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); struct symbol ** sym_re_search(const char *pattern);
const char * sym_type_name(enum symbol_type type); const char * sym_type_name(enum symbol_type type);
void sym_calc_value(struct symbol *sym); void sym_calc_value(struct symbol *sym);

View File

@ -18,22 +18,6 @@
#endif #endif
#include <ncurses.h> #include <ncurses.h>
/*
* Colors in ncurses 1.9.9e do not work properly since foreground and
* background colors are OR'd rather than separately masked. This version
* of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
* with standard curses. The simplest fix (to make this work with standard
* curses) uses the wbkgdset() function, not used in the original hack.
* Turn it off if we're building with 1.9.9e, since it just confuses things.
*/
#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
#define OLD_NCURSES 1
#undef wbkgdset
#define wbkgdset(w,p) /*nothing */
#else
#define OLD_NCURSES 0
#endif
#define TR(params) _tracef params #define TR(params) _tracef params
#define KEY_ESC 27 #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_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height, int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause); int width, int pause);
int dialog_textbox(const char *title, const char *tbuf, int initial_height,
int initial_width, int *_vscroll, int *_hscroll,
typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void int (*extra_key_cb)(int, size_t, size_t, void *), void *data);
*_data);
int dialog_textbox(const char *title, char *tbuf, int initial_height,
int initial_width, int *keys, int *_vscroll, int *_hscroll,
update_text_fn update_text, void *data);
int dialog_menu(const char *title, const char *prompt, int dialog_menu(const char *title, const char *prompt,
const void *selected, int *s_scroll); const void *selected, int *s_scroll);
int dialog_checklist(const char *title, const char *prompt, int height, int dialog_checklist(const char *title, const char *prompt, int height,
int width, int list_height); int width, int list_height);
int dialog_inputbox(const char *title, const char *prompt, int height, int dialog_inputbox(const char *title, const char *prompt, int height,
int width, const char *init); int width, const char *init);
/*
* 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)

View File

@ -63,15 +63,7 @@ static void do_print_item(WINDOW * win, const char *item, int line_y,
/* Clear 'residue' of last item */ /* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr); wattrset(win, dlg.menubox.atr);
wmove(win, line_y, 0); wmove(win, line_y, 0);
#if OLD_NCURSES
{
int i;
for (i = 0; i < menu_width; i++)
waddch(win, ' ');
}
#else
wclrtoeol(win); wclrtoeol(win);
#endif
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr); wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
mvwaddstr(win, line_y, item_x, menu_item); mvwaddstr(win, line_y, item_x, menu_item);
if (hotkey) { if (hotkey) {

View File

@ -8,41 +8,149 @@
#include "dialog.h" #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 hscroll;
static int begin_reached, end_reached, page_length; static int begin_reached, end_reached, page_length;
static char *buf; static const char *buf, *page;
static char *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 * refresh window content
*/ */
static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw, static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
int cur_y, int cur_x, update_text_fn update_text, int cur_y, int cur_x)
void *data)
{ {
print_page(box, boxh, boxw, update_text, data); start = page - buf;
print_page(box, boxh, boxw);
print_position(dialog); print_position(dialog);
wmove(dialog, cur_y, cur_x); /* Restore cursor position */ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog); wrefresh(dialog);
}
end = page - buf;
}
/* /*
* Display text from a file in a dialog box. * Display text from a file in a dialog box.
* *
* keys is a null-terminated array * 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 dialog_textbox(const char *title, const char *tbuf, int initial_height,
int initial_width, int *keys, int *_vscroll, int *_hscroll, int initial_width, int *_vscroll, int *_hscroll,
update_text_fn update_text, void *data) int (*extra_key_cb)(int, size_t, size_t, void *), void *data)
{ {
int i, x, y, cur_x, cur_y, key = 0; int i, x, y, cur_x, cur_y, key = 0;
int height, width, boxh, boxw; int height, width, boxh, boxw;
@ -122,8 +230,7 @@ do_resize:
/* Print first page of text */ /* Print first page of text */
attr_clear(box, boxh, boxw, dlg.dialog.atr); attr_clear(box, boxh, boxw, dlg.dialog.atr);
refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
data);
while (!done) { while (!done) {
key = wgetch(dialog); key = wgetch(dialog);
@ -142,8 +249,7 @@ do_resize:
begin_reached = 1; begin_reached = 1;
page = buf; page = buf;
refresh_text_box(dialog, box, boxh, boxw, refresh_text_box(dialog, box, boxh, boxw,
cur_y, cur_x, update_text, cur_y, cur_x);
data);
} }
break; break;
case 'G': /* Last page */ case 'G': /* Last page */
@ -153,8 +259,7 @@ do_resize:
/* point to last char in buf */ /* point to last char in buf */
page = buf + strlen(buf); page = buf + strlen(buf);
back_lines(boxh); back_lines(boxh);
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case 'K': /* Previous line */ case 'K': /* Previous line */
case 'k': case 'k':
@ -163,8 +268,7 @@ do_resize:
break; break;
back_lines(page_length + 1); back_lines(page_length + 1);
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case 'B': /* Previous page */ case 'B': /* Previous page */
case 'b': case 'b':
@ -173,8 +277,7 @@ do_resize:
if (begin_reached) if (begin_reached)
break; break;
back_lines(page_length + boxh); back_lines(page_length + boxh);
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case 'J': /* Next line */ case 'J': /* Next line */
case 'j': case 'j':
@ -183,8 +286,7 @@ do_resize:
break; break;
back_lines(page_length - 1); back_lines(page_length - 1);
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case KEY_NPAGE: /* Next page */ case KEY_NPAGE: /* Next page */
case ' ': case ' ':
@ -193,8 +295,7 @@ do_resize:
break; break;
begin_reached = 0; begin_reached = 0;
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case '0': /* Beginning of line */ case '0': /* Beginning of line */
case 'H': /* Scroll left */ case 'H': /* Scroll left */
@ -209,8 +310,7 @@ do_resize:
hscroll--; hscroll--;
/* Reprint current page to scroll horizontally */ /* Reprint current page to scroll horizontally */
back_lines(page_length); back_lines(page_length);
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case 'L': /* Scroll right */ case 'L': /* Scroll right */
case 'l': case 'l':
@ -220,8 +320,7 @@ do_resize:
hscroll++; hscroll++;
/* Reprint current page to scroll horizontally */ /* Reprint current page to scroll horizontally */
back_lines(page_length); back_lines(page_length);
refresh_text_box(dialog, box, boxh, boxw, cur_y, refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
cur_x, update_text, data);
break; break;
case KEY_ESC: case KEY_ESC:
if (on_key_esc(dialog) == KEY_ESC) if (on_key_esc(dialog) == KEY_ESC)
@ -234,14 +333,12 @@ do_resize:
on_key_resize(); on_key_resize();
goto do_resize; goto do_resize;
default: default:
for (i = 0; keys[i]; i++) { if (extra_key_cb && extra_key_cb(key, start, end, data)) {
if (key == keys[i]) {
done = true; done = true;
break; break;
} }
} }
} }
}
delwin(box); delwin(box);
delwin(dialog); delwin(dialog);
if (_vscroll) { if (_vscroll) {
@ -259,137 +356,3 @@ do_resize:
*_hscroll = hscroll; *_hscroll = hscroll;
return key; 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);
}

View File

@ -1,19 +1,22 @@
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
cflags=$1
libs=$2
PKG="ncursesw" PKG="ncursesw"
PKG2="ncurses" PKG2="ncurses"
if [ -n "$(command -v pkg-config)" ]; then if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then
if pkg-config --exists $PKG; then if ${HOSTPKG_CONFIG} --exists $PKG; then
echo cflags=\"$(pkg-config --cflags $PKG)\" ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags}
echo libs=\"$(pkg-config --libs $PKG)\" ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs}
exit 0 exit 0
fi fi
if pkg-config --exists $PKG2; then if ${HOSTPKG_CONFIG} --exists ${PKG2}; then
echo cflags=\"$(pkg-config --cflags $PKG2)\" ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags}
echo libs=\"$(pkg-config --libs $PKG2)\" ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs}
exit 0 exit 0
fi fi
fi fi
@ -22,22 +25,22 @@ fi
# (Even if it is installed, some distributions such as openSUSE cannot # (Even if it is installed, some distributions such as openSUSE cannot
# find ncurses by pkg-config.) # find ncurses by pkg-config.)
if [ -f /usr/include/ncursesw/ncurses.h ]; then if [ -f /usr/include/ncursesw/ncurses.h ]; then
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\" echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags}
echo libs=\"-lncursesw\" echo -lncursesw > ${libs}
exit 0 exit 0
fi fi
if [ -f /usr/include/ncurses/ncurses.h ]; then if [ -f /usr/include/ncurses/ncurses.h ]; then
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\" echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags}
echo libs=\"-lncurses\" echo -lncurses > ${libs}
exit 0 exit 0
fi fi
# As a final fallback before giving up, check if $HOSTCC knows of a default # As a final fallback before giving up, check if $HOSTCC knows of a default
# ncurses installation (e.g. from a vendor-specific sysroot). # ncurses installation (e.g. from a vendor-specific sysroot).
if echo '#include <ncurses.h>' | ${HOSTCC} -E - >/dev/null 2>&1; then if echo '#include <ncurses.h>' | ${HOSTCC} -E - >/dev/null 2>&1; then
echo cflags=\"-D_GNU_SOURCE\" echo -D_GNU_SOURCE > ${cflags}
echo libs=\"-lncurses\" echo -lncurses > ${libs}
exit 0 exit 0
fi fi
@ -46,7 +49,7 @@ echo >&2 "* Unable to find the ncurses package."
echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
echo >&2 "* depending on your distribution)." echo >&2 "* depending on your distribution)."
echo >&2 "*" 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 "* ncurses installed in a non-default location."
echo >&2 "*" echo >&2 "*"
exit 1 exit 1

View File

@ -22,8 +22,6 @@
#include "lkc.h" #include "lkc.h"
#include "lxdialog/dialog.h" #include "lxdialog/dialog.h"
#define JUMP_NB 9
static const char mconf_readme[] = static const char mconf_readme[] =
"OpenWrt config is based on Kernel kconfig\n" "OpenWrt config is based on Kernel kconfig\n"
"so ipkg packages are referred here as modules.\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" "(especially with a larger number of unrolled categories) than the\n"
"default mode.\n" "default mode.\n"
"\n" "\n"
"Search\n"
"-------\n"
"Pressing the forward-slash (/) anywhere brings up a search dialog box.\n"
"\n"
"Different color themes available\n" "Different color themes available\n"
"--------------------------------\n" "--------------------------------\n"
"It is possible to select different color themes using the variable\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 show_all_options;
static int save_and_exit; static int save_and_exit;
static int silent; static int silent;
static int jump_key_char;
static void conf(struct menu *menu, struct menu *active_menu); 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 char filename[PATH_MAX+1];
static void set_config_filename(const char *config_filename) static void set_config_filename(const char *config_filename)
@ -355,37 +350,87 @@ static void reset_subtitle(void)
set_dialog_subtitles(subtitles); 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 search_data {
struct list_head *head; struct list_head *head;
struct menu **targets; struct menu *target;
int *keys;
}; };
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 search_data *data = _data;
struct jump_key *pos; 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) { list_for_each_entry(pos, data->head, entries) {
if (pos->offset >= start && pos->offset < end) { index = next_jump_key(index);
char header[4];
if (k < JUMP_NB) { if (pos->offset < start)
int key = '0' + (pos->index % JUMP_NB) + 1; continue;
sprintf(header, "(%c)", key); if (pos->offset >= end)
data->keys[k] = key; break;
data->targets[k] = pos->target;
k++;
} else {
sprintf(header, " ");
}
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) static void search_conf(void)
@ -432,25 +477,21 @@ again:
sym_arr = sym_re_search(dialog_input); sym_arr = sym_re_search(dialog_input);
do { do {
LIST_HEAD(head); LIST_HEAD(head);
struct menu *targets[JUMP_NB];
int keys[JUMP_NB + 1], i;
struct search_data data = { struct search_data data = {
.head = &head, .head = &head,
.targets = targets,
.keys = keys,
}; };
struct jump_key *pos, *tmp; struct jump_key *pos, *tmp;
jump_key_char = 0;
res = get_relations_str(sym_arr, &head); res = get_relations_str(sym_arr, &head);
set_subtitle(); set_subtitle();
dres = show_textbox_ext("Search Results", (char *) dres = show_textbox_ext("Search Results", str_get(&res), 0, 0,
str_get(&res), 0, 0, keys, &vscroll, &vscroll, &hscroll,
&hscroll, &update_text, (void *) handle_search_keys, &data);
&data);
again = false; again = false;
for (i = 0; i < JUMP_NB && keys[i]; i++) if (dres >= '1' && dres <= '9') {
if (dres == keys[i]) { assert(data.target != NULL);
conf(targets[i]->parent, targets[i]); conf(data.target->parent, data.target);
again = true; again = true;
} }
str_free(&res); str_free(&res);
@ -641,158 +682,6 @@ conf_childs:
indent -= doint; 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) static void conf_choice(struct menu *menu)
{ {
const char *prompt = menu_get_prompt(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) static int handle_exit(void)
{ {
int res; int res;

View File

@ -661,11 +661,6 @@ const char *menu_get_prompt(struct menu *menu)
return NULL; return NULL;
} }
struct menu *menu_get_root_menu(struct menu *menu)
{
return &rootmenu;
}
struct menu *menu_get_parent_menu(struct menu *menu) struct menu *menu_get_parent_menu(struct menu *menu)
{ {
enum prop_type type; 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, static void get_prompt_str(struct gstr *r, struct property *prop,
struct list_head *head) struct list_head *head)
{ {
@ -727,45 +727,35 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
if (!expr_eq(prop->menu->dep, prop->visible.expr)) if (!expr_eq(prop->menu->dep, prop->visible.expr))
get_dep_str(r, prop->visible.expr, " Visible if: "); 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) { for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) {
bool accessible = menu_is_visible(menu);
submenu[i++] = menu; submenu[i++] = menu;
if (location == NULL && accessible) if (location == NULL && menu_is_visible(menu))
location = menu; location = menu;
} }
if (head && location) { if (head && location) {
jump = xmalloc(sizeof(struct jump_key)); 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; jump->target = location;
if (list_empty(head))
jump->index = 0;
else
jump->index = list_entry(head->prev, struct jump_key,
entries)->index + 1;
list_add_tail(&jump->entries, head); list_add_tail(&jump->entries, head);
} }
if (i > 0) {
str_printf(r, " Location:\n"); str_printf(r, " Location:\n");
for (j = 4; --i >= 0; j += 2) { for (j = 0; --i >= 0; j++) {
int jk = -1;
int indent = 2 * j + 4;
menu = submenu[i]; menu = submenu[i];
if (jump && menu == location) if (jump && menu == location) {
jump->offset = strlen(r->s); jump->offset = strlen(r->s);
str_printf(r, "%*c-> %s", j, ' ', jk = get_jump_key_char();
menu_get_prompt(menu)); }
if (jk >= 0) {
str_printf(r, "(%c)", jk);
indent -= 3;
}
str_printf(r, "%*c-> %s", indent, ' ', menu_get_prompt(menu));
if (menu->sym) { if (menu->sym) {
str_printf(r, " (%s [=%s])", menu->sym->name ? str_printf(r, " (%s [=%s])", menu->sym->name ?
menu->sym->name : "<choice>", menu->sym->name : "<choice>",
@ -774,7 +764,6 @@ static void get_prompt_str(struct gstr *r, struct property *prop,
str_append(r, "\n"); str_append(r, "\n");
} }
} }
}
static void get_symbol_props_str(struct gstr *r, struct symbol *sym, static void get_symbol_props_str(struct gstr *r, struct symbol *sym,
enum prop_type tok, const char *prefix) enum prop_type tok, const char *prefix)

View File

@ -1,19 +1,22 @@
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only # SPDX-License-Identifier: GPL-2.0-only
cflags=$1
libs=$2
PKG="ncursesw menuw panelw" PKG="ncursesw menuw panelw"
PKG2="ncurses menu panel" PKG2="ncurses menu panel"
if [ -n "$(command -v pkg-config)" ]; then if [ -n "$(command -v ${HOSTPKG_CONFIG})" ]; then
if pkg-config --exists $PKG; then if ${HOSTPKG_CONFIG} --exists $PKG; then
echo cflags=\"$(pkg-config --cflags $PKG)\" ${HOSTPKG_CONFIG} --cflags ${PKG} > ${cflags}
echo libs=\"$(pkg-config --libs $PKG)\" ${HOSTPKG_CONFIG} --libs ${PKG} > ${libs}
exit 0 exit 0
fi fi
if pkg-config --exists $PKG2; then if ${HOSTPKG_CONFIG} --exists $PKG2; then
echo cflags=\"$(pkg-config --cflags $PKG2)\" ${HOSTPKG_CONFIG} --cflags ${PKG2} > ${cflags}
echo libs=\"$(pkg-config --libs $PKG2)\" ${HOSTPKG_CONFIG} --libs ${PKG2} > ${libs}
exit 0 exit 0
fi fi
fi fi
@ -22,20 +25,20 @@ fi
# (Even if it is installed, some distributions such as openSUSE cannot # (Even if it is installed, some distributions such as openSUSE cannot
# find ncurses by pkg-config.) # find ncurses by pkg-config.)
if [ -f /usr/include/ncursesw/ncurses.h ]; then if [ -f /usr/include/ncursesw/ncurses.h ]; then
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncursesw\" echo -D_GNU_SOURCE -I/usr/include/ncursesw > ${cflags}
echo libs=\"-lncursesw -lmenuw -lpanelw\" echo -lncursesw -lmenuw -lpanelw > ${libs}
exit 0 exit 0
fi fi
if [ -f /usr/include/ncurses/ncurses.h ]; then if [ -f /usr/include/ncurses/ncurses.h ]; then
echo cflags=\"-D_GNU_SOURCE -I/usr/include/ncurses\" echo -D_GNU_SOURCE -I/usr/include/ncurses > ${cflags}
echo libs=\"-lncurses -lmenu -lpanel\" echo -lncurses -lmenu -lpanel > ${libs}
exit 0 exit 0
fi fi
if [ -f /usr/include/ncurses.h ]; then if [ -f /usr/include/ncurses.h ]; then
echo cflags=\"-D_GNU_SOURCE\" echo -D_GNU_SOURCE > ${cflags}
echo libs=\"-lncurses -lmenu -lpanel\" echo -lncurses -lmenu -lpanel > ${libs}
exit 0 exit 0
fi fi
@ -44,7 +47,7 @@ echo >&2 "* Unable to find the ncurses package."
echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev"
echo >&2 "* depending on your distribution)." echo >&2 "* depending on your distribution)."
echo >&2 "*" 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 "* ncurses installed in a non-default location."
echo >&2 "*" echo >&2 "*"
exit 1 exit 1

View File

@ -55,8 +55,8 @@ static const char nconf_global_help[] =
"\n" "\n"
"Menu navigation keys\n" "Menu navigation keys\n"
"----------------------------------------------------------------------\n" "----------------------------------------------------------------------\n"
"Linewise up <Up>\n" "Linewise up <Up> <k>\n"
"Linewise down <Down>\n" "Linewise down <Down> <j>\n"
"Pagewise up <Page Up>\n" "Pagewise up <Page Up>\n"
"Pagewise down <Page Down>\n" "Pagewise down <Page Down>\n"
"First entry <Home>\n" "First entry <Home>\n"
@ -223,7 +223,7 @@ search_help[] =
"Location:\n" "Location:\n"
" -> Bus options (PCI, PCMCIA, EISA, ISA)\n" " -> Bus options (PCI, PCMCIA, EISA, ISA)\n"
" -> PCI support (PCI [ = y])\n" " -> PCI support (PCI [ = y])\n"
" -> PCI access mode (<choice> [ = y])\n" "(1) -> PCI access mode (<choice> [ = y])\n"
"Selects: LIBCRC32\n" "Selects: LIBCRC32\n"
"Selected by: BAR\n" "Selected by: BAR\n"
"-----------------------------------------------------------------\n" "-----------------------------------------------------------------\n"
@ -234,9 +234,13 @@ search_help[] =
"o The 'Depends on:' line lists symbols that need to be defined for\n" "o The 'Depends on:' line lists symbols that need to be defined for\n"
" this symbol to be visible and selectable in the menu.\n" " this symbol to be visible and selectable in the menu.\n"
"o The 'Location:' lines tell, where in the menu structure this symbol\n" "o The 'Location:' lines tell, where in the menu structure this symbol\n"
" is located. A location followed by a [ = y] indicates that this is\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" " a selectable menu item, and the current value is displayed inside\n"
" brackets.\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" "o The 'Selects:' line tells, what symbol will be automatically selected\n"
" if this symbol is selected (y or m).\n" " if this symbol is selected (y or m).\n"
"o The 'Selected by' line tells what symbol has selected this symbol.\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 char *dialog_input_result;
static int dialog_input_result_len; 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(struct menu *menu);
static void conf_choice(struct menu *menu); static void conf_choice(struct menu *menu);
static void conf_string(struct menu *menu); static void conf_string(struct menu *menu);
@ -688,6 +694,57 @@ static int do_exit(void)
return 0; 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) static void search_conf(void)
{ {
@ -695,7 +752,8 @@ static void search_conf(void)
struct gstr res; struct gstr res;
struct gstr title; struct gstr title;
char *dialog_input; char *dialog_input;
int dres; int dres, vscroll = 0, hscroll = 0;
bool again;
title = str_new(); title = str_new();
str_printf( &title, "Enter (sub)string or regexp to search for " str_printf( &title, "Enter (sub)string or regexp to search for "
@ -724,11 +782,28 @@ again:
dialog_input += strlen(CONFIG_); dialog_input += strlen(CONFIG_);
sym_arr = sym_re_search(dialog_input); sym_arr = sym_re_search(dialog_input);
res = get_relations_str(sym_arr, NULL);
free(sym_arr); do {
show_scroll_win(main_window, LIST_HEAD(head);
"Search Results", str_get(&res)); 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); str_free(&res);
} while (again);
free(sym_arr);
str_free(&title); 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) 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 menu *submenu = NULL;
struct symbol *sym; struct symbol *sym;
int res; int i, res;
int current_index = 0; int current_index = 0;
int last_top_row = 0; int last_top_row = 0;
struct match_state match_state = { struct match_state match_state = {
@ -1084,6 +1164,19 @@ static void conf(struct menu *menu)
if (!child_count) if (!child_count)
break; 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, show_menu(menu_get_prompt(menu), menu_instructions,
current_index, &last_top_row); current_index, &last_top_row);
keypad((menu_win(curses_menu)), TRUE); keypad((menu_win(curses_menu)), TRUE);
@ -1108,9 +1201,11 @@ static void conf(struct menu *menu)
break; break;
switch (res) { switch (res) {
case KEY_DOWN: case KEY_DOWN:
case 'j':
menu_driver(curses_menu, REQ_DOWN_ITEM); menu_driver(curses_menu, REQ_DOWN_ITEM);
break; break;
case KEY_UP: case KEY_UP:
case 'k':
menu_driver(curses_menu, REQ_UP_ITEM); menu_driver(curses_menu, REQ_UP_ITEM);
break; break;
case KEY_NPAGE: case KEY_NPAGE:
@ -1291,9 +1386,11 @@ static void conf_choice(struct menu *menu)
break; break;
switch (res) { switch (res) {
case KEY_DOWN: case KEY_DOWN:
case 'j':
menu_driver(curses_menu, REQ_DOWN_ITEM); menu_driver(curses_menu, REQ_DOWN_ITEM);
break; break;
case KEY_UP: case KEY_UP:
case 'k':
menu_driver(curses_menu, REQ_UP_ITEM); menu_driver(curses_menu, REQ_UP_ITEM);
break; break;
case KEY_NPAGE: case KEY_NPAGE:

View File

@ -497,10 +497,17 @@ void refresh_all_windows(WINDOW *main_window)
refresh(); refresh();
} }
/* layman's scrollable window... */
void show_scroll_win(WINDOW *main_window, void show_scroll_win(WINDOW *main_window,
const char *title, const char *title,
const char *text) 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 res;
int total_lines = get_line_no(text); int total_lines = get_line_no(text);
@ -514,6 +521,12 @@ void show_scroll_win(WINDOW *main_window,
WINDOW *win; WINDOW *win;
WINDOW *pad; WINDOW *pad;
PANEL *panel; PANEL *panel;
bool done = false;
if (hscroll)
start_x = *hscroll;
if (vscroll)
start_y = *vscroll;
getmaxyx(stdscr, lines, columns); getmaxyx(stdscr, lines, columns);
@ -549,8 +562,7 @@ void show_scroll_win(WINDOW *main_window,
panel = new_panel(win); panel = new_panel(win);
/* handle scrolling */ /* handle scrolling */
do { while (!done) {
copywin(pad, win, start_y, start_x, 2, 2, text_lines, copywin(pad, win, start_y, start_x, 2, 2, text_lines,
text_cols, 0); text_cols, 0);
print_in_middle(win, print_in_middle(win,
@ -593,8 +605,18 @@ void show_scroll_win(WINDOW *main_window,
case 'l': case 'l':
start_x++; start_x++;
break; 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_HELP) || res == KEY_F(F_BACK) ||
res == KEY_F(F_EXIT)) res == KEY_F(F_EXIT))
break; break;
@ -606,9 +628,14 @@ void show_scroll_win(WINDOW *main_window,
start_x = 0; start_x = 0;
if (start_x >= total_cols-text_cols) if (start_x >= total_cols-text_cols)
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); del_panel(panel);
delwin(win); delwin(win);
refresh_all_windows(main_window); refresh_all_windows(main_window);
return res;
} }

View File

@ -67,6 +67,8 @@ typedef enum {
void set_colors(void); void set_colors(void);
typedef int (*extra_key_cb_fn)(int, size_t, size_t, void *);
/* this changes the windows attributes !!! */ /* this changes the windows attributes !!! */
void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs); void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs);
int get_line_length(const char *line); 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 *title, const char *prompt,
const char *init, char **resultp, int *result_len); const char *init, char **resultp, int *result_len);
void refresh_all_windows(WINDOW *main_window); 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, void show_scroll_win(WINDOW *main_window,
const char *title, const char *title,
const char *text); const char *text);

View File

@ -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 /* Bison implementation for Yacc-like parsers in C
@ -46,10 +46,10 @@
USER NAME SPACE" below. */ USER NAME SPACE" below. */
/* Identify Bison output, and Bison version. */ /* Identify Bison output, and Bison version. */
#define YYBISON 30706 #define YYBISON 30802
/* Bison version string. */ /* Bison version string. */
#define YYBISON_VERSION "3.7.6" #define YYBISON_VERSION "3.8.2"
/* Skeleton name. */ /* Skeleton name. */
#define YYSKELETON_NAME "yacc.c" #define YYSKELETON_NAME "yacc.c"
@ -379,12 +379,18 @@ typedef int yy_state_fast_t;
# define YY_USE(E) /* empty */ # define YY_USE(E) /* empty */
#endif #endif
#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
/* Suppress an incorrect diagnostic about yylval being uninitialized. */ /* Suppress an incorrect diagnostic about yylval being uninitialized. */
#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 \ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
_Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic push") \
_Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \
_Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
# endif
# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ # define YY_IGNORE_MAYBE_UNINITIALIZED_END \
_Pragma ("GCC diagnostic pop") _Pragma ("GCC diagnostic pop")
#else #else
@ -661,20 +667,6 @@ yysymbol_name (yysymbol_kind_t yysymbol)
} }
#endif #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_NINF (-105)
#define yypact_value_is_default(Yyn) \ #define yypact_value_is_default(Yyn) \
@ -807,8 +799,8 @@ static const yytype_int16 yycheck[] =
34, -1, -1, -1, 38 34, -1, -1, -1, 38
}; };
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing /* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of
symbol of state STATE-NUM. */ state STATE-NUM. */
static const yytype_int8 yystos[] = static const yytype_int8 yystos[] =
{ {
0, 24, 52, 53, 54, 5, 0, 54, 1, 4, 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 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[] = static const yytype_int8 yyr1[] =
{ {
0, 51, 52, 52, 53, 54, 54, 54, 54, 54, 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 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[] = static const yytype_int8 yyr2[] =
{ {
0, 2, 2, 1, 3, 0, 2, 2, 2, 2, 0, 2, 2, 1, 3, 0, 2, 2, 2, 2,
@ -873,6 +865,7 @@ enum { YYENOMEM = -2 };
#define YYACCEPT goto yyacceptlab #define YYACCEPT goto yyacceptlab
#define YYABORT goto yyabortlab #define YYABORT goto yyabortlab
#define YYERROR goto yyerrorlab #define YYERROR goto yyerrorlab
#define YYNOMEM goto yyexhaustedlab
#define YYRECOVERING() (!!yyerrstatus) #define YYRECOVERING() (!!yyerrstatus)
@ -913,10 +906,7 @@ do { \
YYFPRINTF Args; \ YYFPRINTF Args; \
} while (0) } 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) \ # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \
@ -943,10 +933,6 @@ yy_symbol_value_print (FILE *yyo,
YY_USE (yyoutput); YY_USE (yyoutput);
if (!yyvaluep) if (!yyvaluep)
return; return;
# ifdef YYPRINT
if (yykind < YYNTOKENS)
YYPRINT (yyo, yytoknum[yykind], *yyvaluep);
# endif
YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
YY_USE (yykind); YY_USE (yykind);
YY_IGNORE_MAYBE_UNINITIALIZED_END YY_IGNORE_MAYBE_UNINITIALIZED_END
@ -1162,6 +1148,7 @@ yyparse (void)
YYDPRINTF ((stderr, "Starting parse\n")); YYDPRINTF ((stderr, "Starting parse\n"));
yychar = YYEMPTY; /* Cause a token to be read. */ yychar = YYEMPTY; /* Cause a token to be read. */
goto yysetstate; goto yysetstate;
@ -1187,7 +1174,7 @@ yysetstate:
if (yyss + yystacksize - 1 <= yyssp) if (yyss + yystacksize - 1 <= yyssp)
#if !defined yyoverflow && !defined YYSTACK_RELOCATE #if !defined yyoverflow && !defined YYSTACK_RELOCATE
goto yyexhaustedlab; YYNOMEM;
#else #else
{ {
/* Get the current used size of the three stacks, in elements. */ /* Get the current used size of the three stacks, in elements. */
@ -1215,7 +1202,7 @@ yysetstate:
# else /* defined YYSTACK_RELOCATE */ # else /* defined YYSTACK_RELOCATE */
/* Extend the stack our own way. */ /* Extend the stack our own way. */
if (YYMAXDEPTH <= yystacksize) if (YYMAXDEPTH <= yystacksize)
goto yyexhaustedlab; YYNOMEM;
yystacksize *= 2; yystacksize *= 2;
if (YYMAXDEPTH < yystacksize) if (YYMAXDEPTH < yystacksize)
yystacksize = YYMAXDEPTH; yystacksize = YYMAXDEPTH;
@ -1226,7 +1213,7 @@ yysetstate:
YY_CAST (union yyalloc *, YY_CAST (union yyalloc *,
YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize))));
if (! yyptr) if (! yyptr)
goto yyexhaustedlab; YYNOMEM;
YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyss_alloc, yyss);
YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyvs_alloc, yyvs);
# undef YYSTACK_RELOCATE # undef YYSTACK_RELOCATE
@ -1248,6 +1235,7 @@ yysetstate:
} }
#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */
if (yystate == YYFINAL) if (yystate == YYFINAL)
YYACCEPT; YYACCEPT;
@ -1832,6 +1820,7 @@ yyerrorlab:
label yyerrorlab therefore never appears in user code. */ label yyerrorlab therefore never appears in user code. */
if (0) if (0)
YYERROR; YYERROR;
++yynerrs;
/* Do not reclaim the symbols of the rule whose action triggered /* Do not reclaim the symbols of the rule whose action triggered
this YYERROR. */ this YYERROR. */
@ -1892,7 +1881,7 @@ yyerrlab1:
`-------------------------------------*/ `-------------------------------------*/
yyacceptlab: yyacceptlab:
yyresult = 0; yyresult = 0;
goto yyreturn; goto yyreturnlab;
/*-----------------------------------. /*-----------------------------------.
@ -1900,24 +1889,22 @@ yyacceptlab:
`-----------------------------------*/ `-----------------------------------*/
yyabortlab: yyabortlab:
yyresult = 1; yyresult = 1;
goto yyreturn; goto yyreturnlab;
#if !defined yyoverflow /*-----------------------------------------------------------.
/*-------------------------------------------------. | yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. |
| yyexhaustedlab -- memory exhaustion comes here. | `-----------------------------------------------------------*/
`-------------------------------------------------*/
yyexhaustedlab: yyexhaustedlab:
yyerror (YY_("memory exhausted")); yyerror (YY_("memory exhausted"));
yyresult = 2; yyresult = 2;
goto yyreturn; goto yyreturnlab;
#endif
/*-------------------------------------------------------. /*----------------------------------------------------------.
| yyreturn -- parsing is finished, clean up and return. | | yyreturnlab -- parsing is finished, clean up and return. |
`-------------------------------------------------------*/ `----------------------------------------------------------*/
yyreturn: yyreturnlab:
if (yychar != YYEMPTY) if (yychar != YYEMPTY)
{ {
/* Make sure we have latest lookahead translation. See comments at /* Make sure we have latest lookahead translation. See comments at

View File

@ -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 /* Bison interface for Yacc-like parsers in C
@ -128,6 +128,8 @@ typedef union YYSTYPE YYSTYPE;
extern YYSTYPE yylval; extern YYSTYPE yylval;
int yyparse (void); int yyparse (void);
#endif /* !YY_YY_PARSER_TAB_H_INCLUDED */ #endif /* !YY_YY_PARSER_TAB_H_INCLUDED */

View File

@ -141,7 +141,7 @@ static char *do_lineno(int argc, char *argv[])
static char *do_shell(int argc, char *argv[]) static char *do_shell(int argc, char *argv[])
{ {
FILE *p; FILE *p;
char buf[256]; char buf[4096];
char *cmd; char *cmd;
size_t nread; size_t nread;
int i; int i;
@ -396,6 +396,9 @@ static char *eval_clause(const char *str, size_t len, int argc, char *argv[])
p++; p++;
} }
if (new_argc >= FUNCTION_MAX_ARGS)
pperror("too many function arguments");
new_argv[new_argc++] = prev; new_argv[new_argc++] = prev;
/* /*

View File

@ -1,24 +1,40 @@
#!/bin/sh #!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only # 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 "*"
echo >&2 "* 'make xconfig' requires 'pkg-config'. Please install it." echo >&2 "* 'make xconfig' requires '${HOSTPKG_CONFIG}'. Please install it."
echo >&2 "*" echo >&2 "*"
exit 1 exit 1
fi fi
if pkg-config --exists $PKG; then if ${HOSTPKG_CONFIG} --exists $PKG6; then
echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags $PKG)\" ${HOSTPKG_CONFIG} --cflags ${PKG6} > ${cflags}
echo libs=\"$(pkg-config --libs $PKG)\" # Qt6 requires C++17.
echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\" 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 exit 0
fi fi
echo >&2 "*" echo >&2 "*"
echo >&2 "* Could not find Qt5 via pkg-config." echo >&2 "* Could not find Qt6 or Qt5 via ${HOSTPKG_CONFIG}."
echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH" 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 "*" echo >&2 "*"
exit 1 exit 1

View File

@ -5,10 +5,10 @@
*/ */
#include <QAction> #include <QAction>
#include <QActionGroup>
#include <QApplication> #include <QApplication>
#include <QCloseEvent> #include <QCloseEvent>
#include <QDebug> #include <QDebug>
#include <QDesktopWidget>
#include <QFileDialog> #include <QFileDialog>
#include <QLabel> #include <QLabel>
#include <QLayout> #include <QLayout>
@ -16,6 +16,8 @@
#include <QMenu> #include <QMenu>
#include <QMenuBar> #include <QMenuBar>
#include <QMessageBox> #include <QMessageBox>
#include <QRegularExpression>
#include <QScreen>
#include <QToolBar> #include <QToolBar>
#include <stdlib.h> #include <stdlib.h>
@ -1126,7 +1128,7 @@ QString ConfigInfoView::debug_info(struct symbol *sym)
QString ConfigInfoView::print_filter(const QString &str) QString ConfigInfoView::print_filter(const QString &str)
{ {
QRegExp re("[<>&\"\\n]"); QRegularExpression re("[<>&\"\\n]");
QString res = str; QString res = str;
for (int i = 0; (i = res.indexOf(re, i)) >= 0;) { for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
switch (res[i].toLatin1()) { switch (res[i].toLatin1()) {
@ -1322,15 +1324,15 @@ ConfigMainWindow::ConfigMainWindow(void)
int width, height; int width, height;
char title[256]; char title[256];
QDesktopWidget *d = configApp->desktop();
snprintf(title, sizeof(title), "%s%s", snprintf(title, sizeof(title), "%s%s",
rootmenu.prompt->text, rootmenu.prompt->text,
"" ""
); );
setWindowTitle(title); setWindowTitle(title);
width = configSettings->value("/window width", d->width() - 64).toInt(); QRect g = configApp->primaryScreen()->geometry();
height = configSettings->value("/window height", d->height() - 64).toInt(); width = configSettings->value("/window width", g.width() - 64).toInt();
height = configSettings->value("/window height", g.height() - 64).toInt();
resize(width, height); resize(width, height);
x = configSettings->value("/window x"); x = configSettings->value("/window x");
y = configSettings->value("/window y"); y = configSettings->value("/window y");
@ -1379,17 +1381,17 @@ ConfigMainWindow::ConfigMainWindow(void)
this, &ConfigMainWindow::goBack); this, &ConfigMainWindow::goBack);
QAction *quitAction = new QAction("&Quit", this); QAction *quitAction = new QAction("&Quit", this);
quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); quitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
connect(quitAction, &QAction::triggered, connect(quitAction, &QAction::triggered,
this, &ConfigMainWindow::close); this, &ConfigMainWindow::close);
QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); 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, connect(loadAction, &QAction::triggered,
this, &ConfigMainWindow::loadConfig); this, &ConfigMainWindow::loadConfig);
saveAction = new QAction(QPixmap(xpm_save), "&Save", this); 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, connect(saveAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfig); this, &ConfigMainWindow::saveConfig);
@ -1403,7 +1405,7 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(saveAsAction, &QAction::triggered, connect(saveAsAction, &QAction::triggered,
this, &ConfigMainWindow::saveConfigAs); this, &ConfigMainWindow::saveConfigAs);
QAction *searchAction = new QAction("&Find", this); QAction *searchAction = new QAction("&Find", this);
searchAction->setShortcut(Qt::CTRL + Qt::Key_F); searchAction->setShortcut(Qt::CTRL | Qt::Key_F);
connect(searchAction, &QAction::triggered, connect(searchAction, &QAction::triggered,
this, &ConfigMainWindow::searchConfig); this, &ConfigMainWindow::searchConfig);
singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this);
@ -1750,11 +1752,21 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e)
e->accept(); e->accept();
return; return;
} }
QMessageBox mb("qconf", "Save configuration?", QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::Default, QMessageBox::No, QMessageBox::Cancel | QMessageBox::Escape); QMessageBox mb(QMessageBox::Icon::Warning, "qconf",
mb.setButtonText(QMessageBox::Yes, "&Save Changes"); "Save configuration?");
mb.setButtonText(QMessageBox::No, "&Discard Changes");
mb.setButtonText(QMessageBox::Cancel, "Cancel Exit"); 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()) { switch (mb.exec()) {
case QMessageBox::Yes: case QMessageBox::Yes:
if (saveConfig()) if (saveConfig())

View File

@ -123,9 +123,9 @@ static long long sym_get_range_val(struct symbol *sym, int base)
static void sym_validate_range(struct symbol *sym) static void sym_validate_range(struct symbol *sym)
{ {
struct property *prop; struct property *prop;
struct symbol *range_sym;
int base; int base;
long long val, val2; long long val, val2;
char str[64];
switch (sym->type) { switch (sym->type) {
case S_INT: case S_INT:
@ -141,17 +141,15 @@ static void sym_validate_range(struct symbol *sym)
if (!prop) if (!prop)
return; return;
val = strtoll(sym->curr.val, NULL, base); 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) { 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) if (val <= val2)
return; return;
} }
if (sym->type == S_INT) sym->curr.val = range_sym->curr.val;
sprintf(str, "%lld", val2);
else
sprintf(str, "0x%llx", val2);
sym->curr.val = xstrdup(str);
} }
static void sym_set_changed(struct symbol *sym) static void sym_set_changed(struct symbol *sym)
@ -851,49 +849,6 @@ struct symbol *sym_find(const char *name)
return symbol; 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 sym_match {
struct symbol *sym; struct symbol *sym;
off_t so, eo; off_t so, eo;

View File

@ -74,7 +74,7 @@ void str_printf(struct gstr *gs, const char *fmt, ...)
} }
/* Retrieve value of growable string */ /* Retrieve value of growable string */
const char *str_get(struct gstr *gs) char *str_get(struct gstr *gs)
{ {
return gs->s; return gs->s;
} }