diff options
Diffstat (limited to 'Zend/zend_operators.h')
-rw-r--r-- | Zend/zend_operators.h | 231 |
1 files changed, 58 insertions, 173 deletions
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 41342de020..8075edf939 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -69,14 +69,41 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR ZEND_API zend_bool instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC); ZEND_API zend_bool instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce TSRMLS_DC); + +/** + * Checks whether the string "str" with length "length" is numeric. The value + * of allow_errors determines whether it's required to be entirely numeric, or + * just its prefix. Leading whitespace is allowed. + * + * The function returns 0 if the string did not contain a valid number; IS_LONG + * if it contained a number that fits within the range of a long; or IS_DOUBLE + * if the number was out of long range or contained a decimal point/exponent. + * The number's value is returned into the respective pointer, *lval or *dval, + * if that pointer is not NULL. + * + * This variant also gives information if a string that represents an integer + * could not be represented as such due to overflow. It writes 1 to oflow_info + * if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN. + */ +ZEND_API zend_uchar _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info); + END_EXTERN_C() #if ZEND_DVAL_TO_LVAL_CAST_OK -# define zend_dval_to_lval(d) ((zend_long) (d)) +static zend_always_inline zend_long zend_dval_to_lval(double d) +{ + if (EXPECTED(zend_finite(d)) && EXPECTED(!zend_isnan(d))) { + return (zend_long)d; + } else { + return 0; + } +} #elif SIZEOF_ZEND_LONG == 4 static zend_always_inline zend_long zend_dval_to_lval(double d) { - if (d > ZEND_LONG_MAX || d < ZEND_LONG_MIN) { + if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) { + return 0; + } else if (d > ZEND_LONG_MAX || d < ZEND_LONG_MIN) { double two_pow_32 = pow(2., 32.), dmod; @@ -93,8 +120,10 @@ static zend_always_inline zend_long zend_dval_to_lval(double d) #else static zend_always_inline zend_long zend_dval_to_lval(double d) { + if (UNEXPECTED(!zend_finite(d)) || UNEXPECTED(zend_isnan(d))) { + return 0; /* >= as (double)ZEND_LONG_MAX is outside signed range */ - if (d >= ZEND_LONG_MAX || d < ZEND_LONG_MIN) { + } else if (d >= ZEND_LONG_MAX || d < ZEND_LONG_MIN) { double two_pow_64 = pow(2., 64.), dmod; @@ -114,165 +143,21 @@ static zend_always_inline zend_long zend_dval_to_lval(double d) #define ZEND_IS_DIGIT(c) ((c) >= '0' && (c) <= '9') #define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) -/** - * Checks whether the string "str" with length "length" is numeric. The value - * of allow_errors determines whether it's required to be entirely numeric, or - * just its prefix. Leading whitespace is allowed. - * - * The function returns 0 if the string did not contain a valid number; IS_LONG - * if it contained a number that fits within the range of a long; or IS_DOUBLE - * if the number was out of long range or contained a decimal point/exponent. - * The number's value is returned into the respective pointer, *lval or *dval, - * if that pointer is not NULL. - * - * This variant also gives information if a string that represents an integer - * could not be represented as such due to overflow. It writes 1 to oflow_info - * if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN. - */ -static inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) +static zend_always_inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) { - const char *ptr; - int base = 10, digits = 0, dp_or_e = 0; - double local_dval = 0.0; - zend_uchar type; - - if (!length) { + if (*str > '9') { return 0; } - - if (oflow_info != NULL) { - *oflow_info = 0; - } - - /* Skip any whitespace - * This is much faster than the isspace() function */ - while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') { - str++; - length--; - } - ptr = str; - - if (*ptr == '-' || *ptr == '+') { - ptr++; - } - - if (ZEND_IS_DIGIT(*ptr)) { - /* Handle hex numbers - * str is used instead of ptr to disallow signs and keep old behavior */ - if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { - base = 16; - ptr += 2; - } - - /* Skip any leading 0s */ - while (*ptr == '0') { - ptr++; - } - - /* Count the number of digits. If a decimal point/exponent is found, - * it's a double. Otherwise, if there's a dval or no need to check for - * a full match, stop when there are too many digits for a long */ - for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) { -check_digits: - if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { - continue; - } else if (base == 10) { - if (*ptr == '.' && dp_or_e < 1) { - goto process_double; - } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { - const char *e = ptr + 1; - - if (*e == '-' || *e == '+') { - ptr = e++; - } - if (ZEND_IS_DIGIT(*e)) { - goto process_double; - } - } - } - - break; - } - - if (base == 10) { - if (digits >= MAX_LENGTH_OF_LONG) { - if (oflow_info != NULL) { - *oflow_info = *str == '-' ? -1 : 1; - } - dp_or_e = -1; - goto process_double; - } - } else if (!(digits < SIZEOF_ZEND_LONG * 2 || (digits == SIZEOF_ZEND_LONG * 2 && ptr[-digits] <= '7'))) { - if (dval) { - local_dval = zend_hex_strtod(str, &ptr); - } - if (oflow_info != NULL) { - *oflow_info = 1; - } - type = IS_DOUBLE; - } - } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { -process_double: - type = IS_DOUBLE; - - /* If there's a dval, do the conversion; else continue checking - * the digits if we need to check for a full match */ - if (dval) { - local_dval = zend_strtod(str, &ptr); - } else if (allow_errors != 1 && dp_or_e != -1) { - dp_or_e = (*ptr++ == '.') ? 1 : 2; - goto check_digits; - } - } else { - return 0; - } - - if (ptr != str + length) { - if (!allow_errors) { - return 0; - } - if (allow_errors == -1) { - zend_error(E_NOTICE, "A non well formed numeric value encountered"); - } - } - - if (type == IS_LONG) { - if (digits == MAX_LENGTH_OF_LONG - 1) { - int cmp = strcmp(&ptr[-digits], long_min_digits); - - if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { - if (dval) { - *dval = zend_strtod(str, NULL); - } - if (oflow_info != NULL) { - *oflow_info = *str == '-' ? -1 : 1; - } - - return IS_DOUBLE; - } - } - - if (lval) { - *lval = ZEND_STRTOL(str, NULL, base); - } - - return IS_LONG; - } else { - if (dval) { - *dval = local_dval; - } - - return IS_DOUBLE; - } + return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info); } -static inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors) { +static zend_always_inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors) { return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL); } ZEND_API zend_uchar is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval); -static inline const char * +static zend_always_inline const char * zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char *end) { const char *p = haystack; @@ -309,7 +194,7 @@ zend_memnstr(const char *haystack, const char *needle, size_t needle_len, char * return NULL; } -static inline const void *zend_memrchr(const void *s, int c, size_t n) +static zend_always_inline const void *zend_memrchr(const void *s, int c, size_t n) { register const unsigned char *e; @@ -401,7 +286,6 @@ ZEND_API int zend_atoi(const char *str, int str_len); ZEND_API zend_long zend_atol(const char *str, int str_len); ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC); -END_EXTERN_C() #define convert_to_ex_master(pzv, lower_type, upper_type) \ if (Z_TYPE_P(pzv)!=upper_type) { \ @@ -1021,30 +905,31 @@ static zend_always_inline void fast_is_not_identical_function(zval *result, zval return SUCCESS; \ } -/* input: buf points to the END of the buffer */ -#define _zend_print_unsigned_to_buf(buf, num, vartype, result) do { \ - char *__p = (buf); \ - vartype __num = (num); \ - *__p = '\0'; \ - do { \ - *--__p = (char) (__num % 10) + '0'; \ - __num /= 10; \ - } while (__num > 0); \ - result = __p; \ -} while (0) +/* buf points to the END of the buffer */ +static zend_always_inline char *zend_print_ulong_to_buf(char *buf, zend_ulong num) { + *buf = '\0'; + do { + *--buf = (char) (num % 10) + '0'; + num /= 10; + } while (num > 0); + return buf; +} /* buf points to the END of the buffer */ -#define _zend_print_signed_to_buf(buf, num, vartype, result) do { \ - if (num < 0) { \ - _zend_print_unsigned_to_buf((buf), -(vartype)(num), vartype, (result)); \ - *--(result) = '-'; \ - } else { \ - _zend_print_unsigned_to_buf((buf), (num), vartype, (result)); \ - } \ -} while (0) +static zend_always_inline char *zend_print_long_to_buf(char *buf, zend_long num) { + if (num < 0) { + char *result = zend_print_ulong_to_buf(buf, ~((zend_ulong) num) + 1); + *--result = '-'; + return result; + } else { + return zend_print_ulong_to_buf(buf, num); + } +} ZEND_API zend_string *zend_long_to_str(zend_long num); +END_EXTERN_C() + #endif /* |