/hphp/runtime/base/zend-functions.cpp

https://github.com/tstarling/hiphop-php · C++ · 207 lines · 139 code · 25 blank · 43 comment · 97 complexity · 882aa46427aa1ebc563754e4bb847b15 MD5 · raw file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 2.00 of the Zend license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.zend.com/license/2_00.txt. |
  12. | If you did not receive a copy of the Zend license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@zend.com so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/base/zend-functions.h"
  18. #include "hphp/runtime/base/zend-strtod.h"
  19. namespace HPHP {
  20. #define SIZEOF_LONG 8
  21. #define MAX_LENGTH_OF_LONG 20
  22. static const char long_min_digits[] = "9223372036854775808";
  23. #undef IS_DIGIT
  24. #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
  25. #define IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F')||((c) >= 'a' && (c) <= 'f'))
  26. ///////////////////////////////////////////////////////////////////////////////
  27. StringSlice conv_10(int64_t num, char* buf_end) {
  28. auto p = buf_end;
  29. uint64_t magnitude;
  30. /*
  31. * On a 2's complement machine, negating the most negative integer
  32. * results in a number that cannot be represented as a signed integer.
  33. * Here is what we do to obtain the number's magnitude:
  34. * a. add 1 to the number
  35. * b. negate it (becomes positive)
  36. * c. convert it to unsigned
  37. * d. add 1
  38. */
  39. if (num < 0) {
  40. magnitude = static_cast<uint64_t>(-(num + 1)) + 1;
  41. } else {
  42. magnitude = static_cast<uint64_t>(num);
  43. }
  44. /*
  45. * We use a do-while loop so that we write at least 1 digit
  46. */
  47. do {
  48. auto const q = magnitude / 10;
  49. auto const r = static_cast<uint32_t>(magnitude % 10);
  50. *--p = r + '0';
  51. magnitude = q;
  52. } while (magnitude);
  53. if (num < 0) *--p = '-';
  54. return StringSlice{p, static_cast<uint32_t>(buf_end - p)};
  55. }
  56. DataType is_numeric_string(const char *str, int length, int64_t *lval,
  57. double *dval, int allow_errors /* = 0 */) {
  58. DataType type;
  59. const char *ptr;
  60. int base = 10, digits = 0, dp_or_e = 0;
  61. double local_dval = 0.0;
  62. if (!length || ((unsigned char)(*str)) > '9') {
  63. return KindOfNull;
  64. }
  65. /* Skip any whitespace
  66. * This is much faster than the isspace() function */
  67. while (*str == ' ' ||
  68. *str == '\t' ||
  69. *str == '\n' ||
  70. *str == '\r' ||
  71. *str == '\v' ||
  72. *str == '\f') {
  73. str++;
  74. length--;
  75. }
  76. ptr = str;
  77. if (*ptr == '-' || *ptr == '+') {
  78. ptr++;
  79. }
  80. if (IS_DIGIT(*ptr)) {
  81. /* Handle hex numbers
  82. * str is used instead of ptr to disallow signs and keep old behavior */
  83. if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
  84. base = 16;
  85. ptr += 2;
  86. }
  87. /* Skip any leading 0s */
  88. while (*ptr == '0') {
  89. ptr++;
  90. }
  91. /* Count the number of digits. If a decimal point/exponent is found,
  92. * it's a double. Otherwise, if there's a dval or no need to check for
  93. * a full match, stop when there are too many digits for a int64 */
  94. for (type = KindOfInt64;
  95. !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1));
  96. digits++, ptr++) {
  97. check_digits:
  98. if (IS_DIGIT(*ptr) || (base == 16 && IS_XDIGIT(*ptr))) {
  99. continue;
  100. } else if (base == 10) {
  101. if (*ptr == '.' && dp_or_e < 1) {
  102. goto process_double;
  103. } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
  104. const char *e = ptr + 1;
  105. if (*e == '-' || *e == '+') {
  106. ptr = e++;
  107. }
  108. if (IS_DIGIT(*e)) {
  109. goto process_double;
  110. }
  111. }
  112. }
  113. break;
  114. }
  115. if (base == 10) {
  116. if (digits >= MAX_LENGTH_OF_LONG) {
  117. dp_or_e = -1;
  118. goto process_double;
  119. }
  120. } else if (!(digits < SIZEOF_LONG * 2 ||
  121. (digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) {
  122. if (dval) {
  123. local_dval = zend_hex_strtod(str, (const char **)&ptr);
  124. }
  125. type = KindOfDouble;
  126. }
  127. } else if (*ptr == '.' && IS_DIGIT(ptr[1])) {
  128. process_double:
  129. type = KindOfDouble;
  130. /* If there's a dval, do the conversion; else continue checking
  131. * the digits if we need to check for a full match */
  132. if (dval) {
  133. local_dval = zend_strtod(str, (const char **)&ptr);
  134. } else if (allow_errors != 1 && dp_or_e != -1) {
  135. dp_or_e = (*ptr++ == '.') ? 1 : 2;
  136. goto check_digits;
  137. }
  138. } else {
  139. return KindOfNull;
  140. }
  141. if (ptr != str + length) {
  142. if (!allow_errors) {
  143. return KindOfNull;
  144. }
  145. // if (allow_errors == -1) {
  146. // zend_error(E_NOTICE, "A non well formed numeric value encountered");
  147. // }
  148. }
  149. if (type == KindOfInt64) {
  150. if (digits == MAX_LENGTH_OF_LONG - 1) {
  151. int cmp = strcmp(&ptr[-digits], long_min_digits);
  152. if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
  153. if (dval) {
  154. *dval = strtod(str, nullptr);
  155. }
  156. return KindOfDouble;
  157. }
  158. }
  159. if (lval) {
  160. *lval = strtol(str, nullptr, base);
  161. }
  162. return KindOfInt64;
  163. }
  164. if (dval) {
  165. *dval = local_dval;
  166. }
  167. return KindOfDouble;
  168. }
  169. bool is_valid_var_name(const char *var_name, int len) {
  170. if (!var_name ||
  171. (!isalpha((int)((unsigned char *)var_name)[0]) && var_name[0] != '_')) {
  172. return false;
  173. }
  174. for (int i = 1; i < len; i++) {
  175. if (!isalnum((int)((unsigned char *)var_name)[i]) && var_name[i] != '_') {
  176. return false;
  177. }
  178. }
  179. return true;
  180. }
  181. ///////////////////////////////////////////////////////////////////////////////
  182. }