strtoi64.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #if _MSC_VERS <= 1300
  2. #include "php_strtoi64.h"
  3. /*
  4. From APR, apr_strings.c
  5. See http://www.apache.org/licenses/LICENSE-2.0
  6. */
  7. PHPAPI int64_t _strtoi64(const char *nptr, char **endptr, int base)
  8. {
  9. const char *s;
  10. int64_t acc;
  11. int64_t val;
  12. int neg, any;
  13. char c;
  14. /*
  15. * Skip white space and pick up leading +/- sign if any.
  16. * If base is 0, allow 0x for hex and 0 for octal, else
  17. * assume decimal; if base is already 16, allow 0x.
  18. */
  19. s = nptr;
  20. do {
  21. c = *s++;
  22. } while (isspace((unsigned char)c));
  23. if (c == '-') {
  24. neg = 1;
  25. c = *s++;
  26. } else {
  27. neg = 0;
  28. if (c == '+') {
  29. c = *s++;
  30. }
  31. }
  32. if ((base == 0 || base == 16) && c == '0' && (*s == 'x' || *s == 'X')) {
  33. c = s[1];
  34. s += 2;
  35. base = 16;
  36. }
  37. if (base == 0) {
  38. base = c == '0' ? 8 : 10;
  39. }
  40. acc = any = 0;
  41. if (base < 2 || base > 36) {
  42. errno = EINVAL;
  43. if (endptr != NULL) {
  44. *endptr = (char *)(any ? s - 1 : nptr);
  45. }
  46. return acc;
  47. }
  48. /* The classic bsd implementation requires div/mod operators
  49. * to compute a cutoff. Benchmarking proves that iss very, very
  50. * evil to some 32 bit processors. Instead, look for underflow
  51. * in both the mult and add/sub operation. Unlike the bsd impl,
  52. * we also work strictly in a signed int64 word as we haven't
  53. * implemented the unsigned type in win32.
  54. *
  55. * Set 'any' if any `digits' consumed; make it negative to indicate
  56. * overflow.
  57. */
  58. val = 0;
  59. for ( ; ; c = *s++) {
  60. if (c >= '0' && c <= '9')
  61. c -= '0';
  62. #if (('Z' - 'A') == 25)
  63. else if (c >= 'A' && c <= 'Z')
  64. c -= 'A' - 10;
  65. else if (c >= 'a' && c <= 'z')
  66. c -= 'a' - 10;
  67. #elif APR_CHARSET_EBCDIC
  68. else if (c >= 'A' && c <= 'I')
  69. c -= 'A' - 10;
  70. else if (c >= 'J' && c <= 'R')
  71. c -= 'J' - 19;
  72. else if (c >= 'S' && c <= 'Z')
  73. c -= 'S' - 28;
  74. else if (c >= 'a' && c <= 'i')
  75. c -= 'a' - 10;
  76. else if (c >= 'j' && c <= 'r')
  77. c -= 'j' - 19;
  78. else if (c >= 's' && c <= 'z')
  79. c -= 'z' - 28;
  80. #else
  81. # error "CANNOT COMPILE apr_strtoi64(), only ASCII and EBCDIC supported"
  82. #endif
  83. else {
  84. break;
  85. }
  86. if (c >= base) {
  87. break;
  88. }
  89. val *= base;
  90. if ( (any < 0) /* already noted an over/under flow - short circuit */
  91. || (neg && (val > acc || (val -= c) > acc)) /* underflow */
  92. || (val < acc || (val += c) < acc)) { /* overflow */
  93. any = -1; /* once noted, over/underflows never go away */
  94. #ifdef APR_STRTOI64_OVERFLOW_IS_BAD_CHAR
  95. break;
  96. #endif
  97. } else {
  98. acc = val;
  99. any = 1;
  100. }
  101. }
  102. if (any < 0) {
  103. acc = neg ? INT64_MIN : INT64_MAX;
  104. errno = ERANGE;
  105. } else if (!any) {
  106. errno = EINVAL;
  107. }
  108. if (endptr != NULL) {
  109. *endptr = (char *)(any ? s - 1 : nptr);
  110. }
  111. return (acc);
  112. }
  113. #endif