Attachment "strto.patch" to
ticket [440916ffff]
added by
dgp
2002-02-24 09:51:35.
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.867
diff -u -r1.867 ChangeLog
--- ChangeLog 23 Feb 2002 22:15:40 -0000 1.867
+++ ChangeLog 24 Feb 2002 02:49:30 -0000
@@ -1,3 +1,11 @@
+2002-02-23 Don Porter <[email protected]>
+
+ * compat/strtoull.c (strtoull):
+ * compat/strtoll.c (strtoll):
+ * compat/strtoul.c (strtoul): Fixed failure to handle leading
+ sign symbols '+' and '-' and '0X' and raise overflow errors.
+ [Bug 440916] Also corrects prototype and errno problems.
+
2002-02-23 Mo DeJong <[email protected]>
* configure: Regen.
Index: compat/strtoll.c
===================================================================
RCS file: /cvsroot/tcl/tcl/compat/strtoll.c,v
retrieving revision 1.4
diff -u -r1.4 strtoll.c
--- compat/strtoll.c 22 Feb 2002 09:04:48 -0000 1.4
+++ compat/strtoll.c 24 Feb 2002 02:49:33 -0000
@@ -22,7 +22,7 @@
/*
*----------------------------------------------------------------------
*
- * strtol --
+ * strtoll --
*
* Convert an ASCII string into an integer.
*
@@ -39,7 +39,11 @@
*----------------------------------------------------------------------
*/
+#if TCL_WIDE_INT_IS_LONG
+long long
+#else
Tcl_WideInt
+#endif
strtoll(string, endPtr, base)
CONST char *string; /* String of ASCII digits, possibly
* preceded by white space. For bases
@@ -72,6 +76,7 @@
* Check for a sign.
*/
+ errno = 0;
if (*p == '-') {
p += 1;
uwResult = strtoull(p, endPtr, base);
Index: compat/strtoul.c
===================================================================
RCS file: /cvsroot/tcl/tcl/compat/strtoul.c,v
retrieving revision 1.3
diff -u -r1.3 strtoul.c
--- compat/strtoul.c 15 Feb 2002 23:42:12 -0000 1.3
+++ compat/strtoul.c 24 Feb 2002 02:49:33 -0000
@@ -12,7 +12,8 @@
* RCS: @(#) $Id: strtoul.c,v 1.3 2002/02/15 23:42:12 kennykb Exp $
*/
-#include <ctype.h>
+#include "tclInt.h"
+#include "tclPort.h"
/*
* The table below is used to convert from ASCII digits to a
@@ -53,7 +54,7 @@
unsigned long int
strtoul(string, endPtr, base)
- char *string; /* String of ASCII digits, possibly
+ CONST char *string; /* String of ASCII digits, possibly
* preceded by white space. For bases
* greater than 10, either lower- or
* upper-case digits may be used.
@@ -67,10 +68,12 @@
* else means decimal.
*/
{
- register char *p;
+ register CONST char *p;
register unsigned long int result = 0;
register unsigned digit;
int anyDigits = 0;
+ int negative=0;
+ int overflow=0;
/*
* Skip any leading blanks.
@@ -80,6 +83,14 @@
while (isspace(*p)) {
p += 1;
}
+ if (*p == '-') {
+ negative = 1;
+ p += 1;
+ } else {
+ if (*p == '+') {
+ p += 1;
+ }
+ }
/*
* If no base was provided, pick one from the leading characters
@@ -90,7 +101,7 @@
{
if (*p == '0') {
p += 1;
- if (*p == 'x') {
+ if ((*p == 'x') || (*p == 'X')) {
p += 1;
base = 16;
} else {
@@ -111,7 +122,7 @@
* Skip a leading "0x" from hex numbers.
*/
- if ((p[0] == '0') && (p[1] == 'x')) {
+ if ((p[0] == '0') && ((p[1] == 'x') || (p[1] == 'X'))) {
p += 2;
}
}
@@ -122,24 +133,33 @@
*/
if (base == 8) {
+ unsigned long maxres = ULONG_MAX >> 3;
for ( ; ; p += 1) {
digit = *p - '0';
if (digit > 7) {
break;
}
- result = (result << 3) + digit;
+ if (result > maxres) { overflow = 1; }
+ result = (result << 3);
+ if (digit > (ULONG_MAX - result)) { overflow = 1; }
+ result += digit;
anyDigits = 1;
}
} else if (base == 10) {
+ unsigned long maxres = ULONG_MAX / 10;
for ( ; ; p += 1) {
digit = *p - '0';
if (digit > 9) {
break;
}
- result = (10*result) + digit;
+ if (result > maxres) { overflow = 1; }
+ result *= 10;
+ if (digit > (ULONG_MAX - result)) { overflow = 1; }
+ result += digit;
anyDigits = 1;
}
} else if (base == 16) {
+ unsigned long maxres = ULONG_MAX >> 4;
for ( ; ; p += 1) {
digit = *p - '0';
if (digit > ('z' - '0')) {
@@ -149,10 +169,14 @@
if (digit > 15) {
break;
}
- result = (result << 4) + digit;
+ if (result > maxres) { overflow = 1; }
+ result = (result << 4);
+ if (digit > (ULONG_MAX - result)) { overflow = 1; }
+ result += digit;
anyDigits = 1;
}
} else if ( base >= 2 && base <= 36 ) {
+ unsigned long maxres = ULONG_MAX / base;
for ( ; ; p += 1) {
digit = *p - '0';
if (digit > ('z' - '0')) {
@@ -162,7 +186,10 @@
if (digit >= ( (unsigned) base )) {
break;
}
- result = result*base + digit;
+ if (result > maxres) { overflow = 1; }
+ result *= base;
+ if (digit > (ULONG_MAX - result)) { overflow = 1; }
+ result += digit;
anyDigits = 1;
}
}
@@ -176,8 +203,16 @@
}
if (endPtr != 0) {
- *endPtr = p;
+ /* unsafe, but required by the strtoul prototype */
+ *endPtr = (char *) p;
}
+ if (overflow) {
+ errno = ERANGE;
+ return ULONG_MAX;
+ }
+ if (negative) {
+ return -result;
+ }
return result;
}
Index: compat/strtoull.c
===================================================================
RCS file: /cvsroot/tcl/tcl/compat/strtoull.c,v
retrieving revision 1.4
diff -u -r1.4 strtoull.c
--- compat/strtoull.c 22 Feb 2002 09:04:48 -0000 1.4
+++ compat/strtoull.c 24 Feb 2002 02:49:35 -0000
@@ -54,7 +54,11 @@
*----------------------------------------------------------------------
*/
+#if TCL_WIDE_INT_IS_LONG
+unsigned long long
+#else
Tcl_WideUInt
+#endif
strtoull(string, endPtr, base)
CONST char *string; /* String of ASCII digits, possibly
* preceded by white space. For bases