Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libHX for openSUSE:Factory checked 
in at 2023-11-02 20:20:03
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libHX (Old)
 and      /work/SRC/openSUSE:Factory/.libHX.new.17445 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libHX"

Thu Nov  2 20:20:03 2023 rev:75 rq:1122389 version:4.16

Changes:
--------
--- /work/SRC/openSUSE:Factory/libHX/libHX.changes      2023-09-25 
20:00:18.471897429 +0200
+++ /work/SRC/openSUSE:Factory/.libHX.new.17445/libHX.changes   2023-11-02 
20:20:06.724837923 +0100
@@ -1,0 +2,8 @@
+Thu Nov  2 08:52:49 UTC 2023 - Jan Engelhardt <[email protected]>
+
+- Update to release 4.16
+  * Add HX_strtoull_nsec to parse time period and emit nanoseconds
+  * doc: specify return value and semantics for HXio_fullread,
+    HXio_fullwrite, HX_sendfile
+
+-------------------------------------------------------------------

Old:
----
  libHX-4.15.tar.asc
  libHX-4.15.tar.xz

New:
----
  libHX-4.16.tar.asc
  libHX-4.16.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ libHX.spec ++++++
--- /var/tmp/diff_new_pack.7weIex/_old  2023-11-02 20:20:07.404862945 +0100
+++ /var/tmp/diff_new_pack.7weIex/_new  2023-11-02 20:20:07.404862945 +0100
@@ -18,7 +18,7 @@
 
 Name:           libHX
 %define lname   libHX32
-Version:        4.15
+Version:        4.16
 Release:        0
 Summary:        Collection of routines for C and C++ programming
 License:        LGPL-2.1-or-later

++++++ libHX-4.15.tar.xz -> libHX-4.16.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/configure new/libHX-4.16/configure
--- old/libHX-4.15/configure    2023-09-24 04:52:01.249722457 +0200
+++ new/libHX-4.16/configure    2023-11-02 09:30:26.982598091 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for libHX 4.15.
+# Generated by GNU Autoconf 2.71 for libHX 4.16.
 #
 #
 # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
@@ -618,8 +618,8 @@
 # Identity of this package.
 PACKAGE_NAME='libHX'
 PACKAGE_TARNAME='libhx'
-PACKAGE_VERSION='4.15'
-PACKAGE_STRING='libHX 4.15'
+PACKAGE_VERSION='4.16'
+PACKAGE_STRING='libHX 4.16'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1375,7 +1375,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libHX 4.15 to adapt to many kinds of systems.
+\`configure' configures libHX 4.16 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1446,7 +1446,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libHX 4.15:";;
+     short | recursive ) echo "Configuration of libHX 4.16:";;
    esac
   cat <<\_ACEOF
 
@@ -1561,7 +1561,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libHX configure 4.15
+libHX configure 4.16
 generated by GNU Autoconf 2.71
 
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2195,7 +2195,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libHX $as_me 4.15, which was
+It was created by libHX $as_me 4.16, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -3684,7 +3684,7 @@
 
 # Define the identity of the package.
  PACKAGE='libhx'
- VERSION='4.15'
+ VERSION='4.16'
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -18771,7 +18771,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libHX $as_me 4.15, which was
+This file was extended by libHX $as_me 4.16, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -18839,7 +18839,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-libHX config.status 4.15
+libHX config.status 4.16
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/configure.ac new/libHX-4.16/configure.ac
--- old/libHX-4.15/configure.ac 2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/configure.ac 2023-11-02 09:25:08.000000000 +0100
@@ -1,4 +1,4 @@
-AC_INIT([libHX], [4.15])
+AC_INIT([libHX], [4.16])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/doc/api.rst new/libHX-4.16/doc/api.rst
--- old/libHX-4.15/doc/api.rst  2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/doc/api.rst  2023-11-02 09:25:08.000000000 +0100
@@ -9,6 +9,7 @@
 ======  ======  ======  ========================================
 RMV     MinVer  FirstA  Name
 ======  ======  ======  ========================================
+4.16    4.16    4.16    HX_strtoull_nsec
 4.15    4.15    4.15    HX_flpr
 4.15    4.15    4.15    HX_flprf
 4.11    4.11    4.11    HX_addrport_split
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/doc/changelog.rst 
new/libHX-4.16/doc/changelog.rst
--- old/libHX-4.15/doc/changelog.rst    2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/doc/changelog.rst    2023-11-02 09:25:08.000000000 +0100
@@ -1,13 +1,23 @@
+v4.16 (2023-11-02)
+==================
+
+Enhancements:
+
+* Add ``HX_strtoull_nsec`` to parse time period and emit nanoseconds
+* doc: specify return value and semantics for ``HXio_fullread``,
+  ``HXio_fullwrite``, ``HX_sendfile``
+
+
 v4.15 (2023-09-24)
 ==================
 
 Enhancements:
 
-* Add functions to compute Least Positive Residue (HX_flpr, HX_flprf)
+* Add functions to compute Least Positive Residue (``HX_flpr``, ``HX_flprf``)
 
 Fixes:
 
-* Make HX_strrtrim work on strings longer than INT_MAX
+* Make ``HX_strrtrim`` work on strings longer than ``INT_MAX``
 
 
 v4.14 (2023-07-14)
@@ -15,7 +25,7 @@
 
 Fixes:
 
-* socket: make HX_addrport_split work on portless bracketed hostspec
+* socket: make ``HX_addrport_split`` work on portless bracketed hostspec
 
 
 v4.13 (2023-06-21)
@@ -23,8 +33,8 @@
 
 Fixes:
 
-* io: do not fail HX_mkdir when a component is a symlink to a directory
-* xml_helper: fix infinite recursion in xml_getnsprop
+* io: do not fail ``HX_mkdir`` when a component is a symlink to a directory
+* xml_helper: fix infinite recursion in ``xml_getnsprop``
 
 
 v4.12 (2023-02-27)
@@ -32,7 +42,7 @@
 
 Fixes:
 
-* Plug a memory leak in HX_inet_listen
+* Plug a memory leak in ``HX_inet_listen``
 
 
 v4.11 (2023-02-26)
@@ -40,8 +50,8 @@
 
 Enhancements:
 
-* socket: add HX_addrport_split, HX_inet_connect, HX_inet_listen,
-  HX_local_listen
+* socket: add ``HX_addrport_split``, ``HX_inet_connect``, ``HX_inet_listen``,
+  ``HX_local_listen``
 
 
 v4.10 (2023-01-29)
@@ -49,7 +59,7 @@
 
 Fixes:
 
-* format: plug a memory leak relating to func_entry_clone
+* format: plug a memory leak relating to ``func_entry_clone``
 * Resolve mingw build failure
 
 
@@ -58,13 +68,14 @@
 
 Enhancements:
 
-* socket: add sockaddr_is_local, ipaddr_is_local functions
+* socket: add ``sockaddr_is_local``, ``ipaddr_is_local`` functions
 
 Fixes:
 
-* format: avoid return value truncation from HXformat_aprintf, HXformat_sprintf
-* format: avoid calling HXmc_length on a non-hxmc object
-* format: add new variations of printf functions returning ssize_t
+* format: avoid return value truncation from ``HXformat_aprintf``,
+  ``HXformat_sprintf``
+* format: avoid calling ``HXmc_length`` on a non-hxmc object
+* format: add new variations of printf functions returning ``ssize_t``
 * Resolve Coverity-SCAN reports
 
 
@@ -73,7 +84,7 @@
 
 Enhancements:
 
-* io: call posix_fadvise when slurping files
+* io: call ``posix_fadvise`` when slurping files
 
 Fixes:
 
@@ -85,11 +96,11 @@
 
 Enhancements:
 
-* string: new quoting modes HXQUOTE_BASE64URL & HXQUOTE_BASE64IMAP
+* string: new quoting modes ``HXQUOTE_BASE64URL`` & ``HXQUOTE_BASE64IMAP``
 
 Fixes:
 
-* socket: make HX_socket_from_env functional on OpenBSD
+* socket: make ``HX_socket_from_env`` functional on OpenBSD
 
 
 v4.6 (2022-06-27)
@@ -97,8 +108,8 @@
 
 Enhancements:
 
-* HX_slurp_fd/HX_slurp_file now supports reading from files reporting their
-  own size as 0 (e.g. ttys, /proc special files).
+* ``HX_slurp_fd``/``HX_slurp_file`` now supports reading from files reporting
+  their own size as 0 (e.g. ttys, ``/proc`` special files).
 
 
 v4.5 (2022-04-10)
@@ -144,8 +155,8 @@
 
 Fixes:
 
-* io: fix a use-after-free in conjunction with HX_realpath /
-  fix missing NULLing of a pointer within HX_readlink
+* io: fix a use-after-free in conjunction with ``HX_realpath`` /
+  fix missing NULLing of a pointer within ``HX_readlink``
 
 
 v4.0 (2021-10-03)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/doc/files_and_dirs.rst 
new/libHX-4.16/doc/files_and_dirs.rst
--- old/libHX-4.15/doc/files_and_dirs.rst       2023-09-24 04:51:44.000000000 
+0200
+++ new/libHX-4.16/doc/files_and_dirs.rst       2023-11-02 09:25:08.000000000 
+0100
@@ -180,11 +180,44 @@
        ssize_t HXio_fullwrite(int fd, const void *buf, size_t size, unsigned 
int flags);
        ssize_t HX_sendfile(int dst, int src, size_t count);
 
-Since plain ``read``(2) and ``write``(2) may process only part of the buffer 
—
-even more likely so with sockets —, libHX provides two functions that calls
-these in a loop to retry said operations until the full amount has been
-processed. Since read and write can also be used with socket file descriptors,
-so can these.
+``HXio_fullread`` calls ``read``(2) in a loop so long as to completely read
+``size`` bytes, and thereby masking short read behavior that the *read* system
+call is allowed to exhibit. On success, the return value indicates the number
+of bytes read, which may be shorter than ``size`` if EOF was encountered. On
+error, the return value is negative (but no particular one value).
+
+``HXio_fullwrite`` calls ``write``(2) in a loop so long as to completely write
+``size`` bytes, and thereby masking short write behavior that the *write*
+system call is allowed to exhibit. On success, the return value is the same as
+``size``, as there is never an EOF condition for writes. On error, the return
+value is negative.
+
+There is no way with just HXio_fullwrite to know the number of bytes that were
+read up to the point that the error occurred. This was a subconscious design
+choice in 2010. The reasoning (as of 2023) goes: If the file descriptor is not
+seekable, like a socket or pipe, what are you going to do anyway but abort? You
+cannot recall the data that was sent, the peer already knows how much was sent
+thanks to their socket interface. The peer also either caused the abort itself
+(e.g. by closing the read end of a pipe), or is made aware of connection
+severing (will see EOF). If the file descriptor is seekable, there is no "peer"
+and one can ``lseek`` back and retract the data.
+
+The HXio_fullread API mirrors that of HXio_fullwrite for API consistency. Input
+is often discarded and an error shown instead. However, we acknowledge there
+might be a legitimate case (e.g. wanting to render an incoming image even if
+incomplete), but in this case, HXio_fullread is not for you.
 
 ``HX_sendfile`` wraps ``sendfile``(2) for the same reason; in addition, it
 falls back to a read-write loop on platforms which do not offer sendfile.
+``HX_sendfile`` will transfer at most ``SSIZE_MAX`` bytes in one call. A user
+wishing to emit somewhat more (e.g. still less than ``SIZE_MAX``) will have to
+write a loop around HXio_sendfile, just like for sendfile. On success, the
+return value is the request number of bytes. On error, the return value may be
+a negative errno (``errno`` is set too), or it may be the number of bytes from
+a partially-completed send.
+
+       .. code-block:: c
+
+       ssize_t ret = HX_sendfile(dst, src, count);
+       if (ret < 0 || (ssize_t)ret < count)
+               fprintf(stderr, "sendfile: %s\n", strerror(errno));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/doc/string_ops.rst 
new/libHX-4.16/doc/string_ops.rst
--- old/libHX-4.15/doc/string_ops.rst   2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/doc/string_ops.rst   2023-11-02 09:25:08.000000000 +0100
@@ -456,17 +456,20 @@
        #include <libHX/string.h>
 
        unsigned long long HX_strtoull_sec(const char *s, char **end);
+       unsigned long long HX_strtoull_nsec(const char *s, char **end);
        char *HX_unit_seconds(char *out, size_t outsize,
                              unsigned long long seconds,
                              unsigned int flags);
 
-``HX_strtoull_sec`` converts a time duration with units, such as ``"15min30s"``
-into an all-seconds value. The recognized unit strings are: ``years``,
-``year``, ``y``, ``months``, ``month``, ``days``, ``day``, ``d``, ``hours``,
-``hour``, ``h``, ``minutes``, ``minute``, ``min``, ``seconds``, ``second``,
-``s`` and the empty string (for seconds). When parsing stops at any point,
-``*end`` is set to the location, similar to how the ``strtoull`` C function
-would.
+``HX_strtoull_sec`` and ``HX_strtoull_nsec`` convert a time duration with
+units, such as ``"15min30s"`` into an all-seconds and all-nanoseconds value,
+respectively. The recognized unit strings are: ``years``, ``year``, ``y``,
+``months``, ``month``, ``days``, ``day``, ``d``, ``hours``, ``hour``, ``h``,
+``minutes``, ``minute``, ``min``, ``seconds``, ``second``, ``s``, the empty
+string (to mean seconds), ``msec``, ``ms``, ``µsec``, ``µs``, ``nsec`` and
+``ns``. Negative durations are not supported. Support for fractions is
+implementation-defined. When parsing stops at any point, ``*end`` is set to the
+location, similar to how the ``strtoull`` C function would.
 
 One year is defined to be 365.25 days of 86400 seconds; one month is defined to
 be 1/12 such a year. This is consistent with the units employed by systemd.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/include/libHX/string.h 
new/libHX-4.16/include/libHX/string.h
--- old/libHX-4.15/include/libHX/string.h       2023-09-24 04:51:44.000000000 
+0200
+++ new/libHX-4.16/include/libHX/string.h       2023-11-02 09:25:08.000000000 
+0100
@@ -103,6 +103,7 @@
 extern char *HX_unit_size(char *out, size_t bufsize, unsigned long long size, 
unsigned int divisor, unsigned int cutoff);
 extern char *HX_unit_size_cu(char *out, size_t bufsize, unsigned long long 
size, unsigned int divisor);
 extern unsigned long long HX_strtoull_sec(const char *s, char **);
+extern unsigned long long HX_strtoull_nsec(const char *s, char **);
 extern char *HX_unit_seconds(char *out, size_t bufsize, unsigned long long 
seconds, unsigned int flags);
 
 static __inline__ void *HX_memdup(const void *buf, size_t len)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/io.c new/libHX-4.16/src/io.c
--- old/libHX-4.15/src/io.c     2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/io.c     2023-11-02 09:25:08.000000000 +0100
@@ -665,16 +665,13 @@
                size_t readsize = bufsize;
                if (count < readsize)
                        readsize = count;
+               /* Return value of fullread/write is same as read/write(2). */
                ret = HXio_fullread(src, buf, readsize);
-               if (ret < 0) {
-                       errno = -ret;
+               if (ret < 0)
                        break;
-               }
                ret = HXio_fullwrite(dst, buf, ret);
-               if (ret < 0) {
-                       errno = -ret;
+               if (ret < 0)
                        break;
-               }
                xferd += ret;
                count -= ret;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/libHX.map new/libHX-4.16/src/libHX.map
--- old/libHX-4.15/src/libHX.map        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/libHX.map        2023-11-02 09:25:08.000000000 +0100
@@ -173,3 +173,8 @@
        HX_flpr;
        HX_flprf;
 } LIBHX_4.11;
+
+LIBHX_4.16 {
+global:
+       HX_strtoull_nsec;
+} LIBHX_4.15;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/socket.c new/libHX-4.16/src/socket.c
--- old/libHX-4.15/src/socket.c 2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/socket.c 2023-11-02 09:25:08.000000000 +0100
@@ -41,7 +41,7 @@
 #else
 #      define STUPIDWIN(x) (x)
 #endif
-#if defined(__sunos__) && !defined(SO_PROTOCOL)
+#if defined(__sun) && !defined(SO_PROTOCOL)
 #      define SO_PROTOCOL SO_PROTOTYPE
 #endif
 #ifndef AI_V4MAPPED
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/string.c new/libHX-4.16/src/string.c
--- old/libHX-4.15/src/string.c 2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/string.c 2023-11-02 09:25:08.000000000 +0100
@@ -1037,55 +1037,63 @@
 
 #define SECONDS_PER_YEAR 31557600
 #define SECONDS_PER_MONTH 2629800
+#define NSEC_PER_SECOND 1000000000ULL
 
 static const struct {
        const char name[8];
        unsigned int len;
-       uint32_t mult;
+       uint32_t s_mult;
+       uint64_t ns_mult;
 } time_multiplier[] = {
-       {"seconds", 7, 1},
-       {"second",  6, 1},
-       {"sec",     3, 1},
-       {"s",       1, 1},
-       {"minutes", 7, 60},
-       {"minute",  6, 60},
-       {"min",     3, 60},
-       {"hours",   5, 3600},
-       {"hour",    4, 3600},
-       {"h",       1, 3600},
-       {"days",    4, 86400},
-       {"day",     3, 86400},
-       {"d",       1, 86400},
-       {"weeks",   5, 604800},
-       {"week",    4, 604800},
-       {"months",  6, SECONDS_PER_MONTH},
-       {"month",   5, SECONDS_PER_MONTH},
-       {"years",   5, SECONDS_PER_YEAR},
-       {"year",    4, SECONDS_PER_YEAR},
-       {"y",       1, SECONDS_PER_YEAR},
+       {"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},
+       {"",        0, 1, NSEC_PER_SECOND},
 };
 
-EXPORT_SYMBOL unsigned long long HX_strtoull_sec(const char *s, char **out_end)
+static unsigned long long HX_strtoull_time(const char *s, char **out_end, bool 
nsec)
 {
-       unsigned long long seconds = 0;
+       unsigned long long quant = 0;
 
        while (*s != '\0') {
                while (HX_isspace(*s))
                        ++s;
-               if (*s == '-') {
+               if (*s == '-')
                        break;
-               }
                char *end = nullptr;
                unsigned long long num = strtoull(s, &end, 10);
+               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;
-               if (!HX_isalpha(*s)) {
-                       seconds += num;
-                       continue;
-               }
                unsigned int i;
                for (i = 0; i < ARRAY_SIZE(time_multiplier); ++i)
                        if (strncmp(s, time_multiplier[i].name,
@@ -1094,12 +1102,26 @@
                                break;
                if (i == ARRAY_SIZE(time_multiplier))
                        break;
-               seconds += num * time_multiplier[i].mult;
+               unsigned long long mult = nsec ? time_multiplier[i].ns_mult : 
time_multiplier[i].s_mult;
+               if (have_frac)
+                       quant += frac * mult;
+               else
+                       quant += num * mult;
                s += time_multiplier[i].len;
        }
        if (out_end != nullptr)
                *out_end = const_cast(char *, s);
-       return seconds;
+       return quant;
+}
+
+EXPORT_SYMBOL unsigned long long HX_strtoull_sec(const char *s, char **out_end)
+{
+       return HX_strtoull_time(s, out_end, false);
+}
+
+EXPORT_SYMBOL unsigned long long HX_strtoull_nsec(const char *s, char 
**out_end)
+{
+       return HX_strtoull_time(s, out_end, true);
 }
 
 EXPORT_SYMBOL char *HX_unit_seconds(char *out, size_t outsize,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-cast.c new/libHX-4.16/src/tc-cast.c
--- old/libHX-4.15/src/tc-cast.c        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-cast.c        2023-11-02 09:25:08.000000000 +0100
@@ -77,7 +77,7 @@
 int main(void)
 {
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        c_signed();
        c_reinterpret();
        c_static();
@@ -86,5 +86,5 @@
        c_const3();
        c_constA();
        HX_exit();
-       return 0;
+       return EXIT_SUCCESS;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-compile.c 
new/libHX-4.16/src/tc-compile.c
--- old/libHX-4.15/src/tc-compile.c     2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-compile.c     2023-11-02 09:25:08.000000000 +0100
@@ -17,7 +17,7 @@
        unsigned char bmchar[HXbitmap_size(unsigned char, 256)] = {0};
 
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        printf("sizeof bmllong:\t%" HX_SIZET_FMT "u, array_size: %" 
HX_SIZET_FMT "u\n",
               sizeof(bmllong), ARRAY_SIZE(bmllong));
        printf("sizeof bmlong:\t%" HX_SIZET_FMT "u, array_size: %" HX_SIZET_FMT 
"u\n",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-dir.c new/libHX-4.16/src/tc-dir.c
--- old/libHX-4.15/src/tc-dir.c 2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-dir.c 2023-11-02 09:25:08.000000000 +0100
@@ -25,7 +25,7 @@
 int main(int argc, const char **argv)
 {
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        if (argc == 1) {
                /* On Windows VCRT, "/" yields nothing, "c:/" is needed */
                lookatdir("/");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-io.c new/libHX-4.16/src/tc-io.c
--- old/libHX-4.15/src/tc-io.c  2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-io.c  2023-11-02 09:25:08.000000000 +0100
@@ -20,7 +20,10 @@
                return;
        }
        ssize_t ret = HX_sendfile(dst, src, SIZE_MAX);
-       printf("sendfile transferred %zd bytes\n", ret);
+       if (ret < 0)
+               printf("sendfile: %s\n", strerror(errno));
+       else
+               printf("sendfile transferred %zd bytes\n", ret);
        close(dst);
        close(src);
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-list.c new/libHX-4.16/src/tc-list.c
--- old/libHX-4.15/src/tc-list.c        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-list.c        2023-11-02 09:25:08.000000000 +0100
@@ -22,7 +22,7 @@
 
 static HXCLIST_HEAD(strings_ct);
 
-static void l_init(unsigned int max, bool unshift)
+static int l_init(unsigned int max, bool unshift)
 {
        static const char *const msg[] = {"Pushing", "Unshifting"};
        struct text_object *obj;
@@ -34,7 +34,7 @@
 #else
                obj = malloc(sizeof(*obj));
                if (obj == NULL)
-                       abort();
+                       return EXIT_FAILURE;
 #endif
                HXlist_init(&obj->list);
                obj->id[0] = HX_irand('a', 'z'+1);
@@ -48,6 +48,7 @@
                else
                        HXclist_push(&strings_ct, &obj->list);
        }
+       return EXIT_SUCCESS;
 }
 
 static void l_traverse(void)
@@ -137,16 +138,17 @@
 #pragma GCC diagnostic pop
 }
 
-int main(int argc, const char **argv)
+static int runner(int argc, const char **argv)
 {
        unsigned int max = 10;
 
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        if (argc >= 2)
                max = strtoul(argv[1], NULL, 0);
-
-       l_init(max, HX_rand() & 1);
+       int ret = l_init(max, HX_rand() & 1);
+       if (ret != EXIT_SUCCESS)
+               return ret;
        l_traverse();
        l_dump(HX_rand() & 1);
        l_empty();
@@ -154,3 +156,11 @@
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(int argc, const char **argv)
+{
+       int ret = runner(argc, argv);
+       if (ret != EXIT_FAILURE)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-map.c new/libHX-4.16/src/tc-map.c
--- old/libHX-4.15/src/tc-map.c 2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-map.c 2023-11-02 09:25:08.000000000 +0100
@@ -205,7 +205,7 @@
        tmap_ipop();
 }
 
-static void tmap_flat(const struct HXmap *map)
+static int tmap_flat(const struct HXmap *map)
 {
        struct HXmap_node *nodes;
        unsigned int i;
@@ -215,12 +215,13 @@
        nodes = HXmap_keysvalues(map);
        if (nodes == NULL) {
                perror("HXmap_keysvalues");
-               abort();
+               return EXIT_FAILURE;
        }
        for (i = 0; i < map->items; ++i)
                tmap_printf("%u. %s -> %s\n", i, nodes[i].skey, nodes[i].sdata);
        tmap_ipop();
        free(nodes);
+       return EXIT_SUCCESS;
 }
 
 static void tmap_trav(struct HXmap *map)
@@ -251,7 +252,7 @@
        HXmap_travfree(iter);
 }
 
-static void tmap_generic_tests(enum HXmap_type type,
+static int tmap_generic_tests(enum HXmap_type type,
     unsigned long (*hash_fn)(const void *, size_t), const char *hash_name)
 {
        struct HXmap_ops ops = {.k_hash = hash_fn};
@@ -265,10 +266,13 @@
        tmap_flush(map, false);
 
        tmap_add_rand(map, 2);
-       tmap_flat(map);
+       int ret = tmap_flat(map);
+       if (ret != EXIT_SUCCESS)
+               return ret;
        tmap_trav(map);
        tmap_flush(map, true);
        HXmap_free(map);
+       return EXIT_SUCCESS;
 }
 
 static int tmap_strtolcmp(const void *a, const void *b, size_t z)
@@ -722,15 +726,16 @@
                fprintf(stderr, "eek!\n");
 }
 
-int main(void)
+static int runner(void)
 {
        if (HX_init() <= 0)
-               abort();
-
+               return EXIT_FAILURE;
        tmap_zero();
 
        tmap_printf("* HXhashmap\n");
-       tmap_generic_tests(HXMAPT_HASH, HXhash_djb2, "DJB2");
+       int ret = tmap_generic_tests(HXMAPT_HASH, HXhash_djb2, "DJB2");
+       if (ret != EXIT_SUCCESS)
+               return ret;
        tmap_generic_tests(HXMAPT_HASH, HXhash_jlookup3s, "JL3");
        tmap_hmap_test_1();
 
@@ -742,3 +747,11 @@
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(void)
+{
+       int ret = runner();
+       if (ret != EXIT_SUCCESS)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-memmem.c 
new/libHX-4.16/src/tc-memmem.c
--- old/libHX-4.15/src/tc-memmem.c      2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-memmem.c      2023-11-02 09:25:08.000000000 +0100
@@ -14,14 +14,14 @@
 static const char filler_text[] =
        "Slhrdlu cringle tongle flonging blobbity bleep blingmangl";
 
-static void long_scan(void)
+static int long_scan(void)
 {
        struct timespec start, stop, delta;
        char *filler2, *p;
 
        filler2 = malloc(size);
        if (filler2 == NULL)
-               abort();
+               return EXIT_FAILURE;
        memset(filler2, 'l', size);
        filler2[size-2] = 'a';
 
@@ -32,19 +32,20 @@
        HX_timespec_sub(&delta, &stop, &start);
        printf("long_scan: " HX_TIMESPEC_FMT "\n", HX_TIMESPEC_EXP(&delta));
        free(filler2);
+       return EXIT_SUCCESS;
 }
 
-int main(void)
+static int runner(void)
 {
        unsigned int i;
        char *haystack;
        struct timespec start, stop, delta;
 
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        haystack = malloc(size);
        if (haystack == NULL)
-               abort();
+               return EXIT_FAILURE;
        memset(haystack, 'A', size);
        haystack[size-1] = haystack[size-2] = 'Z';
        printf("Init done\n");
@@ -55,8 +56,11 @@
        printf("%p\n", HX_memmem(filler_text, strlen(filler_text), "ngl", 3));
        printf("%p\n", HX_memmem(filler_text, strlen(filler_text), "ngl", 3));
 
-       long_scan();
-
+       int ret = long_scan();
+       if (ret != EXIT_SUCCESS) {
+               free(haystack);
+               return ret;
+       }
        for (i = 0; i < 10; ++i) {
                printf("Search length %u...", i);
                clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
@@ -66,6 +70,15 @@
                printf(HX_TIMESPEC_FMT "\n", HX_TIMESPEC_EXP(&delta));
        }
 
+       free(haystack);
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(void)
+{
+       int ret = runner();
+       if (ret != EXIT_FAILURE)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-misc.c new/libHX-4.16/src/tc-misc.c
--- old/libHX-4.15/src/tc-misc.c        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-misc.c        2023-11-02 09:25:08.000000000 +0100
@@ -8,13 +8,13 @@
 #include <libHX/init.h>
 #include <libHX/misc.h>
 
-int main(int argc, const char **argv)
+static int runner(int argc, const char **argv)
 {
        unsigned int n;
        struct stat sa, sb;
 
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        printf("%d\n", HX_ffs(0));
        for (n = 1; ; n <<= 1) {
                printf("%08x = %d\n", n, HX_ffs(n));
@@ -30,12 +30,23 @@
 
        if (argc >= 3) {
                if (stat(argv[1], &sa) < 0 ||
-                   stat(argv[2], &sb) < 0)
+                   stat(argv[2], &sb) < 0) {
                        perror("stat");
-               else
+                       return EXIT_FAILURE;
+               } else {
                        printf("Difference: %ld\n", HX_time_compare(&sa, &sb, 
'm'));
+                       return EXIT_FAILURE;
+               }
        }
 
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(int argc, const char **argv)
+{
+       int ret = runner(argc, argv);
+       if (ret != EXIT_FAILURE)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-netio.c 
new/libHX-4.16/src/tc-netio.c
--- old/libHX-4.15/src/tc-netio.c       2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-netio.c       2023-11-02 09:25:08.000000000 +0100
@@ -19,34 +19,47 @@
 #endif
 #include <libHX/init.h>
 #include <libHX/io.h>
+#include "internal.h"
 
-int main(void)
+static int runner(void)
 {
        const char id[] = "SSH-2.0-OpenSSH_9.9";
-       struct addrinfo *res;
+       struct addrinfo *res = nullptr;
        int fd, ret;
 
        if ((ret = HX_init()) <= 0) {
                fprintf(stderr, "HX_init: %s\n", strerror(-ret));
-               abort();
+               return EXIT_FAILURE;
        }
 
        fd = socket(AF_INET6, SOCK_STREAM, 0);
        if (fd < 0) {
                perror("socket");
-               abort();
+               return EXIT_FAILURE;
        }
        if (getaddrinfo("::1", "22", NULL, &res) < 0) {
                perror("getaddrinfo");
-               abort();
+               close(fd);
+               return EXIT_FAILURE;
        }
        if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
                perror("connect");
-               abort();
+               freeaddrinfo(res);
+               close(fd);
+               return EXIT_FAILURE;
        }
        if (HXio_fullwrite(fd, id, strlen(id)) < 0)
                perror("write");
+       freeaddrinfo(res);
        close(fd);
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(void)
+{
+       int ret = runner();
+       if (ret != EXIT_SUCCESS)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-option.c 
new/libHX-4.16/src/tc-option.c
--- old/libHX-4.15/src/tc-option.c      2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-option.c      2023-11-02 09:25:08.000000000 +0100
@@ -99,7 +99,7 @@
 int main(int argc, const char **argv)
 {
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        printf("Return value of HX_getopt: %d\n",
               HX_getopt(table, &argc, &argv, HXOPT_USAGEONERR));
        t_empty_argv();
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-proc.c new/libHX-4.16/src/tc-proc.c
--- old/libHX-4.15/src/tc-proc.c        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-proc.c        2023-11-02 09:25:08.000000000 +0100
@@ -51,7 +51,7 @@
 int main(void)
 {
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        printf("top fd: %d\n", HXproc_top_fd());
 
        /* let it fail - test verbosity */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-rand.c new/libHX-4.16/src/tc-rand.c
--- old/libHX-4.15/src/tc-rand.c        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-rand.c        2023-11-02 09:25:08.000000000 +0100
@@ -12,7 +12,7 @@
        unsigned int i;
 
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        for (i = 0; i < 15; ++i) {
                printf("%d ", HX_irand(i, i));
                printf("%.1f ", HX_drand(i, i));
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-shconfig.c 
new/libHX-4.16/src/tc-shconfig.c
--- old/libHX-4.15/src/tc-shconfig.c    2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-shconfig.c    2023-11-02 09:25:08.000000000 +0100
@@ -26,7 +26,7 @@
                fprintf(stderr, "Read error %s: %s\n", file, strerror(errno));
 }
 
-static void t_shconfig2(const char *file)
+static int t_shconfig2(const char *file)
 {
        const struct HXmap_node *node;
        struct HXmap_trav *trav;
@@ -35,15 +35,16 @@
        map = HX_shconfig_map(file);
        if (map == NULL) {
                fprintf(stderr, "HX_shconfig_map: %s\n", strerror(errno));
-               abort();
+               return EXIT_FAILURE;
        }
        trav = HXmap_travinit(map, HXMAP_NOFLAGS);
        while ((node = HXmap_traverse(trav)) != NULL)
                printf("\t\"%s\" -> \"%s\"\n", node->skey, node->sdata);
        HXmap_travfree(trav);
+       return EXIT_SUCCESS;
 }
 
-int main(int argc, const char **argv)
+static int runner(int argc, const char **argv)
 {
        int ret;
 
@@ -53,7 +54,17 @@
                return EXIT_FAILURE;
        }
        t_shconfig((argc >= 2) ? argv[1] : "tc-shconf.c");
-       t_shconfig2((argc >= 2) ? argv[1] : "tc-shconf.c");
+       ret = t_shconfig2((argc >= 2) ? argv[1] : "tc-shconf.c");
+       if (ret != EXIT_SUCCESS)
+               return ret;
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(int argc, const char **argv)
+{
+       int ret = runner(argc, argv);
+       if (ret != EXIT_SUCCESS)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-string.c 
new/libHX-4.16/src/tc-string.c
--- old/libHX-4.15/src/tc-string.c      2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-string.c      2023-11-02 09:25:08.000000000 +0100
@@ -21,14 +21,14 @@
 #include <libHX/string.h>
 #include "internal.h"
 
-static void t_mc(void)
+static int t_mc(void)
 {
        hxmc_t *s, *old_s;
 
        s = HXmc_meminit(NULL, 4096);
        printf("%" HX_SIZET_FMT "u\n", HXmc_length(s));
        if (HXmc_length(s) != 0)
-               abort();
+               return EXIT_FAILURE;
        old_s = s;
        HXmc_trunc(&s, 8192);
        if (old_s != s)
@@ -37,6 +37,7 @@
        HXmc_setlen(&s, 16384);
        printf("Length is now %" HX_SIZET_FMT "u\n", HXmc_length(s));
        HXmc_free(s);
+       return EXIT_SUCCESS;
 }
 
 static void t_path(void)
@@ -60,13 +61,12 @@
        }
 }
 
-static void t_strcpy(void)
+static int t_strcpy(void)
 {
        hxmc_t *vp = NULL;
 
        HXmc_strcpy(&vp, NULL);
-       if (vp != NULL)
-               abort();
+       return vp == nullptr ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 static void t_strdup(void)
@@ -291,7 +291,7 @@
        assert(a[0] == 49 && a[0] == a[1] && a[1] == a[2]);
 }
 
-static void t_units(void)
+static int t_units(void)
 {
        static const struct {
                unsigned long long num;
@@ -320,18 +320,19 @@
                printf("\t%llu -> %s\n", vt[i].num, buf);
                if (strcmp(buf, vt[i].exp_1024) != 0) {
                        printf("\texpected %s\n", vt[i].exp_1024);
-                       abort();
+                       return EXIT_FAILURE;
                }
                HX_unit_size(buf, ARRAY_SIZE(buf), vt[i].num, 1000, 9120);
                printf("\t%llu -> %s\n", vt[i].num, buf);
                if (strcmp(buf, vt[i].exp_1000) != 0) {
                        printf("\texpected %s\n", vt[i].exp_1000);
-                       abort();
+                       return EXIT_FAILURE;
                }
        }
+       return EXIT_SUCCESS;
 }
 
-static void t_units_cu(void)
+static int t_units_cu(void)
 {
        static const struct {
                unsigned long long num;
@@ -360,18 +361,19 @@
                printf("\t%llu -> %s\n", vt[i].num, buf);
                if (strcmp(buf, vt[i].exp_1024) != 0) {
                        printf("\texpected %s\n", vt[i].exp_1024);
-                       abort();
+                       return EXIT_FAILURE;
                }
                HX_unit_size_cu(buf, ARRAY_SIZE(buf), vt[i].num, 1000);
                printf("\t%llu -> %s\n", vt[i].num, buf);
                if (strcmp(buf, vt[i].exp_1000) != 0) {
                        printf("\texpected %s\n", vt[i].exp_1000);
-                       abort();
+                       return EXIT_FAILURE;
                }
        }
+       return EXIT_SUCCESS;
 }
 
-static void t_units_strto(void)
+static int t_units_strto(void)
 {
        static const struct {
                const char input[24];
@@ -416,8 +418,9 @@
                unsigned long long q = HX_strtoull_unit(vt[i].input, &end, 
vt[i].exponent);
                printf("%s -> %llu __ %s\n", vt[i].input, q, end);
                if (q != vt[i].expect_out || strcmp(end, vt[i].expect_rem) != 0)
-                       printf("BUG\n");
+                       return EXIT_FAILURE;
        }
+       return EXIT_SUCCESS;
 }
 
 static void t_time_units(void)
@@ -454,25 +457,30 @@
 
 static void t_time_strto(void)
 {
+       #define NS_PER_S 1000000000ULL
        static const struct {
                const char *input;
-               unsigned long long expect_out;
-               const char expect_rem[4];
+               unsigned long long expect_s, expect_ns;
+               const char expect_rem[8];
        } vt[] = {
-               {"1y1month1week1d1h1min1s ", 
31557600+2629800+86400*8+3600+60+1, ""},
-               {" -1d", 0, "-1d"},
-               {"1 -", 1, "-"},
-               {"1s", 1, ""},
-               {"1min", 60, ""},
-               {"0", 0, ""},
+               {"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), ""},
+               {" -1d", 0, 0, "-1d"},
+               {"1 -", 1, NS_PER_S, "-"},
+               {"12.5 hours .5 hours 240 minutes 25200 seconds", 86400, 
NS_PER_S * 86400, ""},
+               {"1s", 1, NS_PER_S, ""},
+               {"1min", 60, 60 * NS_PER_S, ""},
+               {"0", 0, 0, ""},
        };
        char *end;
        printf("===== t_time_strto\n");
        for (size_t i = 0; i < ARRAY_SIZE(vt); ++i) {
                unsigned long long q = HX_strtoull_sec(vt[i].input, &end);
-               printf("\"%s\" => %llus + \"%s\"\n", vt[i].input, q, end);
-               if (q != vt[i].expect_out)
-                       printf("\tBUG: expected %llus\n", vt[i].expect_out);
+               unsigned long long qn = HX_strtoull_nsec(vt[i].input, &end);
+               printf("\"%s\" => %llus [%lluns] + \"%s\"\n", vt[i].input, q, 
qn, end);
+               if (q != vt[i].expect_s || qn != vt[i].expect_ns)
+                       printf("\tBUG: expected %llus [%lluns]\n", 
vt[i].expect_s, vt[i].expect_ns);
                if (strcmp(end, vt[i].expect_rem) != 0)
                        printf("\tBUG: expected remainder \"%s\"\n", 
vt[i].expect_rem);
        }
@@ -507,14 +515,14 @@
 #undef T
 }
 
-int main(int argc, const char **argv)
+static int runner(int argc, const char **argv)
 {
        hxmc_t *tx = NULL;
        const char *file = (argc >= 2) ? argv[1] : "tx-string.cpp";
        FILE *fp;
 
        if (HX_init() <= 0)
-               abort();
+               return EXIT_FAILURE;
        int ret = t_strmid();
        if (ret != EXIT_SUCCESS)
                return EXIT_FAILURE;
@@ -528,9 +536,13 @@
                fclose(fp);
        }
 
-       t_mc();
+       ret = t_mc();
+       if (ret != EXIT_SUCCESS)
+               return EXIT_FAILURE;
        t_path();
-       t_strcpy();
+       ret = t_strcpy();
+       if (ret != EXIT_SUCCESS)
+               return EXIT_FAILURE;
        t_strncat();
        t_strnlen();
        t_strdup();
@@ -538,9 +550,15 @@
        t_strtrim();
        t_split();
        t_split2();
-       t_units();
-       t_units_cu();
-       t_units_strto();
+       ret = t_units();
+       if (ret != EXIT_SUCCESS)
+               return EXIT_FAILURE;
+       ret = t_units_cu();
+       if (ret != EXIT_SUCCESS)
+               return EXIT_FAILURE;
+       ret = t_units_strto();
+       if (ret != EXIT_SUCCESS)
+               return EXIT_FAILURE;
        t_time_units();
        t_time_strto();
        t_strlcpy();
@@ -549,3 +567,11 @@
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(int argc, const char **argv)
+{
+       int ret = runner(argc, argv);
+       if (ret != EXIT_FAILURE)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-switchuser.c 
new/libHX-4.16/src/tc-switchuser.c
--- old/libHX-4.15/src/tc-switchuser.c  2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-switchuser.c  2023-11-02 09:25:08.000000000 +0100
@@ -19,7 +19,7 @@
        HXOPT_TABLEEND,
 };
 
-int main(int argc, const char **argv)
+static int runner(int argc, const char **argv)
 {
        HX_getopt(options_table, &argc, &argv, HXOPT_USAGEONERR);
        const char *user = user_name != NULL ? user_name : "-";
@@ -27,12 +27,12 @@
        switch (HXproc_switch_user(user_name, group_name)) {
        case HXPROC_USER_NOT_FOUND:
                if (user_name == NULL)
-                       abort(); /* impossible outcomes */
+                       return EXIT_FAILURE; /* impossible outcomes */
                printf("No such user \"%s\": %s\n", user_name, strerror(errno));
                break;
        case HXPROC_GROUP_NOT_FOUND:
                if (group_name == NULL || *group_name == '\0')
-                       abort(); /* impossible outcome */
+                       return EXIT_FAILURE; /* impossible outcome */
                printf("No such group \"%s\": %s\n", group_name, 
strerror(errno));
                break;
        case HXPROC_SETUID_FAILED:
@@ -64,6 +64,14 @@
        }
        return EXIT_SUCCESS;
 }
+
+int main(int argc, const char **argv)
+{
+       int ret = runner(argc, argv);
+       if (ret != EXIT_SUCCESS)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}
 #else
 int main(void)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.15/src/tc-time.c new/libHX-4.16/src/tc-time.c
--- old/libHX-4.15/src/tc-time.c        2023-09-24 04:51:44.000000000 +0200
+++ new/libHX-4.16/src/tc-time.c        2023-11-02 09:25:08.000000000 +0100
@@ -207,7 +207,7 @@
        printf(HX_TIMESPEC_FMT "\n", HX_TIMESPEC_EXP(r));
 }
 
-static void test_add(void)
+static int test_add(void)
 {
        const struct timespec *a, *b;
        struct timespec r, s;
@@ -220,13 +220,14 @@
                        HX_timespec_add_DIVQ(&s, a, b);
                        print_op2(&r, a, "+Q", b);
                        if (r.tv_sec != s.tv_sec || r.tv_nsec != s.tv_nsec)
-                               abort();
+                               return EXIT_FAILURE;
                        HX_timespec_sub(&r, a, b);
                        print_op2(&r, a, "- ", b);
                        printf("----------\n");
                }
        }
        printf("\n");
+       return EXIT_SUCCESS;
 }
 
 static void test_adds_nz(time_t s, add_func_t fn)
@@ -303,7 +304,7 @@
        printf("\n");
 }
 
-static void test_mul(void)
+static int test_mul(void)
 {
        struct timespec r, s;
        unsigned int i;
@@ -324,7 +325,7 @@
                        printf(HX_TIMESPEC_FMT "\n", HX_TIMESPEC_EXP(&s));
 
                        if (r.tv_sec != s.tv_sec || r.tv_nsec != s.tv_nsec)
-                               abort();
+                               return EXIT_FAILURE;
                }
 
                for (k = -3; k <= 3; k += 0.1) {
@@ -341,6 +342,7 @@
        }
 
        printf("\n");
+       return EXIT_SUCCESS;
 }
 
 static void test_muls_1i(const char *text, mul_func_t fn)
@@ -386,18 +388,29 @@
        printf("\n");
 }
 
-int main(void)
+static int runner(void)
 {
        if (HX_init() <= 0)
-               abort();
-
+               return EXIT_FAILURE;
        test_basic();
        test_same();
        test_neg();
-       test_add();
-       test_mul();
+       int ret = test_add();
+       if (ret != EXIT_SUCCESS)
+               return ret;
+       ret = test_mul();
+       if (ret != EXIT_SUCCESS)
+               return ret;
        test_adds();
        test_muls();
        HX_exit();
        return EXIT_SUCCESS;
 }
+
+int main(void)
+{
+       int ret = runner();
+       if (ret != EXIT_SUCCESS)
+               fprintf(stderr, "FAILED\n");
+       return ret;
+}

Reply via email to