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
This commit is contained in:
committed by
Joseph Mingrone
parent
73c921ef1d
commit
6a6f230d31
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -134,6 +134,7 @@ FBSD_1.8 {
|
||||
FBSD_1.9 {
|
||||
memalignment;
|
||||
recallocarray;
|
||||
strtonumx;
|
||||
tdestroy;
|
||||
};
|
||||
|
||||
|
||||
+57
-17
@@ -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.
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user