diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | Versions | 4 | ||||
-rw-r--r-- | include/bsd/stdlib.h | 3 | ||||
-rw-r--r-- | man/strtonum.3 | 156 | ||||
-rw-r--r-- | src/strtonum.c | 68 |
5 files changed, 233 insertions, 0 deletions
@@ -31,6 +31,7 @@ LIB_SRCS := \ hash/md5.c hash/md5hl.c \ setmode.c \ strmode.c \ + strtonum.c \ strlcat.c strlcpy.c \ fmtcheck.c \ nlist.c \ @@ -62,6 +63,7 @@ LIB_MANS := \ arc4random.3 \ arc4random_addrandom.3 \ arc4random_stir.3 \ + strtonum.3 \ strlcpy.3 \ strlcat.3 \ fgetln.3 \ @@ -42,3 +42,7 @@ LIBBSD_0.1 { nlist; } LIBBSD_0.0; +LIBBSD_0.2 { + strtonum; +} LIBBSD_0.1; + diff --git a/include/bsd/stdlib.h b/include/bsd/stdlib.h index 75f994a..3e1fe83 100644 --- a/include/bsd/stdlib.h +++ b/include/bsd/stdlib.h @@ -47,6 +47,9 @@ int heapsort (void *, size_t, size_t, int (*)(const void *, const void *)); mode_t getmode(const void *set, mode_t mode); void *setmode(const char *mode_str); + +long long strtonum(const char *nptr, long long minval, long long maxval, + const char **errstr); __END_DECLS #endif diff --git a/man/strtonum.3 b/man/strtonum.3 new file mode 100644 index 0000000..90f0b57 --- /dev/null +++ b/man/strtonum.3 @@ -0,0 +1,156 @@ +.\" 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 +.In stdlib.h +.In limits.h +.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 +.Vt "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 +.Vt "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. +On success, +.Fa *errstr +will be set to +.Dv NULL ; +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 +The supplied +.Fa minval +was larger than +.Fa maxval . +.El +.Pp +If an error occurs, +.Fa errstr +will be set to one of the following strings: +.Pp +.Bl -tag -width ".Li too large" -compact +.It Li "too large" +The result was larger than the provided maximum value. +.It Li "too small" +The result was smaller than the provided minimum value. +.It Li 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 +The +.Fn strtonum +function is a +.Bx +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/src/strtonum.c b/src/strtonum.c new file mode 100644 index 0000000..6dccd97 --- /dev/null +++ b/src/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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#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 (errno == EINVAL || 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); +} |