Skip to content

Commit 33260cf

Browse files
committed
Make float to string casts locale-independent
1 parent cb933d6 commit 33260cf

File tree

7 files changed

+89
-100
lines changed

7 files changed

+89
-100
lines changed

Zend/zend_operators.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -512,15 +512,7 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
512512

513513
ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op) /* {{{ */
514514
{
515-
if (Z_TYPE_P(op) == IS_DOUBLE) {
516-
zend_string *str;
517-
double dval = Z_DVAL_P(op);
518-
519-
str = zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), dval);
520-
ZVAL_NEW_STR(op, str);
521-
} else {
522-
_convert_to_string(op);
523-
}
515+
_convert_to_string(op);
524516
}
525517
/* }}} */
526518

@@ -553,7 +545,7 @@ ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op) /* {{{ */
553545
zend_string *str;
554546
double dval = Z_DVAL_P(op);
555547

556-
str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval);
548+
str = zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), dval);
557549
/* %G already handles removing trailing zeros from the fractional part, yay */
558550
ZVAL_NEW_STR(op, str);
559551
break;
@@ -866,7 +858,7 @@ static zend_always_inline zend_string* __zval_get_string_func(zval *op, zend_boo
866858
return zend_long_to_str(Z_LVAL_P(op));
867859
}
868860
case IS_DOUBLE: {
869-
return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
861+
return zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), Z_DVAL_P(op));
870862
}
871863
case IS_ARRAY:
872864
zend_error(E_WARNING, "Array to string conversion");

Zend/zend_strtod.c

Lines changed: 0 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,6 @@
159159
* floating-point numbers and flushes underflows to zero rather
160160
* than implementing gradual underflow, then you must also #define
161161
* Sudden_Underflow.
162-
* #define USE_LOCALE to use the current locale's decimal_point value.
163162
* #define SET_INEXACT if IEEE arithmetic is being used and extra
164163
* computation should be done to set the inexact flag when the
165164
* result is inexact and avoid setting inexact when the result
@@ -206,10 +205,6 @@ static void Bug(const char *message) {
206205
#include "stdlib.h"
207206
#include "string.h"
208207

209-
#ifdef USE_LOCALE
210-
#include "locale.h"
211-
#endif
212-
213208
#ifdef Honor_FLT_ROUNDS
214209
#ifndef Trust_FLT_ROUNDS
215210
#include <fenv.h>
@@ -1827,25 +1822,6 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
18271822
#endif
18281823
#endif /*}}*/
18291824
};
1830-
#ifdef USE_LOCALE
1831-
int i;
1832-
#ifdef NO_LOCALE_CACHE
1833-
const unsigned char *decimalpoint = (unsigned char*)
1834-
localeconv()->decimal_point;
1835-
#else
1836-
const unsigned char *decimalpoint;
1837-
static unsigned char *decimalpoint_cache;
1838-
if (!(s0 = decimalpoint_cache)) {
1839-
s0 = (unsigned char*)localeconv()->decimal_point;
1840-
if ((decimalpoint_cache = (unsigned char*)
1841-
MALLOC(strlen((CONST char*)s0) + 1))) {
1842-
strcpy((char*)decimalpoint_cache, (CONST char*)s0);
1843-
s0 = decimalpoint_cache;
1844-
}
1845-
}
1846-
decimalpoint = s0;
1847-
#endif
1848-
#endif
18491825

18501826
/**** if (!hexdig['0']) hexdig_init(); ****/
18511827
havedig = 0;
@@ -1861,17 +1837,9 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
18611837
havedig++;
18621838
else {
18631839
zret = 1;
1864-
#ifdef USE_LOCALE
1865-
for(i = 0; decimalpoint[i]; ++i) {
1866-
if (s[i] != decimalpoint[i])
1867-
goto pcheck;
1868-
}
1869-
decpt = s += i;
1870-
#else
18711840
if (*s != '.')
18721841
goto pcheck;
18731842
decpt = ++s;
1874-
#endif
18751843
if (!hexdig[*s])
18761844
goto pcheck;
18771845
while(*s == '0')
@@ -1883,17 +1851,8 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
18831851
}
18841852
while(hexdig[*s])
18851853
s++;
1886-
#ifdef USE_LOCALE
1887-
if (*s == *decimalpoint && !decpt) {
1888-
for(i = 1; decimalpoint[i]; ++i) {
1889-
if (s[i] != decimalpoint[i])
1890-
goto pcheck;
1891-
}
1892-
decpt = s += i;
1893-
#else
18941854
if (*s == '.' && !decpt) {
18951855
decpt = ++s;
1896-
#endif
18971856
while(hexdig[*s])
18981857
s++;
18991858
}/*}*/
@@ -1982,19 +1941,9 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
19821941
x = b->x;
19831942
n = 0;
19841943
L = 0;
1985-
#ifdef USE_LOCALE
1986-
for(i = 0; decimalpoint[i+1]; ++i);
1987-
#endif
19881944
while(s1 > s0) {
1989-
#ifdef USE_LOCALE
1990-
if (*--s1 == decimalpoint[i]) {
1991-
s1 -= i;
1992-
continue;
1993-
}
1994-
#else
19951945
if (*--s1 == '.')
19961946
continue;
1997-
#endif
19981947
if (n == ULbits) {
19991948
*x++ = L;
20001949
L = 0;
@@ -2566,10 +2515,6 @@ zend_strtod
25662515
}
25672516
#endif /*}}*/
25682517
#endif /*}*/
2569-
#ifdef USE_LOCALE
2570-
CONST char *s2;
2571-
#endif
2572-
25732518
sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0;
25742519
dval(&rv) = 0.;
25752520
for(s = s00;;s++) switch(*s) {
@@ -2622,25 +2567,6 @@ zend_strtod
26222567
bc.dp0 = bc.dp1 = s - s0;
26232568
for(s1 = s; s1 > s0 && *--s1 == '0'; )
26242569
++nz1;
2625-
#ifdef USE_LOCALE
2626-
s1 = localeconv()->decimal_point;
2627-
if (c == *s1) {
2628-
c = '.';
2629-
if (*++s1) {
2630-
s2 = s;
2631-
for(;;) {
2632-
if (*++s2 != *s1) {
2633-
c = 0;
2634-
break;
2635-
}
2636-
if (!*++s1) {
2637-
s = s2;
2638-
break;
2639-
}
2640-
}
2641-
}
2642-
}
2643-
#endif
26442570
if (c == '.') {
26452571
c = *++s;
26462572
bc.dp1 = s - s0;

Zend/zend_strtod_int.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,6 @@ typedef unsigned long int uint32_t;
6464
# endif
6565
#endif
6666

67-
#ifdef USE_LOCALE
68-
#undef USE_LOCALE
69-
#endif
70-
7167
#ifndef NO_INFNAN_CHECK
7268
#define NO_INFNAN_CHECK
7369
#endif

ext/pdo/pdo_stmt.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -230,15 +230,8 @@ static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_s
230230
}
231231

232232
if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
233-
if (Z_TYPE_P(parameter) == IS_DOUBLE) {
234-
char *p;
235-
int len = zend_spprintf_unchecked(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(parameter));
236-
ZVAL_STRINGL(parameter, p, len);
237-
efree(p);
238-
} else {
239-
if (!try_convert_to_string(parameter)) {
240-
return 0;
241-
}
233+
if (!try_convert_to_string(parameter)) {
234+
return 0;
242235
}
243236
} else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) {
244237
convert_to_long(parameter);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Test that float to string and string to float casts are consistent
3+
--SKIPIF--
4+
<?php
5+
if (!setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8")) {
6+
die("skip locale needed for this test is not supported on this platform");
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
12+
setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8");
13+
14+
$float = 1/3;
15+
$string = (string) $float;
16+
$float = (float) $string;
17+
18+
printf("%.2f", $float);
19+
20+
?>
21+
--EXPECT--
22+
0,33
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
--TEST--
2+
Test that floats are converted to string locale independently
3+
--SKIPIF--
4+
<?php
5+
if (!setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8")) {
6+
die("skip locale needed for this test is not supported on this platform");
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
$f = 3.14;
12+
13+
setlocale(LC_ALL, "C");
14+
echo "C:\n";
15+
16+
var_dump($f);
17+
var_dump((string) $f);
18+
var_dump(strval($f));
19+
var_dump(var_export($f, true));
20+
debug_zval_dump($f);
21+
var_dump(serialize($f));
22+
var_dump(json_encode($f));
23+
printf("%.2f\n", $f);
24+
var_dump(sprintf("%.2f", $f));
25+
26+
setlocale(LC_ALL, "german", "de","de_DE","de_DE.ISO8859-1","de_DE.ISO_8859-1","de_DE.UTF-8");
27+
echo "\nde_DE:\n";
28+
29+
var_dump($f);
30+
var_dump((string) $f);
31+
var_dump(strval($f));
32+
var_dump(var_export($f, true));
33+
debug_zval_dump($f);
34+
var_dump(serialize($f));
35+
var_dump(json_encode($f));
36+
printf("%.2f\n", $f);
37+
var_dump(sprintf("%.2f", $f));
38+
39+
?>
40+
--EXPECT--
41+
C:
42+
float(3.14)
43+
string(4) "3.14"
44+
string(4) "3.14"
45+
string(4) "3.14"
46+
float(3.14)
47+
string(7) "d:3.14;"
48+
string(4) "3.14"
49+
3.14
50+
string(4) "3.14"
51+
52+
de_DE:
53+
float(3,14)
54+
string(4) "3.14"
55+
string(4) "3.14"
56+
string(4) "3.14"
57+
float(3,14)
58+
string(7) "d:3.14;"
59+
string(4) "3.14"
60+
3,14
61+
string(4) "3,14"

main/php.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,7 @@ ssize_t pread(int, void *, size_t, off64_t);
309309
BEGIN_EXTERN_C()
310310
void phperror(char *error);
311311
PHPAPI size_t php_write(void *buf, size_t size);
312-
PHPAPI size_t php_printf(const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1,
313-
2);
312+
PHPAPI size_t php_printf(const char *format, ...) PHP_ATTRIBUTE_FORMAT(printf, 1, 2);
314313
PHPAPI int php_get_module_initialized(void);
315314
#ifdef HAVE_SYSLOG_H
316315
#include "php_syslog.h"

0 commit comments

Comments
 (0)