libc: Add strsuftoll{,x}()
authorSascha Wildner <saw@online.de>
Sat, 5 May 2018 20:07:33 +0000 (22:07 +0200)
committerSascha Wildner <saw@online.de>
Sat, 5 May 2018 20:07:33 +0000 (22:07 +0200)
In preparation for makefs(8).

Various dports (such as ftp/tnftpd) will also pick it up.

Taken-from:     NetBSD
Dports-testing: zrj

include/stdlib.h
lib/libc/stdlib/Makefile.inc
lib/libc/stdlib/Symbol.map
lib/libc/stdlib/strsuftoll.3 [new file with mode: 0644]
lib/libc/stdlib/strsuftoll.c [new file with mode: 0644]
lib/libutil/humanize_number.3
sys/sys/param.h

index bb4295e..b0152cb 100644 (file)
@@ -304,6 +304,11 @@ int         sradixsort(const unsigned char **, int, const unsigned char *,
                    unsigned int);
 void    sranddev(void);
 void    srandomdev(void);
+long long
+        strsuftoll(const char *, const char *, long long, long long);
+long long
+        strsuftollx(const char *, const char *, long long, long long, char *,
+           size_t);
 long long
         strtonum(const char *, long long, long long, const char **);
 
index a73cb66..7e6049b 100644 (file)
@@ -12,8 +12,8 @@ MISRCS+=a64l.c abort.c abs.c atexit.c aligned_alloc.c \
        getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
        insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c \
        merge.c ptsname.c qsort.c qsort_r.c quick_exit.c \
-       radixsort.c rand.c random.c \
-       reallocf.c realpath.c remque.c strfmon.c strtoimax.c \
+       radixsort.c rand.c random.c reallocf.c realpath.c remque.c \
+       strfmon.c strsuftoll.c strtoimax.c \
        strtol.c strtoll.c strtonum.c strtoq.c strtoul.c strtoull.c \
        strtoumax.c strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c
 
@@ -40,8 +40,8 @@ MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 \
        hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
        lsearch.3 malloc.3 memory.3 posix_memalign.3 posix_openpt.3 \
        ptsname.3 qsort.3 quick_exit.3 \
-       radixsort.3 rand.3 random.3 \
-       realpath.3 strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
+       radixsort.3 rand.3 random.3 realpath.3 \
+       strfmon.3 strsuftoll.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \
        tsearch.3
 
 MLINKS+=a64l.3 l64a.3 \
@@ -79,6 +79,7 @@ MLINKS+=random.3 initstate.3 \
        random.3 srandom.3 \
        random.3 srandomdev.3
 MLINKS+=strfmon.3 strfmon_l.3
+MLINKS+=strsuftoll.3 strsuftollx.3
 MLINKS+=strtod.3 strtod_l.3 \
        strtod.3 strtof.3 \
        strtod.3 strtof_l.3 \
index f4f453a..f270ddf 100644 (file)
@@ -111,6 +111,11 @@ DF410.0 {
     __realloc;
 };
 
+DF504.0 {
+    strsuftoll;
+    strsuftollx;
+};
+
 /*
  * ignore WEAK:  __pthread_cxa_finalize;
  */
diff --git a/lib/libc/stdlib/strsuftoll.3 b/lib/libc/stdlib/strsuftoll.3
new file mode 100644 (file)
index 0000000..ac31e24
--- /dev/null
@@ -0,0 +1,150 @@
+.\"    $NetBSD: strsuftoll.3,v 1.11 2010/12/14 13:00:34 jruoho Exp $
+.\"
+.\" Copyright (c) 2002,2007 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Luke Mewburn.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd May 5, 2018
+.Dt STRSUFTOLL 3
+.Os
+.Sh NAME
+.Nm strsuftoll ,
+.Nm strsuftollx
+.Nd "convert a string to a long long, with suffix parsing"
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In stdlib.h
+.Ft long long
+.Fn strsuftoll "const char *desc" "const char *val" "long long min" "long long max"
+.Ft long long
+.Fn strsuftollx "const char *desc" "const char *val" "long long min" "long long max" "char *errbuf" "size_t errbuflen"
+.Sh DESCRIPTION
+The functions
+.Fn strsuftoll
+and
+.Fn strsuftollx
+convert
+.Fa val
+into a number of type
+.Vt long long ,
+checking that the result is not smaller than
+.Fa min
+or larger than
+.Fa max .
+Two or more decimal numbers may be separated by an
+.Dq x
+to indicate a product.
+.Pp
+Each decimal number may have one of the following optional suffixes:
+.Pp
+.Bl -tag -width 3n -offset indent -compact
+.It Em b
+Block; multiply by 512
+.It Em k
+Kibi; multiply by 1024 (1 KiB)
+.It Em m
+Mebi; multiply by 1048576 (1 MiB)
+.It Em g
+Gibi; multiply by 1073741824 (1 GiB)
+.It Em t
+Tebi; multiply by 1099511627776 (1 TiB)
+.It Em w
+Word; multiply by the number of bytes in an integer
+.El
+.Pp
+In the case of an error (range overflow or an invalid number),
+.Fn strsuftollx
+places an error message into
+.Fa errbuf
+(which is
+.Fa errbuflen
+bytes long) and returns 0,
+and
+.Fn strsuftoll
+displays that error and terminates the process.
+The parameter
+.Fa desc
+is used to construct
+.Fa errbuf .
+.Pp
+Neither
+.Fa desc
+nor
+.Fa val
+may be
+.Dv NULL .
+.Sh RETURN VALUES
+The functions
+.Fn strsuftoll
+and
+.Fn strsuftollx
+return either the result of the conversion,
+unless the value overflows or is not a number;
+in the latter case,
+.Fn strsuftoll
+displays an error message and terminates the process with exit code
+.Dv EXIT_FAILURE ,
+and
+.Fn strsuftollx
+returns with 0 and
+.Fa errbuf
+contains a non-empty error message.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er ERANGE
+The given string was out of range; the value converted has been clamped.
+.El
+.Sh SEE ALSO
+.Xr errx 3 ,
+.Xr strtoll 3 ,
+.Xr orders 7
+.Sh BUGS
+At least few limitations should be mentioned:
+.Bl -bullet
+.It
+Both functions ignore the current locale.
+.It
+Neither
+.Fn strsuftoll
+nor
+.Fn strsuftollx
+fail gracefully in case of invalid,
+.Dv NULL ,
+pointers.
+.It
+Arguably the return type should be
+.Vt intmax_t
+instead of
+.Vt long long .
+.It
+The
+.Fn strsuftollx
+function is prone to buffer overflows if used incorrectly.
+Arguably only
+.Fn strsuftoll
+should be exposed to a caller.
+.El
diff --git a/lib/libc/stdlib/strsuftoll.c b/lib/libc/stdlib/strsuftoll.c
new file mode 100644 (file)
index 0000000..9616300
--- /dev/null
@@ -0,0 +1,222 @@
+/*     $NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $  */
+/*-
+ * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Convert an expression of the following forms to a (u)int64_t.
+ *     1) A positive decimal number.
+ *     2) A positive decimal number followed by a b (mult by 512).
+ *     3) A positive decimal number followed by a k (mult by 1024).
+ *     4) A positive decimal number followed by a m (mult by 1048576).
+ *     5) A positive decimal number followed by a g (mult by 1073741824).
+ *     6) A positive decimal number followed by a t (mult by 1099511627776).
+ *     7) A positive decimal number followed by a w (mult by sizeof int)
+ *     8) Two or more positive decimal numbers (with/without k,b or w).
+ *        separated by x (also * for backwards compatibility), specifying
+ *        the product of the indicated values.
+ * Returns the result upon successful conversion, or exits with an
+ * appropriate error.
+ *
+ */
+/* LONGLONG */
+long long
+strsuftoll(const char *desc, const char *val,
+    long long min, long long max)
+{
+       long long result;
+       char    errbuf[100];
+
+       result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
+       if (*errbuf != '\0')
+               errx(EXIT_FAILURE, "%s", errbuf);
+       return result;
+}
+
+/*
+ * As strsuftoll(), but returns the error message into the provided buffer
+ * rather than exiting with it.
+ */
+/* LONGLONG */
+static long long
+__strsuftollx(const char *desc, const char *val,
+    long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
+{
+       long long num, t;
+       char    *expr;
+
+       _DIAGASSERT(desc != NULL);
+       _DIAGASSERT(val != NULL);
+       _DIAGASSERT(ebuf != NULL);
+
+       if (depth > 16) {
+               snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
+               return 0;
+       }
+
+       while (isspace((unsigned char)*val))    /* Skip leading space */
+               val++;
+
+       errno = 0;
+       num = strtoll(val, &expr, 10);
+       if (errno == ERANGE)
+               goto erange;                    /* Overflow */
+
+       if (expr == val)                        /* No digits */
+               goto badnum;
+
+       switch (*expr) {
+       case 'b':
+               t = num;
+               num *= 512;                     /* 1 block */
+               if (t > num)
+                       goto erange;
+               ++expr;
+               break;
+       case 'k':
+               t = num;
+               num *= 1024;                    /* 1 kibibyte */
+               if (t > num)
+                       goto erange;
+               ++expr;
+               break;
+       case 'm':
+               t = num;
+               num *= 1048576;                 /* 1 mebibyte */
+               if (t > num)
+                       goto erange;
+               ++expr;
+               break;
+       case 'g':
+               t = num;
+               num *= 1073741824;              /* 1 gibibyte */
+               if (t > num)
+                       goto erange;
+               ++expr;
+               break;
+       case 't':
+               t = num;
+               num *= 1099511627776LL;         /* 1 tebibyte */
+               if (t > num)
+                       goto erange;
+               ++expr;
+               break;
+       case 'w':
+               t = num;
+               num *= sizeof(int);             /* 1 word */
+               if (t > num)
+                       goto erange;
+               ++expr;
+               break;
+       }
+
+       switch (*expr) {
+       case '\0':
+               break;
+       case '*':                               /* Backward compatible */
+       case 'x':
+               t = num;
+               num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
+                       depth + 1);
+               if (*ebuf != '\0')
+                       return 0;
+               if (t > num) {
+ erange:
+                       errno = ERANGE;
+                       snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
+                       return 0;
+               }
+               break;
+       default:
+ badnum:
+               snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
+               return 0;
+       }
+       if (num < min) {
+               /* LONGLONG */
+               snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
+                   desc, (long long)num, (long long)min);
+               return 0;
+       }
+       if (num > max) {
+               /* LONGLONG */
+               snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
+                   desc, (long long)num, (long long)max);
+               return 0;
+       }
+       *ebuf = '\0';
+       return num;
+}
+
+long long
+strsuftollx(const char *desc, const char *val,
+    long long min, long long max, char *ebuf, size_t ebuflen)
+{
+       return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
+}
index 8f99662..82c2bc5 100644 (file)
@@ -28,7 +28,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd December 30, 2016
+.Dd May 5, 2018
 .Dt HUMANIZE_NUMBER 3
 .Os
 .Sh NAME
@@ -215,6 +215,8 @@ The string in
 represented a number that does not fit in
 .Fa result .
 .El
+.Sh SEE ALSO
+.Xr strsuftoll 3
 .Sh STANDARDS
 The
 .Dv HN_DIVISOR_1000
index 1b2084f..f36597a 100644 (file)
  * 500303 - get rid of sgtty (superseded by termios)
  * 500304 - remove IPSEC/FAST_IPSEC
  * 500305 - remove <sys/ioctl_compat.h> for good
+ * 500306 - strsuftoll(), strsuftollx()
  */
 #undef __DragonFly_version
-#define __DragonFly_version 500305     /* propagated to newvers */
+#define __DragonFly_version 500306     /* propagated to newvers */
 
 #include <sys/_null.h>