Attachment "strtoul-2.patch" to
ticket [440916ffff]
added by
das
2001-09-01 15:27:46.
Index: tcl/compat/strtoul.c
===================================================================
RCS file: /cvsroot/tcl/tcl/compat/strtoul.c,v
retrieving revision 1.2
diff -u -3 -r1.2 strtoul.c
--- tcl/compat/strtoul.c 1998/09/14 18:39:45 1.2
+++ tcl/compat/strtoul.c 2001/09/01 08:13:32
@@ -12,6 +12,18 @@
* RCS: @(#) $Id: strtoul.c,v 1.2 1998/09/14 18:39:45 stanton Exp $
*/
+#include "tcl.h"
+#include "tclPort.h"
+#ifdef NO_LIMITS_H
+# include "../compat/limits.h"
+#else
+# include <limits.h>
+#endif
+
+#ifndef ULONG_MAX
+#define ULONG_MAX (((unsigned long)LONG_MAX<<1)+1)
+#endif
+
#include <ctype.h>
/*
@@ -33,44 +45,29 @@
/*
*----------------------------------------------------------------------
- *
- * strtoul --
*
- * Convert an ASCII string into an integer.
+ * __private_strtoul --
*
- * Results:
- * The return value is the integer equivalent of string. If endPtr
- * is non-NULL, then *endPtr is filled in with the character
- * after the last one that was part of the integer. If string
- * doesn't contain a valid integer value, then zero is returned
- * and *endPtr is set to string.
- *
- * Side effects:
- * None.
+ * Internal helper proc used in both strtoul and strtol, see below
*
*----------------------------------------------------------------------
*/
-unsigned long int
-strtoul(string, endPtr, base)
- 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.
- */
- char **endPtr; /* Where to store address of terminating
- * character, or NULL. */
- int base; /* Base for conversion. Must be less
- * than 37. If 0, then the base is chosen
- * from the leading characters of string:
- * "0x" means hex, "0" means octal, anything
- * else means decimal.
- */
+static unsigned long int
+__private_strtoul(string, endPtr, base, negative, overflow)
+ char *string;
+ char **endPtr;
+ int base;
+ int *negative;
+ int *overflow;
{
register char *p;
register unsigned long int result = 0;
register unsigned digit;
int anyDigits = 0;
+
+ *negative=0;
+ *overflow=0;
/*
* Skip any leading blanks.
@@ -80,6 +77,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 +95,7 @@
{
if (*p == '0') {
p += 1;
- if (*p == 'x') {
+ if ((*p == 'x') || (*p == 'X')) {
p += 1;
base = 16;
} else {
@@ -111,7 +116,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;
}
}
@@ -127,7 +132,10 @@
if (digit > 7) {
break;
}
- result = (result << 3) + digit;
+ if(result > (ULONG_MAX >> 3)) { *overflow=1; }
+ result = result << 3;
+ if(digit > (ULONG_MAX - result)) { *overflow=1; }
+ result += digit;
anyDigits = 1;
}
} else if (base == 10) {
@@ -136,7 +144,10 @@
if (digit > 9) {
break;
}
- result = (10*result) + digit;
+ if(result > (ULONG_MAX/10)) { *overflow=1; }
+ result = (10*result);
+ if(digit > (ULONG_MAX - result)) { *overflow=1; }
+ result += digit;
anyDigits = 1;
}
} else if (base == 16) {
@@ -149,10 +160,14 @@
if (digit > 15) {
break;
}
- result = (result << 4) + digit;
+ if(result > (ULONG_MAX >> 4)) { *overflow=1; }
+ result = (result << 4);
+ if(digit > (ULONG_MAX - result)) { *overflow=1; }
+ result += digit;
anyDigits = 1;
}
} else {
+ unsigned long int maxres = ULONG_MAX/base;
for ( ; ; p += 1) {
digit = *p - '0';
if (digit > ('z' - '0')) {
@@ -162,7 +177,10 @@
if (digit >= base) {
break;
}
- result = result*base + digit;
+ if(result > maxres) { *overflow=1; }
+ result = result*base;
+ if(digit > (ULONG_MAX - result)) { *overflow=1; }
+ result += digit;
anyDigits = 1;
}
}
@@ -180,4 +198,118 @@
}
return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtoul --
+ *
+ * Convert an ASCII string into an integer.
+ *
+ * Results:
+ * The return value is the integer equivalent of string. If endPtr
+ * is non-NULL, then *endPtr is filled in with the character
+ * after the last one that was part of the integer. If string
+ * doesn't contain a valid integer value, then zero is returned
+ * and *endPtr is set to string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+unsigned long int
+strtoul(string, endPtr, base)
+ 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.
+ */
+ char **endPtr; /* Where to store address of terminating
+ * character, or NULL. */
+ int base; /* Base for conversion. Must be less
+ * than 37. If 0, then the base is chosen
+ * from the leading characters of string:
+ * "0x" means hex, "0" means octal, anything
+ * else means decimal.
+ */
+{
+ unsigned long int value;
+ int negative, overflow;
+
+ value = __private_strtoul(string, endPtr, base, &negative, &overflow);
+
+ if (overflow)
+ {
+ value = ULONG_MAX;
+ errno = ERANGE;
+ }
+ else if (negative)
+ value = -value;
+
+ return(value);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * strtol --
+ *
+ * Convert an ASCII string into a signed integer.
+ *
+ * Results:
+ * The return value is the signed integer equivalent of string. If endPtr
+ * is non-NULL, then *endPtr is filled in with the character
+ * after the last one that was part of the integer. If string
+ * doesn't contain a valid integer value, then zero is returned
+ * and *endPtr is set to string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+long int
+strtol(string, endPtr, base)
+ 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.
+ */
+ char **endPtr; /* Where to store address of terminating
+ * character, or NULL. */
+ int base; /* Base for conversion. Must be less
+ * than 37. If 0, then the base is chosen
+ * from the leading characters of string:
+ * "0x" means hex, "0" means octal, anything
+ * else means decimal.
+ */
+{
+ unsigned long int uvalue;
+ long int svalue;
+ int negative, overflow;
+
+ uvalue = __private_strtoul(string, endPtr, base, &negative, &overflow);
+
+ if (overflow || (!negative && uvalue > LONG_MAX) || (negative && uvalue > -LONG_MIN))
+ {
+ svalue = (negative ? -LONG_MIN : LONG_MAX);
+ errno = ERANGE;
+ } else
+ svalue = (negative ? -uvalue : uvalue);
+
+ return(svalue);
+}
+
+int atoi(const char * str)
+{
+ return(strtol(str, NULL, 10));
+}
+
+long atol(const char * str)
+{
+ return(strtol(str, NULL, 10));
}