diff options
| author | Andrey A. Chernov <ache@FreeBSD.org> | 2001-09-04 16:39:11 +0000 | 
|---|---|---|
| committer | Andrey A. Chernov <ache@FreeBSD.org> | 2001-09-04 16:39:11 +0000 | 
| commit | 4e6b1570629ce55fb6038c1d7ea2400c0a47a8a4 (patch) | |
| tree | 7bcee0477a1db7819fa0b437d2bfb0714a1119df /lib | |
| parent | d6669bbcc23dde3f89519a5c2c10ca43fe24d6b7 (diff) | |
Notes
Diffstat (limited to 'lib')
| -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 00a65c58c433..1ee6add80fa8 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 18e39729929f..99c895c49c5d 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 b7a75903e5e7..08d4f0538c88 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 ee68b4e56a33..38bfd34e9624 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 6f89af8e444e..cf893ee876ed 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 304150a546a4..820c3ab271b2 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 3e7c943fc7f1..ac0935e06118 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 926000e6e7f4..3c3e74a32d13 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 | 
