Skip to content

Commit

Permalink
- MFB: strtoi64 forward compatible replacement for VC6
Browse files Browse the repository at this point in the history
  • Loading branch information
pierrejoye committed Nov 7, 2008
1 parent 17c0c53 commit a4e137f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 0 deletions.
5 changes: 5 additions & 0 deletions win32/build/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
7 changes: 7 additions & 0 deletions win32/php_strtoi64.h
Original file line number Diff line number Diff line change
@@ -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
122 changes: 122 additions & 0 deletions win32/strtoi64.c
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit a4e137f

Please sign in to comment.