Tcl Source Code

Artifact [9bbe80fa14]
Login

Artifact 9bbe80fa1471ee859fd22642b7f4b41b0b4f1b59:

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