This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
e9ed1a86cfada5effd39ac94aef72fb56eccc6ba
[perl5.git] / lib / locale.t
1 #!./perl -wT
2
3 # This tests plain 'use locale' and adorned 'use locale ":not_characters"'
4 # Because these pragmas are compile time, and I (khw) am trying to test
5 # without using 'eval' as much as possible, which might cloud the issue,  the
6 # crucial parts of the code are duplicated in a block for each pragma.
7
8 # To make a TODO test, add the string 'TODO' to its %test_names value
9
10 binmode STDOUT, ':utf8';
11 binmode STDERR, ':utf8';
12
13 BEGIN {
14     chdir 't' if -d 't';
15     @INC = '../lib';
16     unshift @INC, '.';
17     require Config; import Config;
18     if (!$Config{d_setlocale} || $Config{ccflags} =~ /\bD?NO_LOCALE\b/) {
19         print "1..0\n";
20         exit;
21     }
22     require './loc_tools.pl';
23     $| = 1;
24 }
25
26 use strict;
27 use feature 'fc';
28
29 # =1 adds debugging output; =2 increases the verbosity somewhat
30 my $debug = $ENV{PERL_DEBUG_FULL_TEST} // 0;
31
32 # Certain tests have been shown to be problematical for a few locales.  Don't
33 # fail them unless at least this percentage of the tested locales fail.
34 # On AIX machines, many locales call a no-break space a graphic.
35 # (There aren't 1000 locales currently in existence, so 99.9 works)
36 my $acceptable_failure_percentage = ($^O =~ / ^ ( AIX ) $ /ix)
37                                      ? 99.9
38                                      : 5;
39
40 # The list of test numbers of the problematic tests.
41 my %problematical_tests;
42
43
44 use Dumpvalue;
45
46 my $dumper = Dumpvalue->new(
47                             tick => qq{"},
48                             quoteHighBit => 0,
49                             unctrl => "quote"
50                            );
51 sub debug {
52   return unless $debug;
53   my($mess) = join "", @_;
54   chop $mess;
55   print $dumper->stringify($mess,1), "\n";
56 }
57
58 sub debug_more {
59   return unless $debug > 1;
60   return debug(@_);
61 }
62
63 sub debugf {
64     printf @_ if $debug;
65 }
66
67 $a = 'abc %9';
68
69 my $test_num = 0;
70
71 sub ok {
72     my ($result, $message) = @_;
73     $message = "" unless defined $message;
74
75     print 'not ' unless ($result);
76     print "ok " . ++$test_num;
77     print " $message";
78     print "\n";
79 }
80
81 # First we'll do a lot of taint checking for locales.
82 # This is the easiest to test, actually, as any locale,
83 # even the default locale will taint under 'use locale'.
84
85 sub is_tainted { # hello, camel two.
86     no warnings 'uninitialized' ;
87     my $dummy;
88     local $@;
89     not eval { $dummy = join("", @_), kill 0; 1 }
90 }
91
92 sub check_taint ($;$) {
93     my $message_tail = $_[1] // "";
94
95     # Extra blanks are so aligns with taint_not output
96     $message_tail = ":     $message_tail" if $message_tail;
97     ok is_tainted($_[0]), "verify that is tainted$message_tail";
98 }
99
100 sub check_taint_not ($;$) {
101     my $message_tail = $_[1] // "";
102     $message_tail = ":  $message_tail" if $message_tail;
103     ok((not is_tainted($_[0])), "verify that isn't tainted$message_tail");
104 }
105
106 "\tb\t" =~ /^m?(\s)(.*)\1$/;
107 check_taint_not   $&, "not tainted outside 'use locale'";
108 ;
109
110 use locale;     # engage locale and therefore locale taint.
111
112 # BE SURE TO COPY ANYTHING YOU ADD to these tests to the block below for
113 # ":notcharacters"
114
115 check_taint_not   $a, '$a';
116
117 check_taint       uc($a), 'uc($a)';
118 check_taint       "\U$a", '"\U$a"';
119 check_taint       ucfirst($a), 'ucfirst($a)';
120 check_taint       "\u$a", '"\u$a"';
121 check_taint       lc($a), 'lc($a)';
122 check_taint       fc($a), 'fc($a)';
123 check_taint       "\L$a", '"\L$a"';
124 check_taint       "\F$a", '"\F$a"';
125 check_taint       lcfirst($a), 'lcfirst($a)';
126 check_taint       "\l$a", '"\l$a"';
127
128 check_taint_not  sprintf('%e', 123.456), "sprintf('%e', 123.456)";
129 check_taint_not  sprintf('%f', 123.456), "sprintf('%f', 123.456)";
130 check_taint_not  sprintf('%g', 123.456), "sprintf('%g', 123.456)";
131 check_taint_not  sprintf('%d', 123.456), "sprintf('%d', 123.456)";
132 check_taint_not  sprintf('%x', 123.456), "sprintf('%x', 123.456)";
133
134 $_ = $a;        # untaint $_
135
136 $_ = uc($a);    # taint $_
137
138 check_taint      $_, '$_ = uc($a)';
139
140 /(\w)/; # taint $&, $`, $', $+, $1.
141 check_taint      $&, "\$& from /(\\w)/";
142 check_taint      $`, "\t\$`";
143 check_taint      $', "\t\$'";
144 check_taint      $+, "\t\$+";
145 check_taint      $1, "\t\$1";
146 check_taint_not  $2, "\t\$2";
147
148 /(.)/;  # untaint $&, $`, $', $+, $1.
149 check_taint_not  $&, "\$& from /(.)/";
150 check_taint_not  $`, "\t\$`";
151 check_taint_not  $', "\t\$'";
152 check_taint_not  $+, "\t\$+";
153 check_taint_not  $1, "\t\$1";
154 check_taint_not  $2, "\t\$2";
155
156 /(\W)/; # taint $&, $`, $', $+, $1.
157 check_taint      $&, "\$& from /(\\W)/";
158 check_taint      $`, "\t\$`";
159 check_taint      $', "\t\$'";
160 check_taint      $+, "\t\$+";
161 check_taint      $1, "\t\$1";
162 check_taint_not  $2, "\t\$2";
163
164 /(.)/;  # untaint $&, $`, $', $+, $1.
165 check_taint_not  $&, "\$& from /(.)/";
166 check_taint_not  $`, "\t\$`";
167 check_taint_not  $', "\t\$'";
168 check_taint_not  $+, "\t\$+";
169 check_taint_not  $1, "\t\$1";
170 check_taint_not  $2, "\t\$2";
171
172 /(\s)/; # taint $&, $`, $', $+, $1.
173 check_taint      $&, "\$& from /(\\s)/";
174 check_taint      $`, "\t\$`";
175 check_taint      $', "\t\$'";
176 check_taint      $+, "\t\$+";
177 check_taint      $1, "\t\$1";
178 check_taint_not  $2, "\t\$2";
179
180 /(.)/;  # untaint $&, $`, $', $+, $1.
181 check_taint_not  $&, "\$& from /(.)/";
182
183 /(\S)/; # taint $&, $`, $', $+, $1.
184 check_taint      $&, "\$& from /(\\S)/";
185 check_taint      $`, "\t\$`";
186 check_taint      $', "\t\$'";
187 check_taint      $+, "\t\$+";
188 check_taint      $1, "\t\$1";
189 check_taint_not  $2, "\t\$2";
190
191 /(.)/;  # untaint $&, $`, $', $+, $1.
192 check_taint_not  $&, "\$& from /(.)/";
193
194 "0" =~ /(\d)/;  # taint $&, $`, $', $+, $1.
195 check_taint      $&, "\$& from /(\\d)/";
196 check_taint      $`, "\t\$`";
197 check_taint      $', "\t\$'";
198 check_taint      $+, "\t\$+";
199 check_taint      $1, "\t\$1";
200 check_taint_not  $2, "\t\$2";
201
202 /(.)/;  # untaint $&, $`, $', $+, $1.
203 check_taint_not  $&, "\$& from /(.)/";
204
205 /(\D)/; # taint $&, $`, $', $+, $1.
206 check_taint      $&, "\$& from /(\\D)/";
207 check_taint      $`, "\t\$`";
208 check_taint      $', "\t\$'";
209 check_taint      $+, "\t\$+";
210 check_taint      $1, "\t\$1";
211 check_taint_not  $2, "\t\$2";
212
213 /(.)/;  # untaint $&, $`, $', $+, $1.
214 check_taint_not  $&, "\$& from /(.)/";
215
216 /([[:alnum:]])/;        # taint $&, $`, $', $+, $1.
217 check_taint      $&, "\$& from /([[:alnum:]])/";
218 check_taint      $`, "\t\$`";
219 check_taint      $', "\t\$'";
220 check_taint      $+, "\t\$+";
221 check_taint      $1, "\t\$1";
222 check_taint_not  $2, "\t\$2";
223
224 /(.)/;  # untaint $&, $`, $', $+, $1.
225 check_taint_not  $&, "\$& from /(.)/";
226
227 /([[:^alnum:]])/;       # taint $&, $`, $', $+, $1.
228 check_taint      $&, "\$& from /([[:^alnum:]])/";
229 check_taint      $`, "\t\$`";
230 check_taint      $', "\t\$'";
231 check_taint      $+, "\t\$+";
232 check_taint      $1, "\t\$1";
233 check_taint_not  $2, "\t\$2";
234
235 "a" =~ /(a)|(\w)/;      # taint $&, $`, $', $+, $1.
236 check_taint      $&, "\$& from /(a)|(\\w)/";
237 check_taint      $`, "\t\$`";
238 check_taint      $', "\t\$'";
239 check_taint      $+, "\t\$+";
240 check_taint      $1, "\t\$1";
241 ok($1 eq 'a', ("\t" x 5) . "\$1 is 'a'");
242 ok(! defined $2, ("\t" x 5) . "\$2 is undefined");
243 check_taint_not  $2, "\t\$2";
244 check_taint_not  $3, "\t\$3";
245
246 /(.)/;  # untaint $&, $`, $', $+, $1.
247 check_taint_not  $&, "\$& from /(.)/";
248
249 "\N{CYRILLIC SMALL LETTER A}" =~ /(\N{CYRILLIC CAPITAL LETTER A})/i;    # no tainting because no locale dependence
250 check_taint_not      $&, "\$& from /(\\N{CYRILLIC CAPITAL LETTER A})/i";
251 check_taint_not      $`, "\t\$`";
252 check_taint_not      $', "\t\$'";
253 check_taint_not      $+, "\t\$+";
254 check_taint_not      $1, "\t\$1";
255 ok($1 eq "\N{CYRILLIC SMALL LETTER A}", ("\t" x 4) . "\t\$1 is 'small cyrillic a'");
256 check_taint_not      $2, "\t\$2";
257
258 /(.)/;  # untaint $&, $`, $', $+, $1.
259 check_taint_not  $&, "\$& from /./";
260
261 "(\N{KELVIN SIGN})" =~ /(\N{KELVIN SIGN})/i;    # taints because depends on locale
262 check_taint      $&, "\$& from /(\\N{KELVIN SIGN})/i";
263 check_taint      $`, "\t\$`";
264 check_taint      $', "\t\$'";
265 check_taint      $+, "\t\$+";
266 check_taint      $1, "\t\$1";
267 check_taint_not      $2, "\t\$2";
268
269 /(.)/;  # untaint $&, $`, $', $+, $1.
270 check_taint_not  $&, "\$& from /(.)/";
271
272 "a:" =~ /(.)\b(.)/;     # taint $&, $`, $', $+, $1.
273 check_taint      $&, "\$& from /(.)\\b(.)/";
274 check_taint      $`, "\t\$`";
275 check_taint      $', "\t\$'";
276 check_taint      $+, "\t\$+";
277 check_taint      $1, "\t\$1";
278 check_taint      $2, "\t\$2";
279 check_taint_not  $3, "\t\$3";
280
281 /(.)/;  # untaint $&, $`, $', $+, $1.
282 check_taint_not  $&, "\$& from /./";
283
284 "aa" =~ /(.)\B(.)/;     # taint $&, $`, $', $+, $1.
285 check_taint      $&, "\$& from /(.)\\B(.)/";
286 check_taint      $`, "\t\$`";
287 check_taint      $', "\t\$'";
288 check_taint      $+, "\t\$+";
289 check_taint      $1, "\t\$1";
290 check_taint      $2, "\t\$2";
291 check_taint_not  $3, "\t\$3";
292
293 /(.)/;  # untaint $&, $`, $', $+, $1.
294 check_taint_not  $&, "\$& from /./";
295
296 "aaa" =~ /(.).(\1)/i;   # notaint because not locale dependent
297 check_taint_not      $&, "\$ & from /(.).(\\1)/";
298 check_taint_not      $`, "\t\$`";
299 check_taint_not      $', "\t\$'";
300 check_taint_not      $+, "\t\$+";
301 check_taint_not      $1, "\t\$1";
302 check_taint_not      $2, "\t\$2";
303 check_taint_not      $3, "\t\$3";
304
305 /(.)/;  # untaint $&, $`, $', $+, $1.
306 check_taint_not  $&, "\$ & from /./";
307
308 $_ = $a;        # untaint $_
309
310 check_taint_not  $_, 'untainting $_ works';
311
312 /(b)/;          # this must not taint
313 check_taint_not  $&, "\$ & from /(b)/";
314 check_taint_not  $`, "\t\$`";
315 check_taint_not  $', "\t\$'";
316 check_taint_not  $+, "\t\$+";
317 check_taint_not  $1, "\t\$1";
318 check_taint_not  $2, "\t\$2";
319
320 $_ = $a;        # untaint $_
321
322 check_taint_not  $_, 'untainting $_ works';
323
324 $b = uc($a);    # taint $b
325 s/(.+)/$b/;     # this must taint only the $_
326
327 check_taint      $_, '$_ (wasn\'t tainted) from s/(.+)/$b/ where $b is tainted';
328 check_taint_not  $&, "\t\$&";
329 check_taint_not  $`, "\t\$`";
330 check_taint_not  $', "\t\$'";
331 check_taint_not  $+, "\t\$+";
332 check_taint_not  $1, "\t\$1";
333 check_taint_not  $2, "\t\$2";
334
335 $_ = $a;        # untaint $_
336
337 s/(.+)/b/;      # this must not taint
338 check_taint_not  $_, '$_ (wasn\'t tainted) from s/(.+)/b/';
339 check_taint_not  $&, "\t\$&";
340 check_taint_not  $`, "\t\$`";
341 check_taint_not  $', "\t\$'";
342 check_taint_not  $+, "\t\$+";
343 check_taint_not  $1, "\t\$1";
344 check_taint_not  $2, "\t\$2";
345
346 $b = $a;        # untaint $b
347
348 ($b = $a) =~ s/\w/$&/;
349 check_taint      $b, '$b from ($b = $a) =~ s/\w/$&/';   # $b should be tainted.
350 check_taint_not  $a, '$a from ($b = $a) =~ s/\w/$&/';   # $a should be not.
351
352 $_ = $a;        # untaint $_
353
354 s/(\w)/\l$1/;   # this must taint
355 check_taint      $_, '$_ (wasn\'t tainted) from s/(\w)/\l$1/,'; # this must taint
356 check_taint      $&, "\t\$&";
357 check_taint      $`, "\t\$`";
358 check_taint      $', "\t\$'";
359 check_taint      $+, "\t\$+";
360 check_taint      $1, "\t\$1";
361 check_taint_not  $2, "\t\$2";
362
363 $_ = $a;        # untaint $_
364
365 s/(\w)/\L$1/;   # this must taint
366 check_taint      $_, '$_ (wasn\'t tainted) from s/(\w)/\L$1/,';
367 check_taint      $&, "\t\$&";
368 check_taint      $`, "\t\$`";
369 check_taint      $', "\t\$'";
370 check_taint      $+, "\t\$+";
371 check_taint      $1, "\t\$1";
372 check_taint_not  $2, "\t\$2";
373
374 $_ = $a;        # untaint $_
375
376 s/(\w)/\u$1/;   # this must taint
377 check_taint      $_, '$_ (wasn\'t tainted) from s/(\w)/\u$1/';
378 check_taint      $&, "\t\$&";
379 check_taint      $`, "\t\$`";
380 check_taint      $', "\t\$'";
381 check_taint      $+, "\t\$+";
382 check_taint      $1, "\t\$1";
383 check_taint_not  $2, "\t\$2";
384
385 $_ = $a;        # untaint $_
386
387 s/(\w)/\U$1/;   # this must taint
388 check_taint      $_, '$_ (wasn\'t tainted) from s/(\w)/\U$1/';
389 check_taint      $&, "\t\$&";
390 check_taint      $`, "\t\$`";
391 check_taint      $', "\t\$'";
392 check_taint      $+, "\t\$+";
393 check_taint      $1, "\t\$1";
394 check_taint_not  $2, "\t\$2";
395
396 # After all this tainting $a should be cool.
397
398 check_taint_not  $a, '$a still not tainted';
399
400 "a" =~ /([a-z])/;
401 check_taint_not $1, '"a" =~ /([a-z])/';
402 "foo.bar_baz" =~ /^(.*)[._](.*?)$/;  # Bug 120675
403 check_taint_not $1, '"foo.bar_baz" =~ /^(.*)[._](.*?)$/';
404
405 # BE SURE TO COPY ANYTHING YOU ADD to the block below
406
407 {   # This is just the previous tests copied here with a different
408     # compile-time pragma.
409
410     use locale ':not_characters'; # engage restricted locale with different
411                                   # tainting rules
412     check_taint_not   $a, '$a';
413
414     check_taint_not   uc($a), 'uc($a)';
415     check_taint_not   "\U$a", '"\U$a"';
416     check_taint_not   ucfirst($a), 'ucfirst($a)';
417     check_taint_not   "\u$a", '"\u$a"';
418     check_taint_not   lc($a), 'lc($a)';
419     check_taint_not   fc($a), 'fc($a)';
420     check_taint_not   "\L$a", '"\L$a"';
421     check_taint_not   "\F$a", '"\F$a"';
422     check_taint_not   lcfirst($a), 'lcfirst($a)';
423     check_taint_not   "\l$a", '"\l$a"';
424
425     check_taint_not  sprintf('%e', 123.456), "sprintf('%e', 123.456)";
426     check_taint_not  sprintf('%f', 123.456), "sprintf('%f', 123.456)";
427     check_taint_not  sprintf('%g', 123.456), "sprintf('%g', 123.456)";
428     check_taint_not  sprintf('%d', 123.456), "sprintf('%d', 123.456)";
429     check_taint_not  sprintf('%x', 123.456), "sprintf('%x', 123.456)";
430
431     $_ = $a;    # untaint $_
432
433     $_ = uc($a);
434
435     check_taint_not  $_, '$_ = uc($a)';
436
437     /(\w)/;
438     check_taint_not  $&, "\$& from /(\\w)/";
439     check_taint_not  $`, "\t\$`";
440     check_taint_not  $', "\t\$'";
441     check_taint_not  $+, "\t\$+";
442     check_taint_not  $1, "\t\$1";
443     check_taint_not  $2, "\t\$2";
444
445     /(.)/;      # untaint $&, $`, $', $+, $1.
446     check_taint_not  $&, "\$& from /(.)/";
447     check_taint_not  $`, "\t\$`";
448     check_taint_not  $', "\t\$'";
449     check_taint_not  $+, "\t\$+";
450     check_taint_not  $1, "\t\$1";
451     check_taint_not  $2, "\t\$2";
452
453     /(\W)/;
454     check_taint_not  $&, "\$& from /(\\W)/";
455     check_taint_not  $`, "\t\$`";
456     check_taint_not  $', "\t\$'";
457     check_taint_not  $+, "\t\$+";
458     check_taint_not  $1, "\t\$1";
459     check_taint_not  $2, "\t\$2";
460
461     /(.)/;      # untaint $&, $`, $', $+, $1.
462     check_taint_not  $&, "\$& from /(.)/";
463     check_taint_not  $`, "\t\$`";
464     check_taint_not  $', "\t\$'";
465     check_taint_not  $+, "\t\$+";
466     check_taint_not  $1, "\t\$1";
467     check_taint_not  $2, "\t\$2";
468
469     /(\s)/;
470     check_taint_not  $&, "\$& from /(\\s)/";
471     check_taint_not  $`, "\t\$`";
472     check_taint_not  $', "\t\$'";
473     check_taint_not  $+, "\t\$+";
474     check_taint_not  $1, "\t\$1";
475     check_taint_not  $2, "\t\$2";
476
477     /(.)/;      # untaint $&, $`, $', $+, $1.
478     check_taint_not  $&, "\$& from /(.)/";
479
480     /(\S)/;
481     check_taint_not  $&, "\$& from /(\\S)/";
482     check_taint_not  $`, "\t\$`";
483     check_taint_not  $', "\t\$'";
484     check_taint_not  $+, "\t\$+";
485     check_taint_not  $1, "\t\$1";
486     check_taint_not  $2, "\t\$2";
487
488     /(.)/;      # untaint $&, $`, $', $+, $1.
489     check_taint_not  $&, "\$& from /(.)/";
490
491     "0" =~ /(\d)/;
492     check_taint_not  $&, "\$& from /(\\d)/";
493     check_taint_not  $`, "\t\$`";
494     check_taint_not  $', "\t\$'";
495     check_taint_not  $+, "\t\$+";
496     check_taint_not  $1, "\t\$1";
497     check_taint_not  $2, "\t\$2";
498
499     /(.)/;      # untaint $&, $`, $', $+, $1.
500     check_taint_not  $&, "\$& from /(.)/";
501
502     /(\D)/;
503     check_taint_not  $&, "\$& from /(\\D)/";
504     check_taint_not  $`, "\t\$`";
505     check_taint_not  $', "\t\$'";
506     check_taint_not  $+, "\t\$+";
507     check_taint_not  $1, "\t\$1";
508     check_taint_not  $2, "\t\$2";
509
510     /(.)/;      # untaint $&, $`, $', $+, $1.
511     check_taint_not  $&, "\$& from /(.)/";
512
513     /([[:alnum:]])/;
514     check_taint_not  $&, "\$& from /([[:alnum:]])/";
515     check_taint_not  $`, "\t\$`";
516     check_taint_not  $', "\t\$'";
517     check_taint_not  $+, "\t\$+";
518     check_taint_not  $1, "\t\$1";
519     check_taint_not  $2, "\t\$2";
520
521     /(.)/;      # untaint $&, $`, $', $+, $1.
522     check_taint_not  $&, "\$& from /(.)/";
523
524     /([[:^alnum:]])/;
525     check_taint_not  $&, "\$& from /([[:^alnum:]])/";
526     check_taint_not  $`, "\t\$`";
527     check_taint_not  $', "\t\$'";
528     check_taint_not  $+, "\t\$+";
529     check_taint_not  $1, "\t\$1";
530     check_taint_not  $2, "\t\$2";
531
532     "a" =~ /(a)|(\w)/;
533     check_taint_not  $&, "\$& from /(a)|(\\w)/";
534     check_taint_not  $`, "\t\$`";
535     check_taint_not  $', "\t\$'";
536     check_taint_not  $+, "\t\$+";
537     check_taint_not  $1, "\t\$1";
538     ok($1 eq 'a', ("\t" x 5) . "\$1 is 'a'");
539     ok(! defined $2, ("\t" x 5) . "\$2 is undefined");
540     check_taint_not  $2, "\t\$2";
541     check_taint_not  $3, "\t\$3";
542
543     /(.)/;      # untaint $&, $`, $', $+, $1.
544     check_taint_not  $&, "\$& from /(.)/";
545
546     "\N{CYRILLIC SMALL LETTER A}" =~ /(\N{CYRILLIC CAPITAL LETTER A})/i;
547     check_taint_not      $&, "\$& from /(\\N{CYRILLIC CAPITAL LETTER A})/i";
548     check_taint_not      $`, "\t\$`";
549     check_taint_not      $', "\t\$'";
550     check_taint_not      $+, "\t\$+";
551     check_taint_not      $1, "\t\$1";
552     ok($1 eq "\N{CYRILLIC SMALL LETTER A}", ("\t" x 4) . "\t\$1 is 'small cyrillic a'");
553     check_taint_not      $2, "\t\$2";
554
555     /(.)/;      # untaint $&, $`, $', $+, $1.
556     check_taint_not  $&, "\$& from /./";
557
558     "(\N{KELVIN SIGN})" =~ /(\N{KELVIN SIGN})/i;
559     check_taint_not  $&, "\$& from /(\\N{KELVIN SIGN})/i";
560     check_taint_not  $`, "\t\$`";
561     check_taint_not  $', "\t\$'";
562     check_taint_not  $+, "\t\$+";
563     check_taint_not  $1, "\t\$1";
564     check_taint_not      $2, "\t\$2";
565
566     /(.)/;      # untaint $&, $`, $', $+, $1.
567     check_taint_not  $&, "\$& from /(.)/";
568
569     "a:" =~ /(.)\b(.)/;
570     check_taint_not  $&, "\$& from /(.)\\b(.)/";
571     check_taint_not  $`, "\t\$`";
572     check_taint_not  $', "\t\$'";
573     check_taint_not  $+, "\t\$+";
574     check_taint_not  $1, "\t\$1";
575     check_taint_not  $2, "\t\$2";
576     check_taint_not  $3, "\t\$3";
577
578     /(.)/;      # untaint $&, $`, $', $+, $1.
579     check_taint_not  $&, "\$& from /./";
580
581     "aa" =~ /(.)\B(.)/;
582     check_taint_not  $&, "\$& from /(.)\\B(.)/";
583     check_taint_not  $`, "\t\$`";
584     check_taint_not  $', "\t\$'";
585     check_taint_not  $+, "\t\$+";
586     check_taint_not  $1, "\t\$1";
587     check_taint_not  $2, "\t\$2";
588     check_taint_not  $3, "\t\$3";
589
590     /(.)/;      # untaint $&, $`, $', $+, $1.
591     check_taint_not  $&, "\$& from /./";
592
593     "aaa" =~ /(.).(\1)/i;       # notaint because not locale dependent
594     check_taint_not      $&, "\$ & from /(.).(\\1)/";
595     check_taint_not      $`, "\t\$`";
596     check_taint_not      $', "\t\$'";
597     check_taint_not      $+, "\t\$+";
598     check_taint_not      $1, "\t\$1";
599     check_taint_not      $2, "\t\$2";
600     check_taint_not      $3, "\t\$3";
601
602     /(.)/;      # untaint $&, $`, $', $+, $1.
603     check_taint_not  $&, "\$ & from /./";
604
605     $_ = $a;    # untaint $_
606
607     check_taint_not  $_, 'untainting $_ works';
608
609     /(b)/;
610     check_taint_not  $&, "\$ & from /(b)/";
611     check_taint_not  $`, "\t\$`";
612     check_taint_not  $', "\t\$'";
613     check_taint_not  $+, "\t\$+";
614     check_taint_not  $1, "\t\$1";
615     check_taint_not  $2, "\t\$2";
616
617     $_ = $a;    # untaint $_
618
619     check_taint_not  $_, 'untainting $_ works';
620
621     s/(.+)/b/;
622     check_taint_not  $_, '$_ (wasn\'t tainted) from s/(.+)/b/';
623     check_taint_not  $&, "\t\$&";
624     check_taint_not  $`, "\t\$`";
625     check_taint_not  $', "\t\$'";
626     check_taint_not  $+, "\t\$+";
627     check_taint_not  $1, "\t\$1";
628     check_taint_not  $2, "\t\$2";
629
630     $b = $a;    # untaint $b
631
632     ($b = $a) =~ s/\w/$&/;
633     check_taint_not     $b, '$b from ($b = $a) =~ s/\w/$&/';
634     check_taint_not  $a, '$a from ($b = $a) =~ s/\w/$&/';
635
636     $_ = $a;    # untaint $_
637
638     s/(\w)/\l$1/;
639     check_taint_not     $_, '$_ (wasn\'t tainted) from s/(\w)/\l$1/,';  # this must taint
640     check_taint_not     $&, "\t\$&";
641     check_taint_not     $`, "\t\$`";
642     check_taint_not     $', "\t\$'";
643     check_taint_not     $+, "\t\$+";
644     check_taint_not     $1, "\t\$1";
645     check_taint_not  $2, "\t\$2";
646
647     $_ = $a;    # untaint $_
648
649     s/(\w)/\L$1/;
650     check_taint_not     $_, '$_ (wasn\'t tainted) from s/(\w)/\L$1/,';
651     check_taint_not     $&, "\t\$&";
652     check_taint_not     $`, "\t\$`";
653     check_taint_not     $', "\t\$'";
654     check_taint_not     $+, "\t\$+";
655     check_taint_not     $1, "\t\$1";
656     check_taint_not  $2, "\t\$2";
657
658     $_ = $a;    # untaint $_
659
660     s/(\w)/\u$1/;
661     check_taint_not     $_, '$_ (wasn\'t tainted) from s/(\w)/\u$1/';
662     check_taint_not     $&, "\t\$&";
663     check_taint_not     $`, "\t\$`";
664     check_taint_not     $', "\t\$'";
665     check_taint_not     $+, "\t\$+";
666     check_taint_not     $1, "\t\$1";
667     check_taint_not  $2, "\t\$2";
668
669     $_ = $a;    # untaint $_
670
671     s/(\w)/\U$1/;
672     check_taint_not     $_, '$_ (wasn\'t tainted) from s/(\w)/\U$1/';
673     check_taint_not     $&, "\t\$&";
674     check_taint_not     $`, "\t\$`";
675     check_taint_not     $', "\t\$'";
676     check_taint_not     $+, "\t\$+";
677     check_taint_not     $1, "\t\$1";
678     check_taint_not  $2, "\t\$2";
679
680     # After all this tainting $a should be cool.
681
682     check_taint_not  $a, '$a still not tainted';
683
684     "a" =~ /([a-z])/;
685     check_taint_not $1, '"a" =~ /([a-z])/';
686     "foo.bar_baz" =~ /^(.*)[._](.*?)$/;  # Bug 120675
687     check_taint_not $1, '"foo.bar_baz" =~ /^(.*)[._](.*?)$/';
688
689 }
690
691 # Here are in scope of 'use locale'
692
693 # I think we've seen quite enough of taint.
694 # Let us do some *real* locale work now,
695 # unless setlocale() is missing (i.e. minitest).
696
697 # The test number before our first setlocale()
698 my $final_without_setlocale = $test_num;
699
700 # Find locales.
701
702 debug "# Scanning for locales...\n";
703
704 require POSIX; import POSIX ':locale_h';
705
706 my @Locale = find_locales([ &POSIX::LC_CTYPE, &POSIX::LC_ALL ]);
707
708 debug "# Locales =\n";
709 for ( @Locale ) {
710     debug "# $_\n";
711 }
712
713 unless (@Locale) {
714     print "1..$test_num\n";
715     exit;
716 }
717
718
719 setlocale(&POSIX::LC_ALL, "C");
720
721 my %posixes;
722
723 my %Problem;
724 my %Okay;
725 my %Testing;
726 my @Added_alpha;   # Alphas that aren't in the C locale.
727 my %test_names;
728
729 sub disp_chars {
730     # This returns a display string denoting the input parameter @_, each
731     # entry of which is a single character in the range 0-255.  The first part
732     # of the output is a string of the characters in @_ that are ASCII
733     # graphics, and hence unambiguously displayable.  They are given by code
734     # point order.  The second part is the remaining code points, the ordinals
735     # of which are each displayed as 2-digit hex.  Blanks are inserted so as
736     # to keep anything from the first part looking like a 2-digit hex number.
737
738     no locale;
739     my @chars = sort { ord $a <=> ord $b } @_;
740     my $output = "";
741     my $range_start;
742     my $start_class;
743     push @chars, chr(258);  # This sentinel simplifies the loop termination
744                             # logic
745     foreach my $i (0 .. @chars - 1) {
746         my $char = $chars[$i];
747         my $range_end;
748         my $class;
749
750         # We avoid using [:posix:] classes, as these are being tested in this
751         # file.  Each equivalence class below is for things that can appear in
752         # a range; those that can't be in a range have class -1.  0 for those
753         # which should be output in hex; and >0 for the other ranges
754         if ($char =~ /[A-Z]/) {
755             $class = 2;
756         }
757         elsif ($char =~ /[a-z]/) {
758             $class = 3;
759         }
760         elsif ($char =~ /[0-9]/) {
761             $class = 4;
762         }
763         # Uncomment to get literal punctuation displayed instead of hex
764         #elsif ($char =~ /[[\]!"#\$\%&\'()*+,.\/:\\;<=>?\@\^_`{|}~-]/) {
765         #    $class = -1;    # Punct never appears in a range
766         #}
767         else {
768             $class = 0;     # Output in hex
769         }
770
771         if (! defined $range_start) {
772             if ($class < 0) {
773                 $output .= " " . $char;
774             }
775             else {
776                 $range_start = ord $char;
777                 $start_class = $class;
778             }
779         } # A range ends if not consecutive, or the class-type changes
780         elsif (ord $char != ($range_end = ord($chars[$i-1])) + 1
781               || $class != $start_class)
782         {
783
784             # Here, the current character is not in the range.  This means the
785             # previous character must have been.  Output the range up through
786             # that one.
787             my $range_length = $range_end - $range_start + 1;
788             if ($start_class > 0) {
789                 $output .= " " . chr($range_start);
790                 $output .= "-" . chr($range_end) if $range_length > 1;
791             }
792             else {
793                 $output .= sprintf(" %02X", $range_start);
794                 $output .= sprintf("-%02X", $range_end) if $range_length > 1;
795             }
796
797             # Handle the new current character, as potentially beginning a new
798             # range
799             undef $range_start;
800             redo;
801         }
802     }
803
804     $output =~ s/^ //;
805     return $output;
806 }
807
808 sub report_result {
809     my ($Locale, $i, $pass_fail, $message) = @_;
810     $message //= "";
811     $message = "  ($message)" if $message;
812     unless ($pass_fail) {
813         $Problem{$i}{$Locale} = 1;
814         debug "# failed $i ($test_names{$i}) with locale '$Locale'$message\n";
815     } else {
816         push @{$Okay{$i}}, $Locale;
817     }
818 }
819
820 sub report_multi_result {
821     my ($Locale, $i, $results_ref) = @_;
822
823     # $results_ref points to an array, each element of which is a character that was
824     # in error for this test numbered '$i'.  If empty, the test passed
825
826     my $message = "";
827     if (@$results_ref) {
828         $message = join " ", "for", disp_chars(@$results_ref);
829     }
830     report_result($Locale, $i, @$results_ref == 0, $message);
831 }
832
833 my $first_locales_test_number = $final_without_setlocale + 1;
834 my $locales_test_number;
835 my $not_necessarily_a_problem_test_number;
836 my $first_casing_test_number;
837 my %setlocale_failed;   # List of locales that setlocale() didn't work on
838
839 foreach my $Locale (@Locale) {
840     $locales_test_number = $first_locales_test_number - 1;
841     debug "#\n";
842     debug "# Locale = $Locale\n";
843
844     unless (setlocale(&POSIX::LC_ALL, $Locale)) {
845         $setlocale_failed{$Locale} = $Locale;
846         next;
847     }
848
849     # We test UTF-8 locales only under ':not_characters';  It is easier to
850     # test them in other test files than here.  Non- UTF-8 locales are tested
851     # only under plain 'use locale', as otherwise we would have to convert
852     # everything in them to Unicode.
853
854     my %UPPER = ();     # All alpha X for which uc(X) == X and lc(X) != X
855     my %lower = ();     # All alpha X for which lc(X) == X and uc(X) != X
856     my %BoThCaSe = ();  # All alpha X for which uc(X) == lc(X) == X
857
858     my $is_utf8_locale = is_locale_utf8($Locale);
859
860     debug "# is utf8 locale? = $is_utf8_locale\n";
861
862     my $radix = localeconv()->{decimal_point};
863     if ($radix !~ / ^ [[:ascii:]] + $/x) {
864         use bytes;
865         $radix = disp_chars(split "", $radix);
866     }
867     debug "# radix = $radix\n";
868
869     if (! $is_utf8_locale) {
870         use locale;
871         @{$posixes{'word'}} = grep /\w/, map { chr } 0..255;
872         @{$posixes{'digit'}} = grep /\d/, map { chr } 0..255;
873         @{$posixes{'space'}} = grep /\s/, map { chr } 0..255;
874         @{$posixes{'alpha'}} = grep /[[:alpha:]]/, map {chr } 0..255;
875         @{$posixes{'alnum'}} = grep /[[:alnum:]]/, map {chr } 0..255;
876         @{$posixes{'ascii'}} = grep /[[:ascii:]]/, map {chr } 0..255;
877         @{$posixes{'blank'}} = grep /[[:blank:]]/, map {chr } 0..255;
878         @{$posixes{'cntrl'}} = grep /[[:cntrl:]]/, map {chr } 0..255;
879         @{$posixes{'graph'}} = grep /[[:graph:]]/, map {chr } 0..255;
880         @{$posixes{'lower'}} = grep /[[:lower:]]/, map {chr } 0..255;
881         @{$posixes{'print'}} = grep /[[:print:]]/, map {chr } 0..255;
882         @{$posixes{'punct'}} = grep /[[:punct:]]/, map {chr } 0..255;
883         @{$posixes{'upper'}} = grep /[[:upper:]]/, map {chr } 0..255;
884         @{$posixes{'xdigit'}} = grep /[[:xdigit:]]/, map {chr } 0..255;
885         @{$posixes{'cased'}} = grep /[[:upper:]]/i, map {chr } 0..255;
886
887         # Sieve the uppercase and the lowercase.
888
889         for (@{$posixes{'word'}}) {
890             if (/[^\d_]/) { # skip digits and the _
891                 if (uc($_) eq $_) {
892                     $UPPER{$_} = $_;
893                 }
894                 if (lc($_) eq $_) {
895                     $lower{$_} = $_;
896                 }
897             }
898         }
899     }
900     else {
901         use locale ':not_characters';
902         @{$posixes{'word'}} = grep /\w/, map { chr } 0..255;
903         @{$posixes{'digit'}} = grep /\d/, map { chr } 0..255;
904         @{$posixes{'space'}} = grep /\s/, map { chr } 0..255;
905         @{$posixes{'alpha'}} = grep /[[:alpha:]]/, map {chr } 0..255;
906         @{$posixes{'alnum'}} = grep /[[:alnum:]]/, map {chr } 0..255;
907         @{$posixes{'ascii'}} = grep /[[:ascii:]]/, map {chr } 0..255;
908         @{$posixes{'blank'}} = grep /[[:blank:]]/, map {chr } 0..255;
909         @{$posixes{'cntrl'}} = grep /[[:cntrl:]]/, map {chr } 0..255;
910         @{$posixes{'graph'}} = grep /[[:graph:]]/, map {chr } 0..255;
911         @{$posixes{'lower'}} = grep /[[:lower:]]/, map {chr } 0..255;
912         @{$posixes{'print'}} = grep /[[:print:]]/, map {chr } 0..255;
913         @{$posixes{'punct'}} = grep /[[:punct:]]/, map {chr } 0..255;
914         @{$posixes{'upper'}} = grep /[[:upper:]]/, map {chr } 0..255;
915         @{$posixes{'xdigit'}} = grep /[[:xdigit:]]/, map {chr } 0..255;
916         @{$posixes{'cased'}} = grep /[[:upper:]]/i, map {chr } 0..255;
917         for (@{$posixes{'word'}}) {
918             if (/[^\d_]/) { # skip digits and the _
919                 if (uc($_) eq $_) {
920                     $UPPER{$_} = $_;
921                 }
922                 if (lc($_) eq $_) {
923                     $lower{$_} = $_;
924                 }
925             }
926         }
927     }
928
929     # Ordered, where possible,  in groups of "this is a subset of the next
930     # one"
931     debug "# :upper:  = ", disp_chars(@{$posixes{'upper'}}), "\n";
932     debug "# :lower:  = ", disp_chars(@{$posixes{'lower'}}), "\n";
933     debug "# :cased:  = ", disp_chars(@{$posixes{'cased'}}), "\n";
934     debug "# :alpha:  = ", disp_chars(@{$posixes{'alpha'}}), "\n";
935     debug "# :alnum:  = ", disp_chars(@{$posixes{'alnum'}}), "\n";
936     debug "#  w       = ", disp_chars(@{$posixes{'word'}}), "\n";
937     debug "# :graph:  = ", disp_chars(@{$posixes{'graph'}}), "\n";
938     debug "# :print:  = ", disp_chars(@{$posixes{'print'}}), "\n";
939     debug "#  d       = ", disp_chars(@{$posixes{'digit'}}), "\n";
940     debug "# :xdigit: = ", disp_chars(@{$posixes{'xdigit'}}), "\n";
941     debug "# :blank:  = ", disp_chars(@{$posixes{'blank'}}), "\n";
942     debug "#  s       = ", disp_chars(@{$posixes{'space'}}), "\n";
943     debug "# :punct:  = ", disp_chars(@{$posixes{'punct'}}), "\n";
944     debug "# :cntrl:  = ", disp_chars(@{$posixes{'cntrl'}}), "\n";
945     debug "# :ascii:  = ", disp_chars(@{$posixes{'ascii'}}), "\n";
946
947     foreach (keys %UPPER) {
948
949         $BoThCaSe{$_}++ if exists $lower{$_};
950     }
951     foreach (keys %lower) {
952         $BoThCaSe{$_}++ if exists $UPPER{$_};
953     }
954     foreach (keys %BoThCaSe) {
955         delete $UPPER{$_};
956         delete $lower{$_};
957     }
958
959     my %Unassigned;
960     foreach my $ord ( 0 .. 255 ) {
961         $Unassigned{chr $ord} = 1;
962     }
963     foreach my $class (keys %posixes) {
964         foreach my $char (@{$posixes{$class}}) {
965             delete $Unassigned{$char};
966         }
967     }
968
969     debug "# UPPER    = ", disp_chars(sort { ord $a <=> ord $b } keys %UPPER), "\n";
970     debug "# lower    = ", disp_chars(sort { ord $a <=> ord $b } keys %lower), "\n";
971     debug "# BoThCaSe = ", disp_chars(sort { ord $a <=> ord $b } keys %BoThCaSe), "\n";
972     debug "# Unassigned = ", disp_chars(sort { ord $a <=> ord $b } keys %Unassigned), "\n";
973
974     my @failures;
975     my @fold_failures;
976     foreach my $x (sort { ord $a <=> ord $b } keys %UPPER) {
977         my $ok;
978         my $fold_ok;
979         if ($is_utf8_locale) {
980             use locale ':not_characters';
981             $ok = $x =~ /[[:upper:]]/;
982             $fold_ok = $x =~ /[[:lower:]]/i;
983         }
984         else {
985             use locale;
986             $ok = $x =~ /[[:upper:]]/;
987             $fold_ok = $x =~ /[[:lower:]]/i;
988         }
989         push @failures, $x unless $ok;
990         push @fold_failures, $x unless $fold_ok;
991     }
992     $locales_test_number++;
993     $first_casing_test_number = $locales_test_number;
994     $test_names{$locales_test_number} = 'Verify that /[[:upper:]]/ matches all alpha X for which uc(X) == X and lc(X) != X';
995     report_multi_result($Locale, $locales_test_number, \@failures);
996
997     $locales_test_number++;
998
999     $test_names{$locales_test_number} = 'Verify that /[[:lower:]]/i matches all alpha X for which uc(X) == X and lc(X) != X';
1000     report_multi_result($Locale, $locales_test_number, \@fold_failures);
1001
1002     undef @failures;
1003     undef @fold_failures;
1004
1005     foreach my $x (sort { ord $a <=> ord $b } keys %lower) {
1006         my $ok;
1007         my $fold_ok;
1008         if ($is_utf8_locale) {
1009             use locale ':not_characters';
1010             $ok = $x =~ /[[:lower:]]/;
1011             $fold_ok = $x =~ /[[:upper:]]/i;
1012         }
1013         else {
1014             use locale;
1015             $ok = $x =~ /[[:lower:]]/;
1016             $fold_ok = $x =~ /[[:upper:]]/i;
1017         }
1018         push @failures, $x unless $ok;
1019         push @fold_failures, $x unless $fold_ok;
1020     }
1021
1022     $locales_test_number++;
1023     $test_names{$locales_test_number} = 'Verify that /[[:lower:]]/ matches all alpha X for which lc(X) == X and uc(X) != X';
1024     report_multi_result($Locale, $locales_test_number, \@failures);
1025
1026     $locales_test_number++;
1027     $test_names{$locales_test_number} = 'Verify that /[[:upper:]]/i matches all alpha X for which lc(X) == X and uc(X) != X';
1028     report_multi_result($Locale, $locales_test_number, \@fold_failures);
1029
1030     {   # Find the alphabetic characters that are not considered alphabetics
1031         # in the default (C) locale.
1032
1033         no locale;
1034
1035         @Added_alpha = ();
1036         for (keys %UPPER, keys %lower, keys %BoThCaSe) {
1037             push(@Added_alpha, $_) if (/\W/);
1038         }
1039     }
1040
1041     @Added_alpha = sort { ord $a <=> ord $b } @Added_alpha;
1042
1043     debug "# Added_alpha = ", disp_chars(@Added_alpha), "\n";
1044
1045     # Cross-check the whole 8-bit character set.
1046
1047     ++$locales_test_number;
1048     my @f;
1049     $test_names{$locales_test_number} = 'Verify that \w and [:word:] are identical';
1050     for (map { chr } 0..255) {
1051         if ($is_utf8_locale) {
1052             use locale ':not_characters';
1053             push @f, $_ unless /[[:word:]]/ == /\w/;
1054         }
1055         else {
1056             push @f, $_ unless /[[:word:]]/ == /\w/;
1057         }
1058     }
1059     report_multi_result($Locale, $locales_test_number, \@f);
1060
1061     ++$locales_test_number;
1062     undef @f;
1063     $test_names{$locales_test_number} = 'Verify that \d and [:digit:] are identical';
1064     for (map { chr } 0..255) {
1065         if ($is_utf8_locale) {
1066             use locale ':not_characters';
1067             push @f, $_ unless /[[:digit:]]/ == /\d/;
1068         }
1069         else {
1070             push @f, $_ unless /[[:digit:]]/ == /\d/;
1071         }
1072     }
1073     report_multi_result($Locale, $locales_test_number, \@f);
1074
1075     ++$locales_test_number;
1076     undef @f;
1077     $test_names{$locales_test_number} = 'Verify that \s and [:space:] are identical';
1078     for (map { chr } 0..255) {
1079         if ($is_utf8_locale) {
1080             use locale ':not_characters';
1081             push @f, $_ unless /[[:space:]]/ == /\s/;
1082         }
1083         else {
1084             push @f, $_ unless /[[:space:]]/ == /\s/;
1085         }
1086     }
1087     report_multi_result($Locale, $locales_test_number, \@f);
1088
1089     ++$locales_test_number;
1090     undef @f;
1091     $test_names{$locales_test_number} = 'Verify that [:posix:] and [:^posix:] are mutually exclusive';
1092     for (map { chr } 0..255) {
1093         if ($is_utf8_locale) {
1094             use locale ':not_characters';
1095             push @f, $_ unless   (/[[:alpha:]]/ xor /[[:^alpha:]]/)   ||
1096                     (/[[:alnum:]]/ xor /[[:^alnum:]]/)   ||
1097                     (/[[:ascii:]]/ xor /[[:^ascii:]]/)   ||
1098                     (/[[:blank:]]/ xor /[[:^blank:]]/)   ||
1099                     (/[[:cntrl:]]/ xor /[[:^cntrl:]]/)   ||
1100                     (/[[:digit:]]/ xor /[[:^digit:]]/)   ||
1101                     (/[[:graph:]]/ xor /[[:^graph:]]/)   ||
1102                     (/[[:lower:]]/ xor /[[:^lower:]]/)   ||
1103                     (/[[:print:]]/ xor /[[:^print:]]/)   ||
1104                     (/[[:space:]]/ xor /[[:^space:]]/)   ||
1105                     (/[[:upper:]]/ xor /[[:^upper:]]/)   ||
1106                     (/[[:word:]]/  xor /[[:^word:]]/)    ||
1107                     (/[[:xdigit:]]/ xor /[[:^xdigit:]]/) ||
1108
1109                     # effectively is what [:cased:] would be if it existed.
1110                     (/[[:upper:]]/i xor /[[:^upper:]]/i);
1111         }
1112         else {
1113             push @f, $_ unless   (/[[:alpha:]]/ xor /[[:^alpha:]]/)   ||
1114                     (/[[:alnum:]]/ xor /[[:^alnum:]]/)   ||
1115                     (/[[:ascii:]]/ xor /[[:^ascii:]]/)   ||
1116                     (/[[:blank:]]/ xor /[[:^blank:]]/)   ||
1117                     (/[[:cntrl:]]/ xor /[[:^cntrl:]]/)   ||
1118                     (/[[:digit:]]/ xor /[[:^digit:]]/)   ||
1119                     (/[[:graph:]]/ xor /[[:^graph:]]/)   ||
1120                     (/[[:lower:]]/ xor /[[:^lower:]]/)   ||
1121                     (/[[:print:]]/ xor /[[:^print:]]/)   ||
1122                     (/[[:space:]]/ xor /[[:^space:]]/)   ||
1123                     (/[[:upper:]]/ xor /[[:^upper:]]/)   ||
1124                     (/[[:word:]]/  xor /[[:^word:]]/)    ||
1125                     (/[[:xdigit:]]/ xor /[[:^xdigit:]]/) ||
1126                     (/[[:upper:]]/i xor /[[:^upper:]]/i);
1127         }
1128     }
1129     report_multi_result($Locale, $locales_test_number, \@f);
1130
1131     # The rules for the relationships are given in:
1132     # http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html
1133
1134
1135     ++$locales_test_number;
1136     undef @f;
1137     $test_names{$locales_test_number} = 'Verify that [:lower:] contains at least a-z';
1138     for ('a' .. 'z') {
1139         if ($is_utf8_locale) {
1140             use locale ':not_characters';
1141             push @f, $_  unless /[[:lower:]]/;
1142         }
1143         else {
1144             push @f, $_  unless /[[:lower:]]/;
1145         }
1146     }
1147     report_multi_result($Locale, $locales_test_number, \@f);
1148
1149     ++$locales_test_number;
1150     undef @f;
1151     $test_names{$locales_test_number} = 'Verify that [:lower:] is a subset of [:alpha:]';
1152     for (map { chr } 0..255) {
1153         if ($is_utf8_locale) {
1154             use locale ':not_characters';
1155             push @f, $_  if /[[:lower:]]/ and ! /[[:alpha:]]/;
1156         }
1157         else {
1158             push @f, $_  if /[[:lower:]]/ and ! /[[:alpha:]]/;
1159         }
1160     }
1161     report_multi_result($Locale, $locales_test_number, \@f);
1162
1163     ++$locales_test_number;
1164     undef @f;
1165     $test_names{$locales_test_number} = 'Verify that [:upper:] contains at least A-Z';
1166     for ('A' .. 'Z') {
1167         if ($is_utf8_locale) {
1168             use locale ':not_characters';
1169             push @f, $_  unless /[[:upper:]]/;
1170         }
1171         else {
1172             push @f, $_  unless /[[:upper:]]/;
1173         }
1174     }
1175     report_multi_result($Locale, $locales_test_number, \@f);
1176
1177     ++$locales_test_number;
1178     undef @f;
1179     $test_names{$locales_test_number} = 'Verify that [:upper:] is a subset of [:alpha:]';
1180     for (map { chr } 0..255) {
1181         if ($is_utf8_locale) {
1182             use locale ':not_characters';
1183             push @f, $_  if /[[:upper:]]/ and ! /[[:alpha:]]/;
1184         }
1185         else {
1186             push @f, $_ if /[[:upper:]]/  and ! /[[:alpha:]]/;
1187         }
1188     }
1189     report_multi_result($Locale, $locales_test_number, \@f);
1190
1191     ++$locales_test_number;
1192     undef @f;
1193     $test_names{$locales_test_number} = 'Verify that /[[:lower:]]/i is a subset of [:alpha:]';
1194     for (map { chr } 0..255) {
1195         if ($is_utf8_locale) {
1196             use locale ':not_characters';
1197             push @f, $_ if /[[:lower:]]/i  and ! /[[:alpha:]]/;
1198         }
1199         else {
1200             push @f, $_ if /[[:lower:]]/i  and ! /[[:alpha:]]/;
1201         }
1202     }
1203     report_multi_result($Locale, $locales_test_number, \@f);
1204
1205     ++$locales_test_number;
1206     undef @f;
1207     $test_names{$locales_test_number} = 'Verify that [:alpha:] is a subset of [:alnum:]';
1208     for (map { chr } 0..255) {
1209         if ($is_utf8_locale) {
1210             use locale ':not_characters';
1211             push @f, $_ if /[[:alpha:]]/  and ! /[[:alnum:]]/;
1212         }
1213         else {
1214             push @f, $_ if /[[:alpha:]]/  and ! /[[:alnum:]]/;
1215         }
1216     }
1217     report_multi_result($Locale, $locales_test_number, \@f);
1218
1219     ++$locales_test_number;
1220     undef @f;
1221     $test_names{$locales_test_number} = 'Verify that [:digit:] contains at least 0-9';
1222     for ('0' .. '9') {
1223         if ($is_utf8_locale) {
1224             use locale ':not_characters';
1225             push @f, $_  unless /[[:digit:]]/;
1226         }
1227         else {
1228             push @f, $_  unless /[[:digit:]]/;
1229         }
1230     }
1231     report_multi_result($Locale, $locales_test_number, \@f);
1232
1233     ++$locales_test_number;
1234     undef @f;
1235     $test_names{$locales_test_number} = 'Verify that [:digit:] is a subset of [:alnum:]';
1236     for (map { chr } 0..255) {
1237         if ($is_utf8_locale) {
1238             use locale ':not_characters';
1239             push @f, $_ if /[[:digit:]]/  and ! /[[:alnum:]]/;
1240         }
1241         else {
1242             push @f, $_ if /[[:digit:]]/  and ! /[[:alnum:]]/;
1243         }
1244     }
1245     report_multi_result($Locale, $locales_test_number, \@f);
1246
1247     ++$locales_test_number;
1248     undef @f;
1249     $test_names{$locales_test_number} = 'Verify that [:digit:] matches either 10 or 20 code points';
1250     report_result($Locale, $locales_test_number, @{$posixes{'digit'}} == 10 || @{$posixes{'digit'}} == 20);
1251
1252     ++$locales_test_number;
1253     undef @f;
1254     $test_names{$locales_test_number} = 'Verify that if there is a second set of digits in [:digit:], they are consecutive';
1255     if (@{$posixes{'digit'}} == 20) {
1256         my $previous_ord;
1257         for (map { chr } 0..255) {
1258             next unless /[[:digit:]]/;
1259             next if /[0-9]/;
1260             if (defined $previous_ord) {
1261                 if ($is_utf8_locale) {
1262                     use locale ':not_characters';
1263                     push @f, $_ if ord $_ != $previous_ord + 1;
1264                 }
1265                 else {
1266                     push @f, $_ if ord $_ != $previous_ord + 1;
1267                 }
1268             }
1269             $previous_ord = ord $_;
1270         }
1271     }
1272     report_multi_result($Locale, $locales_test_number, \@f);
1273
1274     ++$locales_test_number;
1275     undef @f;
1276     my @xdigit_digits;  # :digit: & :xdigit:
1277     $test_names{$locales_test_number} = 'Verify that [:xdigit:] contains one or two blocks of 10 consecutive [:digit:] chars';
1278     for (map { chr } 0..255) {
1279         if ($is_utf8_locale) {
1280             use locale ':not_characters';
1281             # For utf8 locales, we actually use a stricter test: that :digit:
1282             # is a subset of :xdigit:, as we know that only 0-9 should match
1283             push @f, $_ if /[[:digit:]]/ and ! /[[:xdigit:]]/;
1284         }
1285         else {
1286             push @xdigit_digits, $_ if /[[:digit:]]/ and /[[:xdigit:]]/;
1287         }
1288     }
1289     if (! $is_utf8_locale) {
1290
1291         # For non-utf8 locales, @xdigit_digits is a list of the characters
1292         # that are both :xdigit: and :digit:.  Because :digit: is stored in
1293         # increasing code point order (unless the tests above failed),
1294         # @xdigit_digits is as well.  There should be exactly 10 or
1295         # 20 of these.
1296         if (@xdigit_digits != 10 && @xdigit_digits != 20) {
1297             @f = @xdigit_digits;
1298         }
1299         else {
1300
1301             # Look for contiguity in the series, adding any wrong ones to @f
1302             my @temp = @xdigit_digits;
1303             while (@temp > 1) {
1304                 push @f, $temp[1] if ($temp[0] != $temp[1] - 1)
1305
1306                                      # Skip this test for the 0th character of
1307                                      # the second block of 10, as it won't be
1308                                      # contiguous with the previous block
1309                                      && (! defined $xdigit_digits[10]
1310                                          || $temp[1] != $xdigit_digits[10]);
1311                 shift @temp;
1312             }
1313         }
1314     }
1315
1316     report_multi_result($Locale, $locales_test_number, \@f);
1317
1318     ++$locales_test_number;
1319     undef @f;
1320     $test_names{$locales_test_number} = 'Verify that [:xdigit:] contains at least A-F, a-f';
1321     for ('A' .. 'F', 'a' .. 'f') {
1322         if ($is_utf8_locale) {
1323             use locale ':not_characters';
1324             push @f, $_  unless /[[:xdigit:]]/;
1325         }
1326         else {
1327             push @f, $_  unless /[[:xdigit:]]/;
1328         }
1329     }
1330     report_multi_result($Locale, $locales_test_number, \@f);
1331
1332     ++$locales_test_number;
1333     undef @f;
1334     $test_names{$locales_test_number} = 'Verify that any additional members of [:xdigit:], are in groups of 6 consecutive code points';
1335     my $previous_ord;
1336     my $count = 0;
1337     for my $chr (map { chr } 0..255) {
1338         next unless $chr =~ /[[:xdigit:]]/;
1339         if ($is_utf8_locale) {
1340             next if $chr =~ /[[:digit:]]/;
1341         }
1342         else {
1343             next if grep { $chr eq $_ } @xdigit_digits;
1344         }
1345         next if $chr =~ /[A-Fa-f]/;
1346         if (defined $previous_ord) {
1347             if ($is_utf8_locale) {
1348                 use locale ':not_characters';
1349                 push @f, $chr if ord $chr != $previous_ord + 1;
1350             }
1351             else {
1352                 push @f, $chr if ord $chr != $previous_ord + 1;
1353             }
1354         }
1355         $count++;
1356         if ($count == 6) {
1357             undef $previous_ord;
1358         }
1359         else {
1360             $previous_ord = ord $chr;
1361         }
1362     }
1363     report_multi_result($Locale, $locales_test_number, \@f);
1364
1365     ++$locales_test_number;
1366     undef @f;
1367     $test_names{$locales_test_number} = 'Verify that [:xdigit:] is a subset of [:graph:]';
1368     for (map { chr } 0..255) {
1369         if ($is_utf8_locale) {
1370             use locale ':not_characters';
1371             push @f, $_ if /[[:xdigit:]]/  and ! /[[:graph:]]/;
1372         }
1373         else {
1374             push @f, $_ if /[[:xdigit:]]/  and ! /[[:graph:]]/;
1375         }
1376     }
1377     report_multi_result($Locale, $locales_test_number, \@f);
1378
1379     # Note that xdigit doesn't have to be a subset of alnum
1380
1381     ++$locales_test_number;
1382     undef @f;
1383     $test_names{$locales_test_number} = 'Verify that [:punct:] is a subset of [:graph:]';
1384     for (map { chr } 0..255) {
1385         if ($is_utf8_locale) {
1386             use locale ':not_characters';
1387             push @f, $_ if /[[:punct:]]/  and ! /[[:graph:]]/;
1388         }
1389         else {
1390             push @f, $_ if /[[:punct:]]/  and ! /[[:graph:]]/;
1391         }
1392     }
1393     report_multi_result($Locale, $locales_test_number, \@f);
1394
1395     ++$locales_test_number;
1396     undef @f;
1397     $test_names{$locales_test_number} = 'Verify that the space character is not in [:graph:]';
1398     if ($is_utf8_locale) {
1399         use locale ':not_characters';
1400         push @f, " " if " " =~ /[[:graph:]]/;
1401     }
1402     else {
1403         push @f, " " if " " =~ /[[:graph:]]/;
1404     }
1405     report_multi_result($Locale, $locales_test_number, \@f);
1406
1407     ++$locales_test_number;
1408     undef @f;
1409     $test_names{$locales_test_number} = 'Verify that [:space:] contains at least [\f\n\r\t\cK ]';
1410     for (' ', "\f", "\n", "\r", "\t", "\cK") {
1411         if ($is_utf8_locale) {
1412             use locale ':not_characters';
1413             push @f, $_  unless /[[:space:]]/;
1414         }
1415         else {
1416             push @f, $_  unless /[[:space:]]/;
1417         }
1418     }
1419     report_multi_result($Locale, $locales_test_number, \@f);
1420
1421     ++$locales_test_number;
1422     undef @f;
1423     $test_names{$locales_test_number} = 'Verify that [:blank:] contains at least [\t ]';
1424     for (' ', "\t") {
1425         if ($is_utf8_locale) {
1426             use locale ':not_characters';
1427             push @f, $_  unless /[[:blank:]]/;
1428         }
1429         else {
1430             push @f, $_  unless /[[:blank:]]/;
1431         }
1432     }
1433     report_multi_result($Locale, $locales_test_number, \@f);
1434
1435     ++$locales_test_number;
1436     undef @f;
1437     $test_names{$locales_test_number} = 'Verify that [:blank:] is a subset of [:space:]';
1438     for (map { chr } 0..255) {
1439         if ($is_utf8_locale) {
1440             use locale ':not_characters';
1441             push @f, $_ if /[[:blank:]]/  and ! /[[:space:]]/;
1442         }
1443         else {
1444             push @f, $_ if /[[:blank:]]/  and ! /[[:space:]]/;
1445         }
1446     }
1447     report_multi_result($Locale, $locales_test_number, \@f);
1448
1449     ++$locales_test_number;
1450     undef @f;
1451     $test_names{$locales_test_number} = 'Verify that [:graph:] is a subset of [:print:]';
1452     for (map { chr } 0..255) {
1453         if ($is_utf8_locale) {
1454             use locale ':not_characters';
1455             push @f, $_ if /[[:graph:]]/  and ! /[[:print:]]/;
1456         }
1457         else {
1458             push @f, $_ if /[[:graph:]]/  and ! /[[:print:]]/;
1459         }
1460     }
1461     report_multi_result($Locale, $locales_test_number, \@f);
1462
1463     ++$locales_test_number;
1464     undef @f;
1465     $test_names{$locales_test_number} = 'Verify that the space character is in [:print:]';
1466     if ($is_utf8_locale) {
1467         use locale ':not_characters';
1468         push @f, " " if " " !~ /[[:print:]]/;
1469     }
1470     else {
1471         push @f, " " if " " !~ /[[:print:]]/;
1472     }
1473     report_multi_result($Locale, $locales_test_number, \@f);
1474
1475     ++$locales_test_number;
1476     undef @f;
1477     $test_names{$locales_test_number} = 'Verify that isn\'t both [:cntrl:] and [:print:]';
1478     for (map { chr } 0..255) {
1479         if ($is_utf8_locale) {
1480             use locale ':not_characters';
1481             push @f, $_ if (/[[:print:]]/ and /[[:cntrl:]]/);
1482         }
1483         else {
1484             push @f, $_ if (/[[:print:]]/ and /[[:cntrl:]]/);
1485         }
1486     }
1487     report_multi_result($Locale, $locales_test_number, \@f);
1488
1489     ++$locales_test_number;
1490     undef @f;
1491     $test_names{$locales_test_number} = 'Verify that isn\'t both [:alpha:] and [:digit:]';
1492     for (map { chr } 0..255) {
1493         if ($is_utf8_locale) {
1494             use locale ':not_characters';
1495             push @f, $_ if /[[:alpha:]]/ and /[[:digit:]]/;
1496         }
1497         else {
1498             push @f, $_ if /[[:alpha:]]/ and /[[:digit:]]/;
1499         }
1500     }
1501     report_multi_result($Locale, $locales_test_number, \@f);
1502
1503     ++$locales_test_number;
1504     undef @f;
1505     $test_names{$locales_test_number} = 'Verify that isn\'t both [:alnum:] and [:punct:]';
1506     for (map { chr } 0..255) {
1507         if ($is_utf8_locale) {
1508             use locale ':not_characters';
1509             push @f, $_ if /[[:alnum:]]/ and /[[:punct:]]/;
1510         }
1511         else {
1512             push @f, $_ if /[[:alnum:]]/ and /[[:punct:]]/;
1513         }
1514     }
1515     report_multi_result($Locale, $locales_test_number, \@f);
1516
1517     ++$locales_test_number;
1518     undef @f;
1519     $test_names{$locales_test_number} = 'Verify that isn\'t both [:xdigit:] and [:punct:]';
1520     for (map { chr } 0..255) {
1521         if ($is_utf8_locale) {
1522             use locale ':not_characters';
1523             push @f, $_ if (/[[:punct:]]/ and /[[:xdigit:]]/);
1524         }
1525         else {
1526             push @f, $_ if (/[[:punct:]]/ and /[[:xdigit:]]/);
1527         }
1528     }
1529     report_multi_result($Locale, $locales_test_number, \@f);
1530
1531     ++$locales_test_number;
1532     undef @f;
1533     $test_names{$locales_test_number} = 'Verify that isn\'t both [:graph:] and [:space:]';
1534     for (map { chr } 0..255) {
1535         if ($is_utf8_locale) {
1536             use locale ':not_characters';
1537             push @f, $_ if (/[[:graph:]]/ and /[[:space:]]/);
1538         }
1539         else {
1540             push @f, $_ if (/[[:graph:]]/ and /[[:space:]]/);
1541         }
1542     }
1543     report_multi_result($Locale, $locales_test_number, \@f);
1544
1545     foreach ($first_casing_test_number..$locales_test_number) {
1546         $problematical_tests{$_} = 1;
1547     }
1548
1549
1550     # Test for read-only scalars' locale vs non-locale comparisons.
1551
1552     {
1553         no locale;
1554         my $ok;
1555         $a = "qwerty";
1556         if ($is_utf8_locale) {
1557             use locale ':not_characters';
1558             $ok = ($a cmp "qwerty") == 0;
1559         }
1560         else {
1561             use locale;
1562             $ok = ($a cmp "qwerty") == 0;
1563         }
1564         report_result($Locale, ++$locales_test_number, $ok);
1565         $test_names{$locales_test_number} = 'Verify that cmp works with a read-only scalar; no- vs locale';
1566     }
1567
1568     {
1569         my ($from, $to, $lesser, $greater,
1570             @test, %test, $test, $yes, $no, $sign);
1571
1572         ++$locales_test_number;
1573         $test_names{$locales_test_number} = 'Verify that "le", "ne", etc work';
1574         $not_necessarily_a_problem_test_number = $locales_test_number;
1575         for (0..9) {
1576             # Select a slice.
1577             $from = int(($_*@{$posixes{'word'}})/10);
1578             $to = $from + int(@{$posixes{'word'}}/10);
1579             $to = $#{$posixes{'word'}} if ($to > $#{$posixes{'word'}});
1580             $lesser  = join('', @{$posixes{'word'}}[$from..$to]);
1581             # Select a slice one character on.
1582             $from++; $to++;
1583             $to = $#{$posixes{'word'}} if ($to > $#{$posixes{'word'}});
1584             $greater = join('', @{$posixes{'word'}}[$from..$to]);
1585             if ($is_utf8_locale) {
1586                 use locale ':not_characters';
1587                 ($yes, $no, $sign) = ($lesser lt $greater
1588                                     ? ("    ", "not ", 1)
1589                                     : ("not ", "    ", -1));
1590             }
1591             else {
1592                 use locale;
1593                 ($yes, $no, $sign) = ($lesser lt $greater
1594                                     ? ("    ", "not ", 1)
1595                                     : ("not ", "    ", -1));
1596             }
1597             # all these tests should FAIL (return 0).  Exact lt or gt cannot
1598             # be tested because in some locales, say, eacute and E may test
1599             # equal.
1600             @test =
1601                 (
1602                     $no.'    ($lesser  le $greater)',  # 1
1603                     'not      ($lesser  ne $greater)', # 2
1604                     '         ($lesser  eq $greater)', # 3
1605                     $yes.'    ($lesser  ge $greater)', # 4
1606                     $yes.'    ($lesser  ge $greater)', # 5
1607                     $yes.'    ($greater le $lesser )', # 7
1608                     'not      ($greater ne $lesser )', # 8
1609                     '         ($greater eq $lesser )', # 9
1610                     $no.'     ($greater ge $lesser )', # 10
1611                     'not (($lesser cmp $greater) == -($sign))' # 11
1612                     );
1613             @test{@test} = 0 x @test;
1614             $test = 0;
1615             for my $ti (@test) {
1616                 if ($is_utf8_locale) {
1617                     use locale ':not_characters';
1618                     $test{$ti} = eval $ti;
1619                 }
1620                 else {
1621                     # Already in 'use locale';
1622                     $test{$ti} = eval $ti;
1623                 }
1624                 $test ||= $test{$ti}
1625             }
1626             report_result($Locale, $locales_test_number, $test == 0);
1627             if ($test) {
1628                 debug "# lesser  = '$lesser'\n";
1629                 debug "# greater = '$greater'\n";
1630                 debug "# lesser cmp greater = ",
1631                         $lesser cmp $greater, "\n";
1632                 debug "# greater cmp lesser = ",
1633                         $greater cmp $lesser, "\n";
1634                 debug "# (greater) from = $from, to = $to\n";
1635                 for my $ti (@test) {
1636                     debugf("# %-40s %-4s", $ti,
1637                             $test{$ti} ? 'FAIL' : 'ok');
1638                     if ($ti =~ /\(\.*(\$.+ +cmp +\$[^\)]+)\.*\)/) {
1639                         debugf("(%s == %4d)", $1, eval $1);
1640                     }
1641                     debug "\n#";
1642                 }
1643
1644                 last;
1645             }
1646         }
1647     }
1648
1649     my $ok1;
1650     my $ok2;
1651     my $ok3;
1652     my $ok4;
1653     my $ok5;
1654     my $ok6;
1655     my $ok7;
1656     my $ok8;
1657     my $ok9;
1658     my $ok10;
1659     my $ok11;
1660     my $ok12;
1661     my $ok13;
1662     my $ok14;
1663     my $ok14_5;
1664     my $ok15;
1665     my $ok16;
1666     my $ok17;
1667     my $ok18;
1668
1669     my $c;
1670     my $d;
1671     my $e;
1672     my $f;
1673     my $g;
1674     my $h;
1675     my $i;
1676     my $j;
1677
1678     if (! $is_utf8_locale) {
1679         use locale;
1680
1681         my ($x, $y) = (1.23, 1.23);
1682
1683         $a = "$x";
1684         printf ''; # printf used to reset locale to "C"
1685         $b = "$y";
1686         $ok1 = $a eq $b;
1687
1688         $c = "$x";
1689         my $z = sprintf ''; # sprintf used to reset locale to "C"
1690         $d = "$y";
1691         $ok2 = $c eq $d;
1692         {
1693
1694             use warnings;
1695             my $w = 0;
1696             local $SIG{__WARN__} =
1697                 sub {
1698                     print "# @_\n";
1699                     $w++;
1700                 };
1701
1702             # The == (among other ops) used to warn for locales
1703             # that had something else than "." as the radix character.
1704
1705             $ok3 = $c == 1.23;
1706             $ok4 = $c == $x;
1707             $ok5 = $c == $d;
1708             {
1709                 no locale;
1710
1711                 $e = "$x";
1712
1713                 $ok6 = $e == 1.23;
1714                 $ok7 = $e == $x;
1715                 $ok8 = $e == $c;
1716             }
1717
1718             $f = "1.23";
1719             $g = 2.34;
1720             $h = 1.5;
1721             $i = 1.25;
1722             $j = "$h:$i";
1723
1724             $ok9 = $f == 1.23;
1725             $ok10 = $f == $x;
1726             $ok11 = $f == $c;
1727             $ok12 = abs(($f + $g) - 3.57) < 0.01;
1728             $ok13 = $w == 0;
1729             $ok14 = $ok14_5 = $ok15 = $ok16 = 1;  # Skip for non-utf8 locales
1730         }
1731         {
1732             no locale;
1733             $ok17 = "1.5:1.25" eq sprintf("%g:%g", $h, $i);
1734         }
1735         $ok18 = $j eq sprintf("%g:%g", $h, $i);
1736     }
1737     else {
1738         use locale ':not_characters';
1739
1740         my ($x, $y) = (1.23, 1.23);
1741         $a = "$x";
1742         printf ''; # printf used to reset locale to "C"
1743         $b = "$y";
1744         $ok1 = $a eq $b;
1745
1746         $c = "$x";
1747         my $z = sprintf ''; # sprintf used to reset locale to "C"
1748         $d = "$y";
1749         $ok2 = $c eq $d;
1750         {
1751             use warnings;
1752             my $w = 0;
1753             local $SIG{__WARN__} =
1754                 sub {
1755                     print "# @_\n";
1756                     $w++;
1757                 };
1758             $ok3 = $c == 1.23;
1759             $ok4 = $c == $x;
1760             $ok5 = $c == $d;
1761             {
1762                 no locale;
1763                 $e = "$x";
1764
1765                 $ok6 = $e == 1.23;
1766                 $ok7 = $e == $x;
1767                 $ok8 = $e == $c;
1768             }
1769
1770             $f = "1.23";
1771             $g = 2.34;
1772             $h = 1.5;
1773             $i = 1.25;
1774             $j = "$h:$i";
1775
1776             $ok9 = $f == 1.23;
1777             $ok10 = $f == $x;
1778             $ok11 = $f == $c;
1779             $ok12 = abs(($f + $g) - 3.57) < 0.01;
1780             $ok13 = $w == 0;
1781
1782             # Look for non-ASCII error messages, and verify that the first
1783             # such is in UTF-8 (the others almost certainly will be like the
1784             # first).
1785             $ok14 = 1;
1786             $ok14_5 = 1;
1787             foreach my $err (keys %!) {
1788                 use Errno;
1789                 $! = eval "&Errno::$err";   # Convert to strerror() output
1790                 my $strerror = "$!";
1791                 if ("$strerror" =~ /\P{ASCII}/) {
1792                     $ok14 = utf8::is_utf8($strerror);
1793                     no locale;
1794                     $ok14_5 = "$!" !~ /\P{ASCII}/;
1795                     last;
1796                 }
1797             }
1798
1799             # Similarly, we verify that a non-ASCII radix is in UTF-8.  This
1800             # also catches if there is a disparity between sprintf and
1801             # stringification.
1802
1803             my $string_g = "$g";
1804             my $sprintf_g = sprintf("%g", $g);
1805
1806             $ok15 = $string_g =~ / ^ \p{ASCII}+ $ /x || utf8::is_utf8($string_g);
1807             $ok16 = $sprintf_g eq $string_g;
1808         }
1809         {
1810             no locale;
1811             $ok17 = "1.5:1.25" eq sprintf("%g:%g", $h, $i);
1812         }
1813         $ok18 = $j eq sprintf("%g:%g", $h, $i);
1814     }
1815
1816     report_result($Locale, ++$locales_test_number, $ok1);
1817     $test_names{$locales_test_number} = 'Verify that an intervening printf doesn\'t change assignment results';
1818     my $first_a_test = $locales_test_number;
1819
1820     debug "# $first_a_test..$locales_test_number: \$a = $a, \$b = $b, Locale = $Locale\n";
1821
1822     report_result($Locale, ++$locales_test_number, $ok2);
1823     $test_names{$locales_test_number} = 'Verify that an intervening sprintf doesn\'t change assignment results';
1824
1825     my $first_c_test = $locales_test_number;
1826
1827     report_result($Locale, ++$locales_test_number, $ok3);
1828     $test_names{$locales_test_number} = 'Verify that a different locale radix works when doing "==" with a constant';
1829     $problematical_tests{$locales_test_number} = 1;
1830
1831     report_result($Locale, ++$locales_test_number, $ok4);
1832     $test_names{$locales_test_number} = 'Verify that a different locale radix works when doing "==" with a scalar';
1833     $problematical_tests{$locales_test_number} = 1;
1834
1835     report_result($Locale, ++$locales_test_number, $ok5);
1836     $test_names{$locales_test_number} = 'Verify that a different locale radix works when doing "==" with a scalar and an intervening sprintf';
1837     $problematical_tests{$locales_test_number} = 1;
1838
1839     debug "# $first_c_test..$locales_test_number: \$c = $c, \$d = $d, Locale = $Locale\n";
1840
1841     report_result($Locale, ++$locales_test_number, $ok6);
1842     $test_names{$locales_test_number} = 'Verify that can assign stringified under inner no-locale block';
1843     my $first_e_test = $locales_test_number;
1844
1845     report_result($Locale, ++$locales_test_number, $ok7);
1846     $test_names{$locales_test_number} = 'Verify that "==" with a scalar still works in inner no locale';
1847
1848     report_result($Locale, ++$locales_test_number, $ok8);
1849     $test_names{$locales_test_number} = 'Verify that "==" with a scalar and an intervening sprintf still works in inner no locale';
1850     $problematical_tests{$locales_test_number} = 1;
1851
1852     debug "# $first_e_test..$locales_test_number: \$e = $e, no locale\n";
1853
1854     report_result($Locale, ++$locales_test_number, $ok9);
1855     $test_names{$locales_test_number} = 'Verify that after a no-locale block, a different locale radix still works when doing "==" with a constant';
1856     $problematical_tests{$locales_test_number} = 1;
1857     my $first_f_test = $locales_test_number;
1858
1859     report_result($Locale, ++$locales_test_number, $ok10);
1860     $test_names{$locales_test_number} = 'Verify that after a no-locale block, a different locale radix still works when doing "==" with a scalar';
1861     $problematical_tests{$locales_test_number} = 1;
1862
1863     report_result($Locale, ++$locales_test_number, $ok11);
1864     $test_names{$locales_test_number} = 'Verify that after a no-locale block, a different locale radix still works when doing "==" with a scalar and an intervening sprintf';
1865     $problematical_tests{$locales_test_number} = 1;
1866
1867     report_result($Locale, ++$locales_test_number, $ok12);
1868     $test_names{$locales_test_number} = 'Verify that after a no-locale block, a different locale radix can participate in an addition and function call as numeric';
1869     $problematical_tests{$locales_test_number} = 1;
1870
1871     report_result($Locale, ++$locales_test_number, $ok13);
1872     $test_names{$locales_test_number} = 'Verify that don\'t get warning under "==" even if radix is not a dot';
1873     $problematical_tests{$locales_test_number} = 1;
1874
1875     report_result($Locale, ++$locales_test_number, $ok14);
1876     $test_names{$locales_test_number} = 'Verify that non-ASCII UTF-8 error messages are in UTF-8';
1877
1878     report_result($Locale, ++$locales_test_number, $ok14_5);
1879     $test_names{$locales_test_number} = '... and are ASCII outside "use locale"';
1880
1881     report_result($Locale, ++$locales_test_number, $ok15);
1882     $test_names{$locales_test_number} = 'Verify that a number with a UTF-8 radix has a UTF-8 stringification';
1883
1884     report_result($Locale, ++$locales_test_number, $ok16);
1885     $test_names{$locales_test_number} = 'Verify that a sprintf of a number with a UTF-8 radix yields UTF-8';
1886
1887     report_result($Locale, ++$locales_test_number, $ok17);
1888     $test_names{$locales_test_number} = 'Verify that a sprintf of a number outside locale scope uses a dot radix';
1889
1890     report_result($Locale, ++$locales_test_number, $ok18);
1891     $test_names{$locales_test_number} = 'Verify that a sprintf of a number back within locale scope uses locale radix';
1892
1893     debug "# $first_f_test..$locales_test_number: \$f = $f, \$g = $g, back to locale = $Locale\n";
1894
1895     # Does taking lc separately differ from taking
1896     # the lc "in-line"?  (This was the bug 19990704.002, change #3568.)
1897     # The bug was in the caching of the 'o'-magic.
1898     if (! $is_utf8_locale) {
1899         use locale;
1900
1901         sub lcA {
1902             my $lc0 = lc $_[0];
1903             my $lc1 = lc $_[1];
1904             return $lc0 cmp $lc1;
1905         }
1906
1907         sub lcB {
1908             return lc($_[0]) cmp lc($_[1]);
1909         }
1910
1911         my $x = "ab";
1912         my $y = "aa";
1913         my $z = "AB";
1914
1915         report_result($Locale, ++$locales_test_number,
1916                     lcA($x, $y) == 1 && lcB($x, $y) == 1 ||
1917                     lcA($x, $z) == 0 && lcB($x, $z) == 0);
1918     }
1919     else {
1920         use locale ':not_characters';
1921
1922         sub lcC {
1923             my $lc0 = lc $_[0];
1924             my $lc1 = lc $_[1];
1925             return $lc0 cmp $lc1;
1926         }
1927
1928         sub lcD {
1929             return lc($_[0]) cmp lc($_[1]);
1930         }
1931
1932         my $x = "ab";
1933         my $y = "aa";
1934         my $z = "AB";
1935
1936         report_result($Locale, ++$locales_test_number,
1937                     lcC($x, $y) == 1 && lcD($x, $y) == 1 ||
1938                     lcC($x, $z) == 0 && lcD($x, $z) == 0);
1939     }
1940     $test_names{$locales_test_number} = 'Verify "lc(foo) cmp lc(bar)" is the same as using intermediaries for the cmp';
1941
1942     # Does lc of an UPPER (if different from the UPPER) match
1943     # case-insensitively the UPPER, and does the UPPER match
1944     # case-insensitively the lc of the UPPER.  And vice versa.
1945     {
1946         use locale;
1947         no utf8;
1948         my $re = qr/[\[\(\{\*\+\?\|\^\$\\]/;
1949
1950         my @f = ();
1951         ++$locales_test_number;
1952         $test_names{$locales_test_number} = 'Verify case insensitive matching works';
1953         foreach my $x (sort { ord $a <=> ord $b } keys %UPPER) {
1954             if (! $is_utf8_locale) {
1955                 my $y = lc $x;
1956                 next unless uc $y eq $x;
1957                 debug_more( "# UPPER=", disp_chars(($x)),
1958                             "; lc=", disp_chars(($y)), "; ",
1959                             "; fc=", disp_chars((fc $x)), "; ",
1960                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
1961                             $x =~ /$y/i ? 1 : 0,
1962                             "; ",
1963                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
1964                             $y =~ /$x/i ? 1 : 0,
1965                             "\n");
1966                 #
1967                 # If $x and $y contain regular expression characters
1968                 # AND THEY lowercase (/i) to regular expression characters,
1969                 # regcomp() will be mightily confused.  No, the \Q doesn't
1970                 # help here (maybe regex engine internal lowercasing
1971                 # is done after the \Q?)  An example of this happening is
1972                 # the bg_BG (Bulgarian) locale under EBCDIC (OS/390 USS):
1973                 # the chr(173) (the "[") is the lowercase of the chr(235).
1974                 #
1975                 # Similarly losing EBCDIC locales include cs_cz, cs_CZ,
1976                 # el_gr, el_GR, en_us.IBM-037 (!), en_US.IBM-037 (!),
1977                 # et_ee, et_EE, hr_hr, hr_HR, hu_hu, hu_HU, lt_LT,
1978                 # mk_mk, mk_MK, nl_nl.IBM-037, nl_NL.IBM-037,
1979                 # pl_pl, pl_PL, ro_ro, ro_RO, ru_ru, ru_RU,
1980                 # sk_sk, sk_SK, sl_si, sl_SI, tr_tr, tr_TR.
1981                 #
1982                 # Similar things can happen even under (bastardised)
1983                 # non-EBCDIC locales: in many European countries before the
1984                 # advent of ISO 8859-x nationally customised versions of
1985                 # ISO 646 were devised, reusing certain punctuation
1986                 # characters for modified characters needed by the
1987                 # country/language.  For example, the "|" might have
1988                 # stood for U+00F6 or LATIN SMALL LETTER O WITH DIAERESIS.
1989                 #
1990                 if ($x =~ $re || $y =~ $re) {
1991                     print "# Regex characters in '$x' or '$y', skipping test $locales_test_number for locale '$Locale'\n";
1992                     next;
1993                 }
1994                 push @f, $x unless $x =~ /$y/i && $y =~ /$x/i;
1995
1996                 # fc is not a locale concept, so Perl uses lc for it.
1997                 push @f, $x unless lc $x eq fc $x;
1998             }
1999             else {
2000                 use locale ':not_characters';
2001                 my $y = lc $x;
2002                 next unless uc $y eq $x;
2003                 debug_more( "# UPPER=", disp_chars(($x)),
2004                             "; lc=", disp_chars(($y)), "; ",
2005                             "; fc=", disp_chars((fc $x)), "; ",
2006                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2007                             $x =~ /$y/i ? 1 : 0,
2008                             "; ",
2009                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2010                             $y =~ /$x/i ? 1 : 0,
2011                             "\n");
2012
2013                 push @f, $x unless $x =~ /$y/i && $y =~ /$x/i;
2014
2015                 # The places where Unicode's lc is different from fc are
2016                 # skipped here by virtue of the 'next unless uc...' line above
2017                 push @f, $x unless lc $x eq fc $x;
2018             }
2019         }
2020
2021         foreach my $x (sort { ord $a <=> ord $b } keys %lower) {
2022             if (! $is_utf8_locale) {
2023                 my $y = uc $x;
2024                 next unless lc $y eq $x;
2025                 debug_more( "# lower=", disp_chars(($x)),
2026                             "; uc=", disp_chars(($y)), "; ",
2027                             "; fc=", disp_chars((fc $x)), "; ",
2028                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2029                             $x =~ /$y/i ? 1 : 0,
2030                             "; ",
2031                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2032                             $y =~ /$x/i ? 1 : 0,
2033                             "\n");
2034                 if ($x =~ $re || $y =~ $re) { # See above.
2035                     print "# Regex characters in '$x' or '$y', skipping test $locales_test_number for locale '$Locale'\n";
2036                     next;
2037                 }
2038                 push @f, $x unless $x =~ /$y/i && $y =~ /$x/i;
2039
2040                 push @f, $x unless lc $x eq fc $x;
2041             }
2042             else {
2043                 use locale ':not_characters';
2044                 my $y = uc $x;
2045                 next unless lc $y eq $x;
2046                 debug_more( "# lower=", disp_chars(($x)),
2047                             "; uc=", disp_chars(($y)), "; ",
2048                             "; fc=", disp_chars((fc $x)), "; ",
2049                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2050                             $x =~ /$y/i ? 1 : 0,
2051                             "; ",
2052                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2053                             $y =~ /$x/i ? 1 : 0,
2054                             "\n");
2055                 push @f, $x unless $x =~ /$y/i && $y =~ /$x/i;
2056
2057                 push @f, $x unless lc $x eq fc $x;
2058             }
2059         }
2060         report_multi_result($Locale, $locales_test_number, \@f);
2061         $problematical_tests{$locales_test_number} = 1;
2062     }
2063
2064     # [perl #109318]
2065     {
2066         my @f = ();
2067         ++$locales_test_number;
2068         $test_names{$locales_test_number} = 'Verify atof with locale radix and negative exponent';
2069         $problematical_tests{$locales_test_number} = 1;
2070
2071         my $radix = POSIX::localeconv()->{decimal_point};
2072         my @nums = (
2073              "3.14e+9",  "3${radix}14e+9",  "3.14e-9",  "3${radix}14e-9",
2074             "-3.14e+9", "-3${radix}14e+9", "-3.14e-9", "-3${radix}14e-9",
2075         );
2076
2077         if (! $is_utf8_locale) {
2078             use locale;
2079             for my $num (@nums) {
2080                 push @f, $num
2081                     unless sprintf("%g", $num) =~ /3.+14/;
2082             }
2083         }
2084         else {
2085             use locale ':not_characters';
2086             for my $num (@nums) {
2087                 push @f, $num
2088                     unless sprintf("%g", $num) =~ /3.+14/;
2089             }
2090         }
2091
2092         report_result($Locale, $locales_test_number, @f == 0);
2093         if (@f) {
2094             print "# failed $locales_test_number locale '$Locale' numbers @f\n"
2095         }
2096     }
2097 }
2098
2099 my $final_locales_test_number = $locales_test_number;
2100
2101 # Recount the errors.
2102
2103 foreach $test_num ($first_locales_test_number..$final_locales_test_number) {
2104     if (%setlocale_failed) {
2105         print "not ";
2106     }
2107     elsif ($Problem{$test_num} || !defined $Okay{$test_num} || !@{$Okay{$test_num}}) {
2108         if (defined $not_necessarily_a_problem_test_number
2109             && $test_num == $not_necessarily_a_problem_test_number)
2110         {
2111             print "# The failure of test $not_necessarily_a_problem_test_number is not necessarily fatal.\n";
2112             print "# It usually indicates a problem in the environment,\n";
2113             print "# not in Perl itself.\n";
2114         }
2115         if ($Okay{$test_num} && grep { $_ == $test_num } keys %problematical_tests) {
2116             no warnings 'experimental::autoderef';
2117             # Round to nearest .1%
2118             my $percent_fail = (int(.5 + (1000 * scalar(keys $Problem{$test_num})
2119                                           / scalar(@Locale))))
2120                                / 10;
2121             if (! $debug && $percent_fail < $acceptable_failure_percentage)
2122             {
2123                 $test_names{$test_num} .= 'TODO';
2124                 print "# ", 100 - $percent_fail, "% of locales pass the following test, so it is likely that the failures\n";
2125                 print "# are errors in the locale definitions.  The test is marked TODO, as the\n";
2126                 print "# problem is not likely to be Perl's\n";
2127             }
2128         }
2129         print "#\n";
2130         if ($debug) {
2131             print "# The code points that had this failure are given above.  Look for lines\n";
2132             print "# that match 'failed $test_num'\n";
2133         }
2134         else {
2135             print "# For more details, rerun, with environment variable PERL_DEBUG_FULL_TEST=1.\n";
2136             print "# Then look at that output for lines that match 'failed $test_num'\n";
2137         }
2138         print "not ";
2139     }
2140     print "ok $test_num";
2141     if (defined $test_names{$test_num}) {
2142         # If TODO is in the test name, make it thus
2143         my $todo = $test_names{$test_num} =~ s/TODO\s*//;
2144         print " $test_names{$test_num}";
2145         print " # TODO" if $todo;
2146     }
2147     print "\n";
2148 }
2149
2150 $test_num = $final_locales_test_number;
2151
2152 unless ( $^O =~ m!^(dragonfly|openbsd|bitrig|mirbsd)$! ) {
2153     # perl #115808
2154     use warnings;
2155     my $warned = 0;
2156     local $SIG{__WARN__} = sub {
2157         $warned = $_[0] =~ /uninitialized/;
2158     };
2159     my $z = "y" . setlocale(&POSIX::LC_ALL, "xyzzy");
2160     ok($warned, "variable set to setlocale(BAD LOCALE) is considered uninitialized");
2161 }
2162
2163 # Test that tainting and case changing works on utf8 strings.  These tests are
2164 # placed last to avoid disturbing the hard-coded test numbers that existed at
2165 # the time these were added above this in this file.
2166 # This also tests that locale overrides unicode_strings in the same scope for
2167 # non-utf8 strings.
2168 setlocale(&POSIX::LC_ALL, "C");
2169 {
2170     use locale;
2171     use feature 'unicode_strings';
2172
2173     foreach my $function ("uc", "ucfirst", "lc", "lcfirst", "fc") {
2174         my @list;   # List of code points to test for $function
2175
2176         # Used to calculate the changed case for ASCII characters by using the
2177         # ord, instead of using one of the functions under test.
2178         my $ascii_case_change_delta;
2179         my $above_latin1_case_change_delta; # Same for the specific ords > 255
2180                                             # that we use
2181
2182         # We test an ASCII character, which should change case;
2183         # a Latin1 character, which shouldn't change case under this C locale,
2184         # an above-Latin1 character that when the case is changed would cross
2185         #   the 255/256 boundary, so doesn't change case
2186         #   (the \x{149} is one of these, but changes into 2 characters, the
2187         #   first one of which doesn't cross the boundary.
2188         # the final one in each list is an above-Latin1 character whose case
2189         #   does change.  The code below uses its position in its list as a
2190         #   marker to indicate that it, unlike the other code points above
2191         #   ASCII, has a successful case change
2192         #
2193         # All casing operations under locale (but not :not_characters) should
2194         # taint
2195         if ($function =~ /^u/) {
2196             @list = ("", "a", "\xe0", "\xff", "\x{fb00}", "\x{149}", "\x{101}");
2197             $ascii_case_change_delta = -32;
2198             $above_latin1_case_change_delta = -1;
2199         }
2200         else {
2201             @list = ("", "A", "\xC0", "\x{17F}", "\x{100}");
2202             $ascii_case_change_delta = +32;
2203             $above_latin1_case_change_delta = +1;
2204         }
2205         foreach my $is_utf8_locale (0 .. 1) {
2206             foreach my $j (0 .. $#list) {
2207                 my $char = $list[$j];
2208
2209                 for my $encoded_in_utf8 (0 .. 1) {
2210                     my $should_be;
2211                     my $changed;
2212                     if (! $is_utf8_locale) {
2213                         $should_be = ($j == $#list)
2214                             ? chr(ord($char) + $above_latin1_case_change_delta)
2215                             : (length $char == 0 || ord($char) > 127)
2216                             ? $char
2217                             : chr(ord($char) + $ascii_case_change_delta);
2218
2219                         # This monstrosity is in order to avoid using an eval,
2220                         # which might perturb the results
2221                         $changed = ($function eq "uc")
2222                                     ? uc($char)
2223                                     : ($function eq "ucfirst")
2224                                       ? ucfirst($char)
2225                                       : ($function eq "lc")
2226                                         ? lc($char)
2227                                         : ($function eq "lcfirst")
2228                                           ? lcfirst($char)
2229                                           : ($function eq "fc")
2230                                             ? fc($char)
2231                                             : die("Unexpected function \"$function\"");
2232                     }
2233                     else {
2234                         {
2235                             no locale;
2236
2237                             # For utf8-locales the case changing functions
2238                             # should work just like they do outside of locale.
2239                             # Can use eval here because not testing it when
2240                             # not in locale.
2241                             $should_be = eval "$function('$char')";
2242                             die "Unexpected eval error $@ from 'eval \"$function('$char')\"'" if  $@;
2243
2244                         }
2245                         use locale ':not_characters';
2246                         $changed = ($function eq "uc")
2247                                     ? uc($char)
2248                                     : ($function eq "ucfirst")
2249                                       ? ucfirst($char)
2250                                       : ($function eq "lc")
2251                                         ? lc($char)
2252                                         : ($function eq "lcfirst")
2253                                           ? lcfirst($char)
2254                                           : ($function eq "fc")
2255                                             ? fc($char)
2256                                             : die("Unexpected function \"$function\"");
2257                     }
2258                     ok($changed eq $should_be,
2259                         "$function(\"$char\") in C locale "
2260                         . (($is_utf8_locale)
2261                             ? "(use locale ':not_characters'"
2262                             : "(use locale")
2263                         . (($encoded_in_utf8)
2264                             ? "; encoded in utf8)"
2265                             : "; not encoded in utf8)")
2266                         . " should be \"$should_be\", got \"$changed\"");
2267
2268                     # Tainting shouldn't happen for use locale :not_character
2269                     # (a utf8 locale)
2270                     (! $is_utf8_locale)
2271                     ? check_taint($changed)
2272                     : check_taint_not($changed);
2273
2274                     # Use UTF-8 next time through the loop
2275                     utf8::upgrade($char);
2276                 }
2277             }
2278         }
2279     }
2280 }
2281
2282 # Give final advice.
2283
2284 my $didwarn = 0;
2285
2286 foreach ($first_locales_test_number..$final_locales_test_number) {
2287     if ($Problem{$_}) {
2288         my @f = sort keys %{ $Problem{$_} };
2289         my $f = join(" ", @f);
2290         $f =~ s/(.{50,60}) /$1\n#\t/g;
2291         print
2292             "#\n",
2293             "# The locale ", (@f == 1 ? "definition" : "definitions"), "\n#\n",
2294             "#\t", $f, "\n#\n",
2295             "# on your system may have errors because the locale test $_\n",
2296             "# \"$test_names{$_}\"\n",
2297             "# failed in ", (@f == 1 ? "that locale" : "those locales"),
2298             ".\n";
2299         print <<EOW;
2300 #
2301 # If your users are not using these locales you are safe for the moment,
2302 # but please report this failure first to perlbug\@perl.com using the
2303 # perlbug script (as described in the INSTALL file) so that the exact
2304 # details of the failures can be sorted out first and then your operating
2305 # system supplier can be alerted about these anomalies.
2306 #
2307 EOW
2308         $didwarn = 1;
2309     }
2310 }
2311
2312 # Tell which locales were okay and which were not.
2313
2314 if ($didwarn) {
2315     my (@s, @F);
2316
2317     foreach my $l (@Locale) {
2318         my $p = 0;
2319         if ($setlocale_failed{$l}) {
2320             $p++;
2321         }
2322         else {
2323             foreach my $t
2324                         ($first_locales_test_number..$final_locales_test_number)
2325             {
2326                 $p++ if $Problem{$t}{$l};
2327             }
2328         }
2329         push @s, $l if $p == 0;
2330         push @F, $l unless $p == 0;
2331     }
2332
2333     if (@s) {
2334         my $s = join(" ", @s);
2335         $s =~ s/(.{50,60}) /$1\n#\t/g;
2336
2337         print
2338             "# The following locales\n#\n",
2339             "#\t", $s, "\n#\n",
2340             "# tested okay.\n#\n",
2341     } else {
2342         print "# None of your locales were fully okay.\n";
2343     }
2344
2345     if (@F) {
2346         my $F = join(" ", @F);
2347         $F =~ s/(.{50,60}) /$1\n#\t/g;
2348
2349         my $details = "";
2350         unless ($debug) {
2351             $details = "# For more details, rerun, with environment variable PERL_DEBUG_FULL_TEST=1.\n";
2352         }
2353         elsif ($debug == 1) {
2354             $details = "# For even more details, rerun, with environment variable PERL_DEBUG_FULL_TEST=2.\n";
2355         }
2356
2357         print
2358           "# The following locales\n#\n",
2359           "#\t", $F, "\n#\n",
2360           "# had problems.\n#\n",
2361           $details;
2362     } else {
2363         print "# None of your locales were broken.\n";
2364     }
2365 }
2366
2367 print "1..$test_num\n";
2368
2369 # eof