]> granicus.if.org Git - php/commitdiff
Add support for %h and %H in printf()
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 22 Apr 2020 13:02:21 +0000 (15:02 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 27 May 2020 08:19:23 +0000 (10:19 +0200)
These are locale-independent variants of %g and %G.

Closes GH-5436.

UPGRADING
ext/standard/formatted_print.c
ext/standard/tests/strings/printf_h_H.phpt [new file with mode: 0644]

index c49015d17f388ab61e8146365ee8c3eb72fe6ea8..6f3abbfc7c8b557b0890bc5bbe63b74c465ef7e3 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -535,6 +535,11 @@ PHP 8.0 UPGRADE NOTES
     compile-time warnings and replay them on the next include, even if it is
     served from cache.
 
+- Standard:
+  . printf() and friends how support the %h and %H format specifiers. These
+    are the same as %g and %G, but always use "." as the decimal separator,
+    rather than determining it through the LC_NUMERIC locale.
+
 - Zip:
   . Extension updated to version 1.19.0
   . New ZipArchive::lastId property to get index value of last added entry.
index d982de74201d5ddb3980b75c1038a823027b71d3..f32f9f8abf4b70c90c13710b0d73cd63d270852c 100644 (file)
@@ -281,17 +281,25 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos,
 
                case 'g':
                case 'G':
+               case 'h':
+               case 'H':
+               {
                        if (precision == 0)
                                precision = 1;
-                       /*
-                        * * We use &num_buf[ 1 ], so that we have room for the sign
-                        */
+
+                       char decimal_point = '.';
+                       if (fmt == 'g' || fmt == 'G') {
 #ifdef ZTS
-                       localeconv_r(&lconv);
+                               localeconv_r(&lconv);
 #else
-                       lconv = localeconv();
+                               lconv = localeconv();
 #endif
-                       s = php_gcvt(number, precision, LCONV_DECIMAL_POINT, (fmt == 'G')?'E':'e', &num_buf[1]);
+                               decimal_point = LCONV_DECIMAL_POINT;
+                       }
+
+                       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]);
                        is_negative = 0;
                        if (*s == '-') {
                                is_negative = 1;
@@ -303,6 +311,7 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos,
 
                        s_len = strlen(s);
                        break;
+               }
        }
 
        php_sprintf_appendstring(buffer, pos, s, width, 0, padding,
@@ -562,12 +571,14 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n
                                                                                  width, padding, alignment);
                                        break;
 
-                               case 'g':
-                               case 'G':
                                case 'e':
                                case 'E':
                                case 'f':
                                case 'F':
+                               case 'g':
+                               case 'G':
+                               case 'h':
+                               case 'H':
                                        php_sprintf_appenddouble(&result, &outpos,
                                                                                         zval_get_double(tmp),
                                                                                         width, padding, alignment,
diff --git a/ext/standard/tests/strings/printf_h_H.phpt b/ext/standard/tests/strings/printf_h_H.phpt
new file mode 100644 (file)
index 0000000..a4ee0b8
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+sprintf() %h and %H specifiers
+--SKIPIF--
+<?php
+if (!setlocale(LC_ALL, "de_DE.utf8")) die("skip de_DE.utf8 locale not available");
+?>
+--FILE--
+<?php
+
+setlocale(LC_ALL, "de_DE.utf8");
+$f = 1.25;
+printf("%g %G %h %H\n", $f, $f, $f, $f);
+$f = 0.00000125;
+printf("%g %G %h %H\n", $f, $f, $f, $f);
+
+?>
+--EXPECT--
+1,25 1,25 1.25 1.25
+1,25e-6 1,25E-6 1.25e-6 1.25E-6