Skip to content

Commit

Permalink
Move php_gcvt to zend_gcvt
Browse files Browse the repository at this point in the history
Also move PHP_DOUBLE_MAX_LENGTH to ZEND_DOUBLE_MAX_LENGTH.
  • Loading branch information
nikic committed Aug 2, 2021
1 parent 7c9ac47 commit d28f6e6
Show file tree
Hide file tree
Showing 11 changed files with 126 additions and 123 deletions.
99 changes: 99 additions & 0 deletions Zend/zend_strtod.c
Original file line number Diff line number Diff line change
Expand Up @@ -4507,6 +4507,105 @@ ZEND_API double zend_bin_strtod(const char *str, const char **endptr)
return value;
}

ZEND_API char *zend_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf)
{
char *digits, *dst, *src;
int i, decpt;
bool sign;
int mode = ndigit >= 0 ? 2 : 0;

if (mode == 0) {
ndigit = 17;
}
digits = zend_dtoa(value, mode, ndigit, &decpt, &sign, NULL);
if (decpt == 9999) {
/*
* Infinity or NaN, convert to inf or nan with sign.
* We assume the buffer is at least ndigit long.
*/
snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
zend_freedtoa(digits);
return (buf);
}

dst = buf;
if (sign) {
*dst++ = '-';
}

if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
/* exponential format (e.g. 1.2345e+13) */
if (--decpt < 0) {
sign = 1;
decpt = -decpt;
} else {
sign = 0;
}
src = digits;
*dst++ = *src++;
*dst++ = dec_point;
if (*src == '\0') {
*dst++ = '0';
} else {
do {
*dst++ = *src++;
} while (*src != '\0');
}
*dst++ = exponent;
if (sign) {
*dst++ = '-';
} else {
*dst++ = '+';
}
if (decpt < 10) {
*dst++ = '0' + decpt;
*dst = '\0';
} else {
/* XXX - optimize */
int n;
for (n = decpt, i = 0; (n /= 10) != 0; i++);
dst[i + 1] = '\0';
while (decpt != 0) {
dst[i--] = '0' + decpt % 10;
decpt /= 10;
}
}
} else if (decpt < 0) {
/* standard format 0. */
*dst++ = '0'; /* zero before decimal point */
*dst++ = dec_point;
do {
*dst++ = '0';
} while (++decpt < 0);
src = digits;
while (*src != '\0') {
*dst++ = *src++;
}
*dst = '\0';
} else {
/* standard format */
for (i = 0, src = digits; i < decpt; i++) {
if (*src != '\0') {
*dst++ = *src++;
} else {
*dst++ = '0';
}
}
if (*src != '\0') {
if (src == digits) {
*dst++ = '0'; /* zero before decimal point */
}
*dst++ = dec_point;
for (i = decpt; digits[i] != '\0'; i++) {
*dst++ = digits[i];
}
}
*dst = '\0';
}
zend_freedtoa(digits);
return (buf);
}

static void destroy_freelist(void)
{
int i;
Expand Down
11 changes: 10 additions & 1 deletion Zend/zend_strtod.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

BEGIN_EXTERN_C()
ZEND_API void zend_freedtoa(char *s);
ZEND_API char * zend_dtoa(double _d, int mode, int ndigits, int *decpt, bool *sign, char **rve);
ZEND_API char *zend_dtoa(double _d, int mode, int ndigits, int *decpt, bool *sign, char **rve);
ZEND_API char *zend_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf);
ZEND_API double zend_strtod(const char *s00, const char **se);
ZEND_API double zend_hex_strtod(const char *str, const char **endptr);
ZEND_API double zend_oct_strtod(const char *str, const char **endptr);
Expand All @@ -33,4 +34,12 @@ ZEND_API int zend_startup_strtod(void);
ZEND_API int zend_shutdown_strtod(void);
END_EXTERN_C()

/* double limits */
#include <float.h>
#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
#define ZEND_DOUBLE_MAX_LENGTH (3 + DBL_MANT_DIG - DBL_MIN_EXP)
#else
#define ZEND_DOUBLE_MAX_LENGTH 1080
#endif

#endif
6 changes: 3 additions & 3 deletions ext/json/json_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ static inline int php_json_is_valid_double(double d) /* {{{ */
static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */
{
size_t len;
char num[PHP_DOUBLE_MAX_LENGTH];
char num[ZEND_DOUBLE_MAX_LENGTH];

php_gcvt(d, (int)PG(serialize_precision), '.', 'e', num);
zend_gcvt(d, (int)PG(serialize_precision), '.', 'e', num);
len = strlen(num);
if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_DOUBLE_MAX_LENGTH - 2) {
if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < ZEND_DOUBLE_MAX_LENGTH - 2) {
num[len++] = '.';
num[len++] = '0';
num[len] = '\0';
Expand Down
2 changes: 1 addition & 1 deletion ext/mysqlnd/mysql_float_to_double.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ static inline double mysql_float_to_double(float fp4, int decimals) {
char num_buf[MAX_CHAR_BUF_LEN]; /* Over allocated */

if (decimals < 0) {
php_gcvt(fp4, FLT_DIG, '.', 'e', num_buf);
zend_gcvt(fp4, FLT_DIG, '.', 'e', num_buf);
} else {
snprintf(num_buf, MAX_CHAR_BUF_LEN, "%.*F", decimals, fp4);
}
Expand Down
2 changes: 1 addition & 1 deletion ext/soap/php_encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ static xmlNodePtr to_xml_double(encodeTypePtr type, zval *data, int style, xmlNo
ZVAL_DOUBLE(&tmp, zval_get_double(data));

str = (char *) safe_emalloc(EG(precision) >= 0 ? EG(precision) : 17, 1, MAX_LENGTH_OF_DOUBLE + 1);
php_gcvt(Z_DVAL(tmp), EG(precision), '.', 'E', str);
zend_gcvt(Z_DVAL(tmp), EG(precision), '.', 'E', str);
xmlNodeSetContentLen(ret, BAD_CAST(str), strlen(str));
efree(str);

Expand Down
2 changes: 1 addition & 1 deletion ext/standard/formatted_print.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos,

char exp_char = fmt == 'G' || fmt == 'H' ? 'E' : 'e';
/* We use &num_buf[ 1 ], so that we have room for the sign. */
s = php_gcvt(number, precision, decimal_point, exp_char, &num_buf[1]);
s = zend_gcvt(number, precision, decimal_point, exp_char, &num_buf[1]);
is_negative = 0;
if (*s == '-') {
is_negative = 1;
Expand Down
8 changes: 4 additions & 4 deletions ext/standard/var.c
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,7 @@ static void php_object_element_export(zval *zv, zend_ulong index, zend_string *k
PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
{
HashTable *myht;
char tmp_str[PHP_DOUBLE_MAX_LENGTH];
char tmp_str[ZEND_DOUBLE_MAX_LENGTH];
zend_string *ztmp, *ztmp2;
zend_ulong index;
zend_string *key;
Expand Down Expand Up @@ -508,7 +508,7 @@ PHPAPI void php_var_export_ex(zval *struc, int level, smart_str *buf) /* {{{ */
smart_str_append_long(buf, Z_LVAL_P(struc));
break;
case IS_DOUBLE:
php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
zend_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
smart_str_appends(buf, tmp_str);
/* Without a decimal point, PHP treats a number literal as an int.
* This check even works for scientific notation, because the
Expand Down Expand Up @@ -1038,8 +1038,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
return;

case IS_DOUBLE: {
char tmp_str[PHP_DOUBLE_MAX_LENGTH];
php_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);
char tmp_str[ZEND_DOUBLE_MAX_LENGTH];
zend_gcvt(Z_DVAL_P(struc), (int)PG(serialize_precision), '.', 'E', tmp_str);

size_t len = strlen(tmp_str);
char *res = smart_str_extend(buf, 2 + len + 1);
Expand Down
8 changes: 1 addition & 7 deletions main/php.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,7 @@ typedef unsigned int socklen_t;
#define INT_MIN (- INT_MAX - 1)
#endif

/* double limits */
#include <float.h>
#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP)
#define PHP_DOUBLE_MAX_LENGTH (3 + DBL_MANT_DIG - DBL_MIN_EXP)
#else
#define PHP_DOUBLE_MAX_LENGTH 1080
#endif
#define PHP_DOUBLE_MAX_LENGTH ZEND_DOUBLE_MAX_LENGTH

#define PHP_GCC_VERSION ZEND_GCC_VERSION
#define PHP_ATTRIBUTE_MALLOC ZEND_ATTRIBUTE_MALLOC
Expand Down
102 changes: 1 addition & 101 deletions main/snprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,106 +128,6 @@ static inline char *php_fcvt(double value, int ndigit, int *decpt, bool *sign) /
}
/* }}} */

PHPAPI char *php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf) /* {{{ */
{
char *digits, *dst, *src;
int i, decpt;
bool sign;
int mode = ndigit >= 0 ? 2 : 0;

if (mode == 0) {
ndigit = 17;
}
digits = zend_dtoa(value, mode, ndigit, &decpt, &sign, NULL);
if (decpt == 9999) {
/*
* Infinity or NaN, convert to inf or nan with sign.
* We assume the buffer is at least ndigit long.
*/
snprintf(buf, ndigit + 1, "%s%s", (sign && *digits == 'I') ? "-" : "", *digits == 'I' ? "INF" : "NAN");
zend_freedtoa(digits);
return (buf);
}

dst = buf;
if (sign) {
*dst++ = '-';
}

if ((decpt >= 0 && decpt > ndigit) || decpt < -3) { /* use E-style */
/* exponential format (e.g. 1.2345e+13) */
if (--decpt < 0) {
sign = 1;
decpt = -decpt;
} else {
sign = 0;
}
src = digits;
*dst++ = *src++;
*dst++ = dec_point;
if (*src == '\0') {
*dst++ = '0';
} else {
do {
*dst++ = *src++;
} while (*src != '\0');
}
*dst++ = exponent;
if (sign) {
*dst++ = '-';
} else {
*dst++ = '+';
}
if (decpt < 10) {
*dst++ = '0' + decpt;
*dst = '\0';
} else {
/* XXX - optimize */
int n;
for (n = decpt, i = 0; (n /= 10) != 0; i++);
dst[i + 1] = '\0';
while (decpt != 0) {
dst[i--] = '0' + decpt % 10;
decpt /= 10;
}
}
} else if (decpt < 0) {
/* standard format 0. */
*dst++ = '0'; /* zero before decimal point */
*dst++ = dec_point;
do {
*dst++ = '0';
} while (++decpt < 0);
src = digits;
while (*src != '\0') {
*dst++ = *src++;
}
*dst = '\0';
} else {
/* standard format */
for (i = 0, src = digits; i < decpt; i++) {
if (*src != '\0') {
*dst++ = *src++;
} else {
*dst++ = '0';
}
}
if (*src != '\0') {
if (src == digits) {
*dst++ = '0'; /* zero before decimal point */
}
*dst++ = dec_point;
for (i = decpt; digits[i] != '\0'; i++) {
*dst++ = digits[i];
}
}
*dst = '\0';
}
zend_freedtoa(digits);
return (buf);
}
/* }}} */

/* {{{ Apache license */
/* ====================================================================
* Copyright (c) 1995-1998 The Apache Group. All rights reserved.
Expand Down Expand Up @@ -1043,7 +943,7 @@ static size_t format_converter(buffy * odp, const char *fmt, va_list ap) /* {{{
lconv = localeconv();
}
#endif
s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
s = zend_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
if (*s == '-') {
prefix_char = *s++;
} else if (print_sign) {
Expand Down
5 changes: 3 additions & 2 deletions main/snprintf.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ PHPAPI int ap_php_snprintf(char *, size_t, const char *, ...) ZEND_ATTRIBUTE_FOR
PHPAPI int ap_php_vsnprintf(char *, size_t, const char *, va_list ap);
PHPAPI int ap_php_vasprintf(char **buf, const char *format, va_list ap);
PHPAPI int ap_php_asprintf(char **buf, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3);
PHPAPI char * php_gcvt(double value, int ndigit, char dec_point, char exponent, char *buf);
PHPAPI char * php_0cvt(double value, int ndigit, char dec_point, char exponent, char *buf);
PHPAPI char * php_conv_fp(char format, double num,
bool add_dp, int precision, char dec_point, bool * is_negative, char *buf, size_t *len);

END_EXTERN_C()

#define php_gcvt zend_gcvt

#ifdef slprintf
#undef slprintf
#endif
Expand Down Expand Up @@ -138,7 +139,7 @@ PHPAPI char * ap_php_conv_p2(uint64_t num, int nbits,
* another level (see NDIG in php_conv_fp()).
* Applies to the formatting functions of both spprintf.c and snprintf.c, which
* use equally sized buffers of MAX_BUF_SIZE = 512 to hold the result of the
* call to php_gcvt().
* call to zend_gcvt().
* This should be reasonably smaller than MAX_BUF_SIZE (I think MAX_BUF_SIZE - 9
* should be enough, but let's give some more space) */
#define FORMAT_CONV_MAX_PRECISION 500
Expand Down
4 changes: 2 additions & 2 deletions main/spprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
* NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
* which can be at most max length of double
*/
#define NUM_BUF_SIZE PHP_DOUBLE_MAX_LENGTH
#define NUM_BUF_SIZE ZEND_DOUBLE_MAX_LENGTH

#define NUM(c) (c - '0')

Expand Down Expand Up @@ -651,7 +651,7 @@ static void xbuf_format_converter(void *xbuf, bool is_char, const char *fmt, va_
lconv = localeconv();
}
#endif
s = php_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
s = zend_gcvt(fp_num, precision, (*fmt=='H' || *fmt == 'k') ? '.' : LCONV_DECIMAL_POINT, (*fmt == 'G' || *fmt == 'H')?'E':'e', &num_buf[1]);
if (*s == '-')
prefix_char = *s++;
else if (print_sign)
Expand Down

0 comments on commit d28f6e6

Please sign in to comment.