summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am8
-rw-r--r--src/Makefile.in56
-rw-r--r--src/deque.c52
-rw-r--r--src/format.c38
-rw-r--r--src/internal.h2
-rw-r--r--src/io.c34
-rw-r--r--src/libHX.map58
-rw-r--r--src/map_int.h3
-rw-r--r--src/misc.c14
-rw-r--r--src/opt.c299
-rw-r--r--src/string.c370
-rw-r--r--src/tc-list.c2
-rw-r--r--src/tc-map.c22
-rw-r--r--src/tc-option.c207
-rw-r--r--src/tc-realpath.c52
-rw-r--r--src/tc-string.c68
-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-option.cpp21
20 files changed, 755 insertions, 576 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f28c0a6..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 40:0:8
-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 0768775..9cbd614 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.17 from Makefile.am.
+# Makefile.in generated by automake 1.18.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2024 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,
@@ -92,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
@@ -110,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
@@ -131,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/||"`;; \
@@ -296,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)
@@ -360,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)
@@ -410,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 \
@@ -423,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;; \
@@ -563,7 +557,7 @@ am__common_driver_flags = \
# 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).
@@ -780,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 40:0:8 $(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
@@ -825,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
@@ -1041,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)
@@ -1119,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
@@ -1513,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
@@ -1640,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
@@ -1739,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
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..985a527 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 '('
@@ -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..2f5aa8f 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -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 b9041e0..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
@@ -378,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;
@@ -483,7 +490,10 @@ EXPORT_SYMBOL int HX_getcwd(hxmc_t **target)
return 1;
}
if (errno == ERANGE) {
- if (HXmc_setlen(target, linkbuf_size *= 2) != nullptr)
+ 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 */
}
@@ -777,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;
@@ -798,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 922cc3c..1154304 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;
@@ -54,7 +52,6 @@ global:
HX_strrev;
HX_strrtrim;
HX_strsep2;
- HX_strsep;
HX_strupper;
HX_time_compare;
HX_timespec_add;
@@ -123,68 +120,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;
-
-LIBHX_4.24 {
-global:
HX_getcwd;
-} LIBHX_4.18;
+ 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..118c159 100644
--- a/src/opt.c
+++ b/src/opt.c
@@ -1,6 +1,6 @@
/*
* 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
@@ -8,6 +8,7 @@
* either version 2.1 or (at your option) any later version.
*/
#include <errno.h>
+#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -119,13 +120,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 +221,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 +244,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 +510,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 +553,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';
+ value = strchr(cur, '=');
+ if (value == nullptr) {
+ /* Cannot happen either */
+ free(key);
+ return -EINVAL;
+ }
+ ++value;
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 +575,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 +589,48 @@ static int HX_getopt_long(const char *cur, struct HX_getopt_vars *par)
return ret;
}
+ free(key);
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);
+ /*
+ * 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 +639,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 +673,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 +747,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 +814,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/string.c b/src/string.c
index 3a85fa8..e9c162d 100644
--- a/src/string.c
+++ b/src/string.c
@@ -41,6 +41,26 @@ struct HX_quote_rule {
const char *chars;
};
+/* 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)
@@ -217,13 +237,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 +392,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 +453,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 +486,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 +508,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 +577,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 +730,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 +808,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 +1011,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 +1182,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,45 +1204,92 @@ 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,
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-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-realpath.c b/src/tc-realpath.c
index 4d6b79f..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("");
@@ -57,20 +35,28 @@ static void t_2(void)
HXmc_free(tmp);
}
-int main(int argc, char **oargv)
+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");
@@ -78,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-string.c b/src/tc-string.c
index d777268..1c67ede 100644
--- a/src/tc-string.c
+++ b/src/tc-string.c
@@ -108,23 +108,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 +131,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 +140,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);
}
@@ -399,14 +392,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, ""},
@@ -418,23 +416,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;
}
@@ -496,7 +513,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-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;
-}