]> granicus.if.org Git - php/commitdiff
- MFB: strtoi64 forward compatible replacement for VC6
authorPierre Joye <pajoye@php.net>
Fri, 7 Nov 2008 13:11:35 +0000 (13:11 +0000)
committerPierre Joye <pajoye@php.net>
Fri, 7 Nov 2008 13:11:35 +0000 (13:11 +0000)
win32/build/config.w32
win32/php_strtoi64.h [new file with mode: 0644]
win32/strtoi64.c [new file with mode: 0644]

index 86da53be4220d7dc80f81e3482acf6de85cc0d91..29d19a2776f6ab66b163ab8b82889c002f438e61 100644 (file)
@@ -344,6 +344,11 @@ ADD_SOURCES("main", "main.c snprintf.c spprintf.c fopen_wrappers.c \
 
 ADD_SOURCES("win32", "inet.c");
 
+// Newer versions have it
+if (VCVERS <= 1300) {
+       ADD_SOURCES("win32", "strtoi64.c");
+}
+
 ADD_SOURCES("main/streams", "streams.c cast.c memory.c filter.c plain_wrapper.c \
        userspace.c transports.c xp_socket.c mmap.c unicode_filter.c glob_wrapper.c");
 
diff --git a/win32/php_strtoi64.h b/win32/php_strtoi64.h
new file mode 100644 (file)
index 0000000..633ecb1
--- /dev/null
@@ -0,0 +1,7 @@
+#if _MSC_VERS <= 1300
+#include "php.h"
+#include "php_stdint.h"
+
+PHPAPI int64_t _strtoi64(const char *nptr, char **endptr, int base);
+#define _strtoui64 _strtoi64
+#endif
diff --git a/win32/strtoi64.c b/win32/strtoi64.c
new file mode 100644 (file)
index 0000000..689cc09
--- /dev/null
@@ -0,0 +1,122 @@
+#if _MSC_VERS <= 1300
+#include "php_strtoi64.h"
+/*
+       From APR, apr_strings.c
+       See http://www.apache.org/licenses/LICENSE-2.0
+*/
+
+PHPAPI int64_t _strtoi64(const char *nptr, char **endptr, int base)
+{
+       const char *s;
+       int64_t acc;
+       int64_t val;
+       int neg, any;
+       char c;
+
+       /*
+        * 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((unsigned char)c));
+       if (c == '-') {
+               neg = 1;
+               c = *s++;
+       } else {
+               neg = 0;
+               if (c == '+') {
+                       c = *s++;
+               }
+       }
+
+       if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) {
+               c = s[1];
+               s += 2;
+               base = 16;
+       }
+       if (base == 0) {
+               base = c == '0' ? 8 : 10;
+       }
+       acc = any = 0;
+       if (base < 2 || base > 36) {
+               errno = EINVAL;
+               if (endptr != NULL) {
+                       *endptr = (char *)(any ? s - 1 : nptr);
+               }
+               return acc;
+       }
+
+       /* The classic bsd implementation requires div/mod operators
+        * to compute a cutoff.  Benchmarking proves that iss very, very
+        * evil to some 32 bit processors.  Instead, look for underflow
+        * in both the mult and add/sub operation.  Unlike the bsd impl,
+        * we also work strictly in a signed int64 word as we haven't
+        * implemented the unsigned type in win32.
+        *
+        * Set 'any' if any `digits' consumed; make it negative to indicate
+        * overflow.
+        */
+    val = 0;
+       for ( ; ; c = *s++) {
+               if (c >= '0' && c <= '9')
+                       c -= '0';
+
+#if (('Z' - 'A') == 25)
+               else if (c >= 'A' && c <= 'Z')
+                       c -= 'A' - 10;
+               else if (c >= 'a' && c <= 'z')
+                       c -= 'a' - 10;
+#elif APR_CHARSET_EBCDIC
+               else if (c >= 'A' && c <= 'I')
+                       c -= 'A' - 10;
+               else if (c >= 'J' && c <= 'R')
+                       c -= 'J' - 19;
+               else if (c >= 'S' && c <= 'Z')
+                       c -= 'S' - 28;
+               else if (c >= 'a' && c <= 'i')
+                       c -= 'a' - 10;
+               else if (c >= 'j' && c <= 'r')
+                       c -= 'j' - 19;
+               else if (c >= 's' && c <= 'z')
+                       c -= 'z' - 28;
+#else
+# error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported"
+#endif
+               else {
+                       break;
+               }
+
+               if (c >= base) {
+                       break;
+               }
+
+               val *= base;
+               if ( (any < 0)  /* already noted an over/under flow - short circuit */
+                               || (neg && (val > acc || (val -= c) > acc)) /* underflow */
+                               || (val < acc || (val += c) < acc)) {       /* overflow */
+                       any = -1;       /* once noted, over/underflows never go away */
+#ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR
+                       break;
+#endif
+               } else {
+                       acc = val;
+                       any = 1;
+               }
+       }
+
+       if (any < 0) {
+               acc = neg ? INT64_MIN : INT64_MAX;
+               errno = ERANGE;
+       } else if (!any) {
+               errno = EINVAL;
+       }
+
+       if (endptr != NULL) {
+               *endptr = (char *)(any ? s - 1 : nptr);
+       }
+       return (acc);
+}
+#endif