mirror of
https://github.com/php/php-src.git
synced 2025-01-20 10:43:40 +08:00
use BSD licensed implementation of double-to-string utilities instead of LGPL one
this patch also fixes thread safety issues in zend_strtod()
This commit is contained in:
parent
d0792dc615
commit
4789badd3a
@ -994,6 +994,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i
|
||||
fpsetmask(0);
|
||||
#endif
|
||||
|
||||
zend_startup_strtod();
|
||||
zend_startup_extensions_mechanism();
|
||||
|
||||
/* Set up utility functions and values */
|
||||
@ -1177,6 +1178,7 @@ void zend_shutdown(TSRMLS_D)
|
||||
|
||||
zend_hash_destroy(GLOBAL_CONSTANTS_TABLE);
|
||||
free(GLOBAL_CONSTANTS_TABLE);
|
||||
zend_shutdown_strtod();
|
||||
|
||||
#ifdef ZTS
|
||||
GLOBAL_FUNCTION_TABLE = NULL;
|
||||
|
1743
Zend/zend_strtod.c
1743
Zend/zend_strtod.c
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
| Copyright (c) 1998-2006 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 |
|
||||
| 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 |
|
||||
@ -25,7 +25,12 @@
|
||||
#include <zend.h>
|
||||
|
||||
BEGIN_EXTERN_C()
|
||||
ZEND_API void zend_freedtoa(char *s);
|
||||
ZEND_API char * zend_dtoa(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve);
|
||||
ZEND_API double zend_strtod(const char *s00, char **se);
|
||||
ZEND_API double zend_u_strtod(const UChar *nptr, UChar **endptr);
|
||||
ZEND_API int zend_startup_strtod(void);
|
||||
ZEND_API int zend_shutdown_strtod(void);
|
||||
END_EXTERN_C()
|
||||
|
||||
#endif
|
||||
|
@ -51,110 +51,6 @@ static char hexchars[] = "0123456789abcdef";
|
||||
static char HEXCHARS[] = "0123456789ABCDEF";
|
||||
|
||||
|
||||
/*
|
||||
* cvt.c - IEEE floating point formatting routines for FreeBSD
|
||||
* from GNU libc-4.6.27
|
||||
*/
|
||||
|
||||
/*
|
||||
* php_convert_to_decimal converts to decimal
|
||||
* the number of digits is specified by ndigit
|
||||
* decpt is set to the position of the decimal point
|
||||
* sign is set to 0 for positive, 1 for negative
|
||||
*/
|
||||
static char *php_convert_to_decimal(double arg, int ndigits, int *decpt, int *sign, int eflag)
|
||||
{
|
||||
register int r2;
|
||||
int mvl;
|
||||
double fi, fj;
|
||||
register char *p, *p1;
|
||||
/*THREADX*/
|
||||
#ifndef THREAD_SAFE
|
||||
static char cvt_buf[NDIG];
|
||||
#endif
|
||||
|
||||
if (ndigits >= NDIG - 1)
|
||||
ndigits = NDIG - 2;
|
||||
r2 = 0;
|
||||
*sign = 0;
|
||||
p = &cvt_buf[0];
|
||||
if (arg < 0) {
|
||||
*sign = 1;
|
||||
arg = -arg;
|
||||
}
|
||||
arg = modf(arg, &fi);
|
||||
p1 = &cvt_buf[NDIG];
|
||||
/*
|
||||
* Do integer part
|
||||
*/
|
||||
if (fi != 0) {
|
||||
p1 = &cvt_buf[NDIG];
|
||||
while (fi != 0) {
|
||||
fj = modf(fi / 10, &fi);
|
||||
if (p1 <= &cvt_buf[0]) {
|
||||
mvl = NDIG - ndigits;
|
||||
memmove(&cvt_buf[mvl], &cvt_buf[0], NDIG-mvl-1);
|
||||
p1 += mvl;
|
||||
}
|
||||
*--p1 = (int) ((fj + .03) * 10) + '0';
|
||||
r2++;
|
||||
}
|
||||
while (p1 < &cvt_buf[NDIG])
|
||||
*p++ = *p1++;
|
||||
} else if (arg > 0) {
|
||||
while ((fj = arg * 10) < 1) {
|
||||
if (!eflag && (r2 * -1) < ndigits) {
|
||||
break;
|
||||
}
|
||||
arg = fj;
|
||||
r2--;
|
||||
}
|
||||
}
|
||||
p1 = &cvt_buf[ndigits];
|
||||
if (eflag == 0)
|
||||
p1 += r2;
|
||||
*decpt = r2;
|
||||
if (p1 < &cvt_buf[0]) {
|
||||
cvt_buf[0] = '\0';
|
||||
return (cvt_buf);
|
||||
}
|
||||
if (p <= p1 && p < &cvt_buf[NDIG]) {
|
||||
arg = modf(arg * 10, &fj);
|
||||
if ((int)fj==10) {
|
||||
*p++ = '1';
|
||||
fj = 0;
|
||||
*decpt = ++r2;
|
||||
}
|
||||
while (p <= p1 && p < &cvt_buf[NDIG]) {
|
||||
*p++ = (int) fj + '0';
|
||||
arg = modf(arg * 10, &fj);
|
||||
}
|
||||
}
|
||||
if (p1 >= &cvt_buf[NDIG]) {
|
||||
cvt_buf[NDIG - 1] = '\0';
|
||||
return (cvt_buf);
|
||||
}
|
||||
p = p1;
|
||||
*p1 += 5;
|
||||
while (*p1 > '9') {
|
||||
*p1 = '0';
|
||||
if (p1 > cvt_buf)
|
||||
++ * --p1;
|
||||
else {
|
||||
*p1 = '1';
|
||||
(*decpt)++;
|
||||
if (eflag == 0) {
|
||||
if (p > cvt_buf)
|
||||
*p = '0';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return (cvt_buf);
|
||||
}
|
||||
|
||||
|
||||
inline static void
|
||||
php_sprintf_appendchar(char **buffer, int *pos, int *size, char add TSRMLS_DC)
|
||||
{
|
||||
@ -299,19 +195,10 @@ php_sprintf_appenddouble(char **buffer, int *pos,
|
||||
int always_sign
|
||||
TSRMLS_DC)
|
||||
{
|
||||
char numbuf[NUM_BUF_SIZE];
|
||||
char *cvt;
|
||||
register int i = 0, j = 0;
|
||||
int sign, decpt, cvt_len;
|
||||
char decimal_point = '.';
|
||||
#ifdef HAVE_LOCALE_H
|
||||
struct lconv lc;
|
||||
char locale_decimal_point;
|
||||
localeconv_r(&lc);
|
||||
locale_decimal_point = (lc.decimal_point)[0];
|
||||
#else
|
||||
char locale_decimal_point = '.';
|
||||
#endif
|
||||
char num_buf[NUM_BUF_SIZE];
|
||||
char *s, *q;
|
||||
int s_len;
|
||||
int is_negative;
|
||||
|
||||
PRINTF_DEBUG(("sprintf: appenddouble(%x, %x, %x, %f, %d, '%c', %d, %c)\n",
|
||||
*buffer, pos, size, number, width, padding, alignment, fmt));
|
||||
@ -322,92 +209,66 @@ php_sprintf_appenddouble(char **buffer, int *pos,
|
||||
}
|
||||
|
||||
if (zend_isnan(number)) {
|
||||
sign = (number<0);
|
||||
is_negative = (number<0);
|
||||
php_sprintf_appendstring(buffer, pos, size, "NaN", 3, 0, padding,
|
||||
alignment, precision, sign, 0, always_sign);
|
||||
alignment, precision, is_negative, 0, always_sign);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zend_isinf(number)) {
|
||||
sign = (number<0);
|
||||
is_negative = (number<0);
|
||||
php_sprintf_appendstring(buffer, pos, size, "INF", 3, 0, padding,
|
||||
alignment, precision, sign, 0, always_sign);
|
||||
alignment, precision, is_negative, 0, always_sign);
|
||||
return;
|
||||
}
|
||||
|
||||
cvt = php_convert_to_decimal(number, precision, &decpt, &sign, (fmt == 'e'));
|
||||
cvt_len = strlen(cvt);
|
||||
switch (fmt) {
|
||||
case 'e':
|
||||
if (precision) {
|
||||
precision--;
|
||||
}
|
||||
case 'E':
|
||||
case 'f':
|
||||
s = ap_php_conv_fp(fmt, number, 0, precision,
|
||||
&is_negative, &num_buf[1], &s_len);
|
||||
if (is_negative) {
|
||||
num_buf[0] = '-';
|
||||
s = num_buf;
|
||||
s_len++;
|
||||
} else if (always_sign) {
|
||||
num_buf[0] = '+';
|
||||
s = num_buf;
|
||||
s_len++;
|
||||
}
|
||||
break;
|
||||
|
||||
if (sign) {
|
||||
numbuf[i++] = '-';
|
||||
} else if (always_sign) {
|
||||
numbuf[i++] = '+';
|
||||
case 'g':
|
||||
case 'G':
|
||||
if (precision == 0)
|
||||
precision = 1;
|
||||
/*
|
||||
* * We use &num_buf[ 1 ], so that we have room for the sign
|
||||
*/
|
||||
s = bsd_gcvt(number, precision, &num_buf[1]);
|
||||
is_negative = 0;
|
||||
if (*s == '-') {
|
||||
is_negative = 1;
|
||||
s = &num_buf[1];
|
||||
} else if (always_sign) {
|
||||
num_buf[0] = '+';
|
||||
s = num_buf;
|
||||
}
|
||||
|
||||
s_len = strlen(s);
|
||||
|
||||
if (fmt == 'G' && (q = strchr(s, 'e')) != NULL) {
|
||||
*q = 'E';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (fmt == 'f' || fmt == 'F') {
|
||||
if (decpt <= 0) {
|
||||
numbuf[i++] = '0';
|
||||
if (precision > 0) {
|
||||
int k = precision;
|
||||
numbuf[i++] = fmt == 'F' ? decimal_point : locale_decimal_point;
|
||||
while ((decpt++ < 0) && k--) {
|
||||
numbuf[i++] = '0';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (decpt-- > 0) {
|
||||
numbuf[i++] = j < cvt_len ? cvt[j++] : '0';
|
||||
}
|
||||
if (precision > 0) {
|
||||
numbuf[i++] = fmt == 'F' ? decimal_point : locale_decimal_point;
|
||||
while (precision-- > 0) {
|
||||
numbuf[i++] = j < cvt_len ? cvt[j++] : '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fmt == 'e' || fmt == 'E') {
|
||||
char *exp_p;
|
||||
int dec2;
|
||||
|
||||
decpt--;
|
||||
|
||||
numbuf[i++] = cvt[j++];
|
||||
numbuf[i++] = decimal_point;
|
||||
|
||||
if (precision > 0) {
|
||||
int k = precision;
|
||||
|
||||
while (k-- && cvt[j]) {
|
||||
numbuf[i++] = cvt[j++];
|
||||
}
|
||||
} else {
|
||||
numbuf[i++] = '0';
|
||||
}
|
||||
|
||||
numbuf[i++] = fmt;
|
||||
exp_p = php_convert_to_decimal(decpt, 0, &dec2, &sign, 0);
|
||||
numbuf[i++] = sign ? '-' : '+';
|
||||
if (*exp_p) {
|
||||
while (*exp_p) {
|
||||
numbuf[i++] = *(exp_p++);
|
||||
}
|
||||
} else {
|
||||
numbuf[i++] = '0';
|
||||
}
|
||||
} else {
|
||||
numbuf[i++] = cvt[j++];
|
||||
if (precision > 0)
|
||||
numbuf[i++] = decimal_point;
|
||||
}
|
||||
|
||||
while (cvt[j]) {
|
||||
numbuf[i++] = cvt[j++];
|
||||
}
|
||||
|
||||
numbuf[i] = '\0';
|
||||
|
||||
php_sprintf_appendstring(buffer, pos, size, numbuf, width, 0, padding,
|
||||
alignment, i, sign, 0, always_sign);
|
||||
php_sprintf_appendstring(buffer, pos, size, s, width, 0, padding,
|
||||
alignment, s_len, is_negative, 0, always_sign);
|
||||
}
|
||||
|
||||
|
||||
@ -690,7 +551,10 @@ php_formatted_print(int ht, int *len, int use_array, int format_offset TSRMLS_DC
|
||||
width, padding, alignment);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
/* XXX not done */
|
||||
|
@ -15,11 +15,11 @@ foreach(array(1e2, 5.2e25, 85.29e-23, 9e-9) AS $value) {
|
||||
d:100;
|
||||
float\(100\)
|
||||
|
||||
d:5\.2E\+25;
|
||||
d:5[0-9]*;
|
||||
float\(5\.2E\+25\)
|
||||
|
||||
d:8\.52[89][0-9]+E-22;
|
||||
float\(8\.529E-22\)
|
||||
|
||||
d:9\.[0-9]*E-9;
|
||||
d:8\.[9]*[0-9]*E-9;
|
||||
float\(9\.0E-9\)
|
||||
|
@ -37,4 +37,4 @@ string(7) "-5.60 "
|
||||
string(7) "-005.60"
|
||||
string(7) "-5.6000"
|
||||
|
||||
string(105) "12345678%d00000000000000000000000000000000000000000000000000.0000"
|
||||
string(105) "1234567%d.0000"
|
||||
|
439
main/snprintf.c
439
main/snprintf.c
@ -18,6 +18,210 @@
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
|
||||
#include "php.h"
|
||||
|
||||
#include <zend_strtod.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, 2006 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
static char * __cvt(double value, int ndigit, int *decpt, int *sign, int fmode, int pad)
|
||||
{
|
||||
register char *s = NULL;
|
||||
char *p, *rve, c;
|
||||
size_t siz;
|
||||
|
||||
if (ndigit < 0) {
|
||||
siz = -ndigit + 1;
|
||||
} else {
|
||||
siz = ndigit + 1;
|
||||
}
|
||||
|
||||
/* __dtoa() doesn't allocate space for 0 so we do it by hand */
|
||||
if (value == 0.0) {
|
||||
*decpt = 1 - fmode; /* 1 for 'e', 0 for 'f' */
|
||||
*sign = 0;
|
||||
if ((rve = s = (char *)malloc(ndigit?siz:2)) == NULL)
|
||||
return(NULL);
|
||||
*rve++ = '0';
|
||||
*rve = '\0';
|
||||
if (!ndigit) {
|
||||
return(s);
|
||||
}
|
||||
} else {
|
||||
p = zend_dtoa(value, fmode + 2, ndigit, decpt, sign, &rve);
|
||||
if (*decpt == 9999) {
|
||||
/* Infinity or Nan, convert to inf or nan like printf */
|
||||
*decpt = 0;
|
||||
c = *p;
|
||||
zend_freedtoa(p);
|
||||
return(c == 'I' ? "inf" : "nan");
|
||||
}
|
||||
/* Make a local copy and adjust rve to be in terms of s */
|
||||
if (pad && fmode)
|
||||
siz += *decpt;
|
||||
if ((s = (char *)malloc(siz+1)) == NULL) {
|
||||
zend_freedtoa(p);
|
||||
return(NULL);
|
||||
}
|
||||
(void) strlcpy(s, p, siz);
|
||||
rve = s + (rve - p);
|
||||
zend_freedtoa(p);
|
||||
}
|
||||
|
||||
/* Add trailing zeros */
|
||||
if (pad) {
|
||||
siz -= rve - s;
|
||||
while (--siz)
|
||||
*rve++ = '0';
|
||||
*rve = '\0';
|
||||
}
|
||||
|
||||
return(s);
|
||||
}
|
||||
|
||||
char *bsd_ecvt(double value, int ndigit, int *decpt, int *sign)
|
||||
{
|
||||
return(__cvt(value, ndigit, decpt, sign, 0, 1));
|
||||
}
|
||||
|
||||
char *bsd_fcvt(double value, int ndigit, int *decpt, int *sign)
|
||||
{
|
||||
return(__cvt(value, ndigit, decpt, sign, 1, 1));
|
||||
}
|
||||
|
||||
char *bsd_gcvt(double value, int ndigit, char *buf)
|
||||
{
|
||||
char *digits, *dst, *src;
|
||||
int i, decpt, sign;
|
||||
struct lconv *lconv;
|
||||
|
||||
lconv = localeconv();
|
||||
|
||||
digits = zend_dtoa(value, 2, 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' ? "inf" : "nan");
|
||||
zend_freedtoa(digits);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
dst = buf;
|
||||
if (sign)
|
||||
*dst++ = '-';
|
||||
|
||||
for (i = 0; i < ndigit && digits[i] != '\0'; i++);
|
||||
|
||||
if ((decpt >= 0 && decpt - i > 4)
|
||||
|| (decpt < 0 && 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++ = *lconv->decimal_point;
|
||||
if (*src == '\0') {
|
||||
*dst++ = '0';
|
||||
} else {
|
||||
do {
|
||||
*dst++ = *src++;
|
||||
} while (*src != '\0');
|
||||
}
|
||||
*dst++ = 'e';
|
||||
if (sign)
|
||||
*dst++ = '-';
|
||||
else
|
||||
*dst++ = '+';
|
||||
if (decpt < 10) {
|
||||
*dst++ = '0' + decpt;
|
||||
*dst = '\0';
|
||||
} else {
|
||||
/* XXX - optimize */
|
||||
for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
|
||||
continue;
|
||||
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++ = *lconv->decimal_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++ = *lconv->decimal_point;
|
||||
for (i = decpt; digits[i] != '\0'; i++) {
|
||||
*dst++ = digits[i];
|
||||
}
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
zend_freedtoa(digits);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1995-1998 The Apache Group. All rights reserved.
|
||||
*
|
||||
@ -73,20 +277,6 @@
|
||||
* <panos@alumni.cs.colorado.edu> for xinetd.
|
||||
*/
|
||||
|
||||
#include "php.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
#define NUL '\0'
|
||||
@ -171,14 +361,17 @@ char * ap_php_conv_fp(register char format, register double num,
|
||||
boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len)
|
||||
{
|
||||
register char *s = buf;
|
||||
register char *p;
|
||||
register char *p, *p_orig;
|
||||
int decimal_point;
|
||||
char buf1[NDIG];
|
||||
|
||||
if (precision >= NDIG - 1) {
|
||||
precision = NDIG - 2;
|
||||
}
|
||||
|
||||
if (format == 'f')
|
||||
p = ap_php_fcvt(num, precision, &decimal_point, is_negative, buf1);
|
||||
p_orig = p = bsd_fcvt(num, precision, &decimal_point, is_negative);
|
||||
else /* either e or E format */
|
||||
p = ap_php_ecvt(num, precision + 1, &decimal_point, is_negative, buf1);
|
||||
p_orig = p = bsd_ecvt(num, precision + 1, &decimal_point, is_negative);
|
||||
|
||||
/*
|
||||
* Check for Infinity and NaN
|
||||
@ -187,17 +380,20 @@ char * ap_php_conv_fp(register char format, register double num,
|
||||
*len = strlen(p);
|
||||
memcpy(buf, p, *len + 1);
|
||||
*is_negative = FALSE;
|
||||
free(p_orig);
|
||||
return (buf);
|
||||
}
|
||||
if (format == 'f') {
|
||||
if (decimal_point <= 0) {
|
||||
*s++ = '0';
|
||||
if (precision > 0) {
|
||||
*s++ = '.';
|
||||
while (decimal_point++ < 0)
|
||||
*s++ = '0';
|
||||
} else if (add_dp) {
|
||||
*s++ = '.';
|
||||
if (num != 0 || precision > 0) {
|
||||
*s++ = '0';
|
||||
if (precision > 0) {
|
||||
*s++ = '.';
|
||||
while (decimal_point++ < 0)
|
||||
*s++ = '0';
|
||||
} else if (add_dp) {
|
||||
*s++ = '.';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int addz = decimal_point >= NDIG ? decimal_point - NDIG + 1 : 0;
|
||||
@ -239,21 +435,18 @@ char * ap_php_conv_fp(register char format, register double num,
|
||||
/*
|
||||
* Make sure the exponent has at least 2 digits
|
||||
*/
|
||||
if (t_len == 1)
|
||||
*s++ = '0';
|
||||
while (t_len--)
|
||||
*s++ = *p++;
|
||||
} else {
|
||||
*s++ = '+';
|
||||
*s++ = '0';
|
||||
*s++ = '0';
|
||||
}
|
||||
}
|
||||
*len = s - buf;
|
||||
free(p_orig);
|
||||
return (buf);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Convert num to a base X number where X is a power of 2. nbits determines X.
|
||||
* For example, if nbits is 3, we do base 8 conversion
|
||||
@ -283,189 +476,6 @@ char * ap_php_conv_p2(register u_wide_int num, register int nbits,
|
||||
return (p);
|
||||
}
|
||||
|
||||
/*
|
||||
* cvt.c - IEEE floating point formatting routines for FreeBSD
|
||||
* from GNU libc-4.6.27
|
||||
*/
|
||||
|
||||
/*
|
||||
* ap_php_ecvt converts to decimal
|
||||
* the number of digits is specified by ndigit
|
||||
* decpt is set to the position of the decimal point
|
||||
* sign is set to 0 for positive, 1 for negative
|
||||
*/
|
||||
|
||||
|
||||
char * ap_php_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf)
|
||||
{
|
||||
register int r2;
|
||||
int mvl;
|
||||
double fi, fj;
|
||||
register char *p, *p1;
|
||||
|
||||
if (ndigits >= NDIG - 1)
|
||||
ndigits = NDIG - 2;
|
||||
r2 = 0;
|
||||
*sign = 0;
|
||||
p = &buf[0];
|
||||
if (arg < 0) {
|
||||
*sign = 1;
|
||||
arg = -arg;
|
||||
}
|
||||
arg = modf(arg, &fi);
|
||||
p1 = &buf[NDIG];
|
||||
/*
|
||||
* Do integer part
|
||||
*/
|
||||
if (fi != 0) {
|
||||
while (fi != 0) {
|
||||
fj = modf(fi / 10, &fi);
|
||||
if (p1 <= &buf[0]) {
|
||||
mvl = NDIG - ndigits;
|
||||
if (ndigits > 0) {
|
||||
memmove(&buf[mvl], &buf[0], NDIG-mvl-1);
|
||||
}
|
||||
p1 += mvl;
|
||||
}
|
||||
*--p1 = (int) ((fj + .03) * 10) + '0';
|
||||
r2++;
|
||||
}
|
||||
while (p1 < &buf[NDIG]) {
|
||||
*p++ = *p1++;
|
||||
}
|
||||
} else if (arg > 0) {
|
||||
while ((fj = arg * 10) < 1) {
|
||||
if (!eflag && (r2 * -1) < ndigits) {
|
||||
break;
|
||||
}
|
||||
arg = fj;
|
||||
r2--;
|
||||
}
|
||||
}
|
||||
p1 = &buf[ndigits];
|
||||
if (eflag == 0)
|
||||
p1 += r2;
|
||||
*decpt = r2;
|
||||
if (p1 < &buf[0]) {
|
||||
buf[0] = '\0';
|
||||
return (buf);
|
||||
}
|
||||
if (p <= p1 && p < &buf[NDIG]) {
|
||||
arg = modf(arg * 10, &fj);
|
||||
if ((int)fj==10) {
|
||||
*p++ = '1';
|
||||
fj = 0;
|
||||
*decpt = ++r2;
|
||||
}
|
||||
while (p <= p1 && p < &buf[NDIG]) {
|
||||
*p++ = (int) fj + '0';
|
||||
arg = modf(arg * 10, &fj);
|
||||
}
|
||||
}
|
||||
if (p1 >= &buf[NDIG]) {
|
||||
buf[NDIG - 1] = '\0';
|
||||
return (buf);
|
||||
}
|
||||
p = p1;
|
||||
*p1 += 5;
|
||||
while (*p1 > '9') {
|
||||
*p1 = '0';
|
||||
if (p1 > buf)
|
||||
++ * --p1;
|
||||
else {
|
||||
*p1 = '1';
|
||||
(*decpt)++;
|
||||
if (eflag == 0) {
|
||||
if (p > buf)
|
||||
*p = '0';
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return (buf);
|
||||
}
|
||||
|
||||
char * ap_php_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
|
||||
{
|
||||
return (ap_php_cvt(arg, ndigits, decpt, sign, 1, buf));
|
||||
}
|
||||
|
||||
char * ap_php_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf)
|
||||
{
|
||||
return (ap_php_cvt(arg, ndigits, decpt, sign, 0, buf));
|
||||
}
|
||||
|
||||
/*
|
||||
* ap_php_gcvt - Floating output conversion to
|
||||
* minimal length string
|
||||
*/
|
||||
|
||||
char * ap_php_gcvt(double number, int ndigit, char *buf, boolean_e altform)
|
||||
{
|
||||
int sign, decpt;
|
||||
register char *p1, *p2;
|
||||
register int i;
|
||||
char buf1[NDIG];
|
||||
|
||||
if (ndigit >= NDIG - 1) {
|
||||
ndigit = NDIG - 2;
|
||||
}
|
||||
|
||||
p1 = ap_php_ecvt(number, ndigit, &decpt, &sign, buf1);
|
||||
p2 = buf;
|
||||
if (sign)
|
||||
*p2++ = '-';
|
||||
for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--)
|
||||
ndigit--;
|
||||
if ((decpt >= 0 && decpt - ndigit > 4)
|
||||
|| (decpt < 0 && decpt < -3)) { /* use E-style */
|
||||
decpt--;
|
||||
*p2++ = *p1++;
|
||||
*p2++ = '.';
|
||||
for (i = 1; i < ndigit; i++)
|
||||
*p2++ = *p1++;
|
||||
if (*(p2 - 1) == '.') {
|
||||
*p2++ = '0';
|
||||
}
|
||||
*p2++ = 'e';
|
||||
if (decpt < 0) {
|
||||
decpt = -decpt;
|
||||
*p2++ = '-';
|
||||
} else
|
||||
*p2++ = '+';
|
||||
if (decpt / 100 > 0)
|
||||
*p2++ = decpt / 100 + '0';
|
||||
if (decpt / 10 > 0)
|
||||
*p2++ = (decpt % 100) / 10 + '0';
|
||||
*p2++ = decpt % 10 + '0';
|
||||
} else {
|
||||
if (decpt <= 0) {
|
||||
if (*p1 != '0') {
|
||||
*p2++ = '0';
|
||||
*p2++ = '.';
|
||||
}
|
||||
while (decpt < 0) {
|
||||
decpt++;
|
||||
*p2++ = '0';
|
||||
}
|
||||
}
|
||||
for (i = 1; i <= ndigit; i++) {
|
||||
*p2++ = *p1++;
|
||||
if (i == decpt)
|
||||
*p2++ = '.';
|
||||
}
|
||||
if (ndigit < decpt) {
|
||||
while (ndigit++ < decpt)
|
||||
*p2++ = '0';
|
||||
*p2++ = '.';
|
||||
}
|
||||
}
|
||||
if (p2[-1] == '.' && !altform)
|
||||
p2--;
|
||||
*p2 = '\0';
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions
|
||||
@ -909,7 +919,7 @@ static int format_converter(register buffy * odp, const char *fmt,
|
||||
pad_char = ' ';
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case 'f':
|
||||
case 'e':
|
||||
case 'E':
|
||||
@ -979,8 +989,7 @@ static int format_converter(register buffy * odp, const char *fmt,
|
||||
/*
|
||||
* * We use &num_buf[ 1 ], so that we have room for the sign
|
||||
*/
|
||||
s = ap_php_gcvt(fp_num, precision, &num_buf[1],
|
||||
alternate_form);
|
||||
s = bsd_gcvt(fp_num, precision, &num_buf[1]);
|
||||
if (*s == '-')
|
||||
prefix_char = *s++;
|
||||
else if (print_sign)
|
||||
|
@ -106,11 +106,6 @@ typedef enum {
|
||||
LM_LONG_DOUBLE
|
||||
} length_modifier_e;
|
||||
|
||||
extern char * ap_php_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf);
|
||||
extern char * ap_php_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf);
|
||||
extern char * ap_php_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf);
|
||||
extern char * ap_php_gcvt(double number, int ndigit, char *buf, boolean_e altform);
|
||||
|
||||
#ifdef PHP_WIN32
|
||||
# define WIDE_INT __int64
|
||||
#elif SIZEOF_LONG_LONG_INT
|
||||
@ -134,6 +129,9 @@ extern char * ap_php_conv_fp(register char format, register double num,
|
||||
extern char * ap_php_conv_p2(register u_wide_int num, register int nbits,
|
||||
char format, char *buf_end, register int *len);
|
||||
|
||||
extern char * bsd_ecvt(double value, int ndigit, int *decpt, int *sign);
|
||||
extern char * bsd_fcvt(double value, int ndigit, int *decpt, int *sign);
|
||||
extern char * bsd_gcvt(double value, int ndigit, char *buf);
|
||||
|
||||
#endif /* SNPRINTF_H */
|
||||
|
||||
|
@ -685,8 +685,7 @@ fmt_string:
|
||||
/*
|
||||
* * We use &num_buf[ 1 ], so that we have room for the sign
|
||||
*/
|
||||
s = ap_php_gcvt(fp_num, precision, &num_buf[1],
|
||||
alternate_form);
|
||||
s = bsd_gcvt(fp_num, precision, &num_buf[1]);
|
||||
if (*s == '-')
|
||||
prefix_char = *s++;
|
||||
else if (print_sign)
|
||||
|
Loading…
Reference in New Issue
Block a user