diff options
author | Niko Tyni <ntyni@debian.org> | 2010-10-19 21:55:14 +0300 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2010-10-27 05:50:18 -0700 |
commit | 903eb63f7d8d47a38971a8e9af7201b9927882cf (patch) | |
tree | 369b98666559416d15f502c9c080d6941cc4c898 | |
parent | 9c6df44eda98e5e43bb8a8d4d71688ae77f9a590 (diff) | |
download | perl-903eb63f7d8d47a38971a8e9af7201b9927882cf.tar.gz |
LC_NUMERIC documentation updates + tests
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.
-rw-r--r-- | pod/perlform.pod | 20 | ||||
-rw-r--r-- | pod/perllocale.pod | 15 | ||||
-rw-r--r-- | t/run/locale.t | 93 |
3 files changed, 102 insertions, 26 deletions
diff --git a/pod/perlform.pod b/pod/perlform.pod index 3cfa1b768d..df0f0a174d 100644 --- a/pod/perlform.pod +++ b/pod/perlform.pod @@ -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 diff --git a/pod/perllocale.pod b/pod/perllocale.pod index 0dbabe7d40..0bec4236e5 100644 --- a/pod/perllocale.pod +++ b/pod/perllocale.pod @@ -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 diff --git a/t/run/locale.t b/t/run/locale.t index 9f9d32cc19..483123f16b 100644 --- a/t/run/locale.t +++ b/t/run/locale.t @@ -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 } |