Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package libHX for openSUSE:Factory checked 
in at 2021-10-20 20:23:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/libHX (Old)
 and      /work/SRC/openSUSE:Factory/.libHX.new.1890 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "libHX"

Wed Oct 20 20:23:43 2021 rev:64 rq:925881 version:4.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/libHX/libHX.changes      2021-10-16 
22:47:17.984674703 +0200
+++ /work/SRC/openSUSE:Factory/.libHX.new.1890/libHX.changes    2021-10-20 
20:24:30.293386245 +0200
@@ -1,0 +2,8 @@
+Sun Oct 17 16:55:45 UTC 2021 - Jan Engelhardt <jeng...@inai.de>
+
+- Update to release 4.2
+  * string: New functions ``HX_strtod_unit``, ``HX_strtoull_unit``,
+    ``HX_unit_size``, ``HX_unit_size_cu`` for converting between
+    sizes and human-readable sizes like 1457664 <-> "1.45M"/"1.39M".
+
+-------------------------------------------------------------------

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

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

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

Other differences:
------------------
++++++ libHX.spec ++++++
--- /var/tmp/diff_new_pack.uFCO4t/_old  2021-10-20 20:24:30.785386549 +0200
+++ /var/tmp/diff_new_pack.uFCO4t/_new  2021-10-20 20:24:30.785386549 +0200
@@ -18,7 +18,7 @@
 
 Name:           libHX
 %define lname   libHX32
-Version:        4.1
+Version:        4.2
 Release:        0
 Summary:        Collection of routines for C and C++ programming
 License:        LGPL-2.1-or-later

++++++ libHX-4.1.tar.xz -> libHX-4.2.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/Makefile.in new/libHX-4.2/Makefile.in
--- old/libHX-4.1/Makefile.in   2021-10-13 14:57:21.762033922 +0200
+++ new/libHX-4.2/Makefile.in   2021-10-17 15:37:10.051321241 +0200
@@ -290,7 +290,6 @@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-LYX = @LYX@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/configure new/libHX-4.2/configure
--- old/libHX-4.1/configure     2021-10-13 14:57:20.466030028 +0200
+++ new/libHX-4.2/configure     2021-10-17 15:37:08.775317490 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libHX 4.1.
+# Generated by GNU Autoconf 2.69 for libHX 4.2.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@
 # Identity of this package.
 PACKAGE_NAME='libHX'
 PACKAGE_TARNAME='libhx'
-PACKAGE_VERSION='4.1'
-PACKAGE_STRING='libHX 4.1'
+PACKAGE_VERSION='4.2'
+PACKAGE_STRING='libHX 4.2'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -635,9 +635,6 @@
 regular_CXXFLAGS
 regular_CFLAGS
 regular_CPPFLAGS
-BUILD_DOCS_FALSE
-BUILD_DOCS_TRUE
-LYX
 libsocket_LIBS
 libpthread_LIBS
 librt_LIBS
@@ -1340,7 +1337,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.1 to adapt to many kinds of systems.
+\`configure' configures libHX 4.2 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1410,7 +1407,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libHX 4.1:";;
+     short | recursive ) echo "Configuration of libHX 4.2:";;
    esac
   cat <<\_ACEOF
 
@@ -1525,7 +1522,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libHX configure 4.1
+libHX configure 4.2
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2251,7 +2248,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.1, which was
+It was created by libHX $as_me 4.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3112,7 +3109,7 @@
 
 # Define the identity of the package.
  PACKAGE='libhx'
- VERSION='4.1'
+ VERSION='4.2'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -17096,56 +17093,6 @@
 fi
 done
 
-for ac_prog in lyx
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with 
args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LYX+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$LYX"; then
-  ac_cv_prog_LYX="$LYX" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_LYX="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" 
>&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-LYX=$ac_cv_prog_LYX
-if test -n "$LYX"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LYX" >&5
-$as_echo "$LYX" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$LYX" && break
-done
-
- if test -n "$LYX"; then
-  BUILD_DOCS_TRUE=
-  BUILD_DOCS_FALSE='#'
-else
-  BUILD_DOCS_TRUE='#'
-  BUILD_DOCS_FALSE=
-fi
-
 
 regular_CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_REENTRANT"
 regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
@@ -17311,10 +17258,6 @@
   as_fn_error $? "conditional \"HAVE_DLFCN_H\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${BUILD_DOCS_TRUE}" && test -z "${BUILD_DOCS_FALSE}"; then
-  as_fn_error $? "conditional \"BUILD_DOCS\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
 
 : "${CONFIG_STATUS=./config.status}"
 ac_write_fail=0
@@ -17712,7 +17655,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.1, which was
+This file was extended by libHX $as_me 4.2, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -17778,7 +17721,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; 
s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libHX config.status 4.1
+libHX config.status 4.2
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/configure.ac new/libHX-4.2/configure.ac
--- old/libHX-4.1/configure.ac  2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/configure.ac  2021-10-17 15:36:53.000000000 +0200
@@ -1,4 +1,4 @@
-AC_INIT([libHX], [4.1])
+AC_INIT([libHX], [4.2])
 AC_CONFIG_AUX_DIR([build-aux])
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_MACRO_DIR([m4])
@@ -106,8 +106,6 @@
 AC_CHECK_FUNCS([fork execv execvp pipe])
 AC_CHECK_FUNCS([getegid geteuid getpid getppid])
 AC_CHECK_FUNCS([initgroups setgid])
-AC_CHECK_PROGS([LYX], [lyx])
-AM_CONDITIONAL([BUILD_DOCS], [test -n "$LYX"])
 
 regular_CPPFLAGS="-D_FILE_OFFSET_BITS=64 -D_REENTRANT"
 regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/doc/api.rst new/libHX-4.2/doc/api.rst
--- old/libHX-4.1/doc/api.rst   2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/doc/api.rst   2021-10-17 15:36:53.000000000 +0200
@@ -9,6 +9,10 @@
 ======  ======  ======  ========================================
 RMV     MinVer  FirstA  Name
 ======  ======  ======  ========================================
+4.2     4.2     4.2     HX_unit_size
+4.2     4.2     4.2     HX_unit_size_cu
+4.2     4.2     4.2     HX_strtod_unit
+4.2     4.2     4.2     HX_strtoull_unit
 3.27    3.27    3.27    HXOPT_KEEP_ARGV
 3.27    3.27    3.27    HXproc_top_fd
 3.27    3.27    3.27    HXproc_switch_user
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/doc/changelog.rst 
new/libHX-4.2/doc/changelog.rst
--- old/libHX-4.1/doc/changelog.rst     2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/doc/changelog.rst     2021-10-17 15:36:53.000000000 +0200
@@ -1,3 +1,13 @@
+v4.2 (2021-10-17)
+=================
+
+Enhancements:
+
+* string: New functions ``HX_strtod_unit``, ``HX_strtoull_unit``,
+  ``HX_unit_size``, ``HX_unit_size_cu`` for converting between
+  sizes and human-readable sizes like 1457664 <-> "1.45M"/"1.39M".
+
+
 v4.1 (2021-10-13)
 =================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/doc/string_ops.rst 
new/libHX-4.2/doc/string_ops.rst
--- old/libHX-4.1/doc/string_ops.rst    2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/doc/string_ops.rst    2021-10-17 15:36:53.000000000 +0200
@@ -316,7 +316,7 @@
 
 .. code-block:: c
 
-       #include <libHX/string.h>libHX/string.h
+       #include <libHX/string.h>
 
        void *HX_memdup(const void *ptr, size_t length);
        char *HX_strdup(const char *str);
@@ -352,6 +352,87 @@
        deprecated, albeit no replacement is proposed.
 
 
+Numbers to human-readable sizes with units
+==========================================
+
+.. code-block:: c
+
+       #include <libHX/string.h>
+
+       char *HX_unit_size(char *out, size_t outsize, unsigned long long number,
+                          unsigned int divisor, unsigned int cutoff);
+       char *HX_unit_size_p90(char *out, size_t outsize,
+                              unsigned long long number, unsigned int divisor);
+
+``HX_unit_size`` takes an arbitrary number and and produces a more
+readily-readable shortened (string) representation with a unit suffix. It does
+this by dividing ``number`` by ``pow(divisor, i)`` for some integer _i_ such
+that the resulting (integer) quotient is the highest possible value _v_ that is
+less than ``cutoff``. This value _v_ is then emitted into ``out`` together with
+the corresponding SI prefix.
+
+Note that the SI prefix for one iteration (i==1), i.e. kilo, is a lower-case
+``'k'``. If you need consistent upper-case output in your program, (i.e. K/M/G
+instead of k/M/G), use a subsequent call to ``HX_strupper``.
+
+When ``divisor`` is 0, it defaults to 1000. When ``cutoff`` is 0, an
+implementation-defined cutoff point is used. When ``cutoff`` is less than
+``divisor``, the result is implementation-defined.
+
+The output number of ``HX_unit_size`` is always integer; no fractions are
+emitted. This is rooted in the following idea:
+
+* An output like ``1G`` is quite broad and some precision would be nice. The
+  author has historically preferred 3 digits instead of just 2, thanks to wget
+  and rsync.
+
+* ``1.34G`` has the same string length as ``1340M``, i.e. both occupy the same
+  visual space in console outputs, but the latter has another digit of
+  precision.
+
+* By ditching fractions this way, ``HX_unit_size`` also sidesteps the issue of
+  excess digits being emitted (usually up to 5) from the trivial use (by
+  wget/rsync) of ``printf("%.2f",??v)``.
+
+The ``HX_unit_size_cu`` function will instead mimic the behavior of coreutils
+(/usr/bin/df, /usr/bin/ls). That is, it divides ``number`` by ``pow(divisor,
+i)`` for some integer _i_ such that the resulting (real) quotient is
+less-than-or-equal ``divisor-1``. It rounds the value up to the next integer if
+the fractional part is >90%, and if the quotient is greater-or-equal 10, the
+fractional part is stripped and not emitted to ``out``.
+
+In practice, the rounding up of ``HX_unit_size_cu`` lends itself to display
+occupying sizes, whereas the implicit rounding down (of integer divisions)
+in ``HX_unit_size`` lend itself to sizes in progress meters.
+
+
+Unit-suffixed numbers to full numbers
+=====================================
+
+.. code-block:: c
+
+       #include <libHX/string.h>
+
+       double HX_strtod_unit(const char *s, char **end,
+                             unsigned int exponent);
+       unsigned long long HX_strtoull_unit(const char *s, char **end,
+                                           unsigned int exponent);
+
+The ``HX_strtod_unit`` and ``HX_strtoull_unit`` functions behave similar to
+``strtod`` and ``strtoul``, respectively, in that they convert the initial part
+of the string in ``s`` to a ``double`` and ``unsigned long long``,
+respectively, and apply the selected multiplication factor from ``exponent`` in
+resolving an optional unit suffix.
+
+Upon overflow, ``errno`` is set to ``ERANGE`` just like the stdlib functions.
+Unlike some implementations of ``strtoul``, negative numbers are outright
+rejected.
+
+.. code-block:: c
+
+       unsigned long long bytes = HX_strtoull_unit("1.5G", NULL, 1024);
+
+
 Examples
 ========
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/include/Makefile.in 
new/libHX-4.2/include/Makefile.in
--- old/libHX-4.1/include/Makefile.in   2021-10-13 14:57:21.798034030 +0200
+++ new/libHX-4.2/include/Makefile.in   2021-10-17 15:37:10.087321346 +0200
@@ -217,7 +217,6 @@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-LYX = @LYX@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/include/libHX/string.h 
new/libHX-4.2/include/libHX/string.h
--- old/libHX-4.1/include/libHX/string.h        2021-10-13 14:54:52.000000000 
+0200
+++ new/libHX-4.2/include/libHX/string.h        2021-10-17 15:36:53.000000000 
+0200
@@ -90,6 +90,10 @@
 extern char *HX_strsep(char **, const char *);
 extern char *HX_strsep2(char **, const char *);
 extern char *HX_strupper(char *);
+extern double HX_strtod_unit(const char *, char **, unsigned int exponent);
+extern unsigned long long HX_strtoull_unit(const char *, char **, unsigned int 
exponent);
+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);
 
 static __inline__ void *HX_memdup(const void *buf, size_t len)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/src/Makefile.am 
new/libHX-4.2/src/Makefile.am
--- old/libHX-4.1/src/Makefile.am       2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/src/Makefile.am       2021-10-17 15:36:53.000000000 +0200
@@ -12,8 +12,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} ${libpthread_LIBS} ${librt_LIBS}
-libHX_la_LDFLAGS = -no-undefined -version-info 33:0:1
+libHX_la_LIBADD  = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS}
+libHX_la_LDFLAGS = -no-undefined -version-info 34:0:2
 if WITH_GNU_LD
 libHX_la_LDFLAGS += -Wl,--version-script=${srcdir}/libHX.map
 endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/src/Makefile.in 
new/libHX-4.2/src/Makefile.in
--- old/libHX-4.1/src/Makefile.in       2021-10-13 14:57:21.930034427 +0200
+++ new/libHX-4.2/src/Makefile.in       2021-10-17 15:37:10.231321769 +0200
@@ -688,7 +688,6 @@
 LN_S = @LN_S@
 LTLIBOBJS = @LTLIBOBJS@
 LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
-LYX = @LYX@
 MAKEINFO = @MAKEINFO@
 MANIFEST_TOOL = @MANIFEST_TOOL@
 MKDIR_P = @MKDIR_P@
@@ -779,8 +778,8 @@
 lib_LTLIBRARIES = libHX.la $(am__append_1)
 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} ${libpthread_LIBS} ${librt_LIBS}
-libHX_la_LDFLAGS = -no-undefined -version-info 33:0:1 $(am__append_2)
+libHX_la_LIBADD = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS}
+libHX_la_LDFLAGS = -no-undefined -version-info 34:0:2 $(am__append_2)
 EXTRA_libHX_la_DEPENDENCIES = libHX.map
 libHX_rtcheck_la_SOURCES = rtcheck.c
 libHX_rtcheck_la_LIBADD = ${libdl_LIBS}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/src/libHX.map new/libHX-4.2/src/libHX.map
--- old/libHX-4.1/src/libHX.map 2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/src/libHX.map 2021-10-17 15:36:53.000000000 +0200
@@ -135,3 +135,11 @@
        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;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/src/string.c new/libHX-4.2/src/string.c
--- old/libHX-4.1/src/string.c  2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/src/string.c  2021-10-17 15:36:53.000000000 +0200
@@ -8,6 +8,8 @@
  *     either version 2.1 or (at your option) any later version.
  */
 #include <errno.h>
+#include <limits.h>
+#include <math.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -836,3 +838,169 @@
                *expr = HX_toupper(*expr);
        return orig;
 }
+
+EXPORT_SYMBOL char *HX_unit_size(char *buf, size_t bufsize,
+    unsigned long long size, unsigned int divisor, unsigned int cutoff)
+{
+       static const char unit_names[] = "\0kMGTPEZYRQ";
+       unsigned int unit_idx = 0;
+       if (divisor == 0)
+               divisor = 1000;
+       if (cutoff == 0) {
+               cutoff = 10000;
+               if (cutoff < divisor)
+                       cutoff = divisor;
+       }
+       while (unit_idx < ARRAY_SIZE(unit_names) - 1 && size >= cutoff) {
+               ++unit_idx;
+               size /= divisor;
+       }
+       snprintf(buf, bufsize, "%llu%.1s", size, &unit_names[unit_idx]);
+       return buf;
+}
+
+static inline unsigned long long p_90(unsigned long long x)
+{
+       /* Perform x*9/10, but without the risk of overflow. */
+       return x - x / 10 - !!(x % 10);
+}
+
+EXPORT_SYMBOL char *HX_unit_size_cu(char *buf, size_t bufsize,
+    unsigned long long orig_size, unsigned int divisor)
+{
+       /* No floating point. Take that, coreutils! */
+       static const char unit_names[] = "\0kMGTPEZYRQ";
+       unsigned int unit_idx = 0, last_rem = 0;
+       unsigned long long size = orig_size, gpow = 1, grand_rem;
+       if (divisor == 0)
+               divisor = 1000;
+
+       while (unit_idx < ARRAY_SIZE(unit_names) - 1 && size >= divisor) {
+               ++unit_idx;
+               last_rem = size % divisor;
+               size /= divisor;
+               gpow *= divisor;
+       }
+       if (unit_idx == 0) {
+               snprintf(buf, bufsize, "%llu%.1s", size, &unit_names[unit_idx]);
+               return buf;
+       }
+       grand_rem = orig_size - size * gpow;
+       if (grand_rem != 0) {
+               if (grand_rem > p_90(gpow)) {
+                       ++size;
+                       last_rem = 0;
+               } else {
+                       last_rem *= 10;
+                       last_rem /= divisor;
+                       ++last_rem;
+                       if (last_rem == 10 || (size >= 10 && last_rem > 0)) {
+                               ++size;
+                               last_rem = 0;
+                       }
+               }
+               if (unit_idx < ARRAY_SIZE(unit_names) - 1 && size == divisor) {
+                       /* ++size from above may brought size to @divisor again 
*/
+                       ++unit_idx;
+                       size /= divisor;
+               }
+       }
+       if (size >= 10 && last_rem == 0)
+               snprintf(buf, bufsize, "%llu%.1s", size, &unit_names[unit_idx]);
+       else
+               snprintf(buf, bufsize, "%llu.%01u%.1s", size, last_rem, 
&unit_names[unit_idx]);
+       return buf;
+}
+
+static unsigned int suffix_power(char u)
+{
+       switch (HX_toupper(u)) {
+       case 'K': return 1;
+       case 'M': return 2;
+       case 'G': return 3;
+       case 'T': return 4;
+       case 'P': return 5;
+       case 'E': return 6;
+       case 'Z': return 7;
+       case 'Y': return 8;
+       case 'R': return 9;
+       case 'Q': return 10;
+       default: return 0;
+       }
+}
+
+EXPORT_SYMBOL double HX_strtod_unit(const char *s, char **out_end, unsigned 
int exponent)
+{
+       char *end;
+       double q;
+
+       while (HX_isspace(*s))
+               ++s;
+       if (*s == '-') {
+               if (out_end != nullptr)
+                       *out_end = const_cast(char *, s);
+               errno = ERANGE;
+               return ULLONG_MAX;
+       }
+       q = strtod(s, &end);
+       if (exponent == 0)
+               exponent = 1000;
+       if (end == s) {
+               if (out_end != nullptr)
+                       *out_end = end;
+               return q;
+       }
+       while (HX_isspace(*end))
+               ++end;
+       unsigned int pwr = suffix_power(*end);
+       if (pwr == 0) {
+               if (out_end != nullptr)
+                       *out_end = const_cast(char *, end);
+               return q;
+       }
+       if (out_end != nullptr)
+               *out_end = const_cast(char *, end + 1);
+       return q * pow(exponent, pwr);
+}
+
+EXPORT_SYMBOL unsigned long long HX_strtoull_unit(const char *s,
+    char **out_end, unsigned int exponent)
+{
+       char *end;
+       unsigned long long ipart;
+       unsigned int pwr = 0;
+
+       while (HX_isspace(*s))
+               ++s;
+       if (*s == '-') {
+               if (out_end != nullptr)
+                       *out_end = const_cast(char *, s);
+               errno = ERANGE;
+               return ULLONG_MAX;
+       }
+       ipart = strtoull(s, &end, 10);
+       if (*end == '.') {
+               double q = HX_strtod_unit(s, out_end, exponent);
+               return q < ULLONG_MAX ? q : ULLONG_MAX;
+       }
+       if (exponent == 0)
+               exponent = 1000;
+       while (HX_isspace(*end))
+               ++end;
+       pwr = suffix_power(*end);
+       if (pwr == 0) {
+               if (out_end != nullptr)
+                       *out_end = end;
+               return ipart;
+       }
+       if (out_end != nullptr)
+               *out_end = const_cast(char *, end + 1);
+       while (pwr-- > 0) {
+               if (ipart >= ULLONG_MAX / exponent) {
+                       errno = ERANGE;
+                       return ULLONG_MAX;
+               }
+               ipart *= exponent;
+       }
+       return ipart;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/libHX-4.1/src/tc-string.c 
new/libHX-4.2/src/tc-string.c
--- old/libHX-4.1/src/tc-string.c       2021-10-13 14:54:52.000000000 +0200
+++ new/libHX-4.2/src/tc-string.c       2021-10-17 15:36:53.000000000 +0200
@@ -288,6 +288,135 @@
        assert(a[0] == 49 && a[0] == a[1] && a[1] == a[2]);
 }
 
+static void t_units(void)
+{
+       static const struct {
+               unsigned long long num;
+               const char exp_1024[6], exp_1000[6];
+       } vt[] = {
+               {1023, "1023", "1023"},
+               {1024, "1024", "1024"},
+               {1945, "1945", "1945"},
+               {1946, "1946", "1946"},
+               {1022975, "998k", "1022k"},
+               {1022976, "999k", "1022k"},
+               {1022977, "999k", "1022k"},
+               {1047552, "1023k", "1047k"},
+               {1047553, "1023k", "1047k"},
+               {1992294, "1945k", "1992k"},
+               {1992295, "1945k", "1992k"},
+               {1072693248, "1023M", "1072M"},
+               {1072693249, "1023M", "1072M"},
+               {ULLONG_MAX, "15E", "18E"},
+       };
+       char buf[HXSIZEOF_Z64+3];
+       printf("unit_size:\n");
+
+       for (size_t i = 0; i < ARRAY_SIZE(vt); ++i) {
+               HX_unit_size(buf, ARRAY_SIZE(buf), vt[i].num, 1024, 9120);
+               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();
+               }
+               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();
+               }
+       }
+}
+
+static void t_units_cu(void)
+{
+       static const struct {
+               unsigned long long num;
+               const char exp_1024[6], exp_1000[6];
+       } vt[] = {
+               {1023, "1023", "1.1k"},
+               {1024, "1.0k", "1.1k"},
+               {1945, "1.9k", "2.0k"},
+               {1946, "2.0k", "2.0k"},
+               {1022975, "999k", "1.1M"},
+               {1022976, "999k", "1.1M"},
+               {1022977, "1000k", "1.1M"},
+               {1047552, "1023k", "1.1M"},
+               {1047553, "1.0M", "1.1M"},
+               {1992294, "1.9M", "2.0M"},
+               {1992295, "2.0M", "2.0M"},
+               {1072693248, "1023M", "1.1G"},
+               {1072693249, "1.0G", "1.1G"},
+               {ULLONG_MAX, "16E", "19E"},
+       };
+       char buf[80];
+       printf("unit_size_cu:\n");
+
+       for (size_t i = 0; i < ARRAY_SIZE(vt); ++i) {
+               HX_unit_size_cu(buf, ARRAY_SIZE(buf), vt[i].num, 1024);
+               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();
+               }
+               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();
+               }
+       }
+}
+
+static void t_units_strto(void)
+{
+       static const struct {
+               const char input[24];
+               unsigned int exponent;
+               unsigned long long expect_out;
+               const char expect_rem[8];
+       } vt[] = {
+               {"-5k", 1000, ULLONG_MAX, "-5k"},
+               {" -5.2k", 1000, ULLONG_MAX, "-5.2k"},
+               {"1", 9999, 1, ""},
+               {"1024", 9999, 1ULL << 10, ""},
+               {"1048576", 9999, 1ULL << 20, ""},
+               {"1073741824", 9999, 1ULL << 30, ""},
+               {"1099511627776", 9999, 1ULL << 40, ""},
+               {"1125899906842624", 9999, 1ULL << 50, ""},
+               {"1152921504606846976", 9999, 1ULL << 60, ""},
+               {"18446744073709551615", 9, ULLONG_MAX, ""},
+               {"1k", 1000, 1000ULL, ""},
+               {"1M", 1000, 1000000ULL, ""},
+               {"1G", 1000, 1000000000ULL, ""},
+               {"1T", 1000, 1000000000000ULL, ""},
+               {"1P", 1000, 1000000000000000ULL, ""},
+               {"1E", 1000, 1000000000000000000ULL, ""},
+               {"1k", 1024, 1ULL << 10, ""},
+               {"1M", 1024, 1ULL << 20, ""},
+               {"1G", 1024, 1ULL << 30, ""},
+               {"1T", 1024, 1ULL << 40, ""},
+               {"1P", 1024, 1ULL << 50, ""},
+               {"1E", 1024, 1ULL << 60, ""},
+               {"0", 0, 0, ""},
+               {"0k", 0, 0, ""},
+               {"0  Z", 0, 0, ""},
+               {"0.1k", 1000, 100, ""},
+               {"0.1k", 1024, 102, ""},
+               {" 0.1k", 1024, 102, ""},
+               {"0.00000000000000001E", 1024, 11, ""},
+               {"1.525444GiB", 1000, 1525444000, "iB"},
+               {"1.525444GiB", 1024, 1637933022, "iB"},
+       };
+       char *end;
+       for (size_t i = 0; i < ARRAY_SIZE(vt); ++i) {
+               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");
+       }
+}
+
 int main(int argc, const char **argv)
 {
        hxmc_t *tx = NULL;
@@ -316,6 +445,9 @@
        t_strtrim();
        t_split();
        t_split2();
+       t_units();
+       t_units_cu();
+       t_units_strto();
        t_strlcpy();
        t_strlcpy2();
        HXmc_free(tx);

Reply via email to