This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
POSIX:strtod() should restore the locale it changed
authorKarl Williamson <public@khwilliamson.com>
Thu, 12 Dec 2013 06:04:40 +0000 (23:04 -0700)
committerKarl Williamson <public@khwilliamson.com>
Sat, 4 Jan 2014 20:33:05 +0000 (13:33 -0700)
Prior to this commit, the locale remained as strtod() set it to.  I
could not find a case where this actually was a problem, as the other
code is good about checking for and changing the locale where needed.
But uses of atoi(), strtol() in locales where there are spaces in
numbers likely would break.

ext/POSIX/POSIX.xs
ext/POSIX/lib/POSIX.pm
perl.h
t/run/locale.t

index 3e77eb4..08e459c 100644 (file)
@@ -1482,7 +1482,7 @@ strtod(str)
        double num;
        char *unparsed;
     PPCODE:
-       SET_NUMERIC_LOCAL();
+        STORE_NUMERIC_STANDARD_FORCE_LOCAL();
        num = strtod(str, &unparsed);
        PUSHs(sv_2mortal(newSVnv(num)));
        if (GIMME == G_ARRAY) {
@@ -1492,6 +1492,7 @@ strtod(str)
            else
                PUSHs(&PL_sv_undef);
        }
+        RESTORE_NUMERIC_STANDARD();
 
 void
 strtol(str, base = 0)
index 0dd8475..d0bc3fd 100644 (file)
@@ -4,7 +4,7 @@ use warnings;
 
 our ($AUTOLOAD, %SIGRT);
 
-our $VERSION = '1.37';
+our $VERSION = '1.38';
 
 require XSLoader;
 
diff --git a/perl.h b/perl.h
index c777b1b..b6e0c3e 100644 (file)
--- a/perl.h
+++ b/perl.h
@@ -5288,6 +5288,12 @@ typedef struct am_table_short AMTS;
        bool was_standard = PL_numeric_standard && IN_SOME_LOCALE_FORM; \
        if (was_standard) SET_NUMERIC_LOCAL();
 
+/* Rarely, we want to change to the underlying locale even outside of 'use
+ * locale'.  This is principally in the POSIX:: functions */
+#define STORE_NUMERIC_STANDARD_FORCE_LOCAL() \
+       bool was_standard = PL_numeric_standard; \
+       if (was_standard) SET_NUMERIC_LOCAL();
+
 #define RESTORE_NUMERIC_LOCAL() \
        if (was_local) SET_NUMERIC_LOCAL();
 
index d4419ca..d61fbb9 100644 (file)
@@ -20,6 +20,7 @@ BEGIN {
 }
 use Config;
 my $have_setlocale = $Config{d_setlocale} eq 'define';
+my $have_strtod = $Config{d_strtod} eq 'define';
 $have_setlocale = 0 if $@;
 # Visual C's CRT goes silly on strings of the form "en_US.ISO8859-1"
 # and mingw32 uses said silly CRT
@@ -221,8 +222,22 @@ EOF
             print \$i, "\n";
 EOF
             "1,5\n2,5", {}, "Can do math when radix is a comma"); # [perl 115800]
+
+        unless ($have_strtod) {
+            skip("no strtod()", 1);
+        }
+        else {
+            fresh_perl_is(<<"EOF",
+                use POSIX;
+                POSIX::setlocale(POSIX::LC_NUMERIC(),"$comma");
+                my \$one_point_5 = POSIX::strtod("1,5");
+                \$one_point_5 =~ s/0+\$//;  # Remove any trailing zeros
+                print \$one_point_5, "\n";
+EOF
+            "1.5", {}, "POSIX::strtod() uses underlying locale");
+        }
     }
 
 } # SKIP
 
-sub last { 12 }
+sub last { 13 }