summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorfenner <fenner@FreeBSD.org>2001-11-28 03:37:06 +0000
committerfenner <fenner@FreeBSD.org>2001-11-28 03:37:06 +0000
commitb624c038d2a72e52fe1687526f6906262bdb5fd8 (patch)
tree608b64a0bc5428948db687a4ef79785375bc92ce /lib
parentb52e8932fd4a292e39ab71a67b70dddebc5dc547 (diff)
downloadFreeBSD-src-b624c038d2a72e52fe1687526f6906262bdb5fd8.zip
FreeBSD-src-b624c038d2a72e52fe1687526f6906262bdb5fd8.tar.gz
Implement strtoimax() and strtoumax()
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/stdlib/Makefile.inc16
-rw-r--r--lib/libc/stdlib/strtoimax.c142
-rw-r--r--lib/libc/stdlib/strtol.362
-rw-r--r--lib/libc/stdlib/strtoul.339
-rw-r--r--lib/libc/stdlib/strtoumax.c120
5 files changed, 337 insertions, 42 deletions
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index d93c20e..ed88554 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -5,12 +5,12 @@
.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/stdlib ${.CURDIR}/../libc/stdlib
MISRCS+=abort.c abs.c atexit.c atof.c atoi.c atol.c atoll.c \
- bsearch.c calloc.c div.c \
- exit.c getenv.c getopt.c getsubopt.c hcreate.c heapsort.c \
- imaxabs.c imaxdiv.c labs.c ldiv.c llabs.c lldiv.c \
- malloc.c merge.c putenv.c qsort.c radixsort.c rand.c random.c \
- reallocf.c realpath.c setenv.c strfmon.c strhash.c strtol.c \
- strtoll.c strtoq.c strtoul.c strtoull.c strtouq.c system.c \
+ bsearch.c calloc.c div.c exit.c getenv.c getopt.c \
+ getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c \
+ labs.c ldiv.c llabs.c lldiv.c malloc.c merge.c putenv.c \
+ qsort.c radixsort.c rand.c random.c reallocf.c realpath.c \
+ setenv.c strfmon.c strhash.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
.if ${MACHINE_ARCH} == "alpha"
@@ -41,8 +41,8 @@ MLINKS+=qsort.3 heapsort.3 qsort.3 mergesort.3
MLINKS+=rand.3 rand_r.3 rand.3 srand.3 rand.3 sranddev.3
MLINKS+=random.3 initstate.3 random.3 setstate.3 random.3 srandom.3 \
random.3 srandomdev.3
-MLINKS+=strtol.3 strtoll.3 strtol.3 strtoq.3
-MLINKS+=strtoul.3 strtoull.3 strtoul.3 strtouq.3
+MLINKS+=strtol.3 strtoll.3 strtol.3 strtoq.3 strtol.3 strtoimax.3
+MLINKS+=strtoul.3 strtoull.3 strtoul.3 strtouq.3 strtoul.3 strtoumax.3
MLINKS+=malloc.3 calloc.3 malloc.3 free.3 malloc.3 realloc.3 malloc.3 reallocf.3
MLINKS+=tsearch.3 tdelete.3 tsearch.3 tfind.3 tsearch.3 twalk.3
.endif
diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c
new file mode 100644
index 0000000..f8ff09b
--- /dev/null
+++ b/lib/libc/stdlib/strtoimax.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtol.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+/*
+ * Convert a string to a intmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+intmax_t
+strtoimax(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ int base;
+{
+ const char *s;
+ uintmax_t acc;
+ unsigned char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for intmax_t is
+ * [-9223372036854775808..9223372036854775807] and the input base
+ * is 10, cutoff will be set to 922337203685477580 and cutlim to
+ * either 7 (neg==0) or 8 (neg==1), meaning that if we have
+ * accumulated a value > 922337203685477580, or equal but the
+ * next digit is > 7 (or 8), the number is too big, and we will
+ * return a range error.
+ *
+ * Set 'any' if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX
+ : INTMAX_MAX;
+ cutlim = cutoff % base;
+ cutoff /= base;
+ for ( ; ; c = *s++) {
+ if (isxdigit(c))
+ c = digittoint(c);
+ else if (isascii(c) && isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? INTMAX_MIN : INTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
diff --git a/lib/libc/stdlib/strtol.3 b/lib/libc/stdlib/strtol.3
index d01d8ee..c5eb2c8 100644
--- a/lib/libc/stdlib/strtol.3
+++ b/lib/libc/stdlib/strtol.3
@@ -40,8 +40,8 @@
.Dt STRTOL 3
.Os
.Sh NAME
-.Nm strtol , strtoll , strtoq
-.Nd "convert a string value to a long, long long, or quad_t integer"
+.Nm strtol , strtoll , strtoimax , strtoq
+.Nd "convert a string value to a long, long long, intmax_t or quad_t integer"
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -51,6 +51,9 @@
.Fn strtol "const char *nptr" "char **endptr" "int base"
.Ft long long
.Fn strtoll "const char *nptr" "char **endptr" "int base"
+.In inttypes.h
+.Ft intmax_t
+.Fn strtoimax "const char *nptr" "char **endptr" "int base"
.In sys/types.h
.In stdlib.h
.In limits.h
@@ -74,6 +77,14 @@ to a
.Em long long
value.
The
+.Fn strtoimax
+function
+converts the string in
+.Fa nptr
+to an
+.Em intmax_t
+value.
+The
.Fn strtoq
function
converts the string in
@@ -107,7 +118,11 @@ is taken as 10 (decimal) unless the next character is
in which case it is taken as 8 (octal).
.Pp
The remainder of the string is converted to a
-.Em long
+.Em long ,
+.Em long long ,
+.Em intmax_t
+or
+.Em quad_t
value in the obvious manner,
stopping at the first character which is not a valid digit
in the given base.
@@ -143,9 +158,11 @@ is
on return, the entire string was valid.)
.Sh RETURN VALUES
The
-.Fn strtol
+.Fn strtol ,
+.Fn strtoll ,
+.Fn strtoimax
or
-.Fn strtoll
+.Fn strtoq
function
returns the result of the conversion,
unless the value would underflow or overflow.
@@ -154,26 +171,19 @@ the global variable
.Va errno
is set to
.Er EINVAL .
-If an underflow occurs,
-.Fn strtol
-returns
-.Dv LONG_MIN .
-If an overflow occurs,
-.Fn strtol
-returns
-.Dv LONG_MAX .
-If an underflow occurs,
-.Fn strtoll
-returns
-.Dv LLONG_MIN .
-If an overflow occurs,
-.Fn strtoll
-returns
-.Dv LLONG_MAX .
-In all cases,
+If an overflow or underflow occurs,
.Va errno
is set to
-.Er ERANGE .
+.Er ERANGE
+and the function return value is clamped according
+to the following table.
+.Bl -column -offset indent ".Fn strtoimax" ".Sy overflow" ".Sy underflow"
+.It Sy Function Ta Sy overflow Ta Sy underflow
+.It Fn strtol Ta Dv LONG_MIN Ta Dv LONG_MAX
+.It Fn strtoll Ta Dv LLONG_MIN Ta Dv LLONG_MAX
+.It Fn strtoimax Ta Dv INTMAX_MIN Ta Dv INTMAX_MAX
+.It Fn strtoq Ta Dv LLONG_MIN Ta Dv LLONG_MAX
+.El
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINVAL
@@ -198,8 +208,10 @@ conforms to
.St -isoC .
The
.Fn strtoll
-function
-conforms to
+and
+.Fn strtoimax
+functions
+conform to
.St -isoC-99 .
The
.Bx
diff --git a/lib/libc/stdlib/strtoul.3 b/lib/libc/stdlib/strtoul.3
index ff60016..00be953 100644
--- a/lib/libc/stdlib/strtoul.3
+++ b/lib/libc/stdlib/strtoul.3
@@ -40,8 +40,8 @@
.Dt STRTOUL 3
.Os
.Sh NAME
-.Nm strtoul , strtoull , strtouq
-.Nd "convert a string to an unsigned long, unsigned long long, or uquad_t integer"
+.Nm strtoul , strtoull , strtoumax , strtouq
+.Nd "convert a string to an unsigned long, unsigned long long, uintmax_t, or uquad_t integer"
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -51,6 +51,9 @@
.Fn strtoul "const char *nptr" "char **endptr" "int base"
.Ft unsigned long long
.Fn strtoull "const char *nptr" "char **endptr" "int base"
+.In inttypes.h
+.Ft uintmax_t
+.Fn strtoumax "const char *nptr" "char **endptr" "int base"
.In sys/types.h
.In stdlib.h
.In limits.h
@@ -74,6 +77,14 @@ to an
.Em unsigned long long
value.
The
+.Fn strtoumax
+function
+converts the string in
+.Fa nptr
+to an
+.Em uintmax_t
+value.
+The
.Fn strtouq
function
converts the string in
@@ -144,9 +155,11 @@ is
on return, the entire string was valid.)
.Sh RETURN VALUES
The
-.Fn strtoul
+.Fn strtoul ,
+.Fn strtoull ,
+.Fn strtoumax
or
-.Fn strtoull
+.Fn strtouq
function
returns either the result of the conversion
or, if there was a leading minus sign,
@@ -155,10 +168,16 @@ unless the original (non-negated) value would overflow;
in the latter case,
.Fn strtoul
returns
-.Dv ULONG_MAX
-and
+.Dv ULONG_MAX ,
.Fn strtoull
returns
+.Dv ULLONG_MAX ,
+.Fn strtoumax
+returns
+.Dv UINTMAX_MAX
+and
+.Fn strtouq
+returns
.Dv ULLONG_MAX .
In all cases,
.Va errno
@@ -189,10 +208,12 @@ conforms to
.St -isoC .
The
.Fn strtoull
-function
-conforms to
+and
+.Fn strtoumax
+functions
+conform to
.St -isoC-99 .
The
.Bx
-.Fn strtoq
+.Fn strtouq
function is deprecated.
diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c
new file mode 100644
index 0000000..ea59245
--- /dev/null
+++ b/lib/libc/stdlib/strtoumax.c
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "from @(#)strtoul.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+/*
+ * Convert a string to a uintmax_t integer.
+ *
+ * Assumes that the upper and lower case
+ * alphabets and digits are each contiguous.
+ */
+uintmax_t
+strtoumax(nptr, endptr, base)
+ const char *nptr;
+ char **endptr;
+ int base;
+{
+ const char *s;
+ uintmax_t acc;
+ unsigned char c;
+ uintmax_t cutoff;
+ int neg, any, cutlim;
+
+ /*
+ * See strtoimax for comments as to the logic used.
+ */
+ s = nptr;
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else {
+ neg = 0;
+ if (c == '+')
+ c = *s++;
+ }
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ acc = any = 0;
+ if (base < 2 || base > 36)
+ goto noconv;
+
+ cutoff = UINTMAX_MAX / base;
+ cutlim = UINTMAX_MAX % base;
+ for ( ; ; c = *s++) {
+ if (isxdigit(c))
+ c = digittoint(c);
+ else if (isascii(c) && isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = UINTMAX_MAX;
+ errno = ERANGE;
+ } else if (!any) {
+noconv:
+ errno = EINVAL;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != NULL)
+ *endptr = (char *)(any ? s - 1 : nptr);
+ return (acc);
+}
OpenPOWER on IntegriCloud