summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am8
-rw-r--r--src/Makefile.in156
-rw-r--r--src/deque.c52
-rw-r--r--src/format.c42
-rw-r--r--src/internal.h4
-rw-r--r--src/io.c88
-rw-r--r--src/libHX.map56
-rw-r--r--src/map_int.h3
-rw-r--r--src/misc.c14
-rw-r--r--src/opt.c307
-rw-r--r--src/proc.c7
-rw-r--r--src/socket.c12
-rw-r--r--src/string.c397
-rw-r--r--src/tc-compile.c2
-rw-r--r--src/tc-io.c12
-rw-r--r--src/tc-list.c2
-rw-r--r--src/tc-map.c22
-rw-r--r--src/tc-netio.c1
-rw-r--r--src/tc-option.c207
-rw-r--r--src/tc-proc.c1
-rw-r--r--src/tc-realpath.c62
-rw-r--r--src/tc-socket.c1
-rw-r--r--src/tc-string.c79
-rw-r--r--src/tc-strquote.c5
-rw-r--r--src/tc-switchuser.c19
-rw-r--r--src/tc-time.c1
-rw-r--r--src/tx-compile.cpp1
-rw-r--r--src/tx-option.cpp21
28 files changed, 949 insertions, 633 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 11a240e..2e26d7e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,8 +9,8 @@ libHX_la_SOURCES = deque.c dl.c format.c io.c map.c \
mc.c misc.c opt.c proc.c \
rand.c socket.c string.c time.c
libHX_la_LIBADD = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS} ${libsocket_LIBS}
-libHX_la_LDFLAGS = -no-undefined -version-info 39:0:7
-if WITH_GNU_LD
+libHX_la_LDFLAGS = -no-undefined -version-info 43:0:0
+if WITH_LDSYM
libHX_la_LDFLAGS += -Wl,--version-script=${srcdir}/libHX.map
endif
if WITH_SUN_LD
@@ -60,7 +60,7 @@ if HAVE_CXX
check_PROGRAMS += tx-compile tx-cast tx-deque tx-dir \
tx-intdiff tx-list tx-list2 \
tx-misc tx-netio \
- tx-option tx-proc tx-rand tx-strchr2 tx-string \
+ tx-proc tx-rand tx-strchr2 tx-string \
tx-strquote tx-time
TESTS += tx-strchr2 tx-strquote
tx_cast_SOURCES = tx-cast.cpp
@@ -80,8 +80,6 @@ tx_misc_SOURCES = tx-misc.cpp
tx_misc_LDADD = libHX.la
tx_netio_SOURCES = tx-netio.cpp
tx_netio_LDADD = libHX.la ${libsocket_LIBS}
-tx_option_SOURCES = tx-option.cpp
-tx_option_LDADD = libHX.la
tx_proc_SOURCES = tx-proc.cpp
tx_proc_LDADD = libHX.la
tx_rand_SOURCES = tx-rand.cpp
diff --git a/src/Makefile.in b/src/Makefile.in
index 22766b5..9cbd614 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# Makefile.in generated by automake 1.18.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+# Copyright (C) 1994-2025 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -72,6 +72,8 @@ am__make_running_with_option = \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+am__rm_f = rm -f $(am__rm_f_notfound)
+am__rm_rf = rm -rf $(am__rm_f_notfound)
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
@@ -90,7 +92,7 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-@WITH_GNU_LD_TRUE@am__append_1 = -Wl,--version-script=${srcdir}/libHX.map
+@WITH_LDSYM_TRUE@am__append_1 = -Wl,--version-script=${srcdir}/libHX.map
@WITH_SUN_LD_TRUE@am__append_2 = -Wl,-M,${srcdir}/libHX.map
@MINGW32_TRUE@am__append_3 = ux-file.c ux-mmap.c
@MINGW32_TRUE@am__append_4 = -lws2_32
@@ -108,7 +110,7 @@ TESTS = tc-format$(EXEEXT) tc-option$(EXEEXT) tc-strchr2$(EXEEXT) \
@HAVE_CXX_TRUE@am__append_5 = tx-compile tx-cast tx-deque tx-dir \
@HAVE_CXX_TRUE@ tx-intdiff tx-list tx-list2 \
@HAVE_CXX_TRUE@ tx-misc tx-netio \
-@HAVE_CXX_TRUE@ tx-option tx-proc tx-rand tx-strchr2 tx-string \
+@HAVE_CXX_TRUE@ tx-proc tx-rand tx-strchr2 tx-string \
@HAVE_CXX_TRUE@ tx-strquote tx-time
@HAVE_CXX_TRUE@am__append_6 = tx-strchr2 tx-strquote
@@ -129,10 +131,10 @@ CONFIG_CLEAN_VPATH_FILES =
@HAVE_CXX_TRUE@ tx-deque$(EXEEXT) tx-dir$(EXEEXT) \
@HAVE_CXX_TRUE@ tx-intdiff$(EXEEXT) tx-list$(EXEEXT) \
@HAVE_CXX_TRUE@ tx-list2$(EXEEXT) tx-misc$(EXEEXT) \
-@HAVE_CXX_TRUE@ tx-netio$(EXEEXT) tx-option$(EXEEXT) \
-@HAVE_CXX_TRUE@ tx-proc$(EXEEXT) tx-rand$(EXEEXT) \
-@HAVE_CXX_TRUE@ tx-strchr2$(EXEEXT) tx-string$(EXEEXT) \
-@HAVE_CXX_TRUE@ tx-strquote$(EXEEXT) tx-time$(EXEEXT)
+@HAVE_CXX_TRUE@ tx-netio$(EXEEXT) tx-proc$(EXEEXT) \
+@HAVE_CXX_TRUE@ tx-rand$(EXEEXT) tx-strchr2$(EXEEXT) \
+@HAVE_CXX_TRUE@ tx-string$(EXEEXT) tx-strquote$(EXEEXT) \
+@HAVE_CXX_TRUE@ tx-time$(EXEEXT)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -155,10 +157,9 @@ am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
- test -z "$$files" \
- || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
- || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
- $(am__cd) "$$dir" && rm -f $$files; }; \
+ { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && echo $$files | $(am__xargs_n) 40 $(am__rm_f); }; \
}
am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
@@ -295,10 +296,6 @@ am__tx_netio_SOURCES_DIST = tx-netio.cpp
@HAVE_CXX_TRUE@am_tx_netio_OBJECTS = tx-netio.$(OBJEXT)
tx_netio_OBJECTS = $(am_tx_netio_OBJECTS)
@HAVE_CXX_TRUE@tx_netio_DEPENDENCIES = libHX.la $(am__DEPENDENCIES_1)
-am__tx_option_SOURCES_DIST = tx-option.cpp
-@HAVE_CXX_TRUE@am_tx_option_OBJECTS = tx-option.$(OBJEXT)
-tx_option_OBJECTS = $(am_tx_option_OBJECTS)
-@HAVE_CXX_TRUE@tx_option_DEPENDENCIES = libHX.la
am__tx_proc_SOURCES_DIST = tx-proc.cpp
@HAVE_CXX_TRUE@am_tx_proc_OBJECTS = tx-proc.$(OBJEXT)
tx_proc_OBJECTS = $(am_tx_proc_OBJECTS)
@@ -359,11 +356,11 @@ am__depfiles_remade = ./$(DEPDIR)/deque.Plo ./$(DEPDIR)/dl.Plo \
./$(DEPDIR)/tx-deque.Po ./$(DEPDIR)/tx-dir.Po \
./$(DEPDIR)/tx-intdiff.Po ./$(DEPDIR)/tx-list.Po \
./$(DEPDIR)/tx-misc.Po ./$(DEPDIR)/tx-netio.Po \
- ./$(DEPDIR)/tx-option.Po ./$(DEPDIR)/tx-proc.Po \
- ./$(DEPDIR)/tx-rand.Po ./$(DEPDIR)/tx-strchr2.Po \
- ./$(DEPDIR)/tx-string.Po ./$(DEPDIR)/tx-strquote.Po \
- ./$(DEPDIR)/tx-time.Po ./$(DEPDIR)/tx_list2-tx-list2.Po \
- ./$(DEPDIR)/ux-file.Plo ./$(DEPDIR)/ux-mmap.Plo
+ ./$(DEPDIR)/tx-proc.Po ./$(DEPDIR)/tx-rand.Po \
+ ./$(DEPDIR)/tx-strchr2.Po ./$(DEPDIR)/tx-string.Po \
+ ./$(DEPDIR)/tx-strquote.Po ./$(DEPDIR)/tx-time.Po \
+ ./$(DEPDIR)/tx_list2-tx-list2.Po ./$(DEPDIR)/ux-file.Plo \
+ ./$(DEPDIR)/ux-mmap.Plo
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -409,9 +406,8 @@ SOURCES = $(libHX_la_SOURCES) tc-cast.c tc-compile.c tc-deque.c \
$(tx_cast_SOURCES) $(tx_compile_SOURCES) $(tx_deque_SOURCES) \
$(tx_dir_SOURCES) $(tx_intdiff_SOURCES) $(tx_list_SOURCES) \
$(tx_list2_SOURCES) $(tx_misc_SOURCES) $(tx_netio_SOURCES) \
- $(tx_option_SOURCES) $(tx_proc_SOURCES) $(tx_rand_SOURCES) \
- $(tx_strchr2_SOURCES) $(tx_string_SOURCES) \
- $(tx_strquote_SOURCES) $(tx_time_SOURCES)
+ $(tx_proc_SOURCES) $(tx_rand_SOURCES) $(tx_strchr2_SOURCES) \
+ $(tx_string_SOURCES) $(tx_strquote_SOURCES) $(tx_time_SOURCES)
DIST_SOURCES = $(am__libHX_la_SOURCES_DIST) tc-cast.c tc-compile.c \
tc-deque.c tc-dir.c tc-format.c tc-io.c tc-list.c tc-list2.c \
tc-map.c tc-memmem.c tc-misc.c tc-netio.c tc-option.c \
@@ -422,10 +418,9 @@ DIST_SOURCES = $(am__libHX_la_SOURCES_DIST) tc-cast.c tc-compile.c \
$(am__tx_dir_SOURCES_DIST) $(am__tx_intdiff_SOURCES_DIST) \
$(am__tx_list_SOURCES_DIST) $(am__tx_list2_SOURCES_DIST) \
$(am__tx_misc_SOURCES_DIST) $(am__tx_netio_SOURCES_DIST) \
- $(am__tx_option_SOURCES_DIST) $(am__tx_proc_SOURCES_DIST) \
- $(am__tx_rand_SOURCES_DIST) $(am__tx_strchr2_SOURCES_DIST) \
- $(am__tx_string_SOURCES_DIST) $(am__tx_strquote_SOURCES_DIST) \
- $(am__tx_time_SOURCES_DIST)
+ $(am__tx_proc_SOURCES_DIST) $(am__tx_rand_SOURCES_DIST) \
+ $(am__tx_strchr2_SOURCES_DIST) $(am__tx_string_SOURCES_DIST) \
+ $(am__tx_strquote_SOURCES_DIST) $(am__tx_time_SOURCES_DIST)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -556,12 +551,13 @@ am__sh_e_setup = case $$- in *e*) set +e;; esac
# Default flags passed to test drivers.
am__common_driver_flags = \
--color-tests "$$am__color_tests" \
+ $$am__collect_skipped_logs \
--enable-hard-errors "$$am__enable_hard_errors" \
--expect-failure "$$am__expect_failure"
# To be inserted before the command running the test. Creates the
# directory for the log if needed. Stores in $dir the directory
# containing $f, in $tst the test, in $log the log. Executes the
-# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# developer-defined test setup AM_TESTS_ENVIRONMENT (if any), and
# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
# will run the test scripts (or their associated LOG_COMPILER, if
# thy have one).
@@ -580,6 +576,11 @@ if test -f "./$$f"; then dir=./; \
elif test -f "$$f"; then dir=; \
else dir="$(srcdir)/"; fi; \
tst=$$dir$$f; log='$@'; \
+if test -n '$(IGNORE_SKIPPED_LOGS)'; then \
+ am__collect_skipped_logs='--collect-skipped-logs no'; \
+else \
+ am__collect_skipped_logs=''; \
+fi; \
if test -n '$(DISABLE_HARD_ERRORS)'; then \
am__enable_hard_errors=no; \
else \
@@ -712,8 +713,10 @@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
+am__rm_f_notfound = @am__rm_f_notfound@
am__tar = @am__tar@
am__untar = @am__untar@
+am__xargs_n = @am__xargs_n@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
@@ -771,7 +774,7 @@ libHX_la_SOURCES = deque.c dl.c format.c io.c map.c mc.c misc.c opt.c \
proc.c rand.c socket.c string.c time.c $(am__append_3)
libHX_la_LIBADD = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS} \
${libsocket_LIBS} $(am__append_4)
-libHX_la_LDFLAGS = -no-undefined -version-info 39:0:7 $(am__append_1) \
+libHX_la_LDFLAGS = -no-undefined -version-info 43:0:0 $(am__append_1) \
$(am__append_2)
EXTRA_libHX_la_DEPENDENCIES = libHX.map
EXTRA_DIST = internal.h map_int.h libHX.map uxcompat.h analyze.sh
@@ -816,8 +819,6 @@ tc_time_LDADD = libHX.la
@HAVE_CXX_TRUE@tx_misc_LDADD = libHX.la
@HAVE_CXX_TRUE@tx_netio_SOURCES = tx-netio.cpp
@HAVE_CXX_TRUE@tx_netio_LDADD = libHX.la ${libsocket_LIBS}
-@HAVE_CXX_TRUE@tx_option_SOURCES = tx-option.cpp
-@HAVE_CXX_TRUE@tx_option_LDADD = libHX.la
@HAVE_CXX_TRUE@tx_proc_SOURCES = tx-proc.cpp
@HAVE_CXX_TRUE@tx_proc_LDADD = libHX.la
@HAVE_CXX_TRUE@tx_rand_SOURCES = tx-rand.cpp
@@ -865,13 +866,8 @@ $(ACLOCAL_M4): $(am__aclocal_m4_deps)
$(am__aclocal_m4_deps):
clean-checkPROGRAMS:
- @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
- echo " rm -f" $$list; \
- rm -f $$list || exit $$?; \
- test -n "$(EXEEXT)" || exit 0; \
- list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f" $$list; \
- rm -f $$list
+ $(am__rm_f) $(check_PROGRAMS)
+ test -z "$(EXEEXT)" || $(am__rm_f) $(check_PROGRAMS:$(EXEEXT)=)
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
@$(NORMAL_INSTALL)
@@ -898,15 +894,13 @@ uninstall-libLTLIBRARIES:
done
clean-libLTLIBRARIES:
- -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ -$(am__rm_f) $(lib_LTLIBRARIES)
@list='$(lib_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
- test -z "$$locs" || { \
- echo rm -f $${locs}; \
- rm -f $${locs}; \
- }
+ echo rm -f $${locs}; \
+ $(am__rm_f) $${locs}
libHX.la: $(libHX_la_OBJECTS) $(libHX_la_DEPENDENCIES) $(EXTRA_libHX_la_DEPENDENCIES)
$(AM_V_CCLD)$(libHX_la_LINK) -rpath $(libdir) $(libHX_la_OBJECTS) $(libHX_la_LIBADD) $(LIBS)
@@ -1039,10 +1033,6 @@ tx-netio$(EXEEXT): $(tx_netio_OBJECTS) $(tx_netio_DEPENDENCIES) $(EXTRA_tx_netio
@rm -f tx-netio$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(tx_netio_OBJECTS) $(tx_netio_LDADD) $(LIBS)
-tx-option$(EXEEXT): $(tx_option_OBJECTS) $(tx_option_DEPENDENCIES) $(EXTRA_tx_option_DEPENDENCIES)
- @rm -f tx-option$(EXEEXT)
- $(AM_V_CXXLD)$(CXXLINK) $(tx_option_OBJECTS) $(tx_option_LDADD) $(LIBS)
-
tx-proc$(EXEEXT): $(tx_proc_OBJECTS) $(tx_proc_DEPENDENCIES) $(EXTRA_tx_proc_DEPENDENCIES)
@rm -f tx-proc$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(tx_proc_OBJECTS) $(tx_proc_LDADD) $(LIBS)
@@ -1117,7 +1107,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-list.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-misc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-netio.Po@am__quote@ # am--include-marker
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-option.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-proc.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-rand.Po@am__quote@ # am--include-marker
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tx-strchr2.Po@am__quote@ # am--include-marker
@@ -1130,7 +1119,7 @@ distclean-compile:
$(am__depfiles_remade):
@$(MKDIR_P) $(@D)
- @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+ @: >>$@
am--depfiles: $(am__depfiles_remade)
@@ -1295,7 +1284,6 @@ distclean-tags:
am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
am--force-recheck:
@:
-
$(TEST_SUITE_LOG): $(TEST_LOGS)
@$(am__set_TESTS_bases); \
am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
@@ -1371,10 +1359,37 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
result_count $$1 "XPASS:" $$xpass "$$red"; \
result_count $$1 "ERROR:" $$error "$$mgn"; \
}; \
+ output_system_information () \
+ { \
+ echo; \
+ { uname -a | $(AWK) '{ \
+ printf "System information (uname -a):"; \
+ for (i = 1; i < NF; ++i) \
+ { \
+ if (i != 2) \
+ printf " %s", $$i; \
+ } \
+ printf "\n"; \
+}'; } 2>&1; \
+ if test -r /etc/os-release; then \
+ echo "Distribution information (/etc/os-release):"; \
+ sed 8q /etc/os-release; \
+ elif test -r /etc/issue; then \
+ echo "Distribution information (/etc/issue):"; \
+ cat /etc/issue; \
+ fi; \
+ }; \
+ please_report () \
+ { \
+echo "Some test(s) failed. Please report this to $(PACKAGE_BUGREPORT),"; \
+echo "together with the test-suite.log file (gzipped) and your system"; \
+echo "information. Thanks."; \
+ }; \
{ \
echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
$(am__rst_title); \
create_testsuite_report --no-color; \
+ output_system_information; \
echo; \
echo ".. contents:: :depth: 2"; \
echo; \
@@ -1394,26 +1409,25 @@ $(TEST_SUITE_LOG): $(TEST_LOGS)
create_testsuite_report --maybe-color; \
echo "$$col$$br$$std"; \
if $$success; then :; else \
- echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG) for debugging.$${std}";\
if test -n "$(PACKAGE_BUGREPORT)"; then \
- echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ please_report | sed -e "s/^/$${col}/" -e s/'$$'/"$${std}"/; \
fi; \
echo "$$col$$br$$std"; \
fi; \
$$success || exit 1
check-TESTS: $(check_PROGRAMS)
- @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
- @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
- @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @$(am__rm_f) $(RECHECK_LOGS)
+ @$(am__rm_f) $(RECHECK_LOGS:.log=.trs)
+ @$(am__rm_f) $(TEST_SUITE_LOG)
@set +e; $(am__set_TESTS_bases); \
log_list=`for i in $$bases; do echo $$i.log; done`; \
- trs_list=`for i in $$bases; do echo $$i.trs; done`; \
- log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ log_list=`echo $$log_list`; \
$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
exit $$?;
recheck: all $(check_PROGRAMS)
- @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @$(am__rm_f) $(TEST_SUITE_LOG)
@set +e; $(am__set_TESTS_bases); \
bases=`for i in $$bases; do echo $$i; done \
| $(am__list_recheck_tests)` || exit 1; \
@@ -1486,6 +1500,7 @@ tx-strquote.log: tx-strquote$(EXEEXT)
@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
distdir: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) distdir-am
@@ -1550,15 +1565,15 @@ install-strip:
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
- -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
- -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
- -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ -$(am__rm_f) $(TEST_LOGS)
+ -$(am__rm_f) $(TEST_LOGS:.log=.trs)
+ -$(am__rm_f) $(TEST_SUITE_LOG)
clean-generic:
distclean-generic:
- -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
- -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -$(am__rm_f) $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || $(am__rm_f) $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@@ -1569,7 +1584,7 @@ clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
clean-libtool mostlyclean-am
distclean: distclean-am
- -rm -f ./$(DEPDIR)/deque.Plo
+ -rm -f ./$(DEPDIR)/deque.Plo
-rm -f ./$(DEPDIR)/dl.Plo
-rm -f ./$(DEPDIR)/format.Plo
-rm -f ./$(DEPDIR)/io.Plo
@@ -1613,7 +1628,6 @@ distclean: distclean-am
-rm -f ./$(DEPDIR)/tx-list.Po
-rm -f ./$(DEPDIR)/tx-misc.Po
-rm -f ./$(DEPDIR)/tx-netio.Po
- -rm -f ./$(DEPDIR)/tx-option.Po
-rm -f ./$(DEPDIR)/tx-proc.Po
-rm -f ./$(DEPDIR)/tx-rand.Po
-rm -f ./$(DEPDIR)/tx-strchr2.Po
@@ -1668,7 +1682,7 @@ install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
- -rm -f ./$(DEPDIR)/deque.Plo
+ -rm -f ./$(DEPDIR)/deque.Plo
-rm -f ./$(DEPDIR)/dl.Plo
-rm -f ./$(DEPDIR)/format.Plo
-rm -f ./$(DEPDIR)/io.Plo
@@ -1712,7 +1726,6 @@ maintainer-clean: maintainer-clean-am
-rm -f ./$(DEPDIR)/tx-list.Po
-rm -f ./$(DEPDIR)/tx-misc.Po
-rm -f ./$(DEPDIR)/tx-netio.Po
- -rm -f ./$(DEPDIR)/tx-option.Po
-rm -f ./$(DEPDIR)/tx-proc.Po
-rm -f ./$(DEPDIR)/tx-rand.Po
-rm -f ./$(DEPDIR)/tx-strchr2.Po
@@ -1764,3 +1777,10 @@ uninstall-am: uninstall-libLTLIBRARIES
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+
+# Tell GNU make to disable its built-in pattern rules.
+%:: %,v
+%:: RCS/%,v
+%:: RCS/%
+%:: s.%
+%:: SCCS/s.%
diff --git a/src/deque.c b/src/deque.c
index bc39e0e..4124d1a 100644
--- a/src/deque.c
+++ b/src/deque.c
@@ -1,6 +1,6 @@
/*
* Double-ended queues
- * Copyright Jan Engelhardt, 2002-2008
+ * Copyright Jan Engelhardt, 2025
*
* This file is part of libHX. libHX is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser
@@ -8,7 +8,9 @@
* either version 2.1 or (at your option) any later version.
*/
#include <errno.h>
+#include <limits.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <libHX/deque.h>
@@ -162,22 +164,62 @@ EXPORT_SYMBOL void HXdeque_genocide2(struct HXdeque *dq, void (*xfree)(void *))
free(dq);
}
-EXPORT_SYMBOL void **
-HXdeque_to_vec(const struct HXdeque *dq, unsigned int *num)
+static void **
+HXdeque_to_veci(const struct HXdeque *dq, size_t *num, bool sentinel)
{
const struct HXdeque_node *trav;
void **ret, **p;
- ret = malloc((dq->items + 1) * sizeof(void *));
+ ret = malloc((dq->items + sentinel) * sizeof(void *));
if (ret == NULL)
return NULL;
p = ret;
for (trav = dq->first; trav != NULL; trav = trav->next)
*p++ = trav->ptr;
- *p = NULL;
+ if (sentinel)
+ *p = NULL;
if (num != NULL)
*num = dq->items;
return ret;
}
+
+EXPORT_SYMBOL void **
+HXdeque_to_vec(const struct HXdeque *dq, size_t *num)
+{
+ return HXdeque_to_veci(dq, num, true);
+}
+
+EXPORT_SYMBOL void **
+HXdeque_to_vecx(const struct HXdeque *dq, size_t *num)
+{
+ return HXdeque_to_veci(dq, num, false);
+}
+
+char **HXdeque_to_vec_strdup(const struct HXdeque *dq, size_t *num)
+{
+ const struct HXdeque_node *iter;
+ char **ret, **p;
+ int se;
+
+ ret = malloc((dq->items + 1) * sizeof(char *));
+ if (ret == nullptr)
+ return nullptr;
+ p = ret;
+ for (iter = dq->first; iter != nullptr; ++p, iter = iter->next) {
+ *p = strdup(iter->ptr);
+ if (*p == nullptr)
+ goto out;
+ }
+ *p = nullptr;
+ if (num != nullptr)
+ *num = dq->items;
+ return ret;
+
+ out:
+ se = errno;
+ HX_zvecfree(ret);
+ errno = se;
+ return nullptr;
+}
diff --git a/src/format.c b/src/format.c
index e924c6a..18e3f5e 100644
--- a/src/format.c
+++ b/src/format.c
@@ -20,9 +20,6 @@
#undef HXformat_aprintf
#undef HXformat_fprintf
#undef HXformat_sprintf
-extern int HXformat_aprintf(const struct HXformat_map *, hxmc_t **, const char *);
-extern int HXformat_sprintf(const struct HXformat_map *, char *, size_t, const char *);
-extern int HXformat_fprintf(const struct HXformat_map *, FILE *, const char *);
/* To make it easier on the highlighter */
#define C_OPEN '('
@@ -156,9 +153,9 @@ EXPORT_SYMBOL int HXformat_add(struct HXformat_map *blk, const char *key,
static __inline__ char *HX_strchr0(const char *s, char c)
{
- char *ret = strchr(s, c);
+ const char *ret = strchr(s, c);
if (ret != NULL)
- return ret;
+ return const_cast1(char *, ret);
return const_cast1(char *, s) + strlen(s);
}
@@ -380,7 +377,7 @@ static hxmc_t *HXformat2_xcall(const char *name, const char **pptr,
hxmc_t *ret, *ret2, **argv;
struct HXdeque *dq;
const char *s, *delim;
- int err = 0;
+ ssize_t err = 0;
dq = HXdeque_init();
if (dq == NULL)
@@ -563,13 +560,13 @@ HXformat2_xany(const char **pptr, const struct HXformat_map *blk)
/* Closing parenthesis - variable */
const struct fmt_entry *entry;
hxmc_t *new_name = NULL;
- int eret;
+ ssize_t eret;
*pptr = ++s;
eret = HXformat_aprintf(blk, &new_name, name);
if (eret <= 0) {
ret = NULL;
- } else if (*new_name == '\0') {
+ } else if (new_name == nullptr || *new_name == '\0') {
ret = &HXformat2_nexp;
} else {
entry = HXmap_get(blk->vars, new_name);
@@ -630,14 +627,7 @@ EXPORT_SYMBOL struct HXformat_map *HXformat_init(void)
return NULL;
}
-EXPORT_SYMBOL int HXformat_aprintf(const struct HXformat_map *blk,
- hxmc_t **resultp, const char *fmt)
-{
- ssize_t ret = HXformat3_aprintf(blk, resultp, fmt);
- return ret > INT_MAX ? INT_MAX : ret;
-}
-
-EXPORT_SYMBOL ssize_t HXformat3_aprintf(const struct HXformat_map *blk,
+EXPORT_SYMBOL ssize_t HXformat_aprintf(const struct HXformat_map *blk,
hxmc_t **resultp, const char *fmt)
{
hxmc_t *ex, *ts, *out;
@@ -686,20 +676,13 @@ EXPORT_SYMBOL ssize_t HXformat3_aprintf(const struct HXformat_map *blk,
return ret;
}
-EXPORT_SYMBOL int HXformat_fprintf(const struct HXformat_map *ftable,
- FILE *filp, const char *fmt)
-{
- ssize_t ret = HXformat3_fprintf(ftable, filp, fmt);
- return ret > INT_MAX ? INT_MAX : ret;
-}
-
-EXPORT_SYMBOL ssize_t HXformat3_fprintf(const struct HXformat_map *ftable,
+EXPORT_SYMBOL ssize_t HXformat_fprintf(const struct HXformat_map *ftable,
FILE *filp, const char *fmt)
{
hxmc_t *str;
ssize_t ret;
- if ((ret = HXformat3_aprintf(ftable, &str, fmt)) <= 0)
+ if ((ret = HXformat_aprintf(ftable, &str, fmt)) <= 0)
return ret;
errno = 0;
if (fputs(str, filp) < 0)
@@ -708,14 +691,7 @@ EXPORT_SYMBOL ssize_t HXformat3_fprintf(const struct HXformat_map *ftable,
return ret;
}
-EXPORT_SYMBOL int HXformat_sprintf(const struct HXformat_map *ftable,
- char *dest, size_t size, const char *fmt)
-{
- ssize_t ret = HXformat3_sprintf(ftable, dest, size, fmt);
- return ret > INT_MAX ? INT_MAX : ret;
-}
-
-EXPORT_SYMBOL ssize_t HXformat3_sprintf(const struct HXformat_map *ftable,
+EXPORT_SYMBOL ssize_t HXformat_sprintf(const struct HXformat_map *ftable,
char *dest, size_t size, const char *fmt)
{
hxmc_t *str = nullptr;
diff --git a/src/internal.h b/src/internal.h
index f7d83d8..1c24a56 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -40,7 +40,7 @@
#define MAXLNLEN 1024 /* max length for usual line */
#define HXMC_IDENT 0x200571AF
-#if !defined(__cplusplus)
+#if !defined(__cplusplus) && __STDC_VERSION__ < 202300L
# define nullptr NULL
#endif
@@ -50,9 +50,11 @@ struct memcont {
char data[];
};
+struct HXdeque;
struct timespec;
struct timeval;
+extern char **HXdeque_to_vec_strdup(const struct HXdeque *, size_t *);
extern hxmc_t *HXparse_dequote_fmt(const char *, const char *, const char **);
extern size_t HX_substr_helper(size_t, long, long, size_t *);
diff --git a/src/io.c b/src/io.c
index 9199d03..ee47f5a 100644
--- a/src/io.c
+++ b/src/io.c
@@ -65,8 +65,14 @@ static int mkdir_gen(const char *d, unsigned int mode)
if (mkdir(d, mode) == 0) /* use umask() for permissions */
#endif
return 1;
+#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ /* Undocumented extra error codes */
+ if (errno != EEXIST && errno != EISDIR)
+ return -errno;
+#else
if (errno != EEXIST)
return -errno;
+#endif
if (stat(d, &sb) == 0) {
#if defined(_WIN32)
if (sb.st_mode & S_IFDIR)
@@ -98,7 +104,7 @@ EXPORT_SYMBOL struct HXdir *HXdir_open(const char *s)
* and bug-concealing "char d_name[256]", while on Solaris, it is a
* proper "char d_name[]".
*/
- size_t size = sizeof(*d);
+ size_t size = offsetof(struct dirent, d_name);
ssize_t name_max;
DIR *tmp_dh = opendir(s);
if (tmp_dh == NULL)
@@ -110,7 +116,6 @@ EXPORT_SYMBOL struct HXdir *HXdir_open(const char *s)
*/
name_max = fpathconf(dirfd(tmp_dh), _PC_NAME_MAX);
if (name_max > 0) {
- size -= sizeof(struct dirent) - offsetof(struct dirent, d_name);
size += name_max + 1;
} else {
#ifdef NAME_MAX
@@ -351,12 +356,17 @@ EXPORT_SYMBOL int HX_readlink(hxmc_t **target, const char *path)
size_t linkbuf_size;
if (allocate) {
- linkbuf_size = 32;
- *target = HXmc_meminit(NULL, 32);
+ linkbuf_size = 128;
+ *target = HXmc_meminit(nullptr, 128);
if (*target == NULL)
return -errno;
} else {
linkbuf_size = HXmc_length(*target);
+ if (linkbuf_size < 128) {
+ linkbuf_size = 128;
+ if (HXmc_setlen(target, 128) == nullptr)
+ return -errno;
+ }
}
while (true) {
ssize_t ret = readlink(path, *target, linkbuf_size);
@@ -373,6 +383,8 @@ EXPORT_SYMBOL int HX_readlink(hxmc_t **target, const char *path)
HXmc_setlen(target, ret); // \0 set here anyway
return ret;
}
+ if (linkbuf_size > SIZE_MAX / 2)
+ return -E2BIG;
linkbuf_size *= 2;
if (HXmc_setlen(target, linkbuf_size) == NULL) {
int saved_errno = errno;
@@ -453,6 +465,48 @@ HX_realpath_symres(struct HX_realpath_state *state, const char *path)
return 1;
}
+EXPORT_SYMBOL int HX_getcwd(hxmc_t **target)
+{
+ bool allocate = *target == nullptr;
+ size_t linkbuf_size;
+
+ if (allocate) {
+ linkbuf_size = 128;
+ *target = HXmc_meminit(nullptr, linkbuf_size);
+ if (*target == nullptr)
+ return -errno;
+ } else {
+ linkbuf_size = HXmc_length(*target);
+ if (linkbuf_size < 128) {
+ linkbuf_size = 128;
+ if (HXmc_setlen(target, linkbuf_size) == nullptr)
+ return -errno;
+ }
+ }
+ while (true) {
+ const char *ret = getcwd(*target, linkbuf_size);
+ if (ret != nullptr) {
+ HXmc_setlen(target, strlen(ret)); /* shrink to fit */
+ return 1;
+ }
+ if (errno == ERANGE) {
+ if (linkbuf_size > SIZE_MAX / 2)
+ return -E2BIG;
+ linkbuf_size *= 2;
+ if (HXmc_setlen(target, linkbuf_size) != nullptr)
+ continue;
+ /* errno already set by realloc, fall into next if block */
+ }
+ int saved_errno = errno;
+ if (allocate) {
+ HXmc_free(*target);
+ *target = nullptr;
+ }
+ return -(errno = saved_errno);
+ }
+ return -EINVAL;
+}
+
EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
unsigned int flags)
{
@@ -462,7 +516,7 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
int ret = 0;
if (dnull) {
- state.dest = HXmc_meminit(NULL, PATH_MAX);
+ state.dest = HXmc_meminit(NULL, 256);
if (state.dest == NULL)
goto err;
}
@@ -470,11 +524,9 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
if (*path == '/') {
rq_slash = true;
} else if (flags & HX_REALPATH_ABSOLUTE) {
- if (getcwd(state.dest, PATH_MAX) == NULL)
+ if (HX_getcwd(&state.dest) < 0)
goto err;
rq_slash = true;
- if (HXmc_setlen(&state.dest, strlen(state.dest)) == NULL)
- goto err;
}
while (*path != '\0') {
@@ -541,6 +593,8 @@ EXPORT_SYMBOL int HX_realpath(hxmc_t **dest_pptr, const char *path,
/* If caller supplied a buffer, do not take it away. */
HXmc_free(state.dest);
*dest_pptr = NULL;
+ } else {
+ *dest_pptr = state.dest;
}
HXmc_free(state.link_target);
HXmc_free(state.new_path);
@@ -733,16 +787,18 @@ EXPORT_SYMBOL char *HX_slurp_fd(int fd, size_t *outsize)
char *buf = malloc(bufsize);
if (buf == nullptr)
return nullptr;
- ssize_t rdret;
- while ((rdret = read(fd, buf + offset, bufsize - 1 - offset)) > 0) {
+ do {
+ assert(offset < bufsize);
+ ssize_t rdret = read(fd, buf + offset, bufsize - 1 - offset);
+ if (rdret <= 0)
+ break;
offset += rdret;
- /*
- * Make it so that the next read call is not called
- * with an exceptionally small size.
- */
if (bufsize - offset >= 4095)
+ /* 4K room still, just continue reading. */
continue;
- if (bufsize > SSIZE_MAX)
+
+ /* Less than 4K room, enlarge now */
+ if (bufsize > SIZE_MAX / 2)
/* No more doubling */
break;
bufsize *= 2;
@@ -754,7 +810,7 @@ EXPORT_SYMBOL char *HX_slurp_fd(int fd, size_t *outsize)
return nullptr;
}
buf = nbuf;
- }
+ } while (true);
buf[offset] = '\0';
if (outsize != nullptr)
*outsize = offset;
diff --git a/src/libHX.map b/src/libHX.map
index 374a881..4be16ed 100644
--- a/src/libHX.map
+++ b/src/libHX.map
@@ -1,4 +1,4 @@
-LIBHX_3.25 {
+LIBHX_5.0 {
global:
HX_basename;
HX_basename_exact;
@@ -15,7 +15,6 @@ global:
HX_ffs;
HX_fls;
HX_getl;
- HX_getopt;
HX_getopt_help;
HX_getopt_help_cb;
HX_getopt_usage;
@@ -36,7 +35,6 @@ global:
HX_split;
HX_split_fixed;
HX_split_inplace;
- HX_stpltrim;
HX_strbchr;
HX_strchr2;
HX_strclone;
@@ -48,13 +46,11 @@ global:
HX_strltrim;
HX_strmid;
HX_strndup;
- HX_strnlen;
HX_strquote;
HX_strrcspn;
HX_strrev;
HX_strrtrim;
HX_strsep2;
- HX_strsep;
HX_strupper;
HX_time_compare;
HX_timespec_add;
@@ -123,63 +119,35 @@ global:
HXproc_run_async;
HXproc_run_sync;
HXproc_wait;
-local:
- *;
-};
-
-LIBHX_3.27 {
-global:
HX_socket_from_env;
HX_slurp_fd;
HX_slurp_file;
HXproc_switch_user;
HXproc_top_fd;
-} LIBHX_3.25;
-
-LIBHX_4.2 {
-global:
HX_strtod_unit;
HX_strtoull_unit;
HX_unit_size;
HX_unit_size_cu;
-} LIBHX_3.27;
-
-LIBHX_4.3 {
-global:
HX_sendfile;
HX_unit_seconds;
HX_strtoull_sec;
-} LIBHX_4.2;
-
-LIBHX_4.9 {
-global:
- HXformat3_aprintf;
- HXformat3_fprintf;
- HXformat3_sprintf;
+ HXformat_aprintf;
+ HXformat_fprintf;
+ HXformat_sprintf;
HX_ipaddr_is_local;
HX_sockaddr_is_local;
-} LIBHX_4.3;
-
-LIBHX_4.11 {
-global:
HX_addrport_split;
HX_inet_connect;
HX_inet_listen;
HX_local_listen;
-} LIBHX_4.9;
-
-LIBHX_4.15 {
-global:
HX_flpr;
HX_flprf;
-} LIBHX_4.11;
-
-LIBHX_4.16 {
-global:
HX_strtoull_nsec;
-} LIBHX_4.15;
-
-LIBHX_4.18 {
-global:
- HX_getopt5;
-} LIBHX_4.16;
+ HX_getcwd;
+ HX_strtoull8601p_sec;
+ HX_getopt6;
+ HX_getopt6_clean;
+ HXdeque_to_vecx;
+local:
+ *;
+};
diff --git a/src/map_int.h b/src/map_int.h
index 6e95c69..b7d74f8 100644
--- a/src/map_int.h
+++ b/src/map_int.h
@@ -14,7 +14,8 @@ extern "C" {
*/
struct HXmap_private {
/* from struct HXmap */
- unsigned int items, flags;
+ size_t items;
+ unsigned int flags;
/* private: */
enum HXmap_type type;
diff --git a/src/misc.c b/src/misc.c
index c138f23..e0f39fd 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -51,24 +51,24 @@ static __inline__ void hexdump_ascii(FILE *fp, unsigned char c, bool tty)
fprintf(fp, ".");
}
-EXPORT_SYMBOL void HX_hexdump(FILE *fp, const void *vptr, unsigned int len)
+EXPORT_SYMBOL void HX_hexdump(FILE *fp, const void *vptr, size_t len)
{
const unsigned char *ptr = vptr;
- unsigned int i, j;
+ size_t i;
bool tty = isatty(fileno(fp));
- fprintf(fp, "Dumping %u bytes\n", len);
+ fprintf(fp, "Dumping %zu bytes\n", len);
for (i = 0; i < len / 16; ++i) {
- fprintf(fp, "%04x | ", i * 16);
- for (j = 0; j < 16; ++j)
+ fprintf(fp, "%04zx | ", i * 16);
+ for (unsigned int j = 0; j < 16; ++j)
fprintf(fp, "%02x%c", *ptr++, (j == 7) ? '-' : ' ');
ptr -= 16;
fprintf(fp, "| ");
- for (j = 0; j < 16; ++j)
+ for (unsigned int j = 0; j < 16; ++j)
hexdump_ascii(fp, *ptr++, tty);
fprintf(fp, "\n");
}
- fprintf(fp, "%04x | ", i * 16);
+ fprintf(fp, "%04zx | ", i * 16);
len -= i * 16;
for (i = 0; i < len; ++i)
fprintf(fp, "%02x%c", ptr[i], (i == 7) ? '-' : ' ');
diff --git a/src/opt.c b/src/opt.c
index ab482ad..6e3d032 100644
--- a/src/opt.c
+++ b/src/opt.c
@@ -1,19 +1,26 @@
/*
* libHX/opt.c
- * Copyright Jan Engelhardt, 2002-2011
+ * Copyright Jan Engelhardt, 2025
*
* This file is part of libHX. libHX is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation;
* either version 2.1 or (at your option) any later version.
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include <errno.h>
+#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
#include <libHX/ctype_helper.h>
#include <libHX/deque.h>
#include <libHX/map.h>
@@ -119,13 +126,15 @@ enum {
/**
* struct HX_getopt_vars - option parser working variable set
* @arg0: saved program name
- * @remaining: list of extracted non-options
+ * @desc: list of extracted options
+ * @oarg: list of extracted options
+ * @uarg: list of extracted non-options
* @cbi: callback info
* @flags: flags setting the behavior for HX_getopt
*/
struct HX_getopt_vars {
const char *arg0;
- struct HXdeque *remaining;
+ struct HXdeque *desc, *oarg, *uarg;
struct HXoptcb cbi;
unsigned int flags;
};
@@ -218,6 +227,10 @@ static void do_assign(struct HXoptcb *cbi, const char *arg0)
if (opt->ptr != NULL)
*static_cast(char **, opt->ptr) = HX_strdup(cbi->data);
break;
+ case HXTYPE_STRP:
+ if (opt->ptr != nullptr)
+ *static_cast(const char **, opt->ptr) = cbi->data;
+ break;
case HXTYPE_STRDQ:
HXdeque_push(opt->ptr, HX_strdup(cbi->data));
break;
@@ -237,6 +250,15 @@ static void do_assign(struct HXoptcb *cbi, const char *arg0)
opt->cb(cbi);
}
+static int do_assign_front(struct HX_getopt_vars *par)
+{
+ if (HXdeque_push(par->desc, par->cbi.current) == nullptr ||
+ HXdeque_push(par->oarg, par->cbi.data) == nullptr)
+ return -errno;
+ do_assign(&par->cbi, par->arg0);
+ return 0;
+}
+
static __inline__ const struct HXoption *
lookup_short(const struct HXoption *table, char opt)
{
@@ -494,27 +516,14 @@ static int HX_getopt_error(int err, const char *key, unsigned int flags)
return HXOPT_I_ERROR;
}
-static int HX_getopt_twolong(const char *const *opt,
+static int HX_getopt_twolong(const char *key, const char *value,
struct HX_getopt_vars *par)
{
- const char *key = opt[0], *value = opt[1];
-
par->cbi.current = lookup_long_pfx(par->cbi.table, key + 2);
if (par->cbi.current == &HXopt_ambig_prefix)
return HX_getopt_error(HXOPT_E_AMBIG_PREFIX, key, par->flags);
- if (par->cbi.current == NULL) {
- if (par->flags & HXOPT_PTHRU) {
- char *tmp = HX_strdup(key);
- if (tmp == NULL)
- return -errno;
- if (HXdeque_push(par->remaining, tmp) == NULL) {
- free(tmp);
- return -errno;
- }
- return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
- }
+ if (par->cbi.current == nullptr)
return HX_getopt_error(HXOPT_E_LONG_UNKNOWN, key, par->flags);
- }
par->cbi.flags = HXOPTCB_BY_LONG;
if (takes_void(par->cbi.current->type)) {
@@ -550,11 +559,21 @@ static int HX_getopt_long(const char *cur, struct HX_getopt_vars *par)
return -errno;
value = strchr(key, '=');
if (value == nullptr) {
- /* Cannot happen because state is always !S_TWOLONG */
+ /*
+ * Cannot happen because state is always !S_TWOLONG, but make
+ * static analyzers happy.
+ */
free(key);
return -EINVAL;
}
- *value++ = '\0';
+ *value = '\0';
+ const char *cvalue = strchr(cur, '=');
+ if (cvalue == nullptr) {
+ /* Cannot happen either */
+ free(key);
+ return -EINVAL;
+ }
+ ++cvalue;
par->cbi.current = lookup_long_pfx(par->cbi.table, key + 2);
if (par->cbi.current == &HXopt_ambig_prefix) {
ret = HX_getopt_error(HXOPT_E_AMBIG_PREFIX, key, par->flags);
@@ -562,15 +581,6 @@ static int HX_getopt_long(const char *cur, struct HX_getopt_vars *par)
return ret;
}
if (par->cbi.current == NULL) {
- if (par->flags & HXOPT_PTHRU) {
- /* Undo nuke of '=' and reuse alloc */
- value[-1] = '=';
- if (HXdeque_push(par->remaining, key) == NULL) {
- free(key);
- return -errno;
- }
- return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
- }
ret = HX_getopt_error(HXOPT_E_LONG_UNKNOWN, key, par->flags);
free(key);
return ret;
@@ -585,58 +595,48 @@ static int HX_getopt_long(const char *cur, struct HX_getopt_vars *par)
return ret;
}
- par->cbi.flags = HXOPTCB_BY_LONG;
- par->cbi.data = value;
- /* Not possible to use %HXOPT_I_ASSIGN due to transience of @key. */
- do_assign(&par->cbi, par->arg0);
free(key);
+ par->cbi.flags = HXOPTCB_BY_LONG;
+ par->cbi.data = const_cast(char *, cvalue);
+ /*
+ * Not possible to use %HXOPT_I_ASSIGN due to transience of @key. Thus
+ * manually call do_assign now rather than in the superordinate
+ * function.
+ */
+ ret = do_assign_front(par);
+ if (ret < 0)
+ return ret;
return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
}
-static int HX_getopt_short(const char *const *opt, const char *cur,
+static int HX_getopt_short(const char *key, const char *value,
struct HX_getopt_vars *par)
{
- char op = *cur;
+ char op = *key;
if (op == '\0')
return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
par->cbi.current = lookup_short(par->cbi.table, op);
- if (par->cbi.current == NULL) {
- if (par->flags & HXOPT_PTHRU) {
- /*
- * @cur-1 is always valid: it is either the previous
- * char, or it is '-'.
- */
- char *buf = HX_strdup(cur - 1);
- if (buf != NULL)
- *buf = '-';
- if (HXdeque_push(par->remaining, buf) == NULL) {
- free(buf);
- return -errno;
- }
- return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
- }
+ if (par->cbi.current == nullptr)
return HX_getopt_error(HXOPT_E_SHORT_UNKNOWN, &op, par->flags);
- }
par->cbi.flags = HXOPTCB_BY_SHORT;
if (takes_void(par->cbi.current->type)) {
/* -A */
par->cbi.data = NULL;
return HXOPT_S_SHORT | HXOPT_I_ASSIGN | HXOPT_I_ADVCHAR;
- } else if (cur[1] != '\0') {
+ } else if (key[1] != '\0') {
/* -Avalue */
- par->cbi.data = cur + 1;
+ par->cbi.data = key + 1;
return HXOPT_S_NORMAL | HXOPT_I_ASSIGN | HXOPT_I_ADVARG;
}
- cur = *++opt;
if (par->cbi.current->type & HXOPT_OPTIONAL) {
- if (cur == NULL || *cur != '-' ||
- (cur[0] == '-' && cur[1] == '\0')) {
+ if (value == nullptr || *value != '-' ||
+ (value[0] == '-' && value[1] == '\0')) {
/* -f - -f bla */
- par->cbi.data = cur;
+ par->cbi.data = value;
return HXOPT_S_NORMAL | HXOPT_I_ASSIGN | HXOPT_I_ADVARG2;
} else {
/* -f -a-file --another --file -- endofoptions */
@@ -645,41 +645,28 @@ static int HX_getopt_short(const char *const *opt, const char *cur,
}
} else {
/* -A value */
- if (cur == NULL)
+ if (value == nullptr)
return HX_getopt_error(HXOPT_E_SHORT_MISSING, &op, par->flags);
- par->cbi.data = cur;
+ par->cbi.data = value;
return HXOPT_S_NORMAL | HXOPT_I_ASSIGN | HXOPT_I_ADVARG2;
}
}
static int HX_getopt_term(const char *cur, const struct HX_getopt_vars *par)
{
- char *tmp = HX_strdup(cur);
- if (tmp == NULL)
- return -errno;
- if (HXdeque_push(par->remaining, tmp) == NULL) {
- free(tmp);
+ if (HXdeque_push(par->uarg, cur) == nullptr)
return -errno;
- }
return HXOPT_S_TERMINATED | HXOPT_I_ADVARG;
}
static int HX_getopt_normal(const char *cur, const struct HX_getopt_vars *par)
{
if (cur[0] == '-' && cur[1] == '\0') {
- /* Note to popt developers: A single dash is NOT an option! */
- HXdeque_push(par->remaining, HX_strdup(cur));
+ HXdeque_push(par->uarg, cur);
return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
}
- if (cur[0] == '-' && cur[1] == '-' && cur[2] == '\0') {
- /*
- * Double dash. If passthrough is on, "--" must be copied into
- * @remaining. This is done in the next round.
- */
- if (!(par->flags & HXOPT_PTHRU))
- return HXOPT_S_TERMINATED | HXOPT_I_ADVARG;
- return HXOPT_S_TERMINATED;
- }
+ if (cur[0] == '-' && cur[1] == '-' && cur[2] == '\0')
+ return HXOPT_S_TERMINATED | HXOPT_I_ADVARG;
if (cur[0] == '-' && cur[1] == '-') { /* long option */
if (strchr(cur + 2, '=') == NULL)
return HXOPT_S_TWOLONG;
@@ -692,62 +679,71 @@ static int HX_getopt_normal(const char *cur, const struct HX_getopt_vars *par)
if (par->flags & HXOPT_RQ_ORDER)
/* POSIX: first non-option implies option termination */
return HXOPT_S_TERMINATED;
- cur = HX_strdup(cur);
- if (cur == NULL || HXdeque_push(par->remaining, cur) == NULL)
+ if (HXdeque_push(par->uarg, cur) == nullptr)
return -errno;
return HXOPT_S_NORMAL | HXOPT_I_ADVARG;
}
-EXPORT_SYMBOL int HX_getopt5(const struct HXoption *table, char **orig_argv,
- int *new_argc, char ***new_argv, unsigned int flags)
+EXPORT_SYMBOL void HX_getopt6_clean(struct HXopt6_result *r)
+{
+ free(r->desc);
+ free(r->oarg);
+ free(r->uarg);
+ HX_zvecfree(r->dup_argv);
+ r->desc = nullptr;
+ r->oarg = nullptr;
+ r->uarg = nullptr;
+ r->dup_argv = nullptr;
+}
+
+EXPORT_SYMBOL int HX_getopt6(const struct HXoption *table, int argc,
+ char **argv, struct HXopt6_result *result, unsigned int flags)
{
struct HX_getopt_vars ps;
- const char **opt = const_cast(const char **, orig_argv);
+ const char **opt = const_cast(const char **, argv);
int state = HXOPT_S_NORMAL;
int ret = -ENOMEM;
- unsigned int argk = 0;
- if (new_argc != nullptr)
- *new_argc = 0;
- if (new_argv != nullptr)
- *new_argv = nullptr;
+ if ((flags & (HXOPT_RQ_ORDER | HXOPT_ANY_ORDER)) == (HXOPT_RQ_ORDER | HXOPT_ANY_ORDER))
+ return -EINVAL;
+ if (result == nullptr && flags & (HXOPT_ITER_OPTS | HXOPT_ITER_ARGS | HXOPT_DUP_ARGS))
+ return -EINVAL;
+ if (result != nullptr)
+ memset(result, 0, sizeof(*result));
memset(&ps, 0, sizeof(ps));
- ps.remaining = HXdeque_init();
- if (ps.remaining == NULL) {
+ ps.desc = HXdeque_init();
+ ps.oarg = HXdeque_init();
+ ps.uarg = HXdeque_init();
+ if (ps.desc == nullptr || ps.oarg == nullptr || ps.uarg == nullptr) {
ret = -errno;
goto out;
}
ps.flags = flags;
- ps.arg0 = *opt;
- ps.cbi.table = table;
-
- if (*opt != NULL) {
- /* put argv[0] back */
- char *arg = HX_strdup(*opt++);
- if (arg == NULL) {
- ret = -errno;
- goto out;
- }
- if (HXdeque_push(ps.remaining, arg) == NULL) {
- free(arg);
- ret = -errno;
- goto out;
- }
+ if (argc < 0) {
+ argc = 0;
+ for (const char **p = opt; *p != nullptr; ++p)
+ ++argc;
}
+ if (argc > 0) {
+ ps.arg0 = *opt++;
+ --argc;
+ }
+ ps.cbi.table = table;
- if (posix_me_harder())
+ if (!(ps.flags & HXOPT_ANY_ORDER) && posix_me_harder())
ps.flags |= HXOPT_RQ_ORDER;
- for (const char *cur = *opt; cur != NULL; ) {
+ const char *op0 = argc > 0 ? opt[0] : nullptr;
+ while (argc > 0) {
if (state == HXOPT_S_TWOLONG)
- state = HX_getopt_twolong(opt, &ps);
+ state = HX_getopt_twolong(op0, argc > 1 ? opt[1] : nullptr, &ps);
else if (state == HXOPT_S_LONG)
- state = HX_getopt_long(cur, &ps);
+ state = HX_getopt_long(op0, &ps);
else if (state == HXOPT_S_SHORT)
- state = HX_getopt_short(opt, cur, &ps);
+ state = HX_getopt_short(op0, argc > 1 ? opt[1] : nullptr, &ps);
else if (state == HXOPT_S_TERMINATED)
- state = HX_getopt_term(cur, &ps);
+ state = HX_getopt_term(op0, &ps);
else if (state == HXOPT_S_NORMAL)
- state = HX_getopt_normal(cur, &ps);
+ state = HX_getopt_normal(op0, &ps);
if (state < 0) {
ret = state;
@@ -757,31 +753,62 @@ EXPORT_SYMBOL int HX_getopt5(const struct HXoption *table, char **orig_argv,
ret = state & ~HXOPT_I_ERROR;
goto out;
}
- if (state & HXOPT_I_ASSIGN)
- do_assign(&ps.cbi, ps.arg0);
- if (state & HXOPT_I_ADVARG)
- cur = *++opt;
- else if (state & HXOPT_I_ADVARG2)
- cur = *(opt += 2);
- else if (state & HXOPT_I_ADVCHAR)
- ++cur;
+ if (state & HXOPT_I_ASSIGN) {
+ ret = do_assign_front(&ps);
+ if (ret < 0)
+ goto out;
+ }
+ if (state & HXOPT_I_ADVARG) {
+ --argc;
+ if (argc > 0)
+ op0 = *++opt;
+ } else if (state & HXOPT_I_ADVARG2) {
+ opt += 2;
+ argc -= 2;
+ if (argc > 0)
+ op0 = *opt;
+ } else if (state & HXOPT_I_ADVCHAR) {
+ ++op0;
+ }
state &= ~HXOPT_I_MASK;
}
- if (new_argv != nullptr) {
- *new_argv = reinterpret_cast(char **, HXdeque_to_vec(ps.remaining, &argk));
- if (*new_argv == nullptr) {
+ if (flags & HXOPT_ITER_OPTS) {
+ size_t nelem = 0;
+ result->desc = reinterpret_cast(const struct HXoption **, HXdeque_to_vec(ps.desc, &nelem));
+ result->oarg = reinterpret_cast(char **, HXdeque_to_vec(ps.oarg, &nelem));
+ if (result->desc == nullptr || result->oarg == nullptr) {
+ ret = -errno;
+ goto out;
+ }
+ result->nopts = nelem < INT_MAX ? nelem : INT_MAX;
+ }
+ if (flags & HXOPT_ITER_ARGS) {
+ size_t nelem = 0;
+ result->uarg = reinterpret_cast(char **, HXdeque_to_vecx(ps.uarg, &nelem));
+ if (result->uarg == nullptr) {
+ ret = -errno;
+ goto out;
+ }
+ result->nargs = nelem < INT_MAX ? nelem : INT_MAX;
+ }
+ if (flags & HXOPT_DUP_ARGS) {
+ if (ps.arg0 != nullptr && HXdeque_unshift(ps.uarg, ps.arg0) == nullptr) {
ret = -errno;
goto out;
}
- if (new_argc != nullptr)
- *new_argc = argk;
- /* pointers are owned by new_argv now, so free only the deque head */
- HXdeque_free(ps.remaining);
- ps.remaining = nullptr;
+ size_t nelem = 0;
+ result->dup_argv = HXdeque_to_vec_strdup(ps.uarg, &nelem);
+ if (result->dup_argv == nullptr) {
+ ret = -errno;
+ goto out;
+ }
+ result->dup_argc = nelem < INT_MAX ? nelem : INT_MAX;
}
ret = HXOPT_ERR_SUCCESS;
out:
+ if (ret != HXOPT_ERR_SUCCESS && result != nullptr)
+ HX_getopt6_clean(result);
if (ret == HXOPT_ERR_SUCCESS) {
} else if (ret < 0) {
if (!(ps.flags & HXOPT_QUIET))
@@ -793,28 +820,12 @@ EXPORT_SYMBOL int HX_getopt5(const struct HXoption *table, char **orig_argv,
else if (ps.flags & HXOPT_USAGEONERR)
HX_getopt_usage(&ps.cbi, stderr);
}
- if (ps.remaining != nullptr)
- HXdeque_genocide2(ps.remaining, free);
- return ret;
-}
-
-EXPORT_SYMBOL int HX_getopt(const struct HXoption *table, int *argc,
- char ***argv, unsigned int flags)
-{
- int new_argc = 0;
- char **new_argv = nullptr;
- int ret = HX_getopt5(table, *argv, &new_argc,
- flags & HXOPT_KEEP_ARGV ? nullptr : &new_argv, flags);
- if (ret != HXOPT_ERR_SUCCESS)
- return ret;
- if (flags & HXOPT_KEEP_ARGV)
- // NO_CREATE_NEW / DESTROY_NEW
- new_argv = *argv;
- else if (flags & HXOPT_DESTROY_OLD)
- HX_zvecfree(*argv);
- if (argc != nullptr)
- *argc = new_argc;
- *argv = new_argv;
+ if (ps.uarg != nullptr)
+ HXdeque_free(ps.uarg);
+ if (ps.oarg != nullptr)
+ HXdeque_free(ps.oarg);
+ if (ps.desc != nullptr)
+ HXdeque_free(ps.desc);
return ret;
}
diff --git a/src/proc.c b/src/proc.c
index c8957b6..a4bc6ab 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -1,6 +1,6 @@
/*
* Process management
- * Copyright Jan Engelhardt, 2008-2009
+ * Copyright Jan Engelhardt, 2026
*
* This file is part of libHX. libHX is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser
@@ -10,6 +10,10 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#define _DEFAULT_SOURCE
+#ifdef __CYGWIN__
+# define _BSD_SOURCE /* initgroups */
+#endif
#include "internal.h"
#include <errno.h>
#include <limits.h>
@@ -21,7 +25,6 @@
#ifdef _WIN32
# include <winsock2.h>
#endif
-
#if defined(HAVE_INITGROUPS) && defined(HAVE_SETGID)
#include <grp.h>
#include <pwd.h>
diff --git a/src/socket.c b/src/socket.c
index fe813f5..47c7e38 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -1,6 +1,6 @@
/*
* Socket-related functions
- * Copyright Jan Engelhardt, 2021
+ * Copyright Jan Engelhardt, 2026
*
* This file is part of libHX. libHX is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser
@@ -10,6 +10,10 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
+#define _POSIX_C_SOURCE 999900L /* cygwin-need:freeaddrinfo */
+#ifdef __OpenBSD__
+# define _BSD_SOURCE
+#endif
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
@@ -262,11 +266,11 @@ int HX_local_listen(const char *path)
struct sockaddr_un u;
if (strlen(path) >= sizeof(u.sun_path))
return -EINVAL;
- u.sun_family = AF_LOCAL;
+ u.sun_family = AF_UNIX;
strcpy(u.sun_path, path);
struct addrinfo r = {};
r.ai_flags = AI_PASSIVE;
- r.ai_family = AF_LOCAL;
+ r.ai_family = AF_UNIX;
r.ai_socktype = SOCK_STREAM;
r.ai_addrlen = sizeof(u) - sizeof(u.sun_path) + strlen(u.sun_path) + 1;
r.ai_addr = reinterpret_cast(struct sockaddr *, &u);
@@ -289,7 +293,7 @@ int HX_local_listen(const char *path)
if (!S_ISSOCK(sb.st_mode))
return -ENOTSOCK;
- int testfd = socket(AF_LOCAL, SOCK_STREAM | PLATFORM_SKFLAGS, 0);
+ int testfd = socket(AF_UNIX, SOCK_STREAM | PLATFORM_SKFLAGS, 0);
if (testfd < 0)
return -errno;
ret = connect(testfd, r.ai_addr, r.ai_addrlen);
diff --git a/src/string.c b/src/string.c
index e468063..445b466 100644
--- a/src/string.c
+++ b/src/string.c
@@ -7,6 +7,9 @@
* General Public License as published by the Free Software Foundation;
* either version 2.1 or (at your option) any later version.
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include <errno.h>
#include <limits.h>
#include <math.h> /* nextafter */
@@ -16,6 +19,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
#include <libHX/ctype_helper.h>
#include <libHX/string.h>
#include "internal.h"
@@ -41,7 +47,27 @@ struct HX_quote_rule {
const char *chars;
};
-static const char HX_hexenc[16] = "0123456789ABCDEF";
+/* years, months, weeks, days, hours, minutes, seconds, msecs, musecs, nsecs; */
+enum period_idx {
+ PERIDX_YEARS = 0,
+ PERIDX_MONTHS,
+ PERIDX_WEEKS,
+ PERIDX_DAYS,
+ PERIDX_HOURS,
+ PERIDX_MIN,
+ PERIDX_SEC,
+ PERIDX_MSEC,
+ PERIDX_MUSEC,
+ PERIDX_NSEC,
+ PERIDX_MAX,
+};
+
+struct HX_unit_desc {
+ const char name[8];
+ uint8_t len, pidx;
+};
+
+static const char HX_hexenc[] = "0123456789ABCDEF";
EXPORT_SYMBOL char *HX_basename(const char *s)
{
@@ -156,7 +182,6 @@ EXPORT_SYMBOL void *HX_memmem(const void *vspace, size_t spacesize,
const char *space = vspace, *point = vpoint;
const char *head, *end;
size_t tailsize;
- char *tail;
if (pointsize == 0)
return const_cast1(void *, vspace);
@@ -165,9 +190,9 @@ EXPORT_SYMBOL void *HX_memmem(const void *vspace, size_t spacesize,
/* Do a BM-style trailer search and reduce calls to memcmp */
head = space + (pointsize - 1);
- tail = memchr(head, point[pointsize-1], spacesize - (pointsize - 1));
+ const char *tail = memchr(head, point[pointsize-1], spacesize - (pointsize - 1));
if (tail == NULL || pointsize == 1)
- return tail;
+ return const_cast1(char *, tail);
end = space + spacesize;
do {
head = tail - pointsize + 1;
@@ -217,13 +242,11 @@ EXPORT_SYMBOL char **HX_split(const char *str, const char *delim,
ret[*cp] = NULL;
{
- char *seg, *wp = HX_strdup(str), *bg = wp;
+ char *wp = HX_strdup(str), *bg = wp;
size_t i = 0;
- while (--max > 0) {
- seg = HX_strsep(&wp, delim);
- ret[i++] = HX_strdup(seg);
- }
+ while (--max > 0)
+ ret[i++] = HX_strdup(strtok_r(nullptr, delim, &wp));
ret[i++] = HX_strdup(wp);
free(bg);
@@ -374,13 +397,6 @@ EXPORT_SYMBOL size_t HX_strltrim(char *expr)
return diff;
}
-EXPORT_SYMBOL char *HX_stpltrim(const char *p)
-{
- while (HX_isspace(*p))
- ++p;
- return const_cast1(char *, p);
-}
-
/**
* Helper for substr() function for dealing with negative off/len values
* @z: total length of string
@@ -442,14 +458,6 @@ EXPORT_SYMBOL char *HX_strndup(const char *src, size_t size)
return ret;
}
-EXPORT_SYMBOL size_t HX_strnlen(const char *src, size_t size)
-{
- const char *ptr = src;
- for (; *ptr != '\0' && size > 0; --size, ++ptr)
- ;
- return ptr - src;
-}
-
EXPORT_SYMBOL size_t HX_strrcspn(const char *s, const char *rej)
{
size_t n = strlen(s);
@@ -483,35 +491,6 @@ EXPORT_SYMBOL size_t HX_strrtrim(char *expr)
return s;
}
-EXPORT_SYMBOL char *HX_strsep(char **sp, const char *d)
-{
- char *begin, *end;
-
- if (*sp == NULL || **sp == '\0')
- return NULL;
- begin = *sp;
-
- if (d[0] == '\0' || d[1] == '\0') {
- if (*begin == *d)
- end = begin;
- else if (*begin == '\0')
- end = NULL;
- else
- end = strchr(begin + 1, *d);
- } else {
- end = strpbrk(begin, d);
- }
-
- if (end == NULL) {
- *sp = NULL;
- } else {
- *end++ = '\0';
- *sp = end;
- }
-
- return begin;
-}
-
EXPORT_SYMBOL char *HX_strsep2(char **wp, const char *str)
{
char *ptr, *ret;
@@ -534,8 +513,6 @@ static const struct HX_quote_rule HX_quote_rules[] = {
[HXQUOTE_LDAPFLT] = {HXQUOTE_REJECT, "\n*()\\"},
[HXQUOTE_LDAPRDN] = {HXQUOTE_REJECT, "\n \"#+,;<=>\\"},
[HXQUOTE_URIENC] = {HXQUOTE_ACCEPT, "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"},
- [HXQUOTE_SQLSQUOTE] = {HXQUOTE_REJECT, "'"},
- [HXQUOTE_SQLBQUOTE] = {HXQUOTE_REJECT, "`"},
};
/**
@@ -605,30 +582,6 @@ static char *HX_quote_backslash(char *dest, const char *src, const char *qc)
return ret;
}
-static char *
-HX_quote_sqlbackslash(char *dest, const char *src, const char *trm)
-{
- char *ret = dest;
- size_t len;
-
- while (*src != '\0') {
- len = strcspn(src, trm);
- if (len > 0) {
- memcpy(dest, src, len);
- dest += len;
- src += len;
- if (*src == '\0')
- break;
- }
- *dest++ = *trm;
- *dest++ = *trm;
- ++src;
- }
-
- *dest = '\0';
- return ret;
-}
-
/**
* Encode @src into BASE-64 according to RFC 4648 and write result to @dest,
* which must be of appropriate size, plus one for a trailing NUL.
@@ -782,8 +735,6 @@ static size_t HX_quoted_size(const char *s, unsigned int type)
switch (type) {
case HXQUOTE_SQUOTE:
case HXQUOTE_DQUOTE:
- case HXQUOTE_SQLSQUOTE:
- case HXQUOTE_SQLBQUOTE:
return HX_qsize_bsr(s, HX_quote_rules[type].chars, 1);
case HXQUOTE_HTML:
return HX_qsize_html(s);
@@ -862,9 +813,6 @@ EXPORT_SYMBOL char *HX_strquote(const char *src, unsigned int type,
return HX_quote_base64(*free_me, src, '+', ',');
case HXQUOTE_URIENC:
return HX_quote_urlenc(*free_me, src);
- case HXQUOTE_SQLSQUOTE:
- case HXQUOTE_SQLBQUOTE:
- return HX_quote_sqlbackslash(*free_me, src, rule->chars);
}
return NULL;
}
@@ -1068,47 +1016,169 @@ EXPORT_SYMBOL unsigned long long HX_strtoull_unit(const char *s,
return neg ? -ipart : ipart;
}
+static const struct HX_unit_desc txtperiod_utab[] = {
+ {"seconds", 7, PERIDX_SEC},
+ {"second", 6, PERIDX_SEC},
+ {"sec", 3, PERIDX_SEC},
+ {"s", 1, PERIDX_SEC},
+ {"minutes", 7, PERIDX_MIN},
+ {"minute", 6, PERIDX_MIN},
+ {"min", 3, PERIDX_MIN},
+ {"hours", 5, PERIDX_HOURS},
+ {"hour", 4, PERIDX_HOURS},
+ {"h", 1, PERIDX_HOURS},
+ {"days", 4, PERIDX_DAYS},
+ {"day", 3, PERIDX_DAYS},
+ {"d", 1, PERIDX_DAYS},
+ {"weeks", 5, PERIDX_WEEKS},
+ {"week", 4, PERIDX_WEEKS},
+ {"months", 6, PERIDX_MONTHS},
+ {"month", 5, PERIDX_MONTHS},
+ {"years", 5, PERIDX_YEARS},
+ {"year", 4, PERIDX_YEARS},
+ {"y", 1, PERIDX_YEARS},
+ {"msec", 4, PERIDX_MSEC},
+ {"ms", 2, PERIDX_MSEC},
+ {"µsec", 5, PERIDX_MUSEC},
+ {"µs", 3, PERIDX_MUSEC},
+ {"nsec", 4, PERIDX_NSEC},
+ {"ns", 2, PERIDX_NSEC},
+};
+
+static const struct HX_unit_desc iso8601p_dtab[] = {
+ {"D", 1, PERIDX_DAYS},
+ {"M", 1, PERIDX_MONTHS},
+ {"Y", 1, PERIDX_YEARS},
+};
+
+static const struct HX_unit_desc iso8601p_ttab[] = {
+ {"S", 1, PERIDX_SEC},
+ {"M", 1, PERIDX_MIN},
+ {"H", 1, PERIDX_HOURS},
+};
+
/* Numbers also used by systemd — the focus is on longterm averages */
#define SECONDS_PER_YEAR 31557600 /* 365.25 days */
#define SECONDS_PER_MONTH 2629800 /* 1/12th of that year = 30.4375 days */
#define NSEC_PER_SECOND 1000000000ULL
-static const struct {
- const char name[8];
- unsigned int len;
- uint32_t s_mult;
- uint64_t ns_mult;
-} time_multiplier[] = {
- {"seconds", 7, 1, 1 * NSEC_PER_SECOND},
- {"second", 6, 1, 1 * NSEC_PER_SECOND},
- {"sec", 3, 1, 1 * NSEC_PER_SECOND},
- {"s", 1, 1, 1 * NSEC_PER_SECOND},
- {"minutes", 7, 60, 60 * NSEC_PER_SECOND},
- {"minute", 6, 60, 60 * NSEC_PER_SECOND},
- {"min", 3, 60, 60 * NSEC_PER_SECOND},
- {"hours", 5, 3600, 3600 * NSEC_PER_SECOND},
- {"hour", 4, 3600, 3600 * NSEC_PER_SECOND},
- {"h", 1, 3600, 3600 * NSEC_PER_SECOND},
- {"days", 4, 86400, 86400 * NSEC_PER_SECOND},
- {"day", 3, 86400, 86400 * NSEC_PER_SECOND},
- {"d", 1, 86400, 86400 * NSEC_PER_SECOND},
- {"weeks", 5, 604800, 604800 * NSEC_PER_SECOND},
- {"week", 4, 604800, 604800 * NSEC_PER_SECOND},
- {"months", 6, SECONDS_PER_MONTH, SECONDS_PER_MONTH * NSEC_PER_SECOND},
- {"month", 5, SECONDS_PER_MONTH, SECONDS_PER_MONTH * NSEC_PER_SECOND},
- {"years", 5, SECONDS_PER_YEAR, SECONDS_PER_YEAR * NSEC_PER_SECOND},
- {"year", 4, SECONDS_PER_YEAR, SECONDS_PER_YEAR * NSEC_PER_SECOND},
- {"y", 1, SECONDS_PER_YEAR, SECONDS_PER_YEAR * NSEC_PER_SECOND},
- {"msec", 4, 0, 1000000},
- {"ms", 2, 0, 1000000},
- {"µsec", 5, 0, 1000},
- {"µs", 3, 0, 1000},
- {"nsec", 4, 0, 1},
- {"ns", 2, 0, 1},
+static const uint64_t sec_mult[PERIDX_MAX] = {
+ [PERIDX_YEARS] = SECONDS_PER_YEAR,
+ [PERIDX_MONTHS] = SECONDS_PER_MONTH,
+ [PERIDX_WEEKS] = 604800,
+ [PERIDX_DAYS] = 86400,
+ [PERIDX_HOURS] = 3600,
+ [PERIDX_MIN] = 60,
+ [PERIDX_SEC] = 1,
+ [PERIDX_MSEC] = 0,
+ [PERIDX_MUSEC] = 0,
+ [PERIDX_NSEC] = 0,
+};
+
+static const uint64_t nsec_mult[PERIDX_MAX] = {
+ [PERIDX_YEARS] = NSEC_PER_SECOND * SECONDS_PER_YEAR,
+ [PERIDX_MONTHS] = NSEC_PER_SECOND * SECONDS_PER_MONTH,
+ [PERIDX_WEEKS] = NSEC_PER_SECOND * 604800,
+ [PERIDX_DAYS] = NSEC_PER_SECOND * 86400,
+ [PERIDX_HOURS] = NSEC_PER_SECOND * 3600,
+ [PERIDX_MIN] = NSEC_PER_SECOND * 60,
+ [PERIDX_SEC] = NSEC_PER_SECOND,
+ [PERIDX_MSEC] = 1000000,
+ [PERIDX_MUSEC] = 1000,
+ [PERIDX_NSEC] = 1,
};
-static unsigned long long HX_strtoull_time(const char *s, char **out_end, bool nsec)
+/**
+ * Take a textual period string ("1 minute 5 seconds") and break it down.
+ * @s: input string
+ * @utab: allowed unit suffixes
+ * @mtab: multiplication table
+ * @out_end: parsing stopping point
+ *
+ * Returns an errno.
+ */
+static unsigned long long HX_strtoull_period(const char *s,
+ const struct HX_unit_desc *utab, size_t usize, const uint64_t *mtab,
+ size_t msize, char **out_end)
+{
+ unsigned long long quant = 0;
+
+ while (*s != '\0') {
+ while (HX_isspace(*s))
+ ++s;
+ const char *numbegin = s;
+ if (*s == '-')
+ break;
+ char *end = nullptr;
+ unsigned long long num = strtoull(s, &end, 10);
+ if (num == ULLONG_MAX && errno == ERANGE)
+ return num;
+ double frac = 0;
+ bool have_frac = *end == '.';
+ if (have_frac)
+ frac = strtod(s, &end);
+ if (end == s)
+ break;
+ s = end;
+ while (HX_isspace(*s))
+ ++s;
+ unsigned int i;
+ for (i = 0; i < usize; ++i)
+ if (strncasecmp(s, utab[i].name, utab[i].len) == 0 &&
+ /* Ensure a word boundary is present */
+ !HX_isalpha(s[utab[i].len]))
+ break;
+ if (i == usize) {
+ if ((!have_frac && num == 0) || (have_frac && frac == 0))
+ /* 0 is the same no matter what unit, take it */
+ continue;
+ s = numbegin;
+ break;
+ }
+ unsigned long long mult = mtab[utab[i].pidx];
+ if (have_frac) {
+ double v = frac * mult;
+ if (v >= static_cast(double, ULLONG_MAX)) {
+ /*
+ * As ULLONG_MAX gets promoted to double, its
+ * value may _increase_, therefore here we use
+ * >= and not >.
+ */
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, numbegin);
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ num = v;
+ } else {
+ if (mult > 0 && num > ULLONG_MAX / mult) {
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, numbegin);
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ num *= mult;
+ }
+ if (num > ULLONG_MAX - quant) {
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, numbegin);
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ quant += num;
+ s += utab[i].len;
+ }
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, s);
+ errno = 0;
+ return quant;
+}
+
+static unsigned long long HX_strtoull_iso8601p_2(const char *s,
+ const uint64_t *mtab, size_t msize, char **out_end)
{
+ const struct HX_unit_desc *utab = iso8601p_dtab;
+ size_t usize = ARRAY_SIZE(iso8601p_dtab);
unsigned long long quant = 0;
while (*s != '\0') {
@@ -1117,6 +1187,14 @@ static unsigned long long HX_strtoull_time(const char *s, char **out_end, bool n
const char *numbegin = s;
if (*s == '-')
break;
+ if (HX_toupper(*s) == 'T') {
+ if (utab != iso8601p_dtab)
+ break;
+ utab = iso8601p_ttab;
+ usize = ARRAY_SIZE(iso8601p_ttab);
+ ++s;
+ continue;
+ }
char *end = nullptr;
unsigned long long num = strtoull(s, &end, 10);
if (num == ULLONG_MAX && errno == ERANGE)
@@ -1131,51 +1209,98 @@ static unsigned long long HX_strtoull_time(const char *s, char **out_end, bool n
while (HX_isspace(*s))
++s;
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(time_multiplier); ++i)
- if (strncmp(s, time_multiplier[i].name,
- time_multiplier[i].len) == 0 &&
- !HX_isalpha(s[time_multiplier[i].len]))
+ /* No word boundary check for 8601 mode */
+ for (i = 0; i < usize; ++i)
+ if (strncmp(s, utab[i].name, utab[i].len) == 0)
break;
- if (i == ARRAY_SIZE(time_multiplier)) {
+ if (i == usize) {
if ((!have_frac && num == 0) || (have_frac && frac == 0))
/* 0 is the same no matter what unit, take it */
continue;
s = numbegin;
break;
}
- unsigned long long mult = nsec ? time_multiplier[i].ns_mult : time_multiplier[i].s_mult;
+ unsigned long long mult = mtab[utab[i].pidx];
if (have_frac) {
- quant += frac * mult;
+ double v = frac * mult;
+ if (v >= static_cast(double, ULLONG_MAX)) {
+ /*
+ * As ULLONG_MAX gets promoted to double, its
+ * value may _increase_, therefore here we use
+ * >= and not >.
+ */
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, numbegin);
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ num = v;
} else {
- if (mult > 0 && num >= ULLONG_MAX / mult) {
+ if (mult > 0 && num > ULLONG_MAX / mult) {
if (out_end != nullptr)
*out_end = const_cast(char *, numbegin);
errno = ERANGE;
return ULLONG_MAX;
}
- quant += num * mult;
+ num *= mult;
}
- s += time_multiplier[i].len;
+ if (num > ULLONG_MAX - quant) {
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, numbegin);
+ errno = ERANGE;
+ return ULLONG_MAX;
+ }
+ quant += num;
+ s += utab[i].len;
}
if (out_end != nullptr)
*out_end = const_cast(char *, s);
+ errno = 0;
return quant;
}
+static bool looks_like_iso8601(const char *s)
+{
+ if (s[0] != 'P')
+ return false;
+ if (HX_isdigit(s[1]))
+ return true;
+ if (s[1] == 'T' && HX_isdigit(s[2]))
+ return true;
+ return false;
+}
+
EXPORT_SYMBOL unsigned long long HX_strtoull_sec(const char *s, char **out_end)
{
- return HX_strtoull_time(s, out_end, false);
+ if (looks_like_iso8601(s))
+ return HX_strtoull_iso8601p_2(&s[1], sec_mult, ARRAY_SIZE(sec_mult), out_end);
+ return HX_strtoull_period(s,
+ txtperiod_utab, ARRAY_SIZE(txtperiod_utab),
+ sec_mult, ARRAY_SIZE(sec_mult), out_end);
}
EXPORT_SYMBOL unsigned long long HX_strtoull_nsec(const char *s, char **out_end)
{
- return HX_strtoull_time(s, out_end, true);
+ if (looks_like_iso8601(s))
+ return HX_strtoull_iso8601p_2(&s[1], nsec_mult, ARRAY_SIZE(nsec_mult), out_end);
+ return HX_strtoull_period(s,
+ txtperiod_utab, ARRAY_SIZE(txtperiod_utab),
+ nsec_mult, ARRAY_SIZE(nsec_mult), out_end);
+}
+
+EXPORT_SYMBOL unsigned long long HX_strtoull8601p_sec(const char *s, char **out_end)
+{
+ if (*s == 'P')
+ return HX_strtoull_iso8601p_2(&s[1], sec_mult, ARRAY_SIZE(sec_mult), out_end);
+ if (out_end != nullptr)
+ *out_end = const_cast(char *, s);
+ return 0;
}
EXPORT_SYMBOL char *HX_unit_seconds(char *out, size_t outsize,
unsigned long long secs, unsigned int flags)
{
- unsigned long years = 0, months = 0, weeks = 0, days, hours, mins;
+ unsigned long long years = 0, months = 0, weeks = 0, days, hours, mins;
char buf[HXSIZEOF_Z64+4];
if (flags & HXUNIT_YEARS) {
years = secs / SECONDS_PER_YEAR;
@@ -1197,31 +1322,31 @@ EXPORT_SYMBOL char *HX_unit_seconds(char *out, size_t outsize,
secs %= 60;
*out = '\0';
if (years > 0) {
- snprintf(buf, ARRAY_SIZE(buf), "%luy", years);
+ snprintf(buf, ARRAY_SIZE(buf), "%lluy", years);
HX_strlcat(out, buf, outsize);
}
if (months == 1) {
HX_strlcat(out, "1month", outsize);
} else if (months > 0) {
- snprintf(buf, ARRAY_SIZE(buf), "%lumonths", months);
+ snprintf(buf, ARRAY_SIZE(buf), "%llumonths", months);
HX_strlcat(out, buf, outsize);
}
if (weeks == 1) {
HX_strlcat(out, "1week", outsize);
} else if (weeks > 0) {
- snprintf(buf, ARRAY_SIZE(buf), "%luweeks", weeks);
+ snprintf(buf, ARRAY_SIZE(buf), "%lluweeks", weeks);
HX_strlcat(out, buf, outsize);
}
if (days > 0) {
- snprintf(buf, ARRAY_SIZE(buf), "%lud", days);
+ snprintf(buf, ARRAY_SIZE(buf), "%llud", days);
HX_strlcat(out, buf, outsize);
}
if (hours > 0) {
- snprintf(buf, ARRAY_SIZE(buf), "%luh", hours);
+ snprintf(buf, ARRAY_SIZE(buf), "%lluh", hours);
HX_strlcat(out, buf, outsize);
}
if (mins > 0) {
- snprintf(buf, ARRAY_SIZE(buf), "%lumin", mins);
+ snprintf(buf, ARRAY_SIZE(buf), "%llumin", mins);
HX_strlcat(out, buf, outsize);
}
if (secs > 0 ||
diff --git a/src/tc-compile.c b/src/tc-compile.c
index d60ff21..6aa38c4 100644
--- a/src/tc-compile.c
+++ b/src/tc-compile.c
@@ -5,6 +5,8 @@
# include <cstdlib>
#endif
#include <libHX.h>
+#include <libHX/endian.h>
+#include <libHX/endian_float.h>
#define ZZ 64
diff --git a/src/tc-io.c b/src/tc-io.c
index 77baf01..024a46a 100644
--- a/src/tc-io.c
+++ b/src/tc-io.c
@@ -28,6 +28,16 @@ static void sf(void)
close(src);
}
+static void t_getcwd(void)
+{
+ hxmc_t *s = nullptr;
+ if (HX_getcwd(&s) > 0)
+ printf("cwd1: >%s<\n", s);
+ HXmc_setlen(&s, 0);
+ if (HX_getcwd(&s) > 0)
+ printf("cwd2: >%s<\n", s);
+}
+
int main(void)
{
size_t z;
@@ -55,5 +65,7 @@ int main(void)
fprintf(stderr, "copy_file ok\n");
unlink("tciocopy.txt");
}
+
+ t_getcwd();
return 0;
}
diff --git a/src/tc-list.c b/src/tc-list.c
index d31a5c7..abb0944 100644
--- a/src/tc-list.c
+++ b/src/tc-list.c
@@ -81,7 +81,7 @@ static void l_dump(bool pop)
#endif
}
- printf("Remaining elements: %u\n", strings_ct.items);
+ printf("Remaining elements: %zu\n", strings_ct.items);
}
static void l_empty(void)
diff --git a/src/tc-map.c b/src/tc-map.c
index e9e896f..5ad7dfe 100644
--- a/src/tc-map.c
+++ b/src/tc-map.c
@@ -107,7 +107,7 @@ static void tmap_flush(struct HXmap *map, bool verbose)
const struct HXmap_node *node;
struct HXmap_trav *iter;
- tmap_printf("Flushing %u elements (with traversal)\n", map->items);
+ tmap_printf("Flushing %zu elements (with traversal)\n", map->items);
tmap_ipush();
while (map->items != 0) {
/* May need to reload traverser due to deletion */
@@ -141,7 +141,7 @@ static void tmap_add_speed(struct HXmap *map)
tmap_time(&stop);
HX_timespec_sub(&delta, &stop, &start);
} while (!(delta.tv_sec >= 1 || map->items >= 1000000));
- tmap_printf("%u elements in " HX_TIMESPEC_FMT
+ tmap_printf("%zu elements in " HX_TIMESPEC_FMT
" (plus time measurement overhead)\n",
map->items, HX_TIMESPEC_EXP(&delta));
threshold = map->items;
@@ -151,7 +151,7 @@ static void tmap_add_speed(struct HXmap *map)
tmap_add_rand(map, threshold);
tmap_time(&stop);
HX_timespec_sub(&delta, &stop, &start);
- tmap_printf("%u elements in " HX_TIMESPEC_FMT " (w/o overhead)\n",
+ tmap_printf("%zu elements in " HX_TIMESPEC_FMT " (w/o overhead)\n",
map->items, HX_TIMESPEC_EXP(&delta));
tmap_ipop();
}
@@ -176,14 +176,14 @@ static void tmap_trav_speed(struct HXmap *map)
tmap_time(&stop);
HX_timespec_sub(&delta, &stop, &start);
HXmap_travfree(iter);
- tmap_printf("Open traversal of %u nodes: " HX_TIMESPEC_FMT "s\n",
+ tmap_printf("Open traversal of %zu nodes: " HX_TIMESPEC_FMT "s\n",
map->items, HX_TIMESPEC_EXP(&delta));
tmap_time(&start);
HXmap_qfe(map, tmap_each_fn, NULL);
tmap_time(&stop);
HX_timespec_sub(&delta, &stop, &start);
- tmap_printf("QFE traversal of %u nodes: " HX_TIMESPEC_FMT "s\n",
+ tmap_printf("QFE traversal of %zu nodes: " HX_TIMESPEC_FMT "s\n",
map->items, HX_TIMESPEC_EXP(&delta));
tmap_ipop();
@@ -200,7 +200,7 @@ static void tmap_trav_speed(struct HXmap *map)
start = delta;
stop = delta2;
HX_timespec_sub(&delta, &stop, &start);
- tmap_printf("Lookup of %u nodes: " HX_TIMESPEC_FMT "s\n",
+ tmap_printf("Lookup of %zu nodes: " HX_TIMESPEC_FMT "s\n",
map->items, HX_TIMESPEC_EXP(&delta));
tmap_ipop();
}
@@ -210,7 +210,7 @@ static int tmap_flat(const struct HXmap *map)
struct HXmap_node *nodes;
unsigned int i;
- tmap_printf("Retrieving flattened list of %u elements:\n", map->items);
+ tmap_printf("Retrieving flattened list of %zu elements:\n", map->items);
tmap_ipush();
nodes = HXmap_keysvalues(map);
if (nodes == NULL) {
@@ -430,7 +430,7 @@ static void tmap_hmap_test_1a(const char *map_type,
u.map = HXmap_init5(HXMAPT_HASH, HXMAP_SCKEY,
&intstr_ops, 0, 0);
tmap_new_perfect_tree(u.map, power, 2);
- tmap_printf("%s, intstr, %u items/%u buckets, "
+ tmap_printf("%s, intstr, %zu items/%u buckets, "
"agglomeration: %.2f%%\n", map_type,
u.map->items, HXhash_primes[u.hmap->power],
hmap_agg_index(u.hmap, false));
@@ -441,13 +441,13 @@ static void tmap_hmap_test_1a(const char *map_type,
while (u.map->items < 1 << max_power) {
/* Fill up just right up to the maximum load */
tmap_add_rand(u.map, u.hmap->max_load - u.map->items);
- tmap_printf("%s, words, %u items/%u buckets, "
+ tmap_printf("%s, words, %zu items/%u buckets, "
"agglomeration: %.2f%%\n", map_type,
u.map->items, HXhash_primes[u.hmap->power],
hmap_agg_index(u.hmap, false));
/* trigger resize */
tmap_add_rand(u.map, 1);
- tmap_printf("%s, words, %u items/%u buckets, "
+ tmap_printf("%s, words, %zu items/%u buckets, "
"agglomeration: %.2f%%\n", map_type,
u.map->items, HXhash_primes[u.hmap->power],
hmap_agg_index(u.hmap, false));
@@ -535,7 +535,7 @@ static void rbt_height_check(const struct HXrbtree *tree)
max = 2 * log(tree->super.items + 1) / log(2);
avg = log((pow(2, min) + pow(2, max)) / 2) / log(2);
tmap_ipush();
- tmap_printf("%u items; height %u; min/avg/max %.2f/%.2f/%.2f\n",
+ tmap_printf("%zu items; height %u; min/avg/max %.2f/%.2f/%.2f\n",
tree->super.items, rbt_tree_height(tree->root),
min, avg, max);
tmap_ipop();
diff --git a/src/tc-netio.c b/src/tc-netio.c
index 4510d0a..d3c2929 100644
--- a/src/tc-netio.c
+++ b/src/tc-netio.c
@@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
#define WIN32_LEAN_AND_MEAN 1
+#define _POSIX_C_SOURCE 999900L /* cygwin-need:freeaddrinfo */
#ifdef __cplusplus
# include <cstdlib>
# include <cstdio>
diff --git a/src/tc-option.c b/src/tc-option.c
index 8e99b19..860f9d2 100644
--- a/src/tc-option.c
+++ b/src/tc-option.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
-// SPDX-FileCopyrightText: 2022 Jan Engelhardt
+// SPDX-FileCopyrightText: 2025 Jan Engelhardt
/*
* option parser test program
*/
@@ -14,17 +14,22 @@
#include "internal.h"
static int opt_v = 0, opt_mask = 0;
-static char *opt_kstr = NULL;
+static char *opt_kstr, *opt_strp;
static long opt_klong = 0;
static double opt_kdbl = 0;
static int opt_kflag = 0, opt_kint = 0;
static int opt_dst = 0;
static hxmc_t *opt_mcstr = NULL;
+static inline const char *znul(const char *s)
+{
+ return s != nullptr ? s : "(null)";
+}
+
static void opt_cbf(const struct HXoptcb *cbi)
{
printf("cbf was called... with \"%s\"/'%c'\n",
- cbi->current->ln, cbi->current->sh);
+ znul(cbi->current->ln), cbi->current->sh);
}
static const char *opt_eitheror[] = {"neither", "either", "or"};
@@ -59,83 +64,159 @@ static struct HXoption table[] = {
.cb = opt_cbf, .help = "XOR mask test", .htyp = "value"},
{.sh = 'G', .type = HXTYPE_NONE, .help = "Just a flag", .cb = opt_cbf},
{.sh = 'H', .type = HXTYPE_NONE, .help = "Just a flag", .cb = opt_cbf},
- {.sh = 'I', .type = HXTYPE_NONE, .help = "Just a flag", .cb = opt_cbf},
+ {.sh = 'I', .type = HXTYPE_NONE, .ptr = nullptr, .help = "Just a flag", .cb = opt_cbf},
HXOPT_AUTOHELP,
{.sh = 'J', .type = HXTYPE_NONE, .help = "Just a flag", .cb = opt_cbf},
+ {.ln = "strp", .sh = 'Z', .type = HXTYPE_STRP, .ptr = &opt_strp,
+ .help = "String pointer", .cb = opt_cbf},
HXOPT_TABLEEND,
};
-static void dump_argv(char **v)
+static int t_empty_argv(void)
{
- while (*v != NULL)
- printf("[%s] ", *v++);
- printf("\n");
-}
+ char *zero_argv[] = {nullptr};
+ struct HXopt6_result result;
-static int t_pthru(void)
-{
- const char *argv[] = {
- "ARGV0", "-Zomg", "-GZfoo", "bar",
- "--unknown-f=13.37", "--unknown-a",
- "foo", "bar", NULL
- };
- char **nargv = nullptr;
- int nargc = 0;
-
- printf("PTHRU test:\n");
- if (HX_getopt5(table, const_cast(char **, argv), &nargc, &nargv,
- HXOPT_USAGEONERR | HXOPT_PTHRU) != HXOPT_ERR_SUCCESS)
+ printf("...with argv={NULL}\n");
+ if (HX_getopt6(table, 0, zero_argv, &result,
+ HXOPT_USAGEONERR | HXOPT_ITER_OA | HXOPT_DUP_ARGS) != HXOPT_ERR_SUCCESS)
return EXIT_FAILURE;
- printf("argc = %d\n", nargc);
- dump_argv(nargv);
- printf("\n");
- HX_zvecfree(nargv);
- return EXIT_SUCCESS;
+ bool ok = result.nopts == 0 && result.nargs == 0 && result.dup_argc == 0;
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+ return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}
-static int t_empty_argv(void)
+static int runner(int argc, char **argv)
{
- char *zero_argv[] = {nullptr};
- char **new_argv = nullptr;
+ printf("== HX_getopt6 ==\n");
+ int ret = HX_getopt6(table, argc, argv, nullptr, HXOPT_USAGEONERR);
+ printf("Return value of HX_getopt: %d\n", ret);
+ printf("Either-or is: %s\n", opt_eitheror[opt_dst]);
+ printf("values: D=%lf I=%d L=%ld S=%p/%s strp=%p/%s\n",
+ opt_kdbl, opt_kint, opt_klong,
+ opt_kstr, znul(opt_kstr), opt_strp, znul(opt_strp));
+ printf("Verbosity level: %d\n", opt_v);
+ printf("Mask: 0x%08X\n", opt_mask);
+ printf("mcstr: >%s<\n", znul(opt_mcstr));
+ free(opt_kstr);
+ opt_kstr = nullptr;
- printf("Testing argv={NULL}\n");
- if (HX_getopt5(table, zero_argv, nullptr, &new_argv,
- HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
- return EXIT_FAILURE;
- HX_zvecfree(new_argv);
+ ret = t_empty_argv();
+ if (ret != EXIT_SUCCESS)
+ return ret;
return EXIT_SUCCESS;
}
-static int t_keep_argv(void)
+static int t_getopt6_aflags(int unused_argc, char **unused_argv)
{
- static const char *const one_argv[] = {"what", nullptr};
- const char **argv = const_cast2(const char **, one_argv);
- if (HX_getopt(table, nullptr, &argv, HXOPT_KEEP_ARGV) != HXOPT_ERR_SUCCESS)
+ struct HXopt6_result result;
+ char *argv[] = {"./prog", "-q", "foo", "-qS", "quux", "bar", "--NIL", nullptr};
+
+ printf("== ANY_ORDER ==\n");
+ int ret = HX_getopt6(table, 6, argv, &result, HXOPT_ANY_ORDER);
+ if (ret != HXOPT_ERR_SUCCESS ||
+ result.uarg != nullptr || result.dup_argv != nullptr)
+ return EXIT_FAILURE;
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+
+ /* T: Asking for DUP should produce data */
+ /* T: Limit strings -- NIL must not be processed */
+ printf("== ANY_ORDER/DUP_ARGS ==\n");
+ ret = HX_getopt6(table, 6, argv, &result, HXOPT_ANY_ORDER | HXOPT_DUP_ARGS);
+ if (ret != HXOPT_ERR_SUCCESS ||
+ result.uarg != nullptr ||
+ result.dup_argv == nullptr || result.dup_argc != 3)
+ return EXIT_FAILURE;
+ if (strcmp(result.dup_argv[0], argv[0]) != 0 ||
+ strcmp(result.dup_argv[1], argv[2]) != 0 ||
+ strcmp(result.dup_argv[2], argv[5]) != 0)
+ return EXIT_FAILURE;
+ for (int i = 0; i < result.dup_argc; ++i)
+ printf(" %s", result.dup_argv[i]);
+ printf("\n");
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+
+ /* T: POSIX order */
+ printf("== RQ_ORDER/DUP_ARGS ==\n");
+ ret = HX_getopt6(table, 6, argv, &result, HXOPT_RQ_ORDER | HXOPT_DUP_ARGS);
+ if (ret != HXOPT_ERR_SUCCESS ||
+ result.uarg != nullptr ||
+ result.dup_argv == nullptr || result.dup_argc != 5)
+ return EXIT_FAILURE;
+ if (strcmp(result.dup_argv[0], argv[0]) != 0 ||
+ strcmp(result.dup_argv[1], argv[2]) != 0 ||
+ strcmp(result.dup_argv[2], argv[3]) != 0 ||
+ strcmp(result.dup_argv[3], argv[4]) != 0 ||
+ strcmp(result.dup_argv[4], argv[5]) != 0)
return EXIT_FAILURE;
- return argv == one_argv ? EXIT_SUCCESS : EXIT_FAILURE;
+ for (int i = 0; i < result.dup_argc; ++i)
+ printf(" %s", result.dup_argv[i]);
+ printf("\n");
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+
+ /* T: Asking for ITER should produce data */
+ printf("== ANY_ORDER/ITER_ARGS ==\n");
+ ret = HX_getopt6(table, 6, argv, &result, HXOPT_ANY_ORDER | HXOPT_ITER_ARGS);
+ if (ret != HXOPT_ERR_SUCCESS || result.dup_argv != nullptr ||
+ result.nargs != 2 || result.uarg == nullptr)
+ return EXIT_FAILURE;
+ if (strcmp(result.uarg[0], argv[2]) != 0 ||
+ strcmp(result.uarg[1], argv[5]) != 0)
+ return EXIT_FAILURE;
+ for (int i = 0; i < result.nargs; ++i)
+ printf(" %s", result.uarg[i]);
+ printf("\n");
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+
+ /* T: Asking for ITER should produce data */
+ printf("== ANY_ORDER/ITER_OPTS ==\n");
+ ret = HX_getopt6(table, 6, argv, &result, HXOPT_ANY_ORDER | HXOPT_ITER_OPTS);
+ if (ret != HXOPT_ERR_SUCCESS || result.nopts != 3 ||
+ result.desc == nullptr || result.oarg == nullptr)
+ return EXIT_FAILURE;
+ if (result.desc[0]->sh != 'q' || result.oarg[0] != nullptr ||
+ result.desc[1]->sh != 'q' || result.oarg[1] != nullptr ||
+ result.desc[2]->sh != 'S' || result.oarg[2] == nullptr ||
+ strcmp(result.oarg[2], argv[4]) != 0)
+ return EXIT_FAILURE;
+ printf(" %s", argv[0]);
+ for (int i = 0; i < result.nopts; ++i) {
+ printf(" -%c", result.desc[i]->sh);
+ if (result.oarg[i] != nullptr)
+ printf(" %s", result.oarg[i]);
+ }
+ printf("\n");
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+ return EXIT_SUCCESS;
}
-static int runner(int argc, char **argv)
+static int t_getopt6_eq(void)
{
- char **nargv = nullptr;
- int ret = HX_getopt5(table, argv, &argc, &nargv, HXOPT_USAGEONERR);
- printf("Return value of HX_getopt: %d\n", ret);
- if (ret == EXIT_SUCCESS)
- HX_zvecfree(nargv);
- ret = t_empty_argv();
- if (ret != EXIT_SUCCESS)
- return ret;
- ret = t_keep_argv();
- if (ret != EXIT_SUCCESS)
- return ret;
-
- printf("Either-or is: %s\n", opt_eitheror[opt_dst]);
- printf("values: D=%lf I=%d L=%ld S=%s\n",
- opt_kdbl, opt_kint, opt_klong, opt_kstr);
- printf("Verbosity level: %d\n", opt_v);
- printf("Mask: 0x%08X\n", opt_mask);
- printf("mcstr: >%s<\n", opt_mcstr);
- return t_pthru();
+ printf("== getopt6_eq ==\n");
+ char *argv[] = {"./prog", "--strp", "bar", "--strp=bar"};
+ struct HXopt6_result result;
+ int ret = HX_getopt6(table, ARRAY_SIZE(argv), argv, &result,
+ HXOPT_ITER_OPTS | HXOPT_USAGEONERR);
+ if (ret != HXOPT_ERR_SUCCESS || result.nopts != 2)
+ return EXIT_FAILURE;
+ if (strcmp(result.oarg[0], result.oarg[1]) != 0)
+ return EXIT_FAILURE;
+ HX_getopt6_clean(&result);
+ free(opt_kstr);
+ opt_kstr = nullptr;
+ return EXIT_SUCCESS;
}
int main(int argc, char **argv)
@@ -145,6 +226,12 @@ int main(int argc, char **argv)
int ret = runner(argc, argv);
if (ret != EXIT_SUCCESS)
printf("FAILED\n");
+ ret = t_getopt6_aflags(argc, argv);
+ if (ret != EXIT_SUCCESS)
+ printf("FAILED\n");
+ ret = t_getopt6_eq();
+ if (ret != EXIT_SUCCESS)
+ printf("FAILED\n");
HX_exit();
return ret;
}
diff --git a/src/tc-proc.c b/src/tc-proc.c
index c17b232..9af1eba 100644
--- a/src/tc-proc.c
+++ b/src/tc-proc.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
+#define _POSIX_C_SOURCE 999900L /* cygwin:fdopen */
#ifdef __cplusplus
# include <cerrno>
# include <cstdio>
diff --git a/src/tc-realpath.c b/src/tc-realpath.c
index b71c127..e4933a5 100644
--- a/src/tc-realpath.c
+++ b/src/tc-realpath.c
@@ -10,36 +10,14 @@
#include <libHX/string.h>
#include "internal.h"
-static unsigned int rp_flags;
-static unsigned int rp_absolute;
-static unsigned int rp_no_parent, rp_no_self;
-
static const struct HXoption rp_option_table[] = {
- {.sh = 'a', .type = HXTYPE_NONE, .ptr = &rp_absolute,
- .help = "Produce an absolute path"},
- {.sh = 'p', .type = HXTYPE_NONE, .ptr = &rp_no_parent,
- .help = "Deactivate resolution of \"..\" entries"},
- {.sh = 's', .type = HXTYPE_NONE, .ptr = &rp_no_self,
- .help = "Deactivate resolution of \".\" entries"},
+ {.sh = 'a', .type = HXTYPE_NONE, .help = "Produce an absolute path"},
+ {.sh = 'p', .type = HXTYPE_NONE, .help = "Deactivate resolution of \"..\" entries"},
+ {.sh = 's', .type = HXTYPE_NONE, .help = "Deactivate resolution of \".\" entries"},
HXOPT_AUTOHELP,
HXOPT_TABLEEND,
};
-static bool rp_get_options(char **oargv, int *argc, char ***argv)
-{
- if (HX_getopt5(rp_option_table, oargv, argc, argv, HXOPT_USAGEONERR) !=
- HXOPT_ERR_SUCCESS)
- return false;
- rp_flags = HX_REALPATH_DEFAULT;
- if (rp_absolute)
- rp_flags |= HX_REALPATH_ABSOLUTE;
- if (rp_no_parent)
- rp_flags &= ~HX_REALPATH_PARENT;
- if (rp_no_self)
- rp_flags &= ~HX_REALPATH_SELF;
- return true;
-}
-
static void t_1(void)
{
hxmc_t *tmp = HXmc_strinit("");
@@ -48,19 +26,37 @@ static void t_1(void)
HXmc_free(tmp);
}
-int main(int argc, char **oargv)
+static void t_2(void)
+{
+ hxmc_t *tmp = HXmc_strinit("");
+ int ret = HX_realpath(&tmp, "../../../../dev/tty", HX_REALPATH_ABSOLUTE | HX_REALPATH_DEFAULT);
+ if (ret > 0)
+ printf("t_2: %s\n", tmp);
+ HXmc_free(tmp);
+}
+
+int main(int argc, char **argv)
{
- char **argv = nullptr;
hxmc_t *res;
int ret;
-
- if (!rp_get_options(oargv, &argc, &argv))
- return EXIT_FAILURE;
+ struct HXopt6_result result;
+ if (HX_getopt6(rp_option_table, argc, argv, &result,
+ HXOPT_USAGEONERR | HXOPT_ITER_OA) != HXOPT_ERR_SUCCESS)
+ return false;
+ unsigned int rp_flags = HX_REALPATH_DEFAULT;
+ for (int i = 0; i < result.nopts; ++i) {
+ switch (result.desc[i]->sh) {
+ case 'a': rp_flags |= HX_REALPATH_ABSOLUTE; break;
+ case 'p': rp_flags &= ~HX_REALPATH_PARENT; break;
+ case 's': rp_flags &= ~HX_REALPATH_SELF; break;
+ }
+ }
t_1();
+ t_2();
res = NULL;
- for (int i = 1; i < argc; ++i) {
- ret = HX_realpath(&res, argv[argc], rp_flags);
+ for (int i = 0; i < result.nargs; ++i) {
+ ret = HX_realpath(&res, result.uarg[i], rp_flags);
if (ret < 0) {
perror("HX_realpath");
printf("\n");
@@ -68,6 +64,6 @@ int main(int argc, char **oargv)
printf("%s\n", res);
}
}
- HX_zvecfree(argv);
+ HX_getopt6_clean(&result);
return EXIT_SUCCESS;
}
diff --git a/src/tc-socket.c b/src/tc-socket.c
index 2c140a1..dafe509 100644
--- a/src/tc-socket.c
+++ b/src/tc-socket.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: MIT
+#define _POSIX_C_SOURCE 999900L
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/tc-string.c b/src/tc-string.c
index e7f90c2..7c3034d 100644
--- a/src/tc-string.c
+++ b/src/tc-string.c
@@ -1,5 +1,6 @@
/* long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing long line for testing */
// SPDX-License-Identifier: MIT
+#define _POSIX_C_SOURCE 909900L
#ifndef __cplusplus
# include <assert.h>
# include <errno.h>
@@ -108,23 +109,22 @@ static void t_strncat(void)
printf("String: >%s<\n", data);
}
-static void t_strnlen(void)
-{
- static const char s[] = "Hello world";
- printf("# strnlen: %" HX_SIZET_FMT "u %" HX_SIZET_FMT "u "
- "%" HX_SIZET_FMT "u %" HX_SIZET_FMT "u %" HX_SIZET_FMT "u\n",
- HX_strnlen(s, -1), HX_strnlen(s, 0), HX_strnlen(s, 1),
- HX_strnlen(s, strlen(s)), HX_strnlen(s, 999));
-}
-
static void t_strsep(void)
{
- char b[] = "jengelh:x:1500:100:Jan Engelhardt:/home/jengelh:/bin/bash";
+ char orig[] = "jengelh:x:1500:100:Jan Engelhardt:/home/jengelh:/bin/bash";
+ char b[sizeof(orig)];
char *wp = b, *ret;
printf("# strsep\n");
+ memcpy(b, orig, sizeof(orig));
while ((ret = HX_strsep2(&wp, ":")) != NULL)
printf("%s\n", ret);
+
+ printf("# strtok_r\n");
+ memcpy(b, orig, sizeof(orig));
+ wp = b;
+ while ((ret = strtok_r(nullptr, ":", &wp)) != nullptr)
+ printf("%s\n", ret);
}
static void t_strtrim(void)
@@ -132,11 +132,6 @@ static void t_strtrim(void)
char a[] = " a and b ", aexp[] = "a and b ";
char b[] = " a and b ", bexp[] = " a and b";
char c[] = "a&b", cexp[] = "a&b";
- const char *r;
-
- r = HX_stpltrim(a);
- printf("HX_stpltrim(\"%s\") = \"%s\"\n", a, r);
- assert(strcmp(r, aexp) == 0);
printf("HX_strltrim(\"%s\") = ", a);
printf("\"%s\"\n", (HX_strltrim(a), a));
@@ -146,7 +141,6 @@ static void t_strtrim(void)
printf("\"%s\"\n", (HX_strrtrim(b), b));
assert(strcmp(b, bexp) == 0);
- assert(strcmp(cexp, HX_stpltrim(c)) == 0);
assert(strcmp(cexp, (HX_strltrim(c), c)) == 0);
assert(strcmp(cexp, (HX_strrtrim(c), c)) == 0);
}
@@ -355,8 +349,16 @@ static int t_time_units(void)
static const struct {
unsigned long long input;
unsigned int flags;
- const char expect_out[24];
+ const char expect_out[41];
} vt[] = {
+#define SECONDS_PER_YEAR 31557600 /* 365.25 days */
+#define SECONDS_PER_MONTH 2629800 /* 1/12th of that year = 30.4375 days */
+ {18446744073709551615ULL, 0, "213503982334601d7h15s"},
+ {18446744073709526399ULL, 0, "213503982334600d23h59min59s"},
+ {18446744073709180799ULL, HXUNIT_WEEKS, "30500568904942weeks2d23h59min59s"},
+ {18446744073708451799ULL, HXUNIT_MONTHS, "7014504553087months2d23h59min59s"},
+ {18446744073707636399ULL, HXUNIT_MONTHS | HXUNIT_WEEKS, "7014504553086months3weeks2d23h59min59s"},
+ {18446744073688622999ULL, HXUNIT_YEARS | HXUNIT_MONTHS | HXUNIT_WEEKS, "584542046089y11months2weeks2d23h59min59s"},
{31536000, 0, "365d"},
{31622400, 0, "366d"},
{34819200, HXUNIT_WEEKS, "57weeks4d"},
@@ -391,14 +393,19 @@ static int t_time_units(void)
static int t_time_strto(void)
{
#define NS_PER_S 1000000000ULL
+ #define S_PER_Y 31557600
+ enum {
+ NO_NSEC = 0x2U,
+ };
static const struct {
const char *input;
unsigned long long expect_s, expect_ns;
const char expect_rem[16];
+ unsigned int flags;
} vt[] = {
{"29µs", 0, 29000, ""},
- {"1y", 31557600, NS_PER_S * 31557600, ""},
- {"1y1month1week1d1h1min1s ", 31557600+2629800+86400*8+3600+60+1, NS_PER_S * (31557600+2629800+86400*8+3600+60+1), ""},
+ {"1y", S_PER_Y, NS_PER_S * S_PER_Y, ""},
+ {"1y1month1week1d1h1min1s ", S_PER_Y+2629800+86400*8+3600+60+1, NS_PER_S * (S_PER_Y+2629800+86400*8+3600+60+1), ""},
{" -1d", 0, 0, "-1d"},
{"1 -", 0, 0, "1 -"},
{"12.5 hours .5 hours 240 minutes 25200 seconds", 86400, NS_PER_S * 86400, ""},
@@ -410,23 +417,42 @@ static int t_time_strto(void)
{"1s0.0", 1, NS_PER_S, ""},
{"1s1s", 2, 2 * NS_PER_S, ""},
{"1s1", 1, 1 * NS_PER_S, "1"},
+ {"584542046090y", 584542046090ULL * S_PER_Y, ULLONG_MAX, "", NO_NSEC},
+ {"584542046090y19767615s", ULLONG_MAX, ULLONG_MAX, "", NO_NSEC},
+ {"584542046090y19767616s", ULLONG_MAX, ULLONG_MAX, "19767616s", NO_NSEC},
+ {"584542046090y", 584542046090ULL * S_PER_Y, ULLONG_MAX, "", NO_NSEC},
{"584542046091y", ULLONG_MAX, ULLONG_MAX, "584542046091y"},
+ {"584542046091.0y", ULLONG_MAX, ULLONG_MAX, "584542046091.0y"},
+ {"P1M", S_PER_Y / 12, S_PER_Y / 12 * NS_PER_S, ""},
+ {"p1m", 0, 0, "p1m"},
+ {"PT1M", 60, 60 * NS_PER_S, ""},
+ {"P584542046090Y", 584542046090ULL * S_PER_Y, ULLONG_MAX, "", NO_NSEC},
+ {"P0DT0H0M0.0S", 0, 0},
+ {"P0DT12H45M0.0S", 12 * 3600 + 45 * 60, (12 * 3600 + 45 * 60) * NS_PER_S},
+ {"P1D", 86400, 86400 * NS_PER_S},
};
- char *end;
printf("===== t_time_strto\n");
for (size_t i = 0; i < ARRAY_SIZE(vt); ++i) {
+ char *end, *end_ns;
unsigned long long q = HX_strtoull_sec(vt[i].input, &end);
- unsigned long long qn = HX_strtoull_nsec(vt[i].input, &end);
- printf("Observed: \"%s\" => %llus [%lluns] + \"%s\"\n", vt[i].input, q, qn, end);
- if (q != vt[i].expect_s || qn != vt[i].expect_ns) {
- printf("Expected: %llus [%lluns]\n", vt[i].expect_s, vt[i].expect_ns);
+ unsigned long long qn = HX_strtoull_nsec(vt[i].input, &end_ns);
+ printf("Observed: \"%s\" => %llus + \"%s\" [%lluns + \"%s\"]\n",
+ vt[i].input, q, end, qn, end_ns);
+ if (q != vt[i].expect_s || strcmp(end, vt[i].expect_rem) != 0) {
+ printf("-!- Expected: %llus + \"%s\"\n", vt[i].expect_s, vt[i].expect_rem);
return EXIT_FAILURE;
}
- if (strcmp(end, vt[i].expect_rem) != 0) {
- printf("Expected: remainder \"%s\"\n", vt[i].expect_rem);
+ if (vt[i].flags & NO_NSEC)
+ continue;
+ if (qn != vt[i].expect_ns || strcmp(end_ns, vt[i].expect_rem) != 0) {
+ printf("-!- Expected: %llus + \"%s\"\n", vt[i].expect_ns, vt[i].expect_rem);
return EXIT_FAILURE;
}
}
+ if (HX_strtoull8601p_sec("P1D", nullptr) != 86400) {
+ printf("8601p_sec failed\n");
+ return EXIT_FAILURE;
+ }
return EXIT_SUCCESS;
}
@@ -488,7 +514,6 @@ static int runner(int argc, char **argv)
if (ret != EXIT_SUCCESS)
return EXIT_FAILURE;
t_strncat();
- t_strnlen();
t_strdup();
t_strsep();
t_strtrim();
diff --git a/src/tc-strquote.c b/src/tc-strquote.c
index ef357d1..c96aa19 100644
--- a/src/tc-strquote.c
+++ b/src/tc-strquote.c
@@ -10,7 +10,6 @@
static const char input1[] = "\"Good\" ol' \\'escaped\\' strings";
static const char output1a[] = "\"Good\" ol\\' \\\\\\'escaped\\\\\\' strings";
static const char output1b[] = "\\\"Good\\\" ol' \\\\'escaped\\\\' strings";
-static const char output1c[] = "\"Good\" ol'' \\''escaped\\'' strings";
static const char input2[] = "<p style=\"height: 1;\">Foo &amp; \"bar\"</p>";
static const char output2[] =
"&lt;p style=&quot;height: 1;&quot;&gt;Foo &amp;amp; &quot;bar&quot;&lt;/p&gt;";
@@ -20,8 +19,6 @@ static const char output3b[] = "\\20\\23o\\3Dfoo(*)\\2Cba\\5Cr\\20";
static const char output3c[] = "ICNvPWZvbygqKSxiYVxyIA==";
static const char input4[] = "http://user:pass@host.de/~path/file(msvc);stuff.php?query[phpindex]=value&another=one;stuff";
static const char output4[] = "http%3A%2F%2Fuser%3Apass%40host.de%2F~path%2Ffile%28msvc%29%3Bstuff.php%3Fquery%5Bphpindex%5D%3Dvalue%26another%3Done%3Bstuff";
-static const char input5[] = "echo hello `echo world`";
-static const char output5[] = "echo hello ``echo world``";
static const char input6[] = "\xfb\xef\xff";
static const char output6[] = "++//";
static const char input7[] = "\xfb\xef\xff";
@@ -58,13 +55,11 @@ int main(void)
return EXIT_FAILURE;
tst(input1, HXQUOTE_SQUOTE, output1a);
tst(input1, HXQUOTE_DQUOTE, output1b);
- tst(input1, HXQUOTE_SQLSQUOTE, output1c);
tst(input2, HXQUOTE_HTML, output2);
tst(input3, HXQUOTE_LDAPFLT, output3a);
tst(input3, HXQUOTE_LDAPRDN, output3b);
tst(input3, HXQUOTE_BASE64, output3c);
tst(input4, HXQUOTE_URIENC, output4);
- tst(input5, HXQUOTE_SQLBQUOTE, output5);
tst(input6, HXQUOTE_BASE64, output6);
tst(input7, HXQUOTE_BASE64URL, output7);
return 0;
diff --git a/src/tc-switchuser.c b/src/tc-switchuser.c
index e5d2c25..379dfff 100644
--- a/src/tc-switchuser.c
+++ b/src/tc-switchuser.c
@@ -10,19 +10,28 @@
#include <libHX/defs.h>
#include <libHX/option.h>
#include <libHX/proc.h>
+#include "internal.h"
#if defined(HAVE_INITGROUPS)
-static char *user_name, *group_name;
static const struct HXoption options_table[] = {
- {.sh = 'u', .type = HXTYPE_STRING, .ptr = &user_name},
- {.sh = 'g', .type = HXTYPE_STRING, .ptr= &group_name},
+ {.sh = 'u', .type = HXTYPE_STRING},
+ {.sh = 'g', .type = HXTYPE_STRING},
HXOPT_TABLEEND,
};
static int runner(int argc, char **argv)
{
- if (HX_getopt(options_table, &argc, &argv, HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
+ char *user_name = nullptr, *group_name = nullptr;
+ struct HXopt6_result result;
+
+ if (HX_getopt6(options_table, argc, argv, &result,
+ HXOPT_USAGEONERR | HXOPT_ITER_OPTS) != HXOPT_ERR_SUCCESS)
return EXIT_FAILURE;
+ for (int i = 0; i < result.nopts; ++i) {
+ if (result.desc[i]->sh == 'u') user_name = result.oarg[i];
+ if (result.desc[i]->sh == 'g') group_name = result.oarg[i];
+ }
+
const char *user = user_name != NULL ? user_name : "-";
const char *group = group_name != NULL ? group_name : "-";
switch (HXproc_switch_user(user_name, group_name)) {
@@ -63,7 +72,7 @@ static int runner(int argc, char **argv)
break;
}
}
- HX_zvecfree(argv);
+ HX_getopt6_clean(&result);
return EXIT_SUCCESS;
}
diff --git a/src/tc-time.c b/src/tc-time.c
index e810233..e1ec12b 100644
--- a/src/tc-time.c
+++ b/src/tc-time.c
@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
+#include <sys/time.h>
#include <libHX/defs.h>
#include <libHX/init.h>
#include <libHX/misc.h>
diff --git a/src/tx-compile.cpp b/src/tx-compile.cpp
index 2c21e3b..2bcdb1e 100644
--- a/src/tx-compile.cpp
+++ b/src/tx-compile.cpp
@@ -1 +1,2 @@
#include "tc-compile.c"
+#include <libHX/scope.hpp>
diff --git a/src/tx-option.cpp b/src/tx-option.cpp
deleted file mode 100644
index 248ab7c..0000000
--- a/src/tx-option.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __cplusplus
-# include <stdlib.h>
-#else
-# include <cstdlib>
-#endif
-#include <libHX/option.h>
-
-static unsigned int g_verbose;
-static const struct HXoption t[] = {
- {nullptr, 'v', HXTYPE_NONE | HXOPT_INC, &g_verbose},
- HXOPT_AUTOHELP,
- HXOPT_TABLEEND,
-};
-
-int main(int argc, char **argv)
-{
- if (HX_getopt(t, &argc, &argv, HXOPT_USAGEONERR) != HXOPT_ERR_SUCCESS)
- return EXIT_FAILURE;
- HX_zvecfree(argv);
- return EXIT_SUCCESS;
-}