diff options
author | fenner <fenner@FreeBSD.org> | 2001-11-28 03:37:06 +0000 |
---|---|---|
committer | fenner <fenner@FreeBSD.org> | 2001-11-28 03:37:06 +0000 |
commit | b624c038d2a72e52fe1687526f6906262bdb5fd8 (patch) | |
tree | 608b64a0bc5428948db687a4ef79785375bc92ce | |
parent | b52e8932fd4a292e39ab71a67b70dddebc5dc547 (diff) | |
download | FreeBSD-src-b624c038d2a72e52fe1687526f6906262bdb5fd8.zip FreeBSD-src-b624c038d2a72e52fe1687526f6906262bdb5fd8.tar.gz |
Implement strtoimax() and strtoumax()
-rw-r--r-- | lib/libc/stdlib/Makefile.inc | 16 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoimax.c | 142 | ||||
-rw-r--r-- | lib/libc/stdlib/strtol.3 | 62 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoul.3 | 39 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoumax.c | 120 |
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); +} |