From c74dfa2faf6063f8648801f4528074ac770b779f Mon Sep 17 00:00:00 2001 From: Andre Oppermann Date: Tue, 14 Mar 2006 16:57:30 +0000 Subject: [PATCH] Import of OpenBSD's strtonum(3) which is a nicer version of strtoll(3) providing proper error checking and other improvements. Obtained from: OpenBSD Requested by: flz (to port Open[BGP|OSPF]D) MFC after: 3 days --- include/stdlib.h | 2 + lib/libc/stdlib/Makefile.inc | 7 +- lib/libc/stdlib/Symbol.map | 1 + lib/libc/stdlib/strtonum.3 | 154 +++++++++++++++++++++++++++++++++++ lib/libc/stdlib/strtonum.c | 68 ++++++++++++++++ 5 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 lib/libc/stdlib/strtonum.3 create mode 100644 lib/libc/stdlib/strtonum.c diff --git a/include/stdlib.h b/include/stdlib.h index 8953409fac97..98fe8b7756c6 100644 --- a/include/stdlib.h +++ b/include/stdlib.h @@ -271,6 +271,8 @@ int sradixsort(const unsigned char **, int, const unsigned char *, unsigned); void sranddev(void); void srandomdev(void); +long long + strtonum(const char *, long long, long long, const char **); /* Deprecated interfaces, to be removed in FreeBSD 6.0. */ __int64_t diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc index 29bd49287bc6..27eee7d9f8b8 100644 --- a/lib/libc/stdlib/Makefile.inc +++ b/lib/libc/stdlib/Makefile.inc @@ -10,8 +10,8 @@ MISRCS+=_Exit.c a64l.c abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \ insque.c l64a.c labs.c ldiv.c llabs.c lldiv.c lsearch.c malloc.c \ merge.c putenv.c qsort.c qsort_r.c radixsort.c rand.c random.c \ reallocf.c realpath.c remque.c setenv.c strfmon.c strtoimax.c \ - strtol.c strtoll.c strtoq.c strtoul.c strtoull.c strtoumax.c strtouq.c \ - system.c tdelete.c tfind.c tsearch.c twalk.c + strtol.c strtoll.c strtoq.c strtoul.c strtonum.c strtoull.c strtoumax.c \ + strtouq.c system.c tdelete.c tfind.c tsearch.c twalk.c SYM_MAPS+= ${.CURDIR}/stdlib/Symbol.map @@ -25,7 +25,8 @@ MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.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 qsort.3 radixsort.3 \ rand.3 random.3 \ - realpath.3 strfmon.3 strtod.3 strtol.3 strtoul.3 system.3 tsearch.3 + realpath.3 strfmon.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 \ + tsearch.3 MLINKS+=a64l.3 l64a.3 a64l.3 l64a_r.3 MLINKS+=atol.3 atoll.3 diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map index 2fd2582ed4fe..2459fe255db2 100644 --- a/lib/libc/stdlib/Symbol.map +++ b/lib/libc/stdlib/Symbol.map @@ -77,6 +77,7 @@ FBSD_1.0 { strtoimax; strtol; strtoll; + strtonum; strtoq; strtoul; strtoull; diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3 new file mode 100644 index 000000000000..73af822cee6e --- /dev/null +++ b/lib/libc/stdlib/strtonum.3 @@ -0,0 +1,154 @@ +.\" Copyright (c) 2004 Ted Unangst +.\" +.\" 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. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $OpenBSD: strtonum.3,v 1.12 2005/10/26 11:37:58 jmc Exp $ +.\" $FreeBSD$ +.\" +.Dd April 29, 2004 +.Dt STRTONUM 3 +.Os +.Sh NAME +.Nm strtonum +.Nd "reliably convert string value to an integer" +.Sh SYNOPSIS +.Fd #include +.Fd #include +.Ft long long +.Fo strtonum +.Fa "const char *nptr" +.Fa "long long minval" +.Fa "long long maxval" +.Fa "const char **errstr" +.Fc +.Sh DESCRIPTION +The +.Fn strtonum +function converts the string in +.Fa nptr +to a +.Li long long +value. +The +.Fn strtonum +function was 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 ) +followed by a single optional +.Ql + +or +.Ql - +sign. +.Pp +The remainder of the string is converted to a +.Li long long +value according to base 10. +.Pp +The value obtained is then checked against the provided +.Fa minval +and +.Fa maxval +bounds. +If +.Fa errstr +is non-null, +.Fn strtonum +stores an error string in +.Fa *errstr +indicating the failure. +.Sh RETURN VALUES +The +.Fn strtonum +function returns the result of the conversion, +unless the value would exceed the provided bounds or is invalid. +On error, 0 is returned, +.Va errno +is set, and +.Fa errstr +will point to an error message. +.Fa *errstr +will be set to +.Dv NULL +on success; +this fact can be used to differentiate +a successful return of 0 from an error. +.Sh EXAMPLES +Using +.Fn strtonum +correctly is meant to be simpler than the alternative functions. +.Bd -literal -offset indent +int iterations; +const char *errstr; + +iterations = strtonum(optarg, 1, 64, &errstr); +if (errstr) + errx(1, "number of iterations is %s: %s", errstr, optarg); +.Ed +.Pp +The above example will guarantee that the value of iterations is between +1 and 64 (inclusive). +.Sh ERRORS +.Bl -tag -width Er +.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. +.It Bq Er EINVAL +.Ar minval +was larger than +.Ar maxval . +.El +.Pp +If an error occurs, +.Fa errstr +will be set to one of the following strings: +.Pp +.Bl -tag -width "too largeXX" -compact +.It too large +The result was larger than the provided maximum value. +.It too small +The result was smaller than the provided minimum value. +.It invalid +The string did not consist solely of digit characters. +.El +.Sh SEE ALSO +.Xr atof 3 , +.Xr atoi 3 , +.Xr atol 3 , +.Xr atoll 3 , +.Xr sscanf 3 , +.Xr strtod 3 , +.Xr strtol 3 , +.Xr strtoul 3 +.Sh STANDARDS +.Fn strtonum +is an +.Ox +extension. +The existing alternatives, such as +.Xr atoi 3 +and +.Xr strtol 3 , +are either impossible or difficult to use safely. +.Sh HISTORY +The +.Fn strtonum +function first appeared in +.Ox 3.6 . diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c new file mode 100644 index 000000000000..0bf29c37aaad --- /dev/null +++ b/lib/libc/stdlib/strtonum.c @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * 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. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + char *ep; + int error = 0; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) + error = INVALID; + else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +}