794f87542a
why is there a zend version and a c version? we mix and match in `is_numeric_string`. I'm worried this is giving me a problem in the filtering of floats.
219 linhas
6.1 KiB
C++
219 linhas
6.1 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
| Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 2.00 of the Zend license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.zend.com/license/2_00.txt. |
|
|
| If you did not receive a copy of the Zend license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@zend.com so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "hphp/runtime/base/zend/zend_functions.h"
|
|
#include "hphp/runtime/base/zend/zend_strtod.h"
|
|
#include "folly/Conv.h"
|
|
|
|
namespace HPHP {
|
|
|
|
#define SIZEOF_LONG 8
|
|
#define MAX_LENGTH_OF_LONG 20
|
|
static const char long_min_digits[] = "9223372036854775808";
|
|
|
|
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
|
#define IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F')||((c) >= 'a' && (c) <= 'f'))
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
HOT_FUNC
|
|
char *
|
|
conv_10(register int64_t num, register int *is_negative, char *buf_end,
|
|
register int *len) {
|
|
register char *p = buf_end;
|
|
register uint64_t magnitude;
|
|
|
|
*is_negative = (num < 0);
|
|
|
|
/*
|
|
* On a 2's complement machine, negating the most negative integer
|
|
* results in a number that cannot be represented as a signed integer.
|
|
* Here is what we do to obtain the number's magnitude:
|
|
* a. add 1 to the number
|
|
* b. negate it (becomes positive)
|
|
* c. convert it to unsigned
|
|
* d. add 1
|
|
*/
|
|
if (*is_negative) {
|
|
int64_t t = num + 1;
|
|
magnitude = ((uint64_t) - t) + 1;
|
|
} else {
|
|
magnitude = (uint64_t) num;
|
|
}
|
|
|
|
/*
|
|
* We use a do-while loop so that we write at least 1 digit
|
|
*/
|
|
do {
|
|
uint64_t new_magnitude = magnitude / 10;
|
|
|
|
*--p = (char)(magnitude - new_magnitude * 10 + '0');
|
|
magnitude = new_magnitude;
|
|
}
|
|
while (magnitude);
|
|
|
|
if (*is_negative) {
|
|
*--p = '-';
|
|
}
|
|
|
|
*len = buf_end - p;
|
|
return (p);
|
|
}
|
|
|
|
DataType is_numeric_string(const char *str, int length, int64_t *lval,
|
|
double *dval, int allow_errors /* = 1 */) {
|
|
DataType type;
|
|
const char *ptr;
|
|
int base = 10, digits = 0, dp_or_e = 0;
|
|
double local_dval = 0.0;
|
|
|
|
if (!length || ((unsigned char)(*str)) > '9') {
|
|
return KindOfNull;
|
|
}
|
|
|
|
/* 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 (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 int64 */
|
|
for (type = KindOfInt64;
|
|
!(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1));
|
|
digits++, ptr++) {
|
|
check_digits:
|
|
if (IS_DIGIT(*ptr) || (base == 16 && 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 (IS_DIGIT(*e)) {
|
|
goto process_double;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (base == 10) {
|
|
if (digits >= MAX_LENGTH_OF_LONG) {
|
|
dp_or_e = -1;
|
|
goto process_double;
|
|
}
|
|
} else if (!(digits < SIZEOF_LONG * 2 ||
|
|
(digits == SIZEOF_LONG * 2 && ptr[-digits] <= '7'))) {
|
|
if (dval) {
|
|
local_dval = strtod(str, (char **)&ptr);
|
|
}
|
|
type = KindOfDouble;
|
|
}
|
|
} else if (*ptr == '.' && IS_DIGIT(ptr[1])) {
|
|
process_double:
|
|
type = KindOfDouble;
|
|
|
|
/* 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 = strtod(str, (char **)&ptr);
|
|
} else if (allow_errors != 1 && dp_or_e != -1) {
|
|
dp_or_e = (*ptr++ == '.') ? 1 : 2;
|
|
goto check_digits;
|
|
}
|
|
} else {
|
|
return KindOfNull;
|
|
}
|
|
|
|
if (ptr != str + length) {
|
|
if (!allow_errors) {
|
|
return KindOfNull;
|
|
}
|
|
// if (allow_errors == -1) {
|
|
// zend_error(E_NOTICE, "A non well formed numeric value encountered");
|
|
// }
|
|
}
|
|
|
|
if (type == KindOfInt64) {
|
|
if (digits == MAX_LENGTH_OF_LONG - 1) {
|
|
int cmp = strcmp(&ptr[-digits], long_min_digits);
|
|
if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
|
|
if (dval) {
|
|
*dval = folly::to<double>(str);
|
|
}
|
|
return KindOfDouble;
|
|
}
|
|
}
|
|
if (lval) {
|
|
*lval = strtol(str, nullptr, base);
|
|
}
|
|
return KindOfInt64;
|
|
}
|
|
|
|
if (dval) {
|
|
*dval = local_dval;
|
|
}
|
|
return KindOfDouble;
|
|
}
|
|
|
|
bool is_valid_var_name(const char *var_name, int len) {
|
|
if (!var_name ||
|
|
(!isalpha((int)((unsigned char *)var_name)[0]) && var_name[0] != '_')) {
|
|
return false;
|
|
}
|
|
for (int i = 1; i < len; i++) {
|
|
if (!isalnum((int)((unsigned char *)var_name)[i]) && var_name[i] != '_') {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|