summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorache <ache@FreeBSD.org>2001-09-04 16:39:11 +0000
committerache <ache@FreeBSD.org>2001-09-04 16:39:11 +0000
commitcd61d5ab4817c934f249aeb6e7b6ccf8ee382706 (patch)
tree7bcee0477a1db7819fa0b437d2bfb0714a1119df /lib
parent29e117e97875b5c4c297c48dae32a287e46e1785 (diff)
downloadFreeBSD-src-cd61d5ab4817c934f249aeb6e7b6ccf8ee382706.zip
FreeBSD-src-cd61d5ab4817c934f249aeb6e7b6ccf8ee382706.tar.gz
Locale *is* used in strto*l*(), at least for isspace(), so remove
'locale not used' statement from comments and BUGS section of manpage. strtol(): fix non-portable 'cutoff' calculation using the same method as in strtoll(). Cleanup 'cutoff' calculation, remove unneded casts. Misc. cleanup to make all functions looks the same. Implement EINVAL reaction per POSIX, document it in manpage, corresponding POSIX example quotes here: ------------------------------------------------ If the subject sequence is empty or does not have the expected form, no conversion is performed; the value of str is stored in the object pointed to by endptr, provided that endptr is not a null pointer. If no conversion could be performed, 0 shall be returned and errno may be set to [EINVAL]. [EINVAL] The value of base is not supported. Since 0, {LONG_MIN} or {LLONG_MIN}, and {LONG_MAX} or {LLONG_MAX} are returned on error and are also valid returns on success, an application wishing to check for error situations should set errno to 0, then call strtol( ) or strtoll ( ), then check errno. -----------------------------------------------------
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/stdlib/strtol.317
-rw-r--r--lib/libc/stdlib/strtol.c38
-rw-r--r--lib/libc/stdlib/strtoll.c23
-rw-r--r--lib/libc/stdlib/strtoq.c2
-rw-r--r--lib/libc/stdlib/strtoul.323
-rw-r--r--lib/libc/stdlib/strtoul.c34
-rw-r--r--lib/libc/stdlib/strtoull.c24
-rw-r--r--lib/libc/stdlib/strtouq.c2
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
OpenPOWER on IntegriCloud