Skip to content

Commit 903eb63

Browse files
ntyniFather Chrysostomos
authored and
Father Chrysostomos
committed
LC_NUMERIC documentation updates + tests
Most of the confusion around LC_NUMERIC was fixed with commits 7e4353e and 2095daf 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 097ee67). Update the documentation and test the claims in t/run/locale.t.
1 parent 9c6df44 commit 903eb63

File tree

3 files changed

+102
-26
lines changed

3 files changed

+102
-26
lines changed

pod/perlform.pod

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ token on the first line. If an expression evaluates to a number with a
166166
decimal part, and if the corresponding picture specifies that the decimal
167167
part should appear in the output (that is, any picture except multiple "#"
168168
characters B<without> an embedded "."), the character used for the decimal
169-
point is B<always> determined by the current LC_NUMERIC locale. This
170-
means that, if, for example, the run-time environment happens to specify a
171-
German locale, "," will be used instead of the default ".". See
169+
point is determined by the current LC_NUMERIC locale if C<use locale> is in
170+
effect. This means that, if, for example, the run-time environment happens
171+
to specify a German locale, "," will be used instead of the default ".". See
172172
L<perllocale> and L<"WARNINGS"> for more information.
173173

174174

@@ -442,15 +442,11 @@ Lexical variables (declared with "my") are not visible within a
442442
format unless the format is declared within the scope of the lexical
443443
variable. (They weren't visible at all before version 5.001.)
444444

445-
Formats are the only part of Perl that unconditionally use information
446-
from a program's locale; if a program's environment specifies an
447-
LC_NUMERIC locale, it is always used to specify the decimal point
448-
character in formatted output. Perl ignores all other aspects of locale
449-
handling unless the C<use locale> pragma is in effect. Formatted output
450-
cannot be controlled by C<use locale> because the pragma is tied to the
451-
block structure of the program, and, for historical reasons, formats
452-
exist outside that block structure. See L<perllocale> for further
453-
discussion of locale handling.
445+
If a program's environment specifies an LC_NUMERIC locale and C<use
446+
locale> is in effect when the format is declared, the locale is used
447+
to specify the decimal point character in formatted output. Formatted
448+
output cannot be controlled by C<use locale> at the time when write()
449+
is called. See L<perllocale> for further discussion of locale handling.
454450

455451
Within strings that are to be displayed in a fixed length text field,
456452
each control character is substituted by a space. (But remember the

pod/perllocale.pod

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,7 @@ ucfirst(), and lcfirst()) use C<LC_CTYPE>
115115

116116
=item *
117117

118-
B<The formatting functions> (printf(), sprintf() and write()) use
119-
C<LC_NUMERIC>
118+
B<Format declarations> (format()) use C<LC_NUMERIC>
120119

121120
=item *
122121

@@ -967,13 +966,11 @@ system's implementation of the locale system than by Perl.
967966

968967
=head2 write() and LC_NUMERIC
969968

970-
Formats are the only part of Perl that unconditionally use information
971-
from a program's locale; if a program's environment specifies an
972-
LC_NUMERIC locale, it is always used to specify the decimal point
973-
character in formatted output. Formatted output cannot be controlled by
974-
C<use locale> because the pragma is tied to the block structure of the
975-
program, and, for historical reasons, formats exist outside that block
976-
structure.
969+
If a program's environment specifies an LC_NUMERIC locale and C<use
970+
locale> is in effect when the format is declared, the locale is used
971+
to specify the decimal point character in formatted output. Formatted
972+
output cannot be controlled by C<use locale> at the time when write()
973+
is called.
977974

978975
=head2 Freely available locale definitions
979976

t/run/locale.t

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ BEGIN {
88
use strict;
99

1010
########
11-
# This test is here instead of lib/locale.t because
12-
# the bug depends on in the internal state of the locale
11+
# These tests are here instead of lib/locale.t because
12+
# some bugs depend on in the internal state of the locale
1313
# settings and pragma/locale messes up that state pretty badly.
14-
# We need a "fresh run".
14+
# We need "fresh runs".
1515
BEGIN {
16-
eval { require POSIX };
16+
eval { require POSIX; POSIX->import("locale_h") };
1717
if ($@) {
1818
skip_all("could not load the POSIX module"); # running minitest?
1919
}
@@ -47,4 +47,87 @@ fresh_perl_is("for (qw(@locales)) {\n" . <<'EOF',
4747
EOF
4848
"", {}, "no locales where LC_NUMERIC breaks");
4949

50-
sub last { 1 }
50+
fresh_perl_is("for (qw(@locales)) {\n" . <<'EOF',
51+
use POSIX qw(locale_h);
52+
use locale;
53+
my $in = 4.2;
54+
my $s = sprintf "%g", $in; # avoid any constant folding bugs
55+
next if $s eq "4.2";
56+
print "$_ $s\n";
57+
}
58+
EOF
59+
"", {}, "LC_NUMERIC without setlocale() has no effect in any locale");
60+
61+
# try to find out a locale where LC_NUMERIC makes a difference
62+
my $original_locale = setlocale(LC_NUMERIC);
63+
64+
my ($base, $different, $difference);
65+
for ("C", @locales) { # prefer C for the base if available
66+
use locale;
67+
setlocale(LC_NUMERIC, $_) or next;
68+
my $in = 4.2; # avoid any constant folding bugs
69+
if ((my $s = sprintf("%g", $in)) eq "4.2") {
70+
$base ||= $_;
71+
} else {
72+
$different ||= $_;
73+
$difference ||= $s;
74+
}
75+
76+
last if $base && $different;
77+
}
78+
setlocale(LC_NUMERIC, $original_locale);
79+
80+
SKIP: {
81+
skip("no locale available where LC_NUMERIC makes a difference", &last - 2)
82+
if !$different;
83+
note("using the '$different' locale for LC_NUMERIC tests");
84+
for ($different) {
85+
local $ENV{LC_NUMERIC} = $_;
86+
local $ENV{LC_ALL}; # so it never overrides LC_NUMERIC
87+
88+
fresh_perl_is(<<'EOF', "4.2", {},
89+
format STDOUT =
90+
@.#
91+
4.179
92+
.
93+
write;
94+
EOF
95+
"format() does not look at LC_NUMERIC without 'use locale'");
96+
97+
{
98+
fresh_perl_is(<<'EOF', $difference, {},
99+
use locale;
100+
format STDOUT =
101+
@.#
102+
4.179
103+
.
104+
write;
105+
EOF
106+
"format() looks at LC_NUMERIC with 'use locale'");
107+
}
108+
109+
{
110+
fresh_perl_is(<<'EOF', "4.2", {},
111+
format STDOUT =
112+
@.#
113+
4.179
114+
.
115+
{ use locale; write; }
116+
EOF
117+
"too late to look at the locale at write() time");
118+
}
119+
120+
{
121+
fresh_perl_is(<<'EOF', $difference, {},
122+
use locale; format STDOUT =
123+
@.#
124+
4.179
125+
.
126+
{ no locale; write; }
127+
EOF
128+
"too late to ignore the locale at write() time");
129+
}
130+
}
131+
} # SKIP
132+
133+
sub last { 6 }

0 commit comments

Comments
 (0)