Synchronise versions in Maintainers.pl for recent updates
[perl.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_NUMERIC, &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 disp_str ($) {
809     my $string = shift;
810
811     # Displays the string unambiguously.  ASCII printables are always output
812     # as-is, though perhaps separated by blanks from other characters.  If
813     # entirely printable ASCII, just returns the string.  Otherwise if valid
814     # UTF-8 it uses the character names for non-printable-ASCII.  Otherwise it
815     # outputs hex for each non-ASCII-printable byte.
816
817     return $string if $string =~ / ^ [[:print:]]* $/xa;
818
819     my $result = "";
820     my $prev_was_punct = 1; # Beginning is considered punct
821     if (utf8::valid($string) && utf8::is_utf8($string)) {
822         use charnames ();
823         foreach my $char (split "", $string) {
824
825             # Keep punctuation adjacent to other characters; otherwise
826             # separate them with a blank
827             if ($char =~ /[[:punct:]]/a) {
828                 $result .= $char;
829                 $prev_was_punct = 1;
830             }
831             elsif ($char =~ /[[:print:]]/a) {
832                 $result .= "  " unless $prev_was_punct;
833                 $result .= $char;
834                 $prev_was_punct = 0;
835             }
836             else {
837                 $result .= "  " unless $prev_was_punct;
838                 $result .= charnames::viacode(ord $char);
839                 $prev_was_punct = 0;
840             }
841         }
842     }
843     else {
844         use bytes;
845         foreach my $char (split "", $string) {
846             if ($char =~ /[[:punct:]]/a) {
847                 $result .= $char;
848                 $prev_was_punct = 1;
849             }
850             elsif ($char =~ /[[:print:]]/a) {
851                 $result .= " " unless $prev_was_punct;
852                 $result .= $char;
853                 $prev_was_punct = 0;
854             }
855             else {
856                 $result .= " " unless $prev_was_punct;
857                 $result .= sprintf("%02X", ord $char);
858                 $prev_was_punct = 0;
859             }
860         }
861     }
862
863     return $result;
864 }
865
866 sub report_result {
867     my ($Locale, $i, $pass_fail, $message) = @_;
868     $message //= "";
869     $message = "  ($message)" if $message;
870     unless ($pass_fail) {
871         $Problem{$i}{$Locale} = 1;
872         debug "failed $i ($test_names{$i}) with locale '$Locale'$message\n";
873     } else {
874         push @{$Okay{$i}}, $Locale;
875     }
876 }
877
878 sub report_multi_result {
879     my ($Locale, $i, $results_ref) = @_;
880
881     # $results_ref points to an array, each element of which is a character that was
882     # in error for this test numbered '$i'.  If empty, the test passed
883
884     my $message = "";
885     if (@$results_ref) {
886         $message = join " ", "for", disp_chars(@$results_ref);
887     }
888     report_result($Locale, $i, @$results_ref == 0, $message);
889 }
890
891 my $first_locales_test_number = $final_without_setlocale + 1;
892 my $locales_test_number;
893 my $not_necessarily_a_problem_test_number;
894 my $first_casing_test_number;
895 my %setlocale_failed;   # List of locales that setlocale() didn't work on
896
897 foreach my $Locale (@Locale) {
898     $locales_test_number = $first_locales_test_number - 1;
899     debug "\n";
900     debug "Locale = $Locale\n";
901
902     unless (setlocale(&POSIX::LC_ALL, $Locale)) {
903         $setlocale_failed{$Locale} = $Locale;
904         next;
905     }
906
907     # We test UTF-8 locales only under ':not_characters';  It is easier to
908     # test them in other test files than here.  Non- UTF-8 locales are tested
909     # only under plain 'use locale', as otherwise we would have to convert
910     # everything in them to Unicode.
911
912     my %UPPER = ();     # All alpha X for which uc(X) == X and lc(X) != X
913     my %lower = ();     # All alpha X for which lc(X) == X and uc(X) != X
914     my %BoThCaSe = ();  # All alpha X for which uc(X) == lc(X) == X
915
916     my $is_utf8_locale = is_locale_utf8($Locale);
917
918     debug "is utf8 locale? = $is_utf8_locale\n";
919
920     debug "radix = " . disp_str(localeconv()->{decimal_point}) . "\n";
921
922     if (! $is_utf8_locale) {
923         use locale;
924         @{$posixes{'word'}} = grep /\w/, map { chr } 0..255;
925         @{$posixes{'digit'}} = grep /\d/, map { chr } 0..255;
926         @{$posixes{'space'}} = grep /\s/, map { chr } 0..255;
927         @{$posixes{'alpha'}} = grep /[[:alpha:]]/, map {chr } 0..255;
928         @{$posixes{'alnum'}} = grep /[[:alnum:]]/, map {chr } 0..255;
929         @{$posixes{'ascii'}} = grep /[[:ascii:]]/, map {chr } 0..255;
930         @{$posixes{'blank'}} = grep /[[:blank:]]/, map {chr } 0..255;
931         @{$posixes{'cntrl'}} = grep /[[:cntrl:]]/, map {chr } 0..255;
932         @{$posixes{'graph'}} = grep /[[:graph:]]/, map {chr } 0..255;
933         @{$posixes{'lower'}} = grep /[[:lower:]]/, map {chr } 0..255;
934         @{$posixes{'print'}} = grep /[[:print:]]/, map {chr } 0..255;
935         @{$posixes{'punct'}} = grep /[[:punct:]]/, map {chr } 0..255;
936         @{$posixes{'upper'}} = grep /[[:upper:]]/, map {chr } 0..255;
937         @{$posixes{'xdigit'}} = grep /[[:xdigit:]]/, map {chr } 0..255;
938         @{$posixes{'cased'}} = grep /[[:upper:]]/i, map {chr } 0..255;
939
940         # Sieve the uppercase and the lowercase.
941
942         for (@{$posixes{'word'}}) {
943             if (/[^\d_]/) { # skip digits and the _
944                 if (uc($_) eq $_) {
945                     $UPPER{$_} = $_;
946                 }
947                 if (lc($_) eq $_) {
948                     $lower{$_} = $_;
949                 }
950             }
951         }
952     }
953     else {
954         use locale ':not_characters';
955         @{$posixes{'word'}} = grep /\w/, map { chr } 0..255;
956         @{$posixes{'digit'}} = grep /\d/, map { chr } 0..255;
957         @{$posixes{'space'}} = grep /\s/, map { chr } 0..255;
958         @{$posixes{'alpha'}} = grep /[[:alpha:]]/, map {chr } 0..255;
959         @{$posixes{'alnum'}} = grep /[[:alnum:]]/, map {chr } 0..255;
960         @{$posixes{'ascii'}} = grep /[[:ascii:]]/, map {chr } 0..255;
961         @{$posixes{'blank'}} = grep /[[:blank:]]/, map {chr } 0..255;
962         @{$posixes{'cntrl'}} = grep /[[:cntrl:]]/, map {chr } 0..255;
963         @{$posixes{'graph'}} = grep /[[:graph:]]/, map {chr } 0..255;
964         @{$posixes{'lower'}} = grep /[[:lower:]]/, map {chr } 0..255;
965         @{$posixes{'print'}} = grep /[[:print:]]/, map {chr } 0..255;
966         @{$posixes{'punct'}} = grep /[[:punct:]]/, map {chr } 0..255;
967         @{$posixes{'upper'}} = grep /[[:upper:]]/, map {chr } 0..255;
968         @{$posixes{'xdigit'}} = grep /[[:xdigit:]]/, map {chr } 0..255;
969         @{$posixes{'cased'}} = grep /[[:upper:]]/i, map {chr } 0..255;
970         for (@{$posixes{'word'}}) {
971             if (/[^\d_]/) { # skip digits and the _
972                 if (uc($_) eq $_) {
973                     $UPPER{$_} = $_;
974                 }
975                 if (lc($_) eq $_) {
976                     $lower{$_} = $_;
977                 }
978             }
979         }
980     }
981
982     # Ordered, where possible,  in groups of "this is a subset of the next
983     # one"
984     debug ":upper:  = ", disp_chars(@{$posixes{'upper'}}), "\n";
985     debug ":lower:  = ", disp_chars(@{$posixes{'lower'}}), "\n";
986     debug ":cased:  = ", disp_chars(@{$posixes{'cased'}}), "\n";
987     debug ":alpha:  = ", disp_chars(@{$posixes{'alpha'}}), "\n";
988     debug ":alnum:  = ", disp_chars(@{$posixes{'alnum'}}), "\n";
989     debug " w       = ", disp_chars(@{$posixes{'word'}}), "\n";
990     debug ":graph:  = ", disp_chars(@{$posixes{'graph'}}), "\n";
991     debug ":print:  = ", disp_chars(@{$posixes{'print'}}), "\n";
992     debug " d       = ", disp_chars(@{$posixes{'digit'}}), "\n";
993     debug ":xdigit: = ", disp_chars(@{$posixes{'xdigit'}}), "\n";
994     debug ":blank:  = ", disp_chars(@{$posixes{'blank'}}), "\n";
995     debug " s       = ", disp_chars(@{$posixes{'space'}}), "\n";
996     debug ":punct:  = ", disp_chars(@{$posixes{'punct'}}), "\n";
997     debug ":cntrl:  = ", disp_chars(@{$posixes{'cntrl'}}), "\n";
998     debug ":ascii:  = ", disp_chars(@{$posixes{'ascii'}}), "\n";
999
1000     foreach (keys %UPPER) {
1001
1002         $BoThCaSe{$_}++ if exists $lower{$_};
1003     }
1004     foreach (keys %lower) {
1005         $BoThCaSe{$_}++ if exists $UPPER{$_};
1006     }
1007     foreach (keys %BoThCaSe) {
1008         delete $UPPER{$_};
1009         delete $lower{$_};
1010     }
1011
1012     my %Unassigned;
1013     foreach my $ord ( 0 .. 255 ) {
1014         $Unassigned{chr $ord} = 1;
1015     }
1016     foreach my $class (keys %posixes) {
1017         foreach my $char (@{$posixes{$class}}) {
1018             delete $Unassigned{$char};
1019         }
1020     }
1021
1022     debug "UPPER    = ", disp_chars(sort { ord $a <=> ord $b } keys %UPPER), "\n";
1023     debug "lower    = ", disp_chars(sort { ord $a <=> ord $b } keys %lower), "\n";
1024     debug "BoThCaSe = ", disp_chars(sort { ord $a <=> ord $b } keys %BoThCaSe), "\n";
1025     debug "Unassigned = ", disp_chars(sort { ord $a <=> ord $b } keys %Unassigned), "\n";
1026
1027     my @failures;
1028     my @fold_failures;
1029     foreach my $x (sort { ord $a <=> ord $b } keys %UPPER) {
1030         my $ok;
1031         my $fold_ok;
1032         if ($is_utf8_locale) {
1033             use locale ':not_characters';
1034             $ok = $x =~ /[[:upper:]]/;
1035             $fold_ok = $x =~ /[[:lower:]]/i;
1036         }
1037         else {
1038             use locale;
1039             $ok = $x =~ /[[:upper:]]/;
1040             $fold_ok = $x =~ /[[:lower:]]/i;
1041         }
1042         push @failures, $x unless $ok;
1043         push @fold_failures, $x unless $fold_ok;
1044     }
1045     $locales_test_number++;
1046     $first_casing_test_number = $locales_test_number;
1047     $test_names{$locales_test_number} = 'Verify that /[[:upper:]]/ matches all alpha X for which uc(X) == X and lc(X) != X';
1048     report_multi_result($Locale, $locales_test_number, \@failures);
1049
1050     $locales_test_number++;
1051
1052     $test_names{$locales_test_number} = 'Verify that /[[:lower:]]/i matches all alpha X for which uc(X) == X and lc(X) != X';
1053     report_multi_result($Locale, $locales_test_number, \@fold_failures);
1054
1055     undef @failures;
1056     undef @fold_failures;
1057
1058     foreach my $x (sort { ord $a <=> ord $b } keys %lower) {
1059         my $ok;
1060         my $fold_ok;
1061         if ($is_utf8_locale) {
1062             use locale ':not_characters';
1063             $ok = $x =~ /[[:lower:]]/;
1064             $fold_ok = $x =~ /[[:upper:]]/i;
1065         }
1066         else {
1067             use locale;
1068             $ok = $x =~ /[[:lower:]]/;
1069             $fold_ok = $x =~ /[[:upper:]]/i;
1070         }
1071         push @failures, $x unless $ok;
1072         push @fold_failures, $x unless $fold_ok;
1073     }
1074
1075     $locales_test_number++;
1076     $test_names{$locales_test_number} = 'Verify that /[[:lower:]]/ matches all alpha X for which lc(X) == X and uc(X) != X';
1077     report_multi_result($Locale, $locales_test_number, \@failures);
1078
1079     $locales_test_number++;
1080     $test_names{$locales_test_number} = 'Verify that /[[:upper:]]/i matches all alpha X for which lc(X) == X and uc(X) != X';
1081     report_multi_result($Locale, $locales_test_number, \@fold_failures);
1082
1083     {   # Find the alphabetic characters that are not considered alphabetics
1084         # in the default (C) locale.
1085
1086         no locale;
1087
1088         @Added_alpha = ();
1089         for (keys %UPPER, keys %lower, keys %BoThCaSe) {
1090             push(@Added_alpha, $_) if (/\W/);
1091         }
1092     }
1093
1094     @Added_alpha = sort { ord $a <=> ord $b } @Added_alpha;
1095
1096     debug "Added_alpha = ", disp_chars(@Added_alpha), "\n";
1097
1098     # Cross-check the whole 8-bit character set.
1099
1100     ++$locales_test_number;
1101     my @f;
1102     $test_names{$locales_test_number} = 'Verify that \w and [:word:] are identical';
1103     for (map { chr } 0..255) {
1104         if ($is_utf8_locale) {
1105             use locale ':not_characters';
1106             push @f, $_ unless /[[:word:]]/ == /\w/;
1107         }
1108         else {
1109             push @f, $_ unless /[[:word:]]/ == /\w/;
1110         }
1111     }
1112     report_multi_result($Locale, $locales_test_number, \@f);
1113
1114     ++$locales_test_number;
1115     undef @f;
1116     $test_names{$locales_test_number} = 'Verify that \d and [:digit:] are identical';
1117     for (map { chr } 0..255) {
1118         if ($is_utf8_locale) {
1119             use locale ':not_characters';
1120             push @f, $_ unless /[[:digit:]]/ == /\d/;
1121         }
1122         else {
1123             push @f, $_ unless /[[:digit:]]/ == /\d/;
1124         }
1125     }
1126     report_multi_result($Locale, $locales_test_number, \@f);
1127
1128     ++$locales_test_number;
1129     undef @f;
1130     $test_names{$locales_test_number} = 'Verify that \s and [:space:] are identical';
1131     for (map { chr } 0..255) {
1132         if ($is_utf8_locale) {
1133             use locale ':not_characters';
1134             push @f, $_ unless /[[:space:]]/ == /\s/;
1135         }
1136         else {
1137             push @f, $_ unless /[[:space:]]/ == /\s/;
1138         }
1139     }
1140     report_multi_result($Locale, $locales_test_number, \@f);
1141
1142     ++$locales_test_number;
1143     undef @f;
1144     $test_names{$locales_test_number} = 'Verify that [:posix:] and [:^posix:] are mutually exclusive';
1145     for (map { chr } 0..255) {
1146         if ($is_utf8_locale) {
1147             use locale ':not_characters';
1148             push @f, $_ unless   (/[[:alpha:]]/ xor /[[:^alpha:]]/)   ||
1149                     (/[[:alnum:]]/ xor /[[:^alnum:]]/)   ||
1150                     (/[[:ascii:]]/ xor /[[:^ascii:]]/)   ||
1151                     (/[[:blank:]]/ xor /[[:^blank:]]/)   ||
1152                     (/[[:cntrl:]]/ xor /[[:^cntrl:]]/)   ||
1153                     (/[[:digit:]]/ xor /[[:^digit:]]/)   ||
1154                     (/[[:graph:]]/ xor /[[:^graph:]]/)   ||
1155                     (/[[:lower:]]/ xor /[[:^lower:]]/)   ||
1156                     (/[[:print:]]/ xor /[[:^print:]]/)   ||
1157                     (/[[:space:]]/ xor /[[:^space:]]/)   ||
1158                     (/[[:upper:]]/ xor /[[:^upper:]]/)   ||
1159                     (/[[:word:]]/  xor /[[:^word:]]/)    ||
1160                     (/[[:xdigit:]]/ xor /[[:^xdigit:]]/) ||
1161
1162                     # effectively is what [:cased:] would be if it existed.
1163                     (/[[:upper:]]/i xor /[[:^upper:]]/i);
1164         }
1165         else {
1166             push @f, $_ unless   (/[[:alpha:]]/ xor /[[:^alpha:]]/)   ||
1167                     (/[[:alnum:]]/ xor /[[:^alnum:]]/)   ||
1168                     (/[[:ascii:]]/ xor /[[:^ascii:]]/)   ||
1169                     (/[[:blank:]]/ xor /[[:^blank:]]/)   ||
1170                     (/[[:cntrl:]]/ xor /[[:^cntrl:]]/)   ||
1171                     (/[[:digit:]]/ xor /[[:^digit:]]/)   ||
1172                     (/[[:graph:]]/ xor /[[:^graph:]]/)   ||
1173                     (/[[:lower:]]/ xor /[[:^lower:]]/)   ||
1174                     (/[[:print:]]/ xor /[[:^print:]]/)   ||
1175                     (/[[:space:]]/ xor /[[:^space:]]/)   ||
1176                     (/[[:upper:]]/ xor /[[:^upper:]]/)   ||
1177                     (/[[:word:]]/  xor /[[:^word:]]/)    ||
1178                     (/[[:xdigit:]]/ xor /[[:^xdigit:]]/) ||
1179                     (/[[:upper:]]/i xor /[[:^upper:]]/i);
1180         }
1181     }
1182     report_multi_result($Locale, $locales_test_number, \@f);
1183
1184     # The rules for the relationships are given in:
1185     # http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap07.html
1186
1187
1188     ++$locales_test_number;
1189     undef @f;
1190     $test_names{$locales_test_number} = 'Verify that [:lower:] contains at least a-z';
1191     for ('a' .. 'z') {
1192         if ($is_utf8_locale) {
1193             use locale ':not_characters';
1194             push @f, $_  unless /[[:lower:]]/;
1195         }
1196         else {
1197             push @f, $_  unless /[[:lower:]]/;
1198         }
1199     }
1200     report_multi_result($Locale, $locales_test_number, \@f);
1201
1202     ++$locales_test_number;
1203     undef @f;
1204     $test_names{$locales_test_number} = 'Verify that [:lower:] is a subset of [:alpha:]';
1205     for (map { chr } 0..255) {
1206         if ($is_utf8_locale) {
1207             use locale ':not_characters';
1208             push @f, $_  if /[[:lower:]]/ and ! /[[:alpha:]]/;
1209         }
1210         else {
1211             push @f, $_  if /[[:lower:]]/ and ! /[[:alpha:]]/;
1212         }
1213     }
1214     report_multi_result($Locale, $locales_test_number, \@f);
1215
1216     ++$locales_test_number;
1217     undef @f;
1218     $test_names{$locales_test_number} = 'Verify that [:upper:] contains at least A-Z';
1219     for ('A' .. 'Z') {
1220         if ($is_utf8_locale) {
1221             use locale ':not_characters';
1222             push @f, $_  unless /[[:upper:]]/;
1223         }
1224         else {
1225             push @f, $_  unless /[[:upper:]]/;
1226         }
1227     }
1228     report_multi_result($Locale, $locales_test_number, \@f);
1229
1230     ++$locales_test_number;
1231     undef @f;
1232     $test_names{$locales_test_number} = 'Verify that [:upper:] is a subset of [:alpha:]';
1233     for (map { chr } 0..255) {
1234         if ($is_utf8_locale) {
1235             use locale ':not_characters';
1236             push @f, $_  if /[[:upper:]]/ and ! /[[:alpha:]]/;
1237         }
1238         else {
1239             push @f, $_ if /[[:upper:]]/  and ! /[[:alpha:]]/;
1240         }
1241     }
1242     report_multi_result($Locale, $locales_test_number, \@f);
1243
1244     ++$locales_test_number;
1245     undef @f;
1246     $test_names{$locales_test_number} = 'Verify that /[[:lower:]]/i is a subset of [:alpha:]';
1247     for (map { chr } 0..255) {
1248         if ($is_utf8_locale) {
1249             use locale ':not_characters';
1250             push @f, $_ if /[[:lower:]]/i  and ! /[[:alpha:]]/;
1251         }
1252         else {
1253             push @f, $_ if /[[:lower:]]/i  and ! /[[:alpha:]]/;
1254         }
1255     }
1256     report_multi_result($Locale, $locales_test_number, \@f);
1257
1258     ++$locales_test_number;
1259     undef @f;
1260     $test_names{$locales_test_number} = 'Verify that [:alpha:] is a subset of [:alnum:]';
1261     for (map { chr } 0..255) {
1262         if ($is_utf8_locale) {
1263             use locale ':not_characters';
1264             push @f, $_ if /[[:alpha:]]/  and ! /[[:alnum:]]/;
1265         }
1266         else {
1267             push @f, $_ if /[[:alpha:]]/  and ! /[[:alnum:]]/;
1268         }
1269     }
1270     report_multi_result($Locale, $locales_test_number, \@f);
1271
1272     ++$locales_test_number;
1273     undef @f;
1274     $test_names{$locales_test_number} = 'Verify that [:digit:] contains at least 0-9';
1275     for ('0' .. '9') {
1276         if ($is_utf8_locale) {
1277             use locale ':not_characters';
1278             push @f, $_  unless /[[:digit:]]/;
1279         }
1280         else {
1281             push @f, $_  unless /[[:digit:]]/;
1282         }
1283     }
1284     report_multi_result($Locale, $locales_test_number, \@f);
1285
1286     ++$locales_test_number;
1287     undef @f;
1288     $test_names{$locales_test_number} = 'Verify that [:digit:] is a subset of [:alnum:]';
1289     for (map { chr } 0..255) {
1290         if ($is_utf8_locale) {
1291             use locale ':not_characters';
1292             push @f, $_ if /[[:digit:]]/  and ! /[[:alnum:]]/;
1293         }
1294         else {
1295             push @f, $_ if /[[:digit:]]/  and ! /[[:alnum:]]/;
1296         }
1297     }
1298     report_multi_result($Locale, $locales_test_number, \@f);
1299
1300     ++$locales_test_number;
1301     undef @f;
1302     $test_names{$locales_test_number} = 'Verify that [:digit:] matches either 10 or 20 code points';
1303     report_result($Locale, $locales_test_number, @{$posixes{'digit'}} == 10 || @{$posixes{'digit'}} == 20);
1304
1305     ++$locales_test_number;
1306     undef @f;
1307     $test_names{$locales_test_number} = 'Verify that if there is a second set of digits in [:digit:], they are consecutive';
1308     if (@{$posixes{'digit'}} == 20) {
1309         my $previous_ord;
1310         for (map { chr } 0..255) {
1311             next unless /[[:digit:]]/;
1312             next if /[0-9]/;
1313             if (defined $previous_ord) {
1314                 if ($is_utf8_locale) {
1315                     use locale ':not_characters';
1316                     push @f, $_ if ord $_ != $previous_ord + 1;
1317                 }
1318                 else {
1319                     push @f, $_ if ord $_ != $previous_ord + 1;
1320                 }
1321             }
1322             $previous_ord = ord $_;
1323         }
1324     }
1325     report_multi_result($Locale, $locales_test_number, \@f);
1326
1327     ++$locales_test_number;
1328     undef @f;
1329     my @xdigit_digits;  # :digit: & :xdigit:
1330     $test_names{$locales_test_number} = 'Verify that [:xdigit:] contains one or two blocks of 10 consecutive [:digit:] chars';
1331     for (map { chr } 0..255) {
1332         if ($is_utf8_locale) {
1333             use locale ':not_characters';
1334             # For utf8 locales, we actually use a stricter test: that :digit:
1335             # is a subset of :xdigit:, as we know that only 0-9 should match
1336             push @f, $_ if /[[:digit:]]/ and ! /[[:xdigit:]]/;
1337         }
1338         else {
1339             push @xdigit_digits, $_ if /[[:digit:]]/ and /[[:xdigit:]]/;
1340         }
1341     }
1342     if (! $is_utf8_locale) {
1343
1344         # For non-utf8 locales, @xdigit_digits is a list of the characters
1345         # that are both :xdigit: and :digit:.  Because :digit: is stored in
1346         # increasing code point order (unless the tests above failed),
1347         # @xdigit_digits is as well.  There should be exactly 10 or
1348         # 20 of these.
1349         if (@xdigit_digits != 10 && @xdigit_digits != 20) {
1350             @f = @xdigit_digits;
1351         }
1352         else {
1353
1354             # Look for contiguity in the series, adding any wrong ones to @f
1355             my @temp = @xdigit_digits;
1356             while (@temp > 1) {
1357                 push @f, $temp[1] if ($temp[0] != $temp[1] - 1)
1358
1359                                      # Skip this test for the 0th character of
1360                                      # the second block of 10, as it won't be
1361                                      # contiguous with the previous block
1362                                      && (! defined $xdigit_digits[10]
1363                                          || $temp[1] != $xdigit_digits[10]);
1364                 shift @temp;
1365             }
1366         }
1367     }
1368
1369     report_multi_result($Locale, $locales_test_number, \@f);
1370
1371     ++$locales_test_number;
1372     undef @f;
1373     $test_names{$locales_test_number} = 'Verify that [:xdigit:] contains at least A-F, a-f';
1374     for ('A' .. 'F', 'a' .. 'f') {
1375         if ($is_utf8_locale) {
1376             use locale ':not_characters';
1377             push @f, $_  unless /[[:xdigit:]]/;
1378         }
1379         else {
1380             push @f, $_  unless /[[:xdigit:]]/;
1381         }
1382     }
1383     report_multi_result($Locale, $locales_test_number, \@f);
1384
1385     ++$locales_test_number;
1386     undef @f;
1387     $test_names{$locales_test_number} = 'Verify that any additional members of [:xdigit:], are in groups of 6 consecutive code points';
1388     my $previous_ord;
1389     my $count = 0;
1390     for my $chr (map { chr } 0..255) {
1391         next unless $chr =~ /[[:xdigit:]]/;
1392         if ($is_utf8_locale) {
1393             next if $chr =~ /[[:digit:]]/;
1394         }
1395         else {
1396             next if grep { $chr eq $_ } @xdigit_digits;
1397         }
1398         next if $chr =~ /[A-Fa-f]/;
1399         if (defined $previous_ord) {
1400             if ($is_utf8_locale) {
1401                 use locale ':not_characters';
1402                 push @f, $chr if ord $chr != $previous_ord + 1;
1403             }
1404             else {
1405                 push @f, $chr if ord $chr != $previous_ord + 1;
1406             }
1407         }
1408         $count++;
1409         if ($count == 6) {
1410             undef $previous_ord;
1411         }
1412         else {
1413             $previous_ord = ord $chr;
1414         }
1415     }
1416     report_multi_result($Locale, $locales_test_number, \@f);
1417
1418     ++$locales_test_number;
1419     undef @f;
1420     $test_names{$locales_test_number} = 'Verify that [:xdigit:] is a subset of [:graph:]';
1421     for (map { chr } 0..255) {
1422         if ($is_utf8_locale) {
1423             use locale ':not_characters';
1424             push @f, $_ if /[[:xdigit:]]/  and ! /[[:graph:]]/;
1425         }
1426         else {
1427             push @f, $_ if /[[:xdigit:]]/  and ! /[[:graph:]]/;
1428         }
1429     }
1430     report_multi_result($Locale, $locales_test_number, \@f);
1431
1432     # Note that xdigit doesn't have to be a subset of alnum
1433
1434     ++$locales_test_number;
1435     undef @f;
1436     $test_names{$locales_test_number} = 'Verify that [:punct:] is a subset of [:graph:]';
1437     for (map { chr } 0..255) {
1438         if ($is_utf8_locale) {
1439             use locale ':not_characters';
1440             push @f, $_ if /[[:punct:]]/  and ! /[[:graph:]]/;
1441         }
1442         else {
1443             push @f, $_ if /[[:punct:]]/  and ! /[[:graph:]]/;
1444         }
1445     }
1446     report_multi_result($Locale, $locales_test_number, \@f);
1447
1448     ++$locales_test_number;
1449     undef @f;
1450     $test_names{$locales_test_number} = 'Verify that the space character is not in [:graph:]';
1451     if ($is_utf8_locale) {
1452         use locale ':not_characters';
1453         push @f, " " if " " =~ /[[:graph:]]/;
1454     }
1455     else {
1456         push @f, " " if " " =~ /[[:graph:]]/;
1457     }
1458     report_multi_result($Locale, $locales_test_number, \@f);
1459
1460     ++$locales_test_number;
1461     undef @f;
1462     $test_names{$locales_test_number} = 'Verify that [:space:] contains at least [\f\n\r\t\cK ]';
1463     for (' ', "\f", "\n", "\r", "\t", "\cK") {
1464         if ($is_utf8_locale) {
1465             use locale ':not_characters';
1466             push @f, $_  unless /[[:space:]]/;
1467         }
1468         else {
1469             push @f, $_  unless /[[:space:]]/;
1470         }
1471     }
1472     report_multi_result($Locale, $locales_test_number, \@f);
1473
1474     ++$locales_test_number;
1475     undef @f;
1476     $test_names{$locales_test_number} = 'Verify that [:blank:] contains at least [\t ]';
1477     for (' ', "\t") {
1478         if ($is_utf8_locale) {
1479             use locale ':not_characters';
1480             push @f, $_  unless /[[:blank:]]/;
1481         }
1482         else {
1483             push @f, $_  unless /[[:blank:]]/;
1484         }
1485     }
1486     report_multi_result($Locale, $locales_test_number, \@f);
1487
1488     ++$locales_test_number;
1489     undef @f;
1490     $test_names{$locales_test_number} = 'Verify that [:blank:] is a subset of [:space:]';
1491     for (map { chr } 0..255) {
1492         if ($is_utf8_locale) {
1493             use locale ':not_characters';
1494             push @f, $_ if /[[:blank:]]/  and ! /[[:space:]]/;
1495         }
1496         else {
1497             push @f, $_ if /[[:blank:]]/  and ! /[[:space:]]/;
1498         }
1499     }
1500     report_multi_result($Locale, $locales_test_number, \@f);
1501
1502     ++$locales_test_number;
1503     undef @f;
1504     $test_names{$locales_test_number} = 'Verify that [:graph:] is a subset of [:print:]';
1505     for (map { chr } 0..255) {
1506         if ($is_utf8_locale) {
1507             use locale ':not_characters';
1508             push @f, $_ if /[[:graph:]]/  and ! /[[:print:]]/;
1509         }
1510         else {
1511             push @f, $_ if /[[:graph:]]/  and ! /[[:print:]]/;
1512         }
1513     }
1514     report_multi_result($Locale, $locales_test_number, \@f);
1515
1516     ++$locales_test_number;
1517     undef @f;
1518     $test_names{$locales_test_number} = 'Verify that the space character is in [:print:]';
1519     if ($is_utf8_locale) {
1520         use locale ':not_characters';
1521         push @f, " " if " " !~ /[[:print:]]/;
1522     }
1523     else {
1524         push @f, " " if " " !~ /[[:print:]]/;
1525     }
1526     report_multi_result($Locale, $locales_test_number, \@f);
1527
1528     ++$locales_test_number;
1529     undef @f;
1530     $test_names{$locales_test_number} = 'Verify that isn\'t both [:cntrl:] and [:print:]';
1531     for (map { chr } 0..255) {
1532         if ($is_utf8_locale) {
1533             use locale ':not_characters';
1534             push @f, $_ if (/[[:print:]]/ and /[[:cntrl:]]/);
1535         }
1536         else {
1537             push @f, $_ if (/[[:print:]]/ and /[[:cntrl:]]/);
1538         }
1539     }
1540     report_multi_result($Locale, $locales_test_number, \@f);
1541
1542     ++$locales_test_number;
1543     undef @f;
1544     $test_names{$locales_test_number} = 'Verify that isn\'t both [:alpha:] and [:digit:]';
1545     for (map { chr } 0..255) {
1546         if ($is_utf8_locale) {
1547             use locale ':not_characters';
1548             push @f, $_ if /[[:alpha:]]/ and /[[:digit:]]/;
1549         }
1550         else {
1551             push @f, $_ if /[[:alpha:]]/ and /[[:digit:]]/;
1552         }
1553     }
1554     report_multi_result($Locale, $locales_test_number, \@f);
1555
1556     ++$locales_test_number;
1557     undef @f;
1558     $test_names{$locales_test_number} = 'Verify that isn\'t both [:alnum:] and [:punct:]';
1559     for (map { chr } 0..255) {
1560         if ($is_utf8_locale) {
1561             use locale ':not_characters';
1562             push @f, $_ if /[[:alnum:]]/ and /[[:punct:]]/;
1563         }
1564         else {
1565             push @f, $_ if /[[:alnum:]]/ and /[[:punct:]]/;
1566         }
1567     }
1568     report_multi_result($Locale, $locales_test_number, \@f);
1569
1570     ++$locales_test_number;
1571     undef @f;
1572     $test_names{$locales_test_number} = 'Verify that isn\'t both [:xdigit:] and [:punct:]';
1573     for (map { chr } 0..255) {
1574         if ($is_utf8_locale) {
1575             use locale ':not_characters';
1576             push @f, $_ if (/[[:punct:]]/ and /[[:xdigit:]]/);
1577         }
1578         else {
1579             push @f, $_ if (/[[:punct:]]/ and /[[:xdigit:]]/);
1580         }
1581     }
1582     report_multi_result($Locale, $locales_test_number, \@f);
1583
1584     ++$locales_test_number;
1585     undef @f;
1586     $test_names{$locales_test_number} = 'Verify that isn\'t both [:graph:] and [:space:]';
1587     for (map { chr } 0..255) {
1588         if ($is_utf8_locale) {
1589             use locale ':not_characters';
1590             push @f, $_ if (/[[:graph:]]/ and /[[:space:]]/);
1591         }
1592         else {
1593             push @f, $_ if (/[[:graph:]]/ and /[[:space:]]/);
1594         }
1595     }
1596     report_multi_result($Locale, $locales_test_number, \@f);
1597
1598     foreach ($first_casing_test_number..$locales_test_number) {
1599         $problematical_tests{$_} = 1;
1600     }
1601
1602
1603     # Test for read-only scalars' locale vs non-locale comparisons.
1604
1605     {
1606         no locale;
1607         my $ok;
1608         $a = "qwerty";
1609         if ($is_utf8_locale) {
1610             use locale ':not_characters';
1611             $ok = ($a cmp "qwerty") == 0;
1612         }
1613         else {
1614             use locale;
1615             $ok = ($a cmp "qwerty") == 0;
1616         }
1617         report_result($Locale, ++$locales_test_number, $ok);
1618         $test_names{$locales_test_number} = 'Verify that cmp works with a read-only scalar; no- vs locale';
1619     }
1620
1621     {
1622         my ($from, $to, $lesser, $greater,
1623             @test, %test, $test, $yes, $no, $sign);
1624
1625         ++$locales_test_number;
1626         $test_names{$locales_test_number} = 'Verify that "le", "ne", etc work';
1627         $not_necessarily_a_problem_test_number = $locales_test_number;
1628         for (0..9) {
1629             # Select a slice.
1630             $from = int(($_*@{$posixes{'word'}})/10);
1631             $to = $from + int(@{$posixes{'word'}}/10);
1632             $to = $#{$posixes{'word'}} if ($to > $#{$posixes{'word'}});
1633             $lesser  = join('', @{$posixes{'word'}}[$from..$to]);
1634             # Select a slice one character on.
1635             $from++; $to++;
1636             $to = $#{$posixes{'word'}} if ($to > $#{$posixes{'word'}});
1637             $greater = join('', @{$posixes{'word'}}[$from..$to]);
1638             if ($is_utf8_locale) {
1639                 use locale ':not_characters';
1640                 ($yes, $no, $sign) = ($lesser lt $greater
1641                                     ? ("    ", "not ", 1)
1642                                     : ("not ", "    ", -1));
1643             }
1644             else {
1645                 use locale;
1646                 ($yes, $no, $sign) = ($lesser lt $greater
1647                                     ? ("    ", "not ", 1)
1648                                     : ("not ", "    ", -1));
1649             }
1650             # all these tests should FAIL (return 0).  Exact lt or gt cannot
1651             # be tested because in some locales, say, eacute and E may test
1652             # equal.
1653             @test =
1654                 (
1655                     $no.'    ($lesser  le $greater)',  # 1
1656                     'not      ($lesser  ne $greater)', # 2
1657                     '         ($lesser  eq $greater)', # 3
1658                     $yes.'    ($lesser  ge $greater)', # 4
1659                     $yes.'    ($lesser  ge $greater)', # 5
1660                     $yes.'    ($greater le $lesser )', # 7
1661                     'not      ($greater ne $lesser )', # 8
1662                     '         ($greater eq $lesser )', # 9
1663                     $no.'     ($greater ge $lesser )', # 10
1664                     'not (($lesser cmp $greater) == -($sign))' # 11
1665                     );
1666             @test{@test} = 0 x @test;
1667             $test = 0;
1668             for my $ti (@test) {
1669                 if ($is_utf8_locale) {
1670                     use locale ':not_characters';
1671                     $test{$ti} = eval $ti;
1672                 }
1673                 else {
1674                     # Already in 'use locale';
1675                     $test{$ti} = eval $ti;
1676                 }
1677                 $test ||= $test{$ti}
1678             }
1679             report_result($Locale, $locales_test_number, $test == 0);
1680             if ($test) {
1681                 debug "lesser  = '$lesser'\n";
1682                 debug "greater = '$greater'\n";
1683                 debug "lesser cmp greater = ",
1684                         $lesser cmp $greater, "\n";
1685                 debug "greater cmp lesser = ",
1686                         $greater cmp $lesser, "\n";
1687                 debug "(greater) from = $from, to = $to\n";
1688                 for my $ti (@test) {
1689                     debugf("# %-40s %-4s", $ti,
1690                             $test{$ti} ? 'FAIL' : 'ok');
1691                     if ($ti =~ /\(\.*(\$.+ +cmp +\$[^\)]+)\.*\)/) {
1692                         debugf("(%s == %4d)", $1, eval $1);
1693                     }
1694                     debugf("\n#");
1695                 }
1696
1697                 last;
1698             }
1699         }
1700     }
1701
1702     my $ok1;
1703     my $ok2;
1704     my $ok3;
1705     my $ok4;
1706     my $ok5;
1707     my $ok6;
1708     my $ok7;
1709     my $ok8;
1710     my $ok9;
1711     my $ok10;
1712     my $ok11;
1713     my $ok12;
1714     my $ok13;
1715     my $ok14;
1716     my $ok14_5;
1717     my $ok15;
1718     my $ok16;
1719     my $ok17;
1720     my $ok18;
1721     my $ok19;
1722     my $ok20;
1723     my $ok21;
1724
1725     my $c;
1726     my $d;
1727     my $e;
1728     my $f;
1729     my $g;
1730     my $h;
1731     my $i;
1732     my $j;
1733
1734     if (! $is_utf8_locale) {
1735         use locale;
1736
1737         my ($x, $y) = (1.23, 1.23);
1738
1739         $a = "$x";
1740         printf ''; # printf used to reset locale to "C"
1741         $b = "$y";
1742         $ok1 = $a eq $b;
1743
1744         $c = "$x";
1745         my $z = sprintf ''; # sprintf used to reset locale to "C"
1746         $d = "$y";
1747         $ok2 = $c eq $d;
1748         {
1749
1750             use warnings;
1751             my $w = 0;
1752             local $SIG{__WARN__} =
1753                 sub {
1754                     print "# @_\n";
1755                     $w++;
1756                 };
1757
1758             # The == (among other ops) used to warn for locales
1759             # that had something else than "." as the radix character.
1760
1761             $ok3 = $c == 1.23;
1762             $ok4 = $c == $x;
1763             $ok5 = $c == $d;
1764             {
1765                 no locale;
1766
1767                 $e = "$x";
1768
1769                 $ok6 = $e == 1.23;
1770                 $ok7 = $e == $x;
1771                 $ok8 = $e == $c;
1772             }
1773
1774             $f = "1.23";
1775             $g = 2.34;
1776             $h = 1.5;
1777             $i = 1.25;
1778             $j = "$h:$i";
1779
1780             $ok9 = $f == 1.23;
1781             $ok10 = $f == $x;
1782             $ok11 = $f == $c;
1783             $ok12 = abs(($f + $g) - 3.57) < 0.01;
1784             $ok13 = $w == 0;
1785             $ok14 = $ok14_5 = $ok15 = $ok16 = 1;  # Skip for non-utf8 locales
1786         }
1787         {
1788             no locale;
1789             $ok17 = "1.5:1.25" eq sprintf("%g:%g", $h, $i);
1790         }
1791         $ok18 = $j eq sprintf("%g:%g", $h, $i);
1792     }
1793     else {
1794         use locale ':not_characters';
1795
1796         my ($x, $y) = (1.23, 1.23);
1797         $a = "$x";
1798         printf ''; # printf used to reset locale to "C"
1799         $b = "$y";
1800         $ok1 = $a eq $b;
1801
1802         $c = "$x";
1803         my $z = sprintf ''; # sprintf used to reset locale to "C"
1804         $d = "$y";
1805         $ok2 = $c eq $d;
1806         {
1807             use warnings;
1808             my $w = 0;
1809             local $SIG{__WARN__} =
1810                 sub {
1811                     print "# @_\n";
1812                     $w++;
1813                 };
1814             $ok3 = $c == 1.23;
1815             $ok4 = $c == $x;
1816             $ok5 = $c == $d;
1817             {
1818                 no locale;
1819                 $e = "$x";
1820
1821                 $ok6 = $e == 1.23;
1822                 $ok7 = $e == $x;
1823                 $ok8 = $e == $c;
1824             }
1825
1826             $f = "1.23";
1827             $g = 2.34;
1828             $h = 1.5;
1829             $i = 1.25;
1830             $j = "$h:$i";
1831
1832             $ok9 = $f == 1.23;
1833             $ok10 = $f == $x;
1834             $ok11 = $f == $c;
1835             $ok12 = abs(($f + $g) - 3.57) < 0.01;
1836             $ok13 = $w == 0;
1837
1838             # Look for non-ASCII error messages, and verify that the first
1839             # such is in UTF-8 (the others almost certainly will be like the
1840             # first).  This is only done if the current locale has LC_MESSAGES
1841             $ok14 = 1;
1842             $ok14_5 = 1;
1843             if (setlocale(&POSIX::LC_MESSAGES, $Locale)) {
1844                 foreach my $err (keys %!) {
1845                     use Errno;
1846                     $! = eval "&Errno::$err";   # Convert to strerror() output
1847                     my $strerror = "$!";
1848                     if ("$strerror" =~ /\P{ASCII}/) {
1849                         $ok14 = utf8::is_utf8($strerror);
1850                         no locale;
1851                         $ok14_5 = "$!" !~ /\P{ASCII}/;
1852                         last;
1853                     }
1854                 }
1855             }
1856
1857             # Similarly, we verify that a non-ASCII radix is in UTF-8.  This
1858             # also catches if there is a disparity between sprintf and
1859             # stringification.
1860
1861             my $string_g = "$g";
1862             my $sprintf_g = sprintf("%g", $g);
1863
1864             $ok15 = $string_g =~ / ^ \p{ASCII}+ $ /x || utf8::is_utf8($string_g);
1865             $ok16 = $sprintf_g eq $string_g;
1866         }
1867         {
1868             no locale;
1869             $ok17 = "1.5:1.25" eq sprintf("%g:%g", $h, $i);
1870         }
1871         $ok18 = $j eq sprintf("%g:%g", $h, $i);
1872     }
1873
1874     $ok19 = $ok20 = 1;
1875     if (setlocale(&POSIX::LC_TIME, $Locale)) { # These tests aren't affected by
1876                                                # :not_characters
1877         my @times = CORE::localtime();
1878
1879         use locale;
1880         $ok19 = POSIX::strftime("%p", @times) ne "%p"; # [perl #119425]
1881         my $date = POSIX::strftime("'%A'  '%B'  '%Z'  '%p'", @times);
1882         debug("'Day' 'Month' 'TZ' 'am/pm' = ", disp_str($date));
1883
1884         # If there is any non-ascii, it better be UTF-8 in a UTF-8 locale, and
1885         # not UTF-8 if the locale isn't UTF-8.
1886         $ok20 = $date =~ / ^ \p{ASCII}+ $ /x
1887                 || $is_utf8_locale == utf8::is_utf8($date);
1888     }
1889
1890     $ok21 = 1;
1891     foreach my $err (keys %!) {
1892         no locale;
1893         use Errno;
1894         $! = eval "&Errno::$err";   # Convert to strerror() output
1895         my $strerror = "$!";
1896         if ("$strerror" =~ /\P{ASCII}/) {
1897             $ok21 = 0;
1898             last;
1899         }
1900     }
1901
1902     report_result($Locale, ++$locales_test_number, $ok1);
1903     $test_names{$locales_test_number} = 'Verify that an intervening printf doesn\'t change assignment results';
1904     my $first_a_test = $locales_test_number;
1905
1906     debug "$first_a_test..$locales_test_number: \$a = $a, \$b = $b, Locale = $Locale\n";
1907
1908     report_result($Locale, ++$locales_test_number, $ok2);
1909     $test_names{$locales_test_number} = 'Verify that an intervening sprintf doesn\'t change assignment results';
1910
1911     my $first_c_test = $locales_test_number;
1912
1913     $test_names{++$locales_test_number} = 'Verify that a different locale radix works when doing "==" with a constant';
1914     if ($Config{usequadmath}) {
1915         print "# Skip: no locale radix with usequadmath ($test_names{$locales_test_number})\n";
1916         report_result($Locale, $locales_test_number, 1);
1917     } else {
1918         report_result($Locale, $locales_test_number, $ok3);
1919         $problematical_tests{$locales_test_number} = 1;
1920     }
1921
1922     $test_names{++$locales_test_number} = 'Verify that a different locale radix works when doing "==" with a scalar';
1923     if ($Config{usequadmath}) {
1924         print "# Skip: no locale radix with usequadmath ($test_names{$locales_test_number})\n";
1925         report_result($Locale, $locales_test_number, 1);
1926     } else {
1927         report_result($Locale, $locales_test_number, $ok4);
1928         $problematical_tests{$locales_test_number} = 1;
1929     }
1930
1931     report_result($Locale, ++$locales_test_number, $ok5);
1932     $test_names{$locales_test_number} = 'Verify that a different locale radix works when doing "==" with a scalar and an intervening sprintf';
1933     $problematical_tests{$locales_test_number} = 1;
1934
1935     debug "$first_c_test..$locales_test_number: \$c = $c, \$d = $d, Locale = $Locale\n";
1936
1937     report_result($Locale, ++$locales_test_number, $ok6);
1938     $test_names{$locales_test_number} = 'Verify that can assign stringified under inner no-locale block';
1939     my $first_e_test = $locales_test_number;
1940
1941     report_result($Locale, ++$locales_test_number, $ok7);
1942     $test_names{$locales_test_number} = 'Verify that "==" with a scalar still works in inner no locale';
1943
1944     $test_names{++$locales_test_number} = 'Verify that "==" with a scalar and an intervening sprintf still works in inner no locale';
1945     if ($Config{usequadmath}) {
1946         print "# Skip: no locale radix with usequadmath ($test_names{$locales_test_number})\n";
1947         report_result($Locale, $locales_test_number, 1);
1948     } else {
1949         report_result($Locale, $locales_test_number, $ok8);
1950         $problematical_tests{$locales_test_number} = 1;
1951     }
1952
1953     debug "$first_e_test..$locales_test_number: \$e = $e, no locale\n";
1954
1955     report_result($Locale, ++$locales_test_number, $ok9);
1956     $test_names{$locales_test_number} = 'Verify that after a no-locale block, a different locale radix still works when doing "==" with a constant';
1957     $problematical_tests{$locales_test_number} = 1;
1958     my $first_f_test = $locales_test_number;
1959
1960     report_result($Locale, ++$locales_test_number, $ok10);
1961     $test_names{$locales_test_number} = 'Verify that after a no-locale block, a different locale radix still works when doing "==" with a scalar';
1962     $problematical_tests{$locales_test_number} = 1;
1963
1964     $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';
1965     if ($Config{usequadmath}) {
1966         print "# Skip: no locale radix with usequadmath ($test_names{$locales_test_number})\n";
1967         report_result($Locale, $locales_test_number, 1);
1968     } else {
1969         report_result($Locale, $locales_test_number, $ok11);
1970         $problematical_tests{$locales_test_number} = 1;
1971     }
1972
1973     report_result($Locale, ++$locales_test_number, $ok12);
1974     $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';
1975     $problematical_tests{$locales_test_number} = 1;
1976
1977     report_result($Locale, ++$locales_test_number, $ok13);
1978     $test_names{$locales_test_number} = 'Verify that don\'t get warning under "==" even if radix is not a dot';
1979     $problematical_tests{$locales_test_number} = 1;
1980
1981     report_result($Locale, ++$locales_test_number, $ok14);
1982     $test_names{$locales_test_number} = 'Verify that non-ASCII UTF-8 error messages are in UTF-8';
1983
1984     report_result($Locale, ++$locales_test_number, $ok14_5);
1985     $test_names{$locales_test_number} = '... and are ASCII outside "use locale"';
1986
1987     report_result($Locale, ++$locales_test_number, $ok15);
1988     $test_names{$locales_test_number} = 'Verify that a number with a UTF-8 radix has a UTF-8 stringification';
1989
1990     report_result($Locale, ++$locales_test_number, $ok16);
1991     $test_names{$locales_test_number} = 'Verify that a sprintf of a number with a UTF-8 radix yields UTF-8';
1992
1993     report_result($Locale, ++$locales_test_number, $ok17);
1994     $test_names{$locales_test_number} = 'Verify that a sprintf of a number outside locale scope uses a dot radix';
1995
1996     report_result($Locale, ++$locales_test_number, $ok18);
1997     $test_names{$locales_test_number} = 'Verify that a sprintf of a number back within locale scope uses locale radix';
1998
1999     report_result($Locale, ++$locales_test_number, $ok19);
2000     $test_names{$locales_test_number} = 'Verify that strftime doesn\'t return "%p" in locales where %p is empty';
2001
2002     report_result($Locale, ++$locales_test_number, $ok20);
2003     $test_names{$locales_test_number} = 'Verify that strftime returns date with UTF-8 flag appropriately set';
2004     $problematical_tests{$locales_test_number} = 1;   # This is broken in
2005                                                       # OS X 10.9.3
2006
2007     report_result($Locale, ++$locales_test_number, $ok21);
2008     $test_names{$locales_test_number} = '"$!" is ASCII only outside of locale scope';
2009
2010     debug "$first_f_test..$locales_test_number: \$f = $f, \$g = $g, back to locale = $Locale\n";
2011
2012     # Does taking lc separately differ from taking
2013     # the lc "in-line"?  (This was the bug 19990704.002, change #3568.)
2014     # The bug was in the caching of the 'o'-magic.
2015     if (! $is_utf8_locale) {
2016         use locale;
2017
2018         sub lcA {
2019             my $lc0 = lc $_[0];
2020             my $lc1 = lc $_[1];
2021             return $lc0 cmp $lc1;
2022         }
2023
2024         sub lcB {
2025             return lc($_[0]) cmp lc($_[1]);
2026         }
2027
2028         my $x = "ab";
2029         my $y = "aa";
2030         my $z = "AB";
2031
2032         report_result($Locale, ++$locales_test_number,
2033                     lcA($x, $y) == 1 && lcB($x, $y) == 1 ||
2034                     lcA($x, $z) == 0 && lcB($x, $z) == 0);
2035     }
2036     else {
2037         use locale ':not_characters';
2038
2039         sub lcC {
2040             my $lc0 = lc $_[0];
2041             my $lc1 = lc $_[1];
2042             return $lc0 cmp $lc1;
2043         }
2044
2045         sub lcD {
2046             return lc($_[0]) cmp lc($_[1]);
2047         }
2048
2049         my $x = "ab";
2050         my $y = "aa";
2051         my $z = "AB";
2052
2053         report_result($Locale, ++$locales_test_number,
2054                     lcC($x, $y) == 1 && lcD($x, $y) == 1 ||
2055                     lcC($x, $z) == 0 && lcD($x, $z) == 0);
2056     }
2057     $test_names{$locales_test_number} = 'Verify "lc(foo) cmp lc(bar)" is the same as using intermediaries for the cmp';
2058
2059     # Does lc of an UPPER (if different from the UPPER) match
2060     # case-insensitively the UPPER, and does the UPPER match
2061     # case-insensitively the lc of the UPPER.  And vice versa.
2062     {
2063         use locale;
2064         no utf8;
2065         my $re = qr/[\[\(\{\*\+\?\|\^\$\\]/;
2066
2067         my @f = ();
2068         ++$locales_test_number;
2069         $test_names{$locales_test_number} = 'Verify case insensitive matching works';
2070         foreach my $x (sort { ord $a <=> ord $b } keys %UPPER) {
2071             if (! $is_utf8_locale) {
2072                 my $y = lc $x;
2073                 next unless uc $y eq $x;
2074                 debug_more( "UPPER=", disp_chars(($x)),
2075                             "; lc=", disp_chars(($y)), "; ",
2076                             "; fc=", disp_chars((fc $x)), "; ",
2077                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2078                             $x =~ /\Q$y/i ? 1 : 0,
2079                             "; ",
2080                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2081                             $y =~ /\Q$x/i ? 1 : 0,
2082                             "\n");
2083                 #
2084                 # If $x and $y contain regular expression characters
2085                 # AND THEY lowercase (/i) to regular expression characters,
2086                 # regcomp() will be mightily confused.  No, the \Q doesn't
2087                 # help here (maybe regex engine internal lowercasing
2088                 # is done after the \Q?)  An example of this happening is
2089                 # the bg_BG (Bulgarian) locale under EBCDIC (OS/390 USS):
2090                 # the chr(173) (the "[") is the lowercase of the chr(235).
2091                 #
2092                 # Similarly losing EBCDIC locales include cs_cz, cs_CZ,
2093                 # el_gr, el_GR, en_us.IBM-037 (!), en_US.IBM-037 (!),
2094                 # et_ee, et_EE, hr_hr, hr_HR, hu_hu, hu_HU, lt_LT,
2095                 # mk_mk, mk_MK, nl_nl.IBM-037, nl_NL.IBM-037,
2096                 # pl_pl, pl_PL, ro_ro, ro_RO, ru_ru, ru_RU,
2097                 # sk_sk, sk_SK, sl_si, sl_SI, tr_tr, tr_TR.
2098                 #
2099                 # Similar things can happen even under (bastardised)
2100                 # non-EBCDIC locales: in many European countries before the
2101                 # advent of ISO 8859-x nationally customised versions of
2102                 # ISO 646 were devised, reusing certain punctuation
2103                 # characters for modified characters needed by the
2104                 # country/language.  For example, the "|" might have
2105                 # stood for U+00F6 or LATIN SMALL LETTER O WITH DIAERESIS.
2106                 #
2107                 if ($x =~ $re || $y =~ $re) {
2108                     print "# Regex characters in '$x' or '$y', skipping test $locales_test_number for locale '$Locale'\n";
2109                     next;
2110                 }
2111                 push @f, $x unless $x =~ /\Q$y/i && $y =~ /\Q$x/i;
2112
2113                 # fc is not a locale concept, so Perl uses lc for it.
2114                 push @f, $x unless lc $x eq fc $x;
2115             }
2116             else {
2117                 use locale ':not_characters';
2118                 my $y = lc $x;
2119                 next unless uc $y eq $x;
2120                 debug_more( "UPPER=", disp_chars(($x)),
2121                             "; lc=", disp_chars(($y)), "; ",
2122                             "; fc=", disp_chars((fc $x)), "; ",
2123                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2124                             $x =~ /\Q$y/i ? 1 : 0,
2125                             "; ",
2126                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2127                             $y =~ /\Q$x/i ? 1 : 0,
2128                             "\n");
2129
2130                 push @f, $x unless $x =~ /\Q$y/i && $y =~ /\Q$x/i;
2131
2132                 # The places where Unicode's lc is different from fc are
2133                 # skipped here by virtue of the 'next unless uc...' line above
2134                 push @f, $x unless lc $x eq fc $x;
2135             }
2136         }
2137
2138         foreach my $x (sort { ord $a <=> ord $b } keys %lower) {
2139             if (! $is_utf8_locale) {
2140                 my $y = uc $x;
2141                 next unless lc $y eq $x;
2142                 debug_more( "lower=", disp_chars(($x)),
2143                             "; uc=", disp_chars(($y)), "; ",
2144                             "; fc=", disp_chars((fc $x)), "; ",
2145                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2146                             $x =~ /\Q$y/i ? 1 : 0,
2147                             "; ",
2148                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2149                             $y =~ /\Q$x/i ? 1 : 0,
2150                             "\n");
2151                 if ($x =~ $re || $y =~ $re) { # See above.
2152                     print "# Regex characters in '$x' or '$y', skipping test $locales_test_number for locale '$Locale'\n";
2153                     next;
2154                 }
2155                 push @f, $x unless $x =~ /\Q$y/i && $y =~ /\Q$x/i;
2156
2157                 push @f, $x unless lc $x eq fc $x;
2158             }
2159             else {
2160                 use locale ':not_characters';
2161                 my $y = uc $x;
2162                 next unless lc $y eq $x;
2163                 debug_more( "lower=", disp_chars(($x)),
2164                             "; uc=", disp_chars(($y)), "; ",
2165                             "; fc=", disp_chars((fc $x)), "; ",
2166                             disp_chars(($x)), "=~/", disp_chars(($y)), "/i=",
2167                             $x =~ /\Q$y/i ? 1 : 0,
2168                             "; ",
2169                             disp_chars(($y)), "=~/", disp_chars(($x)), "/i=",
2170                             $y =~ /\Q$x/i ? 1 : 0,
2171                             "\n");
2172                 push @f, $x unless $x =~ /\Q$y/i && $y =~ /\Q$x/i;
2173
2174                 push @f, $x unless lc $x eq fc $x;
2175             }
2176         }
2177         report_multi_result($Locale, $locales_test_number, \@f);
2178         $problematical_tests{$locales_test_number} = 1;
2179     }
2180
2181     # [perl #109318]
2182     {
2183         my @f = ();
2184         ++$locales_test_number;
2185         $test_names{$locales_test_number} = 'Verify atof with locale radix and negative exponent';
2186         $problematical_tests{$locales_test_number} = 1;
2187
2188         my $radix = POSIX::localeconv()->{decimal_point};
2189         my @nums = (
2190              "3.14e+9",  "3${radix}14e+9",  "3.14e-9",  "3${radix}14e-9",
2191             "-3.14e+9", "-3${radix}14e+9", "-3.14e-9", "-3${radix}14e-9",
2192         );
2193
2194         if (! $is_utf8_locale) {
2195             use locale;
2196             for my $num (@nums) {
2197                 push @f, $num
2198                     unless sprintf("%g", $num) =~ /3.+14/;
2199             }
2200         }
2201         else {
2202             use locale ':not_characters';
2203             for my $num (@nums) {
2204                 push @f, $num
2205                     unless sprintf("%g", $num) =~ /3.+14/;
2206             }
2207         }
2208
2209         if ($Config{usequadmath}) {
2210             print "# Skip: no locale radix with usequadmath ($Locale)\n";
2211             report_result($Locale, $locales_test_number, 1);
2212         } else {
2213             report_result($Locale, $locales_test_number, @f == 0);
2214             if (@f) {
2215                 print "# failed $locales_test_number locale '$Locale' numbers @f\n"
2216             }
2217         }
2218     }
2219 }
2220
2221 my $final_locales_test_number = $locales_test_number;
2222
2223 # Recount the errors.
2224
2225 foreach $test_num ($first_locales_test_number..$final_locales_test_number) {
2226     if (%setlocale_failed) {
2227         print "not ";
2228     }
2229     elsif ($Problem{$test_num} || !defined $Okay{$test_num} || !@{$Okay{$test_num}}) {
2230         if (defined $not_necessarily_a_problem_test_number
2231             && $test_num == $not_necessarily_a_problem_test_number)
2232         {
2233             print "# The failure of test $not_necessarily_a_problem_test_number is not necessarily fatal.\n";
2234             print "# It usually indicates a problem in the environment,\n";
2235             print "# not in Perl itself.\n";
2236         }
2237         if ($Okay{$test_num} && grep { $_ == $test_num } keys %problematical_tests) {
2238             no warnings 'experimental::autoderef';
2239             # Round to nearest .1%
2240             my $percent_fail = (int(.5 + (1000 * scalar(keys $Problem{$test_num})
2241                                           / scalar(@Locale))))
2242                                / 10;
2243             if ($percent_fail < $acceptable_failure_percentage) {
2244                 if (! $debug) {
2245                     $test_names{$test_num} .= 'TODO';
2246                     print "# ", 100 - $percent_fail, "% of locales pass the following test, so it is likely that the failures\n";
2247                     print "# are errors in the locale definitions.  The test is marked TODO, as the\n";
2248                     print "# problem is not likely to be Perl's\n";
2249                 }
2250             }
2251             if ($debug) {
2252                 print "# $percent_fail% of locales (",
2253                       scalar(keys $Problem{$test_num}),
2254                       " of ",
2255                       scalar(@Locale),
2256                       ") fail the above test (TODO cut-off is ",
2257                       $acceptable_failure_percentage,
2258                       "%)\n";
2259             }
2260         }
2261         print "#\n";
2262         if ($debug) {
2263             print "# The code points that had this failure are given above.  Look for lines\n";
2264             print "# that match 'failed $test_num'\n";
2265         }
2266         else {
2267             print "# For more details, rerun, with environment variable PERL_DEBUG_FULL_TEST=1.\n";
2268             print "# Then look at that output for lines that match 'failed $test_num'\n";
2269         }
2270         print "not ";
2271     }
2272     print "ok $test_num";
2273     if (defined $test_names{$test_num}) {
2274         # If TODO is in the test name, make it thus
2275         my $todo = $test_names{$test_num} =~ s/TODO\s*//;
2276         print " $test_names{$test_num}";
2277         print " # TODO" if $todo;
2278     }
2279     print "\n";
2280 }
2281
2282 $test_num = $final_locales_test_number;
2283
2284 unless ( $^O =~ m!^(dragonfly|openbsd|bitrig|mirbsd)$! ) {
2285     # perl #115808
2286     use warnings;
2287     my $warned = 0;
2288     local $SIG{__WARN__} = sub {
2289         $warned = $_[0] =~ /uninitialized/;
2290     };
2291     my $z = "y" . setlocale(&POSIX::LC_ALL, "xyzzy");
2292     ok($warned, "variable set to setlocale(BAD LOCALE) is considered uninitialized");
2293 }
2294
2295 # Test that tainting and case changing works on utf8 strings.  These tests are
2296 # placed last to avoid disturbing the hard-coded test numbers that existed at
2297 # the time these were added above this in this file.
2298 # This also tests that locale overrides unicode_strings in the same scope for
2299 # non-utf8 strings.
2300 setlocale(&POSIX::LC_ALL, "C");
2301 {
2302     use locale;
2303     use feature 'unicode_strings';
2304
2305     foreach my $function ("uc", "ucfirst", "lc", "lcfirst", "fc") {
2306         my @list;   # List of code points to test for $function
2307
2308         # Used to calculate the changed case for ASCII characters by using the
2309         # ord, instead of using one of the functions under test.
2310         my $ascii_case_change_delta;
2311         my $above_latin1_case_change_delta; # Same for the specific ords > 255
2312                                             # that we use
2313
2314         # We test an ASCII character, which should change case;
2315         # a Latin1 character, which shouldn't change case under this C locale,
2316         # an above-Latin1 character that when the case is changed would cross
2317         #   the 255/256 boundary, so doesn't change case
2318         #   (the \x{149} is one of these, but changes into 2 characters, the
2319         #   first one of which doesn't cross the boundary.
2320         # the final one in each list is an above-Latin1 character whose case
2321         #   does change.  The code below uses its position in its list as a
2322         #   marker to indicate that it, unlike the other code points above
2323         #   ASCII, has a successful case change
2324         #
2325         # All casing operations under locale (but not :not_characters) should
2326         # taint
2327         if ($function =~ /^u/) {
2328             @list = ("", "a", "\xe0", "\xff", "\x{fb00}", "\x{149}", "\x{101}");
2329             $ascii_case_change_delta = -32;
2330             $above_latin1_case_change_delta = -1;
2331         }
2332         else {
2333             @list = ("", "A", "\xC0", "\x{17F}", "\x{100}");
2334             $ascii_case_change_delta = +32;
2335             $above_latin1_case_change_delta = +1;
2336         }
2337         foreach my $is_utf8_locale (0 .. 1) {
2338             foreach my $j (0 .. $#list) {
2339                 my $char = $list[$j];
2340
2341                 for my $encoded_in_utf8 (0 .. 1) {
2342                     my $should_be;
2343                     my $changed;
2344                     if (! $is_utf8_locale) {
2345                         $should_be = ($j == $#list)
2346                             ? chr(ord($char) + $above_latin1_case_change_delta)
2347                             : (length $char == 0 || ord($char) > 127)
2348                             ? $char
2349                             : chr(ord($char) + $ascii_case_change_delta);
2350
2351                         # This monstrosity is in order to avoid using an eval,
2352                         # which might perturb the results
2353                         $changed = ($function eq "uc")
2354                                     ? uc($char)
2355                                     : ($function eq "ucfirst")
2356                                       ? ucfirst($char)
2357                                       : ($function eq "lc")
2358                                         ? lc($char)
2359                                         : ($function eq "lcfirst")
2360                                           ? lcfirst($char)
2361                                           : ($function eq "fc")
2362                                             ? fc($char)
2363                                             : die("Unexpected function \"$function\"");
2364                     }
2365                     else {
2366                         {
2367                             no locale;
2368
2369                             # For utf8-locales the case changing functions
2370                             # should work just like they do outside of locale.
2371                             # Can use eval here because not testing it when
2372                             # not in locale.
2373                             $should_be = eval "$function('$char')";
2374                             die "Unexpected eval error $@ from 'eval \"$function('$char')\"'" if  $@;
2375
2376                         }
2377                         use locale ':not_characters';
2378                         $changed = ($function eq "uc")
2379                                     ? uc($char)
2380                                     : ($function eq "ucfirst")
2381                                       ? ucfirst($char)
2382                                       : ($function eq "lc")
2383                                         ? lc($char)
2384                                         : ($function eq "lcfirst")
2385                                           ? lcfirst($char)
2386                                           : ($function eq "fc")
2387                                             ? fc($char)
2388                                             : die("Unexpected function \"$function\"");
2389                     }
2390                     ok($changed eq $should_be,
2391                         "$function(\"$char\") in C locale "
2392                         . (($is_utf8_locale)
2393                             ? "(use locale ':not_characters'"
2394                             : "(use locale")
2395                         . (($encoded_in_utf8)
2396                             ? "; encoded in utf8)"
2397                             : "; not encoded in utf8)")
2398                         . " should be \"$should_be\", got \"$changed\"");
2399
2400                     # Tainting shouldn't happen for use locale :not_character
2401                     # (a utf8 locale)
2402                     (! $is_utf8_locale)
2403                     ? check_taint($changed)
2404                     : check_taint_not($changed);
2405
2406                     # Use UTF-8 next time through the loop
2407                     utf8::upgrade($char);
2408                 }
2409             }
2410         }
2411     }
2412 }
2413
2414 # Give final advice.
2415
2416 my $didwarn = 0;
2417
2418 foreach ($first_locales_test_number..$final_locales_test_number) {
2419     if ($Problem{$_}) {
2420         my @f = sort keys %{ $Problem{$_} };
2421         my $f = join(" ", @f);
2422         $f =~ s/(.{50,60}) /$1\n#\t/g;
2423         print
2424             "#\n",
2425             "# The locale ", (@f == 1 ? "definition" : "definitions"), "\n#\n",
2426             "#\t", $f, "\n#\n",
2427             "# on your system may have errors because the locale test $_\n",
2428             "# \"$test_names{$_}\"\n",
2429             "# failed in ", (@f == 1 ? "that locale" : "those locales"),
2430             ".\n";
2431         print <<EOW;
2432 #
2433 # If your users are not using these locales you are safe for the moment,
2434 # but please report this failure first to perlbug\@perl.com using the
2435 # perlbug script (as described in the INSTALL file) so that the exact
2436 # details of the failures can be sorted out first and then your operating
2437 # system supplier can be alerted about these anomalies.
2438 #
2439 EOW
2440         $didwarn = 1;
2441     }
2442 }
2443
2444 # Tell which locales were okay and which were not.
2445
2446 if ($didwarn) {
2447     my (@s, @F);
2448
2449     foreach my $l (@Locale) {
2450         my $p = 0;
2451         if ($setlocale_failed{$l}) {
2452             $p++;
2453         }
2454         else {
2455             foreach my $t
2456                         ($first_locales_test_number..$final_locales_test_number)
2457             {
2458                 $p++ if $Problem{$t}{$l};
2459             }
2460         }
2461         push @s, $l if $p == 0;
2462         push @F, $l unless $p == 0;
2463     }
2464
2465     if (@s) {
2466         my $s = join(" ", @s);
2467         $s =~ s/(.{50,60}) /$1\n#\t/g;
2468
2469         print
2470             "# The following locales\n#\n",
2471             "#\t", $s, "\n#\n",
2472             "# tested okay.\n#\n",
2473     } else {
2474         print "# None of your locales were fully okay.\n";
2475     }
2476
2477     if (@F) {
2478         my $F = join(" ", @F);
2479         $F =~ s/(.{50,60}) /$1\n#\t/g;
2480
2481         my $details = "";
2482         unless ($debug) {
2483             $details = "# For more details, rerun, with environment variable PERL_DEBUG_FULL_TEST=1.\n";
2484         }
2485         elsif ($debug == 1) {
2486             $details = "# For even more details, rerun, with environment variable PERL_DEBUG_FULL_TEST=2.\n";
2487         }
2488
2489         print
2490           "# The following locales\n#\n",
2491           "#\t", $F, "\n#\n",
2492           "# had problems.\n#\n",
2493           $details;
2494     } else {
2495         print "# None of your locales were broken.\n";
2496     }
2497 }
2498
2499 print "1..$test_num\n";
2500
2501 # eof