The branch main has been updated by jrm:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=6a6f230d3143a1dedddf6fa99b83d040f0fafe53

commit 6a6f230d3143a1dedddf6fa99b83d040f0fafe53
Author:     Hans Rosenfeld <[email protected]>
AuthorDate: 2025-12-16 16:04:30 +0000
Commit:     Joseph Mingrone <[email protected]>
CommitDate: 2026-01-15 13:45:42 +0000

    libc/stdlib: Port strtonumx() from Illumos
    
    Add strtonumx(), a companion to strtonum(3) that preserves its safety
    and error-reporting semantics while allowing the caller to specify a
    conversion base, similar to the strtol(3) family of functions.
    
    Reviewed by:    emaste, kib, ziaee
    Obtained from:  https://www.illumos.org/issues/15365
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D54270
---
 include/stdlib.h             |  2 ++
 lib/libc/stdlib/Makefile.inc |  1 +
 lib/libc/stdlib/Symbol.map   |  1 +
 lib/libc/stdlib/strtonum.3   | 74 ++++++++++++++++++++++++++++++++++----------
 lib/libc/stdlib/strtonum.c   | 27 ++++++++++++----
 5 files changed, 82 insertions(+), 23 deletions(-)

diff --git a/include/stdlib.h b/include/stdlib.h
index 3e54b5feb6de..305aea4b8672 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -333,6 +333,8 @@ int  sradixsort(const unsigned char **, int, const unsigned 
char *,
 void    srandomdev(void);
 long long
        strtonum(const char *, long long, long long, const char **);
+long long
+       strtonumx(const char *, long long, long long, const char **, int);
 
 /* Deprecated interfaces, to be removed. */
 __int64_t
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index c311ba3d2bcc..c2107fdaeaae 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -142,6 +142,7 @@ MLINKS+=strtod.3 strtof.3 \
 MLINKS+=strtol.3 strtoll.3 \
        strtol.3 strtoq.3 \
        strtol.3 strtoimax.3
+MLINKS+=strtonum.3 strtonumx.3
 MLINKS+=strtoul.3 strtoull.3 \
        strtoul.3 strtouq.3 \
        strtoul.3 strtoumax.3
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 03a6d0b543ac..373006b4a388 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -134,6 +134,7 @@ FBSD_1.8 {
 FBSD_1.9 {
        memalignment;
        recallocarray;
+       strtonumx;
        tdestroy;
 };
 
diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3
index 2650d147e7cc..7e6111a6ff71 100644
--- a/lib/libc/stdlib/strtonum.3
+++ b/lib/libc/stdlib/strtonum.3
@@ -1,4 +1,5 @@
 .\" Copyright (c) 2004 Ted Unangst
+.\" Copyright 2023 Oxide Computer Company
 .\"
 .\" Permission to use, copy, modify, and distribute this software for any
 .\" purpose with or without fee is hereby granted, provided that the above
@@ -14,11 +15,12 @@
 .\"
 .\" $OpenBSD: strtonum.3,v 1.13 2006/04/25 05:15:42 tedu Exp $
 .\"
-.Dd April 29, 2004
+.Dd January 15, 2026
 .Dt STRTONUM 3
 .Os
 .Sh NAME
-.Nm strtonum
+.Nm strtonum ,
+.Nm strtonumx
 .Nd "reliably convert string value to an integer"
 .Sh SYNOPSIS
 .In stdlib.h
@@ -29,26 +31,33 @@
 .Fa "long long maxval"
 .Fa "const char **errstr"
 .Fc
+.Ft long long
+.Fo strtonumx
+.Fa "const char *nptr"
+.Fa "long long minval"
+.Fa "long long maxval"
+.Fa "const char **errstr"
+.Fa "int base"
+.Fc
 .Sh DESCRIPTION
 The
 .Fn strtonum
-function converts the string in
+and
+.Fn strtonumx
+functions convert the string in
 .Fa nptr
 to a
 .Vt "long long"
 value.
-The
-.Fn strtonum
-function was designed to facilitate safe, robust programming
-and overcome the shortcomings of the
+These functions were designed to facilitate safe, robust programming and
+overcome the shortcomings of the
 .Xr atoi 3
 and
 .Xr strtol 3
 family of interfaces.
 .Pp
 The string may begin with an arbitrary amount of whitespace
-(as determined by
-.Xr isspace 3 )
+.Pq as determined by Xr isspace 3
 followed by a single optional
 .Ql +
 or
@@ -57,7 +66,10 @@ sign.
 .Pp
 The remainder of the string is converted to a
 .Vt "long long"
-value according to base 10.
+value according to base 10
+.Pq for Fn strtonum
+or the provided base
+.Pq for Fn strtonumx .
 .Pp
 The value obtained is then checked against the provided
 .Fa minval
@@ -68,13 +80,30 @@ If
 .Fa errstr
 is non-null,
 .Fn strtonum
-stores an error string in
+and
+.Fn strtonumx
+store an error string in
 .Fa *errstr
 indicating the failure.
+.Pp
+For
+.Fn strtonumx
+the value of
+.Ar base
+is interpreted in the same way as described in
+.Xr strtoll 3 .
+In particular, if the value of
+.Ar base
+is 0, then the expected form of
+.Ar nptr
+is that of a decimal constant, octal constant or hexadecimal constant, any of
+which may be preceded by a + or - sign.
 .Sh RETURN VALUES
 The
 .Fn strtonum
-function returns the result of the conversion,
+and
+.Fn strtonumx
+functions return the result of the conversion,
 unless the value would exceed the provided bounds or is invalid.
 On error, 0 is returned,
 .Va errno
@@ -90,6 +119,8 @@ a successful return of 0 from an error.
 .Sh EXAMPLES
 Using
 .Fn strtonum
+and
+.Fn strtonumx
 correctly is meant to be simpler than the alternative functions.
 .Bd -literal -offset indent
 int iterations;
@@ -107,7 +138,10 @@ The above example will guarantee that the value of 
iterations is between
 .It Bq Er ERANGE
 The given string was out of range.
 .It Bq Er EINVAL
-The given string did not consist solely of digit characters.
+The given string did not consist solely of digit characters
+.Pq for Fn strtonum ,
+or characters which are valid in the given base
+.Pq for Fn strtonumx .
 .It Bq Er EINVAL
 The supplied
 .Fa minval
@@ -120,12 +154,15 @@ If an error occurs,
 will be set to one of the following strings:
 .Pp
 .Bl -tag -width ".Li too large" -compact
-.It Li "too large"
+.It Qq too large
 The result was larger than the provided maximum value.
-.It Li "too small"
+.It Qq too small
 The result was smaller than the provided minimum value.
-.It Li invalid
-The string did not consist solely of digit characters.
+.It Qq invalid
+The string did not consist solely of characters valid in the specified base
+.Pq or base 10 for Fn strtonum .
+.It Qq unparsable; invalid base specified
+The specified base was outside the permitted range.
 .El
 .Sh SEE ALSO
 .Xr atof 3 ,
@@ -152,3 +189,6 @@ The
 .Fn strtonum
 function first appeared in
 .Ox 3.6 .
+The
+.Fn strtonumx
+function first appeared in illumos in 2023.
diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c
index 0d0715bf39c1..44c27d6af3ad 100644
--- a/lib/libc/stdlib/strtonum.c
+++ b/lib/libc/stdlib/strtonum.c
@@ -2,6 +2,8 @@
  * Copyright (c) 2004 Ted Unangst and Todd Miller
  * All rights reserved.
  *
+ * Copyright 2023 Oxide Computer Company
+ *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * copyright notice and this permission notice appear in all copies.
@@ -24,10 +26,13 @@
 #define        INVALID         1
 #define        TOOSMALL        2
 #define        TOOLARGE        3
+#define        BADBASE         4
+
+#define        MBASE           ('z' - 'a' + 1 + 10)
 
 long long
-strtonum(const char *numstr, long long minval, long long maxval,
-    const char **errstrp)
+strtonumx(const char *numstr, long long minval, long long maxval,
+    const char **errstrp, int base)
 {
        long long ll = 0;
        int error = 0;
@@ -35,20 +40,23 @@ strtonum(const char *numstr, long long minval, long long 
maxval,
        struct errval {
                const char *errstr;
                int err;
-       } ev[4] = {
+       } ev[5] = {
                { NULL,         0 },
                { "invalid",    EINVAL },
                { "too small",  ERANGE },
                { "too large",  ERANGE },
+               { "unparsable; invalid base specified", EINVAL },
        };
 
        ev[0].err = errno;
        errno = 0;
        if (minval > maxval) {
                error = INVALID;
+       } else if (base < 0 || base > MBASE || base == 1) {
+               error = BADBASE;
        } else {
-               ll = strtoll(numstr, &ep, 10);
-               if (errno == EINVAL || numstr == ep || *ep != '\0')
+               ll = strtoll(numstr, &ep, base);
+               if (numstr == ep || *ep != '\0')
                        error = INVALID;
                else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
                        error = TOOSMALL;
@@ -58,8 +66,15 @@ strtonum(const char *numstr, long long minval, long long 
maxval,
        if (errstrp != NULL)
                *errstrp = ev[error].errstr;
        errno = ev[error].err;
-       if (error)
+       if (error != 0)
                ll = 0;
 
        return (ll);
 }
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+       return (strtonumx(numstr, minval, maxval, errstrp, 10));
+}

Reply via email to