diff options
Diffstat (limited to 'lib/libc/stdlib')
-rw-r--r-- | lib/libc/stdlib/strtol.3 | 17 | ||||
-rw-r--r-- | lib/libc/stdlib/strtol.c | 38 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoll.c | 23 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoq.c | 2 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoul.3 | 23 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoul.c | 34 | ||||
-rw-r--r-- | lib/libc/stdlib/strtoull.c | 24 | ||||
-rw-r--r-- | lib/libc/stdlib/strtouq.c | 2 |
8 files changed, 105 insertions, 58 deletions
diff --git a/lib/libc/stdlib/strtol.3 b/lib/libc/stdlib/strtol.3 index 00a65c5..1ee6add 100644 --- a/lib/libc/stdlib/strtol.3 +++ b/lib/libc/stdlib/strtol.3 @@ -144,9 +144,16 @@ on return, the entire string was valid.) .Sh RETURN VALUES The .Fn strtol +or +.Fn strtoll function returns the result of the conversion, unless the value would underflow or overflow. +If no conversion could be performed, 0 shall be returned and +.Va errno +will be +set to +.Er EINVAL . If an underflow occurs, .Fn strtol returns @@ -155,11 +162,6 @@ If an overflow occurs, .Fn strtol returns .Dv LONG_MAX . -The -.Fn strtoll -function -returns the result of the conversion, -unless the value would underflow or overflow. If an underflow occurs, .Fn strtoll returns @@ -174,6 +176,9 @@ is set to .Er ERANGE . .Sh ERRORS .Bl -tag -width Er +.It Bq Er EINVAL +The value of base is not supported or +no conversion could be performed. .It Bq Er ERANGE The given string was out of range; the value converted has been clamped. .El @@ -198,5 +203,3 @@ The .Bx .Fn strtoq function is deprecated. -.Sh BUGS -Ignores the current locale. diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c index 18e3972..99c895c 100644 --- a/lib/libc/stdlib/strtol.c +++ b/lib/libc/stdlib/strtol.c @@ -35,6 +35,11 @@ static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ +#ifndef lint +static const char rcsid[] = +"$FreeBSD$"; +#endif + #include <limits.h> #include <ctype.h> #include <errno.h> @@ -44,7 +49,7 @@ static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; /* * Convert a string to a long integer. * - * Ignores `locale' stuff. Assumes that the upper and lower case + * Assumes that the upper and lower case * alphabets and digits are each contiguous. */ long @@ -53,25 +58,29 @@ strtol(nptr, endptr, base) char **endptr; register int base; { - register const char *s = nptr; + register const char *s; register unsigned long acc; register unsigned char c; register unsigned long cutoff; - register int neg = 0, any, cutlim; + register 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 if (c == '+') - c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; @@ -80,6 +89,9 @@ strtol(nptr, endptr, base) } if (base == 0) base = c == '0' ? 8 : 10; + any = 0; + if (base < 2 || base > 36) + goto noconv; /* * Compute the cutoff value between legal numbers and illegal @@ -95,13 +107,14 @@ strtol(nptr, endptr, base) * a value > 214748364, 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 + * Set 'any' if any `digits' consumed; make it negative to indicate * overflow. */ - cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; - cutlim = cutoff % (unsigned long)base; - cutoff /= (unsigned long)base; - for (acc = 0, any = 0;; c = *s++) { + cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX + : LONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + for (acc = 0; ; c = *s++) { if (!isascii(c)) break; if (isdigit(c)) @@ -123,9 +136,12 @@ strtol(nptr, endptr, base) if (any < 0) { acc = neg ? LONG_MIN : LONG_MAX; errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; } else if (neg) acc = -acc; - if (endptr != 0) + if (endptr != NULL) *endptr = (char *)(any ? s - 1 : nptr); return (acc); } diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c index b7a7590..08d4f05 100644 --- a/lib/libc/stdlib/strtoll.c +++ b/lib/libc/stdlib/strtoll.c @@ -50,7 +50,7 @@ static const char rcsid[] = /* * Convert a string to a long long integer. * - * Ignores `locale' stuff. Assumes that the upper and lower case + * Assumes that the upper and lower case * alphabets and digits are each contiguous. */ long long @@ -62,7 +62,7 @@ strtoll(nptr, endptr, base) register const char *s; register unsigned long long acc; register unsigned char c; - register unsigned long long qbase, cutoff; + register unsigned long long cutoff; register int neg, any, cutlim; /* @@ -90,6 +90,9 @@ strtoll(nptr, endptr, base) } if (base == 0) base = c == '0' ? 8 : 10; + any = 0; + if (base < 2 || base > 36) + goto noconv; /* * Compute the cutoff value between legal numbers and illegal @@ -106,15 +109,14 @@ strtoll(nptr, endptr, base) * 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 + * Set 'any' if any `digits' consumed; make it negative to indicate * overflow. */ - qbase = (unsigned)base; cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX : LLONG_MAX; - cutlim = cutoff % qbase; - cutoff /= qbase; - for (acc = 0, any = 0;; c = *s++) { + cutlim = cutoff % base; + cutoff /= base; + for (acc = 0; ; c = *s++) { if (!isascii(c)) break; if (isdigit(c)) @@ -129,16 +131,19 @@ strtoll(nptr, endptr, base) any = -1; else { any = 1; - acc *= qbase; + acc *= base; acc += c; } } if (any < 0) { acc = neg ? LLONG_MIN : LLONG_MAX; errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; } else if (neg) acc = -acc; - if (endptr != 0) + if (endptr != NULL) *endptr = (char *)(any ? s - 1 : nptr); return (acc); } diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c index ee68b4e..38bfd34 100644 --- a/lib/libc/stdlib/strtoq.c +++ b/lib/libc/stdlib/strtoq.c @@ -47,7 +47,7 @@ static const char rcsid[] = /* * Convert a string to a quad integer. * - * Ignores `locale' stuff. Assumes that the upper and lower case + * Assumes that the upper and lower case * alphabets and digits are each contiguous. */ quad_t diff --git a/lib/libc/stdlib/strtoul.3 b/lib/libc/stdlib/strtoul.3 index 6f89af8..cf893ee 100644 --- a/lib/libc/stdlib/strtoul.3 +++ b/lib/libc/stdlib/strtoul.3 @@ -145,6 +145,8 @@ on return, the entire string was valid.) .Sh RETURN VALUES The .Fn strtoul +or +.Fn strtoull function returns either the result of the conversion or, if there was a leading minus sign, @@ -153,15 +155,8 @@ unless the original (non-negated) value would overflow; in the latter case, .Fn strtoul returns -.Dv ULONG_MAX . -The -.Fn strtoull -function -returns either the result of the conversion -or, if there was a leading minus sign, -the negation of the result of the conversion, -unless the original (non-negated) value would overflow; -in the latter case, +.Dv ULONG_MAX +and .Fn strtoull returns .Dv ULLONG_MAX . @@ -169,8 +164,16 @@ In all cases, .Va errno is set to .Er ERANGE . +If no conversion could be performed, 0 shall be returned and +.Va errno +will be +set to +.Er EINVAL . .Sh ERRORS .Bl -tag -width Er +.It Bq Er EINVAL +The value of base is not supported or +no conversion could be performed. .It Bq Er ERANGE The given string was out of range; the value converted has been clamped. .El @@ -191,5 +194,3 @@ The .Bx .Fn strtoq function is deprecated. -.Sh BUGS -Ignores the current locale. diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c index 304150a..820c3ab 100644 --- a/lib/libc/stdlib/strtoul.c +++ b/lib/libc/stdlib/strtoul.c @@ -35,6 +35,11 @@ static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; #endif /* LIBC_SCCS and not lint */ +#ifndef lint +static const char rcsid[] = +"$FreeBSD$"; +#endif + #include <limits.h> #include <ctype.h> #include <errno.h> @@ -43,7 +48,7 @@ static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; /* * Convert a string to an unsigned long integer. * - * Ignores `locale' stuff. Assumes that the upper and lower case + * Assumes that the upper and lower case * alphabets and digits are each contiguous. */ unsigned long @@ -52,23 +57,27 @@ strtoul(nptr, endptr, base) char **endptr; register int base; { - register const char *s = nptr; + register const char *s; register unsigned long acc; register unsigned char c; register unsigned long cutoff; - register int neg = 0, any, cutlim; + register int neg, any, cutlim; /* * See strtol for comments as to the logic used. */ + s = nptr; do { c = *s++; } while (isspace(c)); if (c == '-') { neg = 1; c = *s++; - } else if (c == '+') - c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) { c = s[1]; @@ -77,9 +86,13 @@ strtoul(nptr, endptr, base) } if (base == 0) base = c == '0' ? 8 : 10; - cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; - cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; - for (acc = 0, any = 0;; c = *s++) { + any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULONG_MAX / base; + cutlim = ULONG_MAX % base; + for (acc = 0; ; c = *s++) { if (!isascii(c)) break; if (isdigit(c)) @@ -101,9 +114,12 @@ strtoul(nptr, endptr, base) if (any < 0) { acc = ULONG_MAX; errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; } else if (neg) acc = -acc; - if (endptr != 0) + if (endptr != NULL) *endptr = (char *)(any ? s - 1 : nptr); return (acc); } diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c index 3e7c943..ac0935e 100644 --- a/lib/libc/stdlib/strtoull.c +++ b/lib/libc/stdlib/strtoull.c @@ -50,7 +50,7 @@ static const char rcsid[] = /* * Convert a string to an unsigned long long integer. * - * Ignores `locale' stuff. Assumes that the upper and lower case + * Assumes that the upper and lower case * alphabets and digits are each contiguous. */ unsigned long long @@ -59,10 +59,10 @@ strtoull(nptr, endptr, base) char **endptr; register int base; { - register const char *s = nptr; + register const char *s; register unsigned long long acc; register unsigned char c; - register unsigned long long qbase, cutoff; + register unsigned long long cutoff; register int neg, any, cutlim; /* @@ -88,10 +88,13 @@ strtoull(nptr, endptr, base) } if (base == 0) base = c == '0' ? 8 : 10; - qbase = (unsigned)base; - cutoff = (unsigned long long)ULLONG_MAX / qbase; - cutlim = (unsigned long long)ULLONG_MAX % qbase; - for (acc = 0, any = 0;; c = *s++) { + any = 0; + if (base < 2 || base > 36) + goto noconv; + + cutoff = ULLONG_MAX / base; + cutlim = ULLONG_MAX % base; + for (acc = 0; ; c = *s++) { if (!isascii(c)) break; if (isdigit(c)) @@ -106,16 +109,19 @@ strtoull(nptr, endptr, base) any = -1; else { any = 1; - acc *= qbase; + acc *= base; acc += c; } } if (any < 0) { acc = ULLONG_MAX; errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; } else if (neg) acc = -acc; - if (endptr != 0) + if (endptr != NULL) *endptr = (char *)(any ? s - 1 : nptr); return (acc); } diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c index 926000e..3c3e74a 100644 --- a/lib/libc/stdlib/strtouq.c +++ b/lib/libc/stdlib/strtouq.c @@ -47,7 +47,7 @@ static const char rcsid[] = /* * Convert a string to an unsigned quad integer. * - * Ignores `locale' stuff. Assumes that the upper and lower case + * Assumes that the upper and lower case * alphabets and digits are each contiguous. */ u_quad_t |