Add strotonum(3) into the !ANSI_SOURCE && !_POSIX_SOURCE && !__STRICT_ANSI
authorJoerg Sonnenberger <joerg@dragonflybsd.org>
Sun, 15 Aug 2004 16:01:11 +0000 (16:01 +0000)
committerJoerg Sonnenberger <joerg@dragonflybsd.org>
Sun, 15 Aug 2004 16:01:11 +0000 (16:01 +0000)
part of stdlib.h.

strtonum simplifies string conversion by allowing automatic boundary checks.

Submitted-by: Andre Nathan <andre@digirati.com.br>
Obtained-from: OpenBSD

include/stdlib.h
lib/libc/stdlib/Makefile.inc
lib/libc/stdlib/strtonum.3 [new file with mode: 0644]
lib/libc/stdlib/strtonum.c [new file with mode: 0644]

index f8640bd..f1313e0 100644 (file)
@@ -32,7 +32,7 @@
  *
  *     @(#)stdlib.h    8.5 (Berkeley) 5/19/95
  * $FreeBSD: src/include/stdlib.h,v 1.16.2.5 2002/12/13 01:34:00 tjr Exp $
- * $DragonFly: src/include/stdlib.h,v 1.7 2004/02/26 13:58:25 joerg Exp $
+ * $DragonFly: src/include/stdlib.h,v 1.8 2004/08/15 16:01:11 joerg Exp $
  */
 
 #ifndef _STDLIB_H_
@@ -178,6 +178,11 @@ char       *user_from_uid(unsigned long, int);
 #ifndef __STRICT_ANSI__
 __int64_t      strtoq(const char *, char **, int);
 __uint64_t     strtouq(const char *, char **, int);
+
+#ifdef __LONG_LONG_SUPPORTED
+unsigned long long strtonum(const char *, long long, unsigned long long,
+                           const char **);
+#endif
 #endif
 void    unsetenv(const char *);
 #endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */
index 7aafbd0..aabda33 100644 (file)
@@ -1,6 +1,6 @@
 #      from @(#)Makefile.inc   8.3 (Berkeley) 2/4/95
 # $FreeBSD: src/lib/libc/stdlib/Makefile.inc,v 1.19.2.4 2001/10/02 11:15:38 ru Exp $
-# $DragonFly: src/lib/libc/stdlib/Makefile.inc,v 1.6 2004/02/26 14:06:13 joerg Exp $
+# $DragonFly: src/lib/libc/stdlib/Makefile.inc,v 1.7 2004/08/15 16:01:11 joerg Exp $
 
 # machine-independent stdlib sources
 .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/stdlib ${.CURDIR}/../libc/stdlib
@@ -8,7 +8,7 @@
 MISRCS+=abort.c abs.c atexit.c atof.c atoi.c atol.c bsearch.c calloc.c div.c \
        exit.c getenv.c getopt.c getopt_long.c getsubopt.c hcreate.c heapsort.c \
        labs.c ldiv.c malloc.c merge.c putenv.c qsort.c radixsort.c rand.c \
-       random.c reallocf.c realpath.c setenv.c strtol.c strtoll.c \
+       random.c reallocf.c realpath.c setenv.c strtol.c strtoll.c strtonum.c \
        strtoq.c strtoul.c strtoull.c strtouq.c system.c tdelete.c tfind.c \
        tsearch.c twalk.c
 
@@ -30,7 +30,7 @@ SRCS+=        strtod.c
 MAN+=  abort.3 abs.3 alloca.3 atexit.3 atof.3 atoi.3 atol.3 bsearch.3 \
        div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 hcreate.3 \
        labs.3 ldiv.3 malloc.3 memory.3 qsort.3 radixsort.3 rand.3 random.3 \
-       realpath.3 strtod.3 strtol.3 strtoul.3 system.3 tsearch.3
+       realpath.3 strtod.3 strtol.3 strtonum.3 strtoul.3 system.3 tsearch.3
 
 MLINKS+=getenv.3 putenv.3 getenv.3 setenv.3 getenv.3 unsetenv.3
 MLINKS+=hcreate.3 hdestroy.3 hcreate.3 hsearch.3
diff --git a/lib/libc/stdlib/strtonum.3 b/lib/libc/stdlib/strtonum.3
new file mode 100644 (file)
index 0000000..0eb6d7c
--- /dev/null
@@ -0,0 +1,135 @@
+.\" $OpenBSD: strtonum.3,v 1.5 2004/05/06 06:19:01 tedu Exp $
+.\" $DragonFly: src/lib/libc/stdlib/strtonum.3,v 1.1 2004/08/15 16:01:11 joerg Exp $ 
+.\"
+.\" 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.
+.\"
+.Dd July 25, 2004
+.Dt STRTONUM 3
+.Os
+.Sh NAME
+.Nm strtonum
+.Nd "reliably convert string value to an integer"
+.Sh SYNOPSIS
+.Fd #include <stdlib.h>
+.Fd #include <limits.h>
+.Ft unsigned long long
+.Fo strtonum
+.Fa "const char *nptr"
+.Fa "long long minval"
+.Fa "unsigned long long maxval"
+.Fa "const char **errstr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn strtonum
+function converts the string in
+.Fa nptr
+to an
+.Li unsigned long long
+value.
+Negative values may be obtained by casting the result.
+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 an
+.Li unsigned 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 and
+.Fa errstr
+will point to an error message.
+.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.
+.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.
+.El
+.Pp
+If an error occurs, errstr will be set to one of the following strings.
+.Bl -tag -width "too large"
+.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
+was originally implemented as an extension on
+.Ox .
+
+The existing alternatives, such as
+.Xr atoi 3
+and
+.Xr strtol 3
+are either impossible or difficult to use safely.
diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c
new file mode 100644 (file)
index 0000000..4f5c634
--- /dev/null
@@ -0,0 +1,84 @@
+/* $OpenBSD: strtonum.c,v 1.5 2004/07/16 18:36:05 otto Exp $ */
+/* $DragonFly: src/lib/libc/stdlib/strtonum.c,v 1.1 2004/08/15 16:01:11 joerg Exp $ */
+/*
+ * 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.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define INVALID        1
+#define TOOSMALL       2
+#define TOOLARGE       3
+
+static struct errval {
+       const char *errstr;
+       int err;
+} ev[4] = {
+       { NULL,         0 },
+       { "invalid",    EINVAL },
+       { "too small",  ERANGE },
+       { "too large",  ERANGE },
+};
+
+unsigned long long
+strtonum(const char *numstr, long long minval, unsigned long long umaxval,
+        const char **errstrp)
+{
+       long long ll, maxval = (long long)umaxval;
+       unsigned long long ull = 0;
+       char *ep;
+       int error = 0;
+
+       ev[0].err = errno;
+       errno = 0;
+       if (umaxval > LLONG_MAX ) {
+               if (minval < 0) {
+                       error = INVALID;
+                       goto done;
+               }
+               ull = strtoull(numstr, &ep, 10);
+               if (numstr == ep || *ep != '\0')
+                       error = INVALID;
+               else if ((ull == ULLONG_MAX && errno == ERANGE) ||
+                        ull > umaxval)
+                       error = TOOLARGE;
+               else if (ull < minval)
+                       error = TOOSMALL;
+       } else {
+               if (minval > maxval || maxval < minval) {
+                       error = INVALID;
+                       goto done;
+               }
+               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;
+               ull = (unsigned long long)ll;
+       }
+done:
+       if (errstrp != NULL)
+               *errstrp = ev[error].errstr;
+       errno = ev[error].err;
+       if (error)
+               ull = 0;
+
+       return(ull);
+}