This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
LC_NUMERIC documentation updates + tests
authorNiko Tyni <ntyni@debian.org>
Tue, 19 Oct 2010 18:55:14 +0000 (21:55 +0300)
committerFather Chrysostomos <sprout@cpan.org>
Wed, 27 Oct 2010 12:50:18 +0000 (05:50 -0700)
Most of the confusion around LC_NUMERIC was fixed with commits
7e4353e96785be675a69a6886d154405dbfdc124 and
2095dafae09cfface71d4202b3188926ea0ccc1c
but two errors remain:

- the early parts of perllocale.pod still say printf() uses LC_NUMERIC
  with just 'use locale' when actually a POSIX::setlocale() call is
  also needed

- format() hasn't used LC_NUMERIC unconditionally since 5.005_03
  (commit 097ee67dff1c60f201bc09435bc6eaeeafcd8123).

Update the documentation and test the claims in t/run/locale.t.

pod/perlform.pod
pod/perllocale.pod
t/run/locale.t

index 3cfa1b7..df0f0a1 100644 (file)
@@ -166,9 +166,9 @@ token on the first line.  If an expression evaluates to a number with a
 decimal part, and if the corresponding picture specifies that the decimal
 part should appear in the output (that is, any picture except multiple "#"
 characters B<without> an embedded "."), the character used for the decimal
-point is B<always> determined by the current LC_NUMERIC locale.  This
-means that, if, for example, the run-time environment happens to specify a
-German locale, "," will be used instead of the default ".".  See
+point is determined by the current LC_NUMERIC locale if C<use locale> is in
+effect.  This means that, if, for example, the run-time environment happens
+to specify a German locale, "," will be used instead of the default ".".  See
 L<perllocale> and L<"WARNINGS"> for more information.
 
 
@@ -442,15 +442,11 @@ Lexical variables (declared with "my") are not visible within a
 format unless the format is declared within the scope of the lexical
 variable.  (They weren't visible at all before version 5.001.)
 
-Formats are the only part of Perl that unconditionally use information
-from a program's locale; if a program's environment specifies an
-LC_NUMERIC locale, it is always used to specify the decimal point
-character in formatted output.  Perl ignores all other aspects of locale
-handling unless the C<use locale> pragma is in effect.  Formatted output
-cannot be controlled by C<use locale> because the pragma is tied to the
-block structure of the program, and, for historical reasons, formats
-exist outside that block structure.  See L<perllocale> for further
-discussion of locale handling.
+If a program's environment specifies an LC_NUMERIC locale and C<use
+locale> is in effect when the format is declared, the locale is used
+to specify the decimal point character in formatted output.  Formatted
+output cannot be controlled by C<use locale> at the time when write()
+is called. See L<perllocale> for further discussion of locale handling.
 
 Within strings that are to be displayed in a fixed length text field,
 each control character is substituted by a space. (But remember the
index 0dbabe7..0bec423 100644 (file)
@@ -115,8 +115,7 @@ ucfirst(), and lcfirst()) use C<LC_CTYPE>
 
 =item *
 
-B<The formatting functions> (printf(), sprintf() and write()) use
-C<LC_NUMERIC>
+B<Format declarations> (format()) use C<LC_NUMERIC>
 
 =item *
 
@@ -967,13 +966,11 @@ system's implementation of the locale system than by Perl.
 
 =head2 write() and LC_NUMERIC
 
-Formats are the only part of Perl that unconditionally use information
-from a program's locale; if a program's environment specifies an
-LC_NUMERIC locale, it is always used to specify the decimal point
-character in formatted output.  Formatted output cannot be controlled by
-C<use locale> because the pragma is tied to the block structure of the
-program, and, for historical reasons, formats exist outside that block
-structure.
+If a program's environment specifies an LC_NUMERIC locale and C<use
+locale> is in effect when the format is declared, the locale is used
+to specify the decimal point character in formatted output.  Formatted
+output cannot be controlled by C<use locale> at the time when write()
+is called.
 
 =head2 Freely available locale definitions
 
index 9f9d32c..483123f 100644 (file)
@@ -8,12 +8,12 @@ BEGIN {
 use strict;
 
 ########
-# This test is here instead of lib/locale.t because
-# the bug depends on in the internal state of the locale
+# These tests are here instead of lib/locale.t because
+# some bugs depend on in the internal state of the locale
 # settings and pragma/locale messes up that state pretty badly.
-# We need a "fresh run".
+# We need "fresh runs".
 BEGIN {
-    eval { require POSIX };
+    eval { require POSIX; POSIX->import("locale_h") };
     if ($@) {
        skip_all("could not load the POSIX module"); # running minitest?
     }
@@ -47,4 +47,87 @@ fresh_perl_is("for (qw(@locales)) {\n" . <<'EOF',
 EOF
     "", {}, "no locales where LC_NUMERIC breaks");
 
-sub last { 1 }
+fresh_perl_is("for (qw(@locales)) {\n" . <<'EOF',
+    use POSIX qw(locale_h);
+    use locale;
+    my $in = 4.2;
+    my $s = sprintf "%g", $in; # avoid any constant folding bugs
+    next if $s eq "4.2";
+    print "$_ $s\n";
+}
+EOF
+    "", {}, "LC_NUMERIC without setlocale() has no effect in any locale");
+
+# try to find out a locale where LC_NUMERIC makes a difference
+my $original_locale = setlocale(LC_NUMERIC);
+
+my ($base, $different, $difference);
+for ("C", @locales) { # prefer C for the base if available
+    use locale;
+    setlocale(LC_NUMERIC, $_) or next;
+    my $in = 4.2; # avoid any constant folding bugs
+    if ((my $s = sprintf("%g", $in)) eq "4.2")  {
+       $base ||= $_;
+    } else {
+       $different ||= $_;
+       $difference ||= $s;
+    }
+
+    last if $base && $different;
+}
+setlocale(LC_NUMERIC, $original_locale);
+
+SKIP: {
+    skip("no locale available where LC_NUMERIC makes a difference", &last - 2)
+       if !$different;
+    note("using the '$different' locale for LC_NUMERIC tests");
+    for ($different) {
+       local $ENV{LC_NUMERIC} = $_;
+       local $ENV{LC_ALL}; # so it never overrides LC_NUMERIC
+
+       fresh_perl_is(<<'EOF', "4.2", {},
+format STDOUT =
+@.#
+4.179
+.
+write;
+EOF
+           "format() does not look at LC_NUMERIC without 'use locale'");
+
+        {
+           fresh_perl_is(<<'EOF', $difference, {},
+use locale;
+format STDOUT =
+@.#
+4.179
+.
+write;
+EOF
+           "format() looks at LC_NUMERIC with 'use locale'");
+        }
+
+        {
+           fresh_perl_is(<<'EOF', "4.2", {},
+format STDOUT =
+@.#
+4.179
+.
+{ use locale; write; }
+EOF
+           "too late to look at the locale at write() time");
+        }
+
+        {
+           fresh_perl_is(<<'EOF', $difference, {},
+use locale; format STDOUT =
+@.#
+4.179
+.
+{ no locale; write; }
+EOF
+           "too late to ignore the locale at write() time");
+        }
+    }
+} # SKIP
+
+sub last { 6 }