File Coverage

lib/mb.pm
Criterion Covered Total %
statement 1745 2271 76.8
branch 1596 2096 76.1
condition 145 253 57.3
subroutine 129 137 94.1
pod 2 71 2.8
total 3617 4828 74.9


line stmt bran cond sub pod time code
1             package mb;
2             '有朋自遠方来不亦楽乎'=~/^\xE6\x9C\x89/ or die "Perl script '@{[__FILE__]}' must be UTF-8 encoding.\n";
3             # You are welcome! MOJIBAKE-san, you are our friend forever!!
4             ######################################################################
5             #
6             # mb - Can easy script in Big5, Big5-HKSCS, GBK, Sjis(also CP932), UHC, UTF-8, ...
7             #
8             # https://metacpan.org/release/mb
9             #
10             # Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2026 INABA Hitoshi in a CPAN
11             ######################################################################
12              
13 173     167   4851036 use 5.00503; # Universal Consensus 1998 for primetools
  167         546  
14             # use 5.008001; # Lancaster Consensus 2013 for toolchains
15              
16             $VERSION = '0.65';
17             $VERSION = $VERSION;
18              
19             # internal use
20             $mb::last_s_passed = 0; # last s/// status (1 if s/// passed)
21              
22             # filehandle sequence counter for _open_a/_open_r/_open_w
23             $mb::_fh_seq = 0;
24              
25 173 100   167   4344 BEGIN { pop @INC if $INC[-1] eq '.' } # CVE-2016-1238: Important unsafe module load path flaw
26 173     163   1143 use strict;
  173         516  
  173         10607  
27 169 50 33 163   3602 BEGIN { if ($] < 5.006 && !defined(&warnings::import)) { $INC{'warnings.pm'} = 'stub'; eval 'package warnings; sub import {}' } } use warnings; local $^W=1;
  10     162   53  
  10         129  
  169         655  
  169         259  
  169         90893  
28              
29             # set OSNAME
30             my $OSNAME = $^O;
31              
32             # encoding name of operating system
33             my $system_encoding = undef;
34              
35             # encoding name of MBCS script
36             my $script_encoding = undef;
37              
38             # over US-ASCII
39             my $over_ascii = undef;
40              
41             # supports qr/./ in MBCS script
42             my $x = undef;
43              
44             # supports [\b] \d \h \s \v \w in MBCS script
45             my $bare_backspace = '\x08';
46             my $bare_d = '0123456789';
47             my $bare_h = '\x09\x20';
48             my $bare_s = '\t\n\f\r\x20';
49             my $bare_v = '\x0A\x0B\x0C\x0D';
50             my $bare_w = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';
51              
52             # as many escapes as possible to avoid perl's feature
53             my $escapee_in_qq_like = join('', map {"\\$_"} grep( ! /[A-Za-z0-9_]/, map { CORE::chr } 0x21..0x7E));
54              
55             # as less escapes as possible to avoid over-escaping
56             my $escapee_in_q__like = '\\' . "\x5C";
57              
58             # generic linebreak
59             my $R = '(?>\\r\\n|\\r|\\n)';
60              
61             # check running perl interpreter
62             if ($^X =~ /jperl/i) {
63             die "script '@{[__FILE__]}' can run on only perl, not JPerl\n";
64             }
65              
66             # this file is used as command on command line
67             if ($0 eq __FILE__) {
68              
69             # register this modulino in %INC so that a "use mb;" / "require mb" inside an
70             # in-process transpiled script (see sub main) is satisfied by the already
71             # loaded modulino instead of reloading mb.pm (which would emit a flood of
72             # "Subroutine ... redefined" warnings). This mirrors the child-interpreter
73             # path, where -Mmb=ver,enc already populates $INC{'mb.pm'}.
74             $INC{'mb.pm'} = __FILE__ if not exists $INC{'mb.pm'};
75              
76             main();
77             }
78              
79             ######################################################################
80             # main program
81             ######################################################################
82              
83             #---------------------------------------------------------------------
84             # running as module, runtime routines
85             sub import {
86 144     144   3618 my $self = shift @_;
87              
88             # confirm version
89 144 50 66     1807 if (defined($_[0]) and ($_[0] =~ /\A [0-9] /xms)) {
90 3 50       18 if ($_[0] ne $mb::VERSION) {
91 3         4 my($package, $filename, $line) = caller;
92 3         87 die "$filename requires @{[__PACKAGE__]} $_[0], however @{[__FILE__]} am only $mb::VERSION, stopped at $filename line $line.\n";
  3         16  
  3         5  
93             }
94 3         167 shift @_;
95             }
96              
97             # scan import arguments
98 144         564 my $want_runtime = 0; # *mb or %mb requested -> runtime interface, no filter
99 144         589 my $encoding = undef;
100 144         785 for my $arg (@_) {
101 51 100 100     493 if (($arg eq '*mb') or ($arg eq '%mb')) {
    100          
102 6         10 $want_runtime = 1;
103             }
104             elsif ($arg =~ /\A (?: big5 | big5hkscs | eucjp | euctw | gb18030 | gbk | hp15 | informixv6als | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
105 36         194 $encoding = $arg;
106             }
107             else {
108 15         27 die "@{[__FILE__]} import argument '$arg' not supported (use one of: *mb, %mb, big5, big5hkscs, eucjp, euctw, gb18030, gbk, hp15, informixv6als, rfc2279, sjis, uhc, utf8, wtf8).\n";
  15         39  
109             }
110             }
111              
112             # set system encoding
113 132         463 $system_encoding = detect_system_encoding();
114              
115             # set script encoding
116 132 100       404 if (defined $encoding) {
117 36         105 mb::set_script_encoding($encoding);
118             }
119             else {
120 99         363 mb::set_script_encoding($system_encoding);
121             }
122              
123             # tie my %mb, __PACKAGE__; # makes: Parentheses missing around "my" list
124 168     162   1045 no strict qw(refs);
  168         235  
  168         129969  
125 132         756 tie my %mb, 'mb';
126 132         558 *{caller().'::mb'} = { %mb };
  132         1015  
127              
128             # $^X($EXECUTABLE_NAME) for execute MBCS Perl script
129 132         273 $mb::PERL = qq{$^X @{[__FILE__]}};
  132         507  
130 132         327 $mb::PERL = $mb::PERL; # to avoid: Name "mb::PERL" used only once: possible typo at ...
131              
132             # original $0($PROGRAM_NAME) before transpile
133 132         565 ($mb::ORIG_PROGRAM_NAME = $0) =~ s/\.oo(\.[^.]+)\z/$1/;
134 132         286 $mb::ORIG_PROGRAM_NAME = $mb::ORIG_PROGRAM_NAME; # to avoid: Name "mb::ORIG_PROGRAM_NAME" used only once: possible typo at ...
135              
136             # Sjis software compatible subroutines
137 132         462 my $old_package = mb::get_old_package();
138 132         380 for my $subroutine (qw( chop chr do dosglob eval getc index index_byte length ord require reverse rindex rindex_byte substr tr )) {
139 2067         1760 *{$old_package . $subroutine} = \&{"mb::$subroutine"};
  2067         4818  
  2067         3255  
140             }
141              
142             # path 1: opportunistic source code filter
143             #
144             # Installed for "use mb;" style loading (no *mb/%mb token) and not when
145             # running an already transpiled *.oo script through -Mmb=ver,enc (the
146             # modulino sets PERL_MB_OCTET in that case, see sub main).
147             #
148             # ADDITIVE GUARD (zero regression): a script that calls
149             # mb::set_script_encoding() itself is, by construction, an octet-oriented
150             # / runtime-managed script (this is mb's long-standing "use mb; then call
151             # mb::* functions on octet data" convention, used throughout t/*.t). Such
152             # a script must NOT have its own source transpiled, so the filter passes it
153             # through unchanged. Only a genuine path-1 script -- one that does not
154             # manage the encoding at run time -- is auto-transpiled. This keeps every
155             # pre-existing "use mb;" caller behaving exactly as before (it was never
156             # source-filtered, because no filter existed in mb-0.63) while still letting
157             # a plain "use mb;" / "use mb 'utf8';" script be transpiled with no modulino.
158             #
159             # Filter::Util::Call has been a core module since perl 5.8.0; it is only
160             # require()d at run time, so no extra dependency is declared. On perl
161             # 5.005_03 / 5.6 the filter is unavailable and "use mb;" loads as a plain
162             # runtime import (the modulino remains the way to transpile there).
163 132 100 100     21865 if ((not $want_runtime) and (not $ENV{'PERL_MB_OCTET'}) and ($] >= 5.008)) {
      66        
164 114 50       298 if (eval { require Filter::Util::Call; 1 }) {
  114         58649  
  114         98942  
165 114         275 my $done = 0;
166             Filter::Util::Call::filter_add(sub {
167 120 100   120   9669 return 0 if $done;
168 114         319 my $buffer = '';
169 114         186 my $status = 0;
170 114         1104 while (($status = Filter::Util::Call::filter_read()) > 0) {
171 37826         32403 $buffer .= $_;
172 37826         51376 $_ = '';
173             }
174 114 50       422 if ($status == 0) {
175              
176             # runtime-managed (octet-oriented) script: pass through as is
177 114 100       1074 if ($buffer =~ /\b mb::set_script_encoding \s* \(/xms) {
178 94         240 $_ = $buffer;
179             }
180             else {
181 23         66 $_ = mb::_insert_source_encoding_unimport(mb::parse($buffer));
182             }
183 114         354 $done = 1;
184 114         10845 return 1;
185             }
186 3         4 return $status;
187 114         884 });
188             }
189             }
190             }
191              
192             #---------------------------------------------------------------------
193             # running as command
194             sub main {
195              
196             # usage
197 27 50   27 0 333 if (scalar(@ARGV) == 0) {
198 3         16 die <
199             usage:
200              
201             perl mb.pm script_by_mbcs.pl (auto detect)
202             perl mb.pm -e big5 script_by_big5.pl
203             perl mb.pm -e big5hkscs script_by_big5hkscs.pl
204             perl mb.pm -e eucjp script_by_eucjp.pl
205             perl mb.pm -e euctw script_by_euctw.pl
206             perl mb.pm -e gb18030 script_by_gb18030.pl
207             perl mb.pm -e gbk script_by_gbk.pl
208             perl mb.pm -e hp15 script_by_hp15.pl
209             perl mb.pm -e informixv6als script_by_informixv6als.pl
210             perl mb.pm -e rfc2279 script_by_rfc2279.pl
211             perl mb.pm -e sjis script_by_sjis.pl
212             perl mb.pm -e sjis script_by_cp932.pl
213             perl mb.pm -e uhc script_by_uhc.pl
214             perl mb.pm -e utf8 script_by_utf8.pl
215             perl mb.pm -e wtf8 script_by_wtf8.pl
216              
217             perl mb.pm script.pl ??-DOS-like *wildcard* available
218              
219             END
220             }
221              
222             # set system encoding
223 27         53 $system_encoding = detect_system_encoding();
224              
225             # set script encoding from command line
226 27         115 my $encoding = '';
227 27 100       103 if (($encoding) = $ARGV[0] =~ /\A -e ( .+ ) \z/xms) {
    50          
228 17 50       24 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | euctw | gb18030 | gbk | hp15 | informixv6als | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
229 3         85 mb::set_script_encoding($encoding);
230 3         17 shift @ARGV;
231             }
232             else {
233 17         33 die "script_encoding '$encoding' not supported (use one of: big5, big5hkscs, eucjp, euctw, gb18030, gbk, hp15, informixv6als, rfc2279, sjis, uhc, utf8, wtf8).\n";
234             }
235             }
236             elsif ($ARGV[0] =~ /\A -e \z/xms) {
237 13         127 $encoding = $ARGV[1];
238 13 100       51 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | euctw | gb18030 | gbk | hp15 | informixv6als | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
239 9         33 mb::set_script_encoding($encoding);
240 9         94 shift @ARGV;
241 9         35 shift @ARGV;
242             }
243             else {
244 7         27 die "script_encoding '$encoding' not supported (use one of: big5, big5hkscs, eucjp, euctw, gb18030, gbk, hp15, informixv6als, rfc2279, sjis, uhc, utf8, wtf8).\n";
245             }
246             }
247             else {
248 3         99 mb::set_script_encoding($system_encoding);
249             }
250              
251             # remember the target script name and read its source once
252 9         29 my $script = $ARGV[0];
253              
254             # read application script
255 9 50       47 my $rfh = mb::_open_r($script) or die "$0(@{[__LINE__]}): can't open file: $script\n";
  3         88  
256              
257             # sysread(...) has hidden binmode($fh) that's not portable
258             # local $_; sysread($fh, $_, -s $ARGV[0]);
259 168     162   1013 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$rfh}) };
  168         231  
  168         6358  
  9         25  
  9         29  
  9         2684  
  9         1101  
260 168     162   594 { no strict 'refs'; close($rfh) }
  348         424  
  726         53034  
  9         723  
  9         897  
261 9         32 my $source = $_;
262              
263             # @ARGV wildcard globbing
264 9 50       30 if ($OSNAME =~ /MSWin32/) {
265 3         82 my @argv = ();
266 3         16 for (@ARGV) {
267              
268             # has space
269 3 0       5 if (/\A (?:$x)*? [ ] /xms) {
    0          
270 3 0       135 if (my @glob = mb::dosglob(qq{"$_"})) {
271 3         16 push @argv, @glob;
272             }
273             else {
274 3         5 push @argv, $_;
275             }
276             }
277              
278             # has wildcard metachar
279             elsif (/\A (?:$x)*? [*?] /xms) {
280 3 0       81 if (my @glob = mb::dosglob($_)) {
281 3         16 push @argv, @glob;
282             }
283             else {
284 3         4 push @argv, $_;
285             }
286             }
287              
288             # no wildcard globbing
289             else {
290 3         82 push @argv, $_;
291             }
292             }
293 3         15 @ARGV = @argv;
294             }
295              
296             # Strategy for :
297             # - no __DATA__/__END__ : transpile and run in-process by CORE::eval
298             # (no temporary file is created)
299             # - has __DATA__/__END__: a string eval cannot provide a working
300             # handle, so write a *.oo script and run it as a
301             # real file through a child interpreter.
302 9 100       68 if ($source =~ /^__(?:END|DATA)__\b/m) {
303              
304             # poor "make": (re)transpile to *.oo only when stale
305 5         104 (my $script_oo = $script) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
306 5 50 66     104 if (
      66        
307             (not -e $script_oo) or
308             (mtime($script_oo) <= mtime($script)) or
309             (mtime($script_oo) <= mtime(__FILE__))
310             ) {
311              
312             # poor file locking
313 4     3   14 local $SIG{__DIE__} = sub { rmdir "$script.lock"; };
  3         86  
314 4 50       293 if (mkdir "$script.lock", 0755) {
315 4 50       8 my $wfh = mb::_open_w($script_oo) or die "$0(@{[__LINE__]}): can't open file: $script_oo\n";
  3         86  
316 168     162   976 { no strict 'refs'; print {*{$wfh}} mb::_insert_source_encoding_unimport(mb::parse($source)) }
  168         604  
  168         8631  
  4         9  
  4         79  
  4         21  
317 162     162   767 { no strict 'refs'; close($wfh) }
  162         264  
  168         190897  
  4         15  
  4         9  
  4         175  
318 4         128 rmdir "$script.lock";
319             }
320             else {
321 3         4 die "$0(@{[__LINE__]}): can't mkdir: $script.lock\n";
  3         81  
322             }
323             }
324              
325             # locate this module for the child interpreter
326 5         22 my $module_path = '';
327 5         7 my $module_name = '';
328 5         89 my $quote = '';
329 5 50       22 if ($OSNAME =~ /MSWin32/) {
330 3 0       4 if ($0 =~ m{ ([^\/\\]+)\.pm \z}xmsi) {
331 3         107 ($module_path, $module_name) = ($`, $1);
332 3   0     27 $module_path ||= '.';
333 3         12 $module_path =~ s{ [\/\\] \z}{}xms;
334             }
335             else {
336 3         103 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         16  
337             }
338 3         5 $quote = q{"};
339             }
340             else {
341 5 50       110 if ($0 =~ m{ ([^\/]+)\.pm \z}xmsi) {
342 5         29 ($module_path, $module_name) = ($`, $1);
343 5   50     11 $module_path ||= '.';
344 5         102 $module_path =~ s{ / \z}{}xms;
345             }
346             else {
347 3         16 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         6  
348             }
349 5         87 $quote = q{'};
350             }
351              
352             # run octet-oriented script
353             # PERL_MB_OCTET tells the child interpreter (which loads -Mmb=ver,enc) not
354             # to install the path-1 source filter on the already transpiled *.oo script.
355 5         24 $| = 1;
356 5         38 local $ENV{'PERL_MB_OCTET'} = 1;
357 5 50       140 system($^X, "-I$module_path", "-M$module_name=$mb::VERSION,$script_encoding", map { / / ? "$quote$_$quote" : $_ } $script_oo, @ARGV[1..$#ARGV]);
  5         4412503  
358 5         7 exit($? >> 8);
359             }
360             else {
361              
362             # transpile and run in-process (no temporary file is created)
363 7         126 my $transpiled = mb::_insert_source_encoding_unimport(mb::parse($source));
364              
365             # make the script see its own name and its own arguments
366 7         81 local $0 = $script;
367 7         20 local @ARGV = @ARGV[1..$#ARGV];
368              
369             # escape the file name for the #line directive so error messages
370             # point back at the original script with correct line numbers
371 7         118 (my $filename = $script) =~ s/([\\"])/\\$1/g;
372 7         28 my $code = "package main;\n#line 1 \"$filename\"\n" . $transpiled;
373              
374             # PERL_MB_OCTET keeps any "use mb ..." inside the transpiled source from
375             # re-installing the path-1 source filter (which would transpile twice).
376 7         19 $| = 1;
377 7         126 local $ENV{'PERL_MB_OCTET'} = 1;
378 7         1364 CORE::eval $code;
379 7 100       166 if ($@) {
380 4         131 print STDERR $@;
381 4         17 exit 1;
382             }
383 6         5 exit 0;
384             }
385             }
386              
387             #---------------------------------------------------------------------
388             # cluck() for MBCS encoding
389             sub cluck {
390 3     3 0 102 my $i = 0;
391 3         17 my @cluck = ();
392 3         5 while (my($package, $filename, $line, $subroutine) = caller($i)) {
393 3         88 push @cluck, "[$i] $filename($line) $subroutine\n";
394 3         16 $i++;
395             }
396 3         6 print STDERR "\n", @_, "\n";
397 3         104 print STDERR CORE::reverse @cluck;
398             }
399              
400             #---------------------------------------------------------------------
401             # confess() for MBCS encoding
402             sub confess {
403 3     3 0 19 my $i = 0;
404 3         5 my @confess = ();
405 3         94 while (my($package, $filename, $line, $subroutine) = caller($i)) {
406 3         19 push @confess, "[$i] $filename($line) $subroutine\n";
407 3         4 $i++;
408             }
409 3         106 print STDERR "\n", @_, "\n";
410 3         15 print STDERR CORE::reverse @confess;
411 3         15 die;
412             }
413              
414             #---------------------------------------------------------------------
415             # short cut of (stat(file))[9]
416             sub mtime {
417 7     7 0 98 my($file) = @_;
418 7         54 return ((stat $file)[9]);
419             }
420              
421             ######################################################################
422             # subroutines for MBCS application programmers
423             ######################################################################
424              
425             #---------------------------------------------------------------------
426             # chop() for MBCS encoding
427             sub mb::chop (@) {
428 49     49 0 622 my $chop = '';
429 49 100       175 for (@_ ? @_ : $_) {
430 57 100       701 if (my @x = /\G$x/g) {
431 51         67 $chop = pop @x;
432 51         192 $_ = join '', @x;
433             }
434             }
435 49         92 return $chop;
436             }
437              
438             #---------------------------------------------------------------------
439             # chr() for MBCS encoding
440             sub mb::chr (;$) {
441 30 100   30 0 280 my $number = @_ ? $_[0] : $_;
442              
443             # Negative values give the Unicode replacement character (chr(0xfffd)),
444             # except under the bytes pragma, where the low eight bits of the value
445             # (truncated to an integer) are used.
446              
447 30         129 my @octet = ();
448 30         47 CORE::do {
449 34         62 unshift @octet, ($number % 0x100);
450 34         159 $number = int($number / 0x100);
451             } while ($number > 0);
452 30         140 return pack 'C*', @octet;
453             }
454              
455             #---------------------------------------------------------------------
456             # do FILE for MBCS encoding
457             sub mb::do ($) {
458 8     8 0 1772 my($file) = @_;
459 8         109 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  43         66  
460 8 50       68 if (-f $prefix_file) {
461              
462             # poor "make"
463 8         139 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
464 8 0 33     196 if (
      33        
465             (not -e $prefix_file_oo) or
466             (mtime($prefix_file_oo) <= mtime($prefix_file)) or
467             (mtime($prefix_file_oo) <= mtime(__FILE__))
468             ) {
469 8 50       22 my $fh = mb::_open_r($prefix_file) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file\n";
  3         79  
470 168     162   1162 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  168         283  
  162         7243  
  8         25  
  8         21  
  8         88  
  8         149  
471 162     162   647 { no strict 'refs'; close($fh) }
  162         241  
  162         16798  
  8         14  
  8         171  
472              
473             # poor file locking
474 8     3   54 local $SIG{__DIE__} = sub { rmdir "$prefix_file.lock"; };
  3         5  
475 8 50       735 if (mkdir "$prefix_file.lock", 0755) {
476 8 50       48 my $fh = mb::_open_w($prefix_file_oo) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file_oo\n";
  3         6  
477 162     162   729 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  162         266  
  162         7305  
  8         20  
  8         10  
  8         139  
478 162     162   655 { no strict 'refs'; close($fh) }
  162         255  
  162         341757  
  8         105  
  8         27  
  8         186  
479 8         489 rmdir "$prefix_file.lock";
480             }
481             else {
482 3         17 confess "$0(@{[__LINE__]}): can't mkdir: $prefix_file.lock\n";
  3         5  
483             }
484             }
485 8         111 $INC{$file} = $prefix_file_oo;
486              
487             # run as Perl script
488             # must use CORE::do to use , because CORE::eval cannot do it
489             # moreover "goto &CORE::do" doesn't work
490 8         301 return CORE::eval sprintf(<<'END', (caller)[0,2,1]);
491             package %s;
492             #line %s "%s"
493             CORE::do "$prefix_file_oo";
494             END
495             }
496             }
497 3         6 confess "Can't find $file in \@INC";
498             }
499              
500             #---------------------------------------------------------------------
501             # DOS-like glob() for MBCS encoding
502             sub mb::dosglob (;$) {
503 11 50   11 0 688 my $expr = @_ ? $_[0] : $_;
504 11         27 my @glob = ();
505              
506             # works on not MSWin32
507 11 50       20 if ($OSNAME !~ /MSWin32/) {
508 11         2073 @glob = CORE::glob($expr);
509             }
510              
511             # works on MSWin32
512             else {
513              
514             # gets pattern
515 3         15 while ($expr =~ s{\A [\x20]* ( "(?:$x)+?" | (?:(?!["\x20])$x)+ ) }{}xms) {
516 3         5 my $pattern = $1;
517              
518             # avoids command injection
519 3 0       155 next if $pattern =~ /\G${mb::_anchor} \& /xms;
520 3 0       16 next if $pattern =~ /\G${mb::_anchor} \( /xms;
521 3 0       5 next if $pattern =~ /\G${mb::_anchor} \) /xms;
522 3 0       84 next if $pattern =~ /\G${mb::_anchor} \< /xms;
523 3 0       16 next if $pattern =~ /\G${mb::_anchor} \> /xms;
524 3 0       4 next if $pattern =~ /\G${mb::_anchor} \^ /xms;
525 3 0       82 next if $pattern =~ /\G${mb::_anchor} \| /xms;
526              
527             # makes globbing result
528 3         14 mb::tr($pattern, '/', "\x5C");
529 3 0       6 if (my($dir) = $pattern =~ m{\A ($x*) \\ }xms) {
530 3         107 push @glob, map { "$dir\\$_" } CORE::split /\n/, `DIR /B $pattern 2>NUL`;
  3         18  
531             }
532             else {
533 3         6 push @glob, CORE::split /\n/, `DIR /B $pattern 2>NUL`;
534             }
535             }
536             }
537              
538             # returns globbing result
539 11         132 my %glob = map { $_ => 1 } @glob;
  27         59  
540 11 50       33 return sort { (mb::uc($a) cmp mb::uc($b)) || ($a cmp $b) } keys %glob;
  27         169  
541             }
542              
543             #---------------------------------------------------------------------
544             # eval STRING for MBCS encoding
545             sub mb::eval (;$) {
546 15039 100   15039 0 37443380 local $_ = @_ ? $_[0] : $_;
547              
548             # run as Perl script in caller package
549 15039         59346 return CORE::eval sprintf(<<'END', (caller)[0,2,1], mb::parse());
550             package %s;
551             #line %s "%s"
552             %s
553             END
554             }
555              
556             #---------------------------------------------------------------------
557             # getc() for MBCS encoding
558             sub mb::getc (;*) {
559 153 100   153 0 2348315 my $fh = @_ ? shift(@_) : \*STDIN;
560 153 50 33     297 confess 'Too many arguments for mb::getc' if @_ and not wantarray;
561 153         1054 my $getc = CORE::getc $fh;
562 153 50       390 return wantarray ? ($getc,@_) : $getc if not defined $getc;
    100          
563 119 100       461 if ($script_encoding =~ /\A (?: sjis ) \z/xms) {
    100          
    100          
    100          
    100          
    100          
    100          
    50          
564 45 100       78 if ($getc =~ /\A [\x81-\x9F\xE0-\xFC] \z/xms) {
565 25 100       126 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  25         61  
566             }
567             }
568             elsif ($script_encoding =~ /\A (?: informixv6als ) \z/xms) {
569 10 100       26 if ($getc =~ /\A [\x81-\x9F\xE0-\xFC] \z/xms) {
    100          
570 5 100       91 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  5         37  
571             }
572             elsif ($getc =~ /\A [\xFD] \z/xms) {
573 6         11 my $c;
574 6 100       108 $c = CORE::getc $fh; $getc .= $c if defined $c;
  6         22  
575 6 100       11 $c = CORE::getc $fh; $getc .= $c if defined $c;
  6         92  
576             }
577             }
578             elsif ($script_encoding =~ /\A (?: hp15 ) \z/xms) {
579 13 100       35 if ($getc =~ /\A [\x80-\xA0\xE0-\xFE] \z/xms) {
580 10 100       19 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  10         95  
581             }
582             }
583             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
584 9 100       28 if ($getc =~ /\A [\xA1-\xFE] \z/xms) {
585 7 100       14 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  7         129  
586             }
587             }
588             elsif ($script_encoding =~ /\A (?: euctw ) \z/xms) {
589 11 100       36 if ($getc =~ /\A [\x8E] \z/xms) {
    100          
590 7         11 my $c;
591 7 100       91 $c = CORE::getc $fh; $getc .= $c if defined $c;
  6         18  
592 6 100       9 $c = CORE::getc $fh; $getc .= $c if defined $c;
  6         57  
593 4 100       6 $c = CORE::getc $fh; $getc .= $c if defined $c;
  4         7  
594             }
595             elsif ($getc =~ /\A [\xA1-\xFE] \z/xms) {
596 2 100       5 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  2         5  
597             }
598             }
599             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
600 24 100       39 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
601 16 100       29 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  16         27  
602             }
603             }
604             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
605 7 100       14 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
606 5 100       9 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  5         9  
607 5 100       8 if ($getc =~ /\A [\x81-\xFE] [\x30-\x39] \z/xms) {
608 3 100       7 $c = CORE::getc $fh; $getc .= $c if defined $c;
  3         3  
609 3 100       6 $c = CORE::getc $fh; $getc .= $c if defined $c;
  3         6  
610             }
611             }
612             }
613             elsif ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
614 12 100       50 if ($getc =~ /\A [\x00-\x7F\x80-\xC1\xF5-\xFF] \z/xms) {
    100          
    100          
    50          
615             }
616             elsif ($getc =~ /\A [\xC2-\xDF] \z/xms) {
617 2 100       7 my $c = CORE::getc $fh; $getc .= $c if defined $c;
  2         5  
618             }
619             elsif ($getc =~ /\A [\xE0-\xEF] \z/xms) {
620 3         3 my $c;
621 3 100       5 $c = CORE::getc $fh; $getc .= $c if defined $c;
  3         5  
622 3 100       6 $c = CORE::getc $fh; $getc .= $c if defined $c;
  3         5  
623             }
624             elsif ($getc =~ /\A [\xF0-\xF4] \z/xms) {
625 4         4 my $c;
626 4 100       8 $c = CORE::getc $fh; $getc .= $c if defined $c;
  4         8  
627 4 100       7 $c = CORE::getc $fh; $getc .= $c if defined $c;
  4         5  
628 4 100       7 $c = CORE::getc $fh; $getc .= $c if defined $c;
  4         7  
629             }
630             }
631 116 100       279 return wantarray ? ($getc,@_) : $getc;
632             }
633              
634             #---------------------------------------------------------------------
635             # index() for MBCS encoding
636             sub mb::index ($$;$) {
637 65     68 0 646 my $index = 0;
638 65 100       102 if (@_ == 3) {
639 4         79 $index = mb::index_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
640             }
641             else {
642 61         99 $index = mb::index_byte($_[0], $_[1]);
643             }
644 65 100       93 if ($index == -1) {
645 20         37 return -1;
646             }
647             else {
648 45         83 return mb::length(CORE::substr $_[0], 0, $index);
649             }
650             }
651              
652             #---------------------------------------------------------------------
653             # JPerl like index() for MBCS encoding
654             sub mb::index_byte ($$;$) {
655 73     76 0 308 my($str,$substr,$position) = @_;
656 73   100     206 $position ||= 0;
657 73         65 my $pos = 0;
658 73         114 while ($pos < CORE::length($str)) {
659 363 100       447 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
660 53 100       80 if ($pos >= $position) {
661 49         91 return $pos;
662             }
663             }
664 314 50       1271 if (CORE::substr($str,$pos) =~ /\A($x)/xms) {
665 314         510 $pos += CORE::length($1);
666             }
667             else {
668 0         0 $pos += 1;
669             }
670             }
671 24         35 return -1;
672             }
673              
674             #---------------------------------------------------------------------
675             # universal lc() for MBCS encoding
676             sub mb::lc (;$) {
677 11 100   14 1 1395 local $_ = @_ ? $_[0] : $_;
678             # A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z
679 11 100       296 return join '', map { {qw( A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z )}->{$_}||$_ } /\G$x/g;
  119         1087  
680             # A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z
681             }
682              
683             #---------------------------------------------------------------------
684             # universal lcfirst() for MBCS encoding
685             sub mb::lcfirst (;$) {
686 2 100   5 0 139 local $_ = @_ ? $_[0] : $_;
687 2 50       59 if (/\A($x)(.*)\z/s) {
688 2         5 return mb::lc($1) . $2;
689             }
690             else {
691 0         0 return '';
692             }
693             }
694              
695             #---------------------------------------------------------------------
696             # length() for MBCS encoding
697             sub mb::length (;$) {
698 110 100   113 0 115270 local $_ = @_ ? $_[0] : $_;
699 110         1907 return scalar(() = /\G$x/g);
700             }
701              
702             #---------------------------------------------------------------------
703             # ord() for MBCS encoding
704             sub mb::ord (;$) {
705 4 100   7 0 166 local $_ = @_ ? $_[0] : $_;
706 4         5 my $ord = 0;
707 4 50       67 if (/\A($x)/) {
708 4         10 for my $octet (unpack 'C*', $1) {
709 6         9 $ord = $ord * 0x100 + $octet;
710             }
711             }
712 4         7 return $ord;
713             }
714              
715             #---------------------------------------------------------------------
716             # valid() tests well-formedness of a string for the current script encoding
717             sub mb::valid (;$) {
718 51 100   54 0 1398 local $_ = @_ ? $_[0] : $_;
719              
720             # mb has no UTF-8 flag and no decode boundary, so the everyday operations
721             # are deliberately lenient (every octet is at least a one-byte character).
722             # mb::valid is the explicit, opt-in validity check for callers who do want
723             # to reject malformed input. It uses the STRICT unit -- $over_ascii (a
724             # well-formed multi-byte sequence) or a US-ASCII byte -- NOT the lenient
725             # $x, so any stray octet makes the whole string fail to match and the
726             # predicate returns false. The string itself is never modified.
727             #
728             # $over_ascii is undef until a script encoding is selected (set_script_encoding
729             # or import). If valid() is called before then, there is no multi-byte unit to
730             # test against, so fall back to US-ASCII only rather than interpolating an
731             # undefined pattern (which would warn "Use of uninitialized value").
732 51 50       82 if (not defined $over_ascii) {
733 0 0       0 return /\A [\x00-\x7F]* \z/xms ? 1 : 0;
734             }
735 51 100       1935 return /\A (?: $over_ascii | [\x00-\x7F] )* \z/xms ? 1 : 0;
736             }
737              
738             #---------------------------------------------------------------------
739             # require for MBCS encoding
740             sub mb::require (;$) {
741 5 50   8 0 1738 local $_ = @_ ? $_[0] : $_;
742              
743             # require perl version
744 5 50       16 if (/^[0-9]/) {
745 0 0       0 if ($] < $_) {
746 0         0 confess "Perl $_ required--this is only version $], stopped";
747             }
748             else {
749 0         0 undef $@;
750 0         0 return 1;
751             }
752             }
753              
754             # require expr
755             else {
756              
757             # find expr in @INC
758 5         7 my $file = $_;
759 5 50 33     33 if (($file =~ s{::}{/}g) or ($file !~ m{[\./\\]})) {
760 0         0 $file .= '.pm';
761             }
762 5 100       13 if (exists $INC{$file}) {
763 1         2 undef $@;
764 1 50       8 return 1 if $INC{$file};
765 0         0 confess "Compilation failed in require";
766             }
767 4         7 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  32         42  
768 4 50       59 if (-f $prefix_file) {
769              
770             # poor "make"
771 4         43 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
772 4 0 33     160 if (
      33        
773             (not -e $prefix_file_oo) or
774             (mtime($prefix_file_oo) <= mtime($prefix_file)) or
775             (mtime($prefix_file_oo) <= mtime(__FILE__))
776             ) {
777 4 50       16 my $fh = mb::_open_r($prefix_file) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file\n";
  0         0  
778 162     162   1154 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  162         282  
  162         8003  
  4         4  
  4         26  
  4         5  
  4         153  
779 162     162   668 { no strict 'refs'; close($fh) }
  162         828  
  162         20802  
  4         5  
  4         33  
780              
781             # poor file locking
782 4     3   36 local $SIG{__DIE__} = sub { rmdir "$prefix_file.lock"; };
  0         0  
783 4 50       456 if (mkdir "$prefix_file.lock", 0755) {
784 4 50       19 my $fh = mb::_open_w($prefix_file_oo) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file_oo\n";
  0         0  
785 162     162   959 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  162         310  
  162         7269  
  4         4  
  4         4  
  4         21  
786 162     162   669 { no strict 'refs'; close($fh) }
  162         296  
  162         217408  
  4         4  
  4         8  
  4         151  
787 4         360 rmdir "$prefix_file.lock";
788             }
789             else {
790 0         0 confess "$0(@{[__LINE__]}): can't mkdir: $prefix_file.lock\n";
  0         0  
791             }
792             }
793 4         17 $INC{$_} = $prefix_file_oo;
794              
795             # run as Perl script
796             # must use CORE::do to use , because CORE::eval cannot do it.
797 4         5 local $@;
798 4         245 my $result = CORE::eval sprintf(<<'END', (caller)[0,2,1]);
799             package %s;
800             #line %s "%s"
801             CORE::do "$prefix_file_oo";
802             END
803              
804             # return result
805 4 50       296 if ($@) {
    50          
806 0         0 $INC{$_} = undef;
807 0         0 confess $@;
808             }
809             elsif (not $result) {
810 0         0 delete $INC{$_};
811 0         0 confess "$_ did not return true value";
812             }
813             else {
814 4         24 return $result;
815             }
816             }
817             }
818 0         0 confess "Can't find $_ in \@INC";
819             }
820             }
821              
822             #---------------------------------------------------------------------
823             # reverse() for MBCS encoding
824             sub mb::reverse (@) {
825              
826             # in list context,
827 21 100   24 0 378 if (wantarray) {
828              
829             # returns a list value consisting of the elements of @_ in the opposite order
830 2         5 return CORE::reverse @_;
831             }
832              
833             # in scalar context,
834             else {
835              
836             # returns a string value with all characters in the opposite order of
837 19 100       678 return (join '',
838             CORE::reverse(
839             @_ ?
840             join('',@_) =~ /\G$x/g : # concatenates the elements of @_
841             /\G$x/g # $_ when without arguments
842             )
843             );
844             }
845             }
846              
847             #---------------------------------------------------------------------
848             # rindex() for MBCS encoding
849             sub mb::rindex ($$;$) {
850 19     22 0 309 my $rindex = 0;
851 19 100       75 if (@_ == 3) {
852 4         68 $rindex = mb::rindex_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
853             }
854             else {
855 15         63 $rindex = mb::rindex_byte($_[0], $_[1]);
856             }
857 19 100       36 if ($rindex == -1) {
858 4         6 return -1;
859             }
860             else {
861 15         41 return mb::length(CORE::substr $_[0], 0, $rindex);
862             }
863             }
864              
865             #---------------------------------------------------------------------
866             # JPerl like rindex() for MBCS encoding
867             sub mb::rindex_byte ($$;$) {
868 27     30 0 369 my($str,$substr,$position) = @_;
869 27   66     114 $position ||= CORE::length($str) - 1;
870 27         76 my $pos = 0;
871 27         69 my $rindex = -1;
872 27   100     89 while (($pos < CORE::length($str)) and ($pos <= $position)) {
873 284 100       355 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
874 41         43 $rindex = $pos;
875             }
876 284 50       1176 if (CORE::substr($str,$pos) =~ /\A($x)/xms) {
877 284         576 $pos += CORE::length($1);
878             }
879             else {
880 0         0 $pos += 1;
881             }
882             }
883 27         47 return $rindex;
884             }
885              
886             #---------------------------------------------------------------------
887             # set OSNAME
888             sub mb::set_OSNAME ($) {
889 86     89 0 438 $OSNAME = $_[0];
890             }
891              
892             #---------------------------------------------------------------------
893             # get OSNAME
894             sub mb::get_OSNAME () {
895 43     46 0 694 return $OSNAME;
896             }
897              
898             #---------------------------------------------------------------------
899             # set script encoding name and more
900             sub mb::set_script_encoding ($) {
901 277     280 0 11228599 $script_encoding = $_[0];
902              
903             # over US-ASCII
904             $over_ascii = {
905             'sjis' => '(?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|[\x80-\xFF])', # shift_jis ANSI/OEM Japanese; Japanese (Shift-JIS)
906             'informixv6als' => '(?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|\xFD[\xA1-\xFE][\x00-\xFF]|[\x80-\xFF])', # INFORMIX V6 ALS: Shift_JIS-compatible 2 byte core plus \xFD 3 byte user-defined plane
907             'gbk' => '(?>[\x81-\xFE][\x00-\xFF])', # gb2312 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
908             'uhc' => '(?>[\x81-\xFE][\x00-\xFF])', # ks_c_5601-1987 ANSI/OEM Korean (Unified Hangul Code)
909             'big5' => '(?>[\x81-\xFE][\x00-\xFF])', # big5 ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
910             'big5hkscs' => '(?>[\x81-\xFE][\x00-\xFF])', # HKSCS support on top of traditional Chinese Windows
911             'hp15' => '(?>[\x80-\xA0\xE0-\xFE][\x00-\xFF]|[\x80-\xFF])', # HP-15 (HP-UX Japanese): 2 byte DBCS lead [\x80-\xA0\xE0-\xFE]; JIS X 0201 katakana [\xA1-\xDF] and \xFF are single octet; the standard 2 byte area encodes JIS X 0208 with the same octets as Shift-JIS and the extra leads serve only the user-defined area (Ken Lunde, CJKV Information Processing 2nd ed., Appendixes E and F; see "=head2 hp15" in POD for URLs)
912             'eucjp' => '(?>[\xA1-\xFE][\x00-\xFF])', # EUC-JP Japanese (JIS 0208-1990 and 0121-1990)
913             'euctw' => '(?>\x8E[\xA1-\xB0][\xA1-\xFE][\x00-\xFF]|[\xA1-\xFE][\xA1-\xFE])', # EUC-TW Traditional Chinese (CNS 11643 plane 1 (2 byte) and SS2 planes 2..16 (4 byte))
914             'gb18030' => '(?>[\x81-\xFE][\x30-\x39][\x81-\xFE][\x30-\x39]|[\x81-\xFE][\x00-\xFF])', # GB18030 Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
915             'rfc2279' => '(?>[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF])', # utf-8 Unicode (UTF-8) RFC2279
916             'utf8' => '(?>[\xE1-\xEC][\x80-\xBF][\x80-\xBF]|[\xC2-\xDF][\x80-\xBF]|[\xEE-\xEF][\x80-\xBF][\x80-\xBF]|[\xF0-\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]|[\xE0-\xE0][\xA0-\xBF][\x80-\xBF]|[\xED-\xED][\x80-\x9F][\x80-\xBF]|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]|[\xF4-\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF])', # utf-8 Unicode (UTF-8) optimized RFC3629 for ja_JP
917             'wtf8' => '(?>[\xE1-\xEF][\x80-\xBF][\x80-\xBF]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xE0][\xA0-\xBF][\x80-\xBF]|[\xF0-\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]|[\xF4-\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF])', # optimized WTF-8 for ja_JP
918 277   50     3529 }->{$script_encoding} || '[\x80-\xFF]';
919              
920             # supports qr/./ in MBCS script
921             #
922             # NOTE (0.64 step 4 read-only audit): this transpile-path $x is kept as a
923             # qr// OBJECT on purpose. A qr// interpolates into another pattern as a
924             # modifier-isolated subpattern ((?^...:...) / (?-xism:...)); the transpile
925             # path relies on that isolation when $x is embedded inside /x and escape
926             # contexts. Re-expressing $x as a plain string (the form used by mb8 and
927             # by the local $x inside _r2_qr) drops that wrapper and regresses the
928             # qr-as-q / s-as-q escape transpilation (observed: 406 failures on perl
929             # 5.38). So the "mitigation B" stringification is NOT applied here; the
930             # file-scoped $x stays a qr// object and stays STRICT ([\x00-\x7F]).
931             # Read-only safety on perl 5.005_03 is not needed for this $x: it is only
932             # ever interpolated into search patterns, never the target of a
933             # destructive s///. The runtime engine that DOES need a writable copy
934             # (_r2_qr) already takes one via my $source = "$_[0]".
935 277         24434 $x = qr/(?>$over_ascii|[\x00-\x7F])/;
936              
937             # regexp of multi-byte anchoring
938              
939             # Quantifiers
940             # {n,m} --- Match at least n but not more than m times
941             #
942             # n and m are limited to non-negative integral values less than a
943             # preset limit defined when perl is built. This is usually 32766 on
944             # the most common platforms.
945             #
946             # The following code is an attempt to solve the above limitations
947             # in a multi-byte anchoring.
948             #
949             # avoid "Segmentation fault" and "Error: Parse exception"
950             #
951             # perl5101delta
952             # http://perldoc.perl.org/perl5101delta.html
953             # In 5.10.0, the * quantifier in patterns was sometimes treated as {0,32767}
954             # [RT #60034, #60464]. For example, this match would fail:
955             # ("ab" x 32768) =~ /^(ab)*$/
956             #
957             # SEE ALSO
958             #
959             # Complex regular subexpression recursion limit
960             # http://www.perlmonks.org/?node_id=810857
961             #
962             # regexp iteration limits
963             # http://www.nntp.perl.org/group/perl.perl5.porters/2009/02/msg144065.html
964             #
965             # latest Perl won't match certain regexes more than 32768 characters long
966             # http://stackoverflow.com/questions/26226630/latest-perl-wont-match-certain-regexes-more-than-32768-characters-long
967             #
968             # Break through the limitations of regular expressions of Perl
969             # http://d.hatena.ne.jp/gfx/20110212/1297512479
970             #
971             # REG_INF has been raised from 65,536 to 2,147,483,647
972             # https://perldoc.perl.org/perl5380delta#REG_INF-has-been-raised-from-65,536-to-2,147,483,647
973              
974 277 100       2311 if ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
    50          
    0          
    0          
975 143         375 ${mb::_anchor} = qr{.*?}xms;
976             }
977             elsif ($] >= 5.038000) {
978             ${mb::_anchor} = {
979             'sjis' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
980             'hp15' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x80-\xA0\xE0-\xFE]+\z).*?|.*?[^\x80-\xA0\xE0-\xFE](?>[\x80-\xA0\xE0-\xFE][\x80-\xA0\xE0-\xFE])*?))}xms,
981             'informixv6als' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFD]+\z).*?|.*?[^\x81-\x9F\xE0-\xFD](?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|\xFD[\xA1-\xFE][\x00-\xFF])*?))}xms,
982             'eucjp' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
983             'euctw' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x8E\xA1-\xFE]+\z).*?|.*?[^\x8E\xA1-\xFE](?>\x8E[\xA1-\xB0][\xA1-\xFE][\x00-\xFF]|[\xA1-\xFE][\xA1-\xFE])*?))}xms,
984             'gbk' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
985             'uhc' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
986             'big5' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
987             'big5hkscs' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
988             'gb18030' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
989 134   50     88044 }->{$script_encoding} || die;
990             }
991             elsif ($] >= 5.030000) {
992             ${mb::_anchor} = {
993             'sjis' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
994             'hp15' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x80-\xA0\xE0-\xFE]+\z).*?|.*?[^\x80-\xA0\xE0-\xFE](?>[\x80-\xA0\xE0-\xFE][\x80-\xA0\xE0-\xFE])*?))}xms,
995             'informixv6als' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFD]+\z).*?|.*?[^\x81-\x9F\xE0-\xFD](?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|\xFD[\xA1-\xFE][\x00-\xFF])*?))}xms,
996             'eucjp' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
997             'euctw' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x8E\xA1-\xFE]+\z).*?|.*?[^\x8E\xA1-\xFE](?>\x8E[\xA1-\xB0][\xA1-\xFE][\x00-\xFF]|[\xA1-\xFE][\xA1-\xFE])*?))}xms,
998             'gbk' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
999             'uhc' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1000             'big5' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1001             'big5hkscs' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1002             'gb18030' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1003 0   0     0 }->{$script_encoding} || die;
1004             }
1005             elsif ($] >= 5.010001) {
1006             ${mb::_anchor} = {
1007             'sjis' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
1008             'hp15' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x80-\xA0\xE0-\xFE]+\z).*?|.*?[^\x80-\xA0\xE0-\xFE](?>[\x80-\xA0\xE0-\xFE][\x80-\xA0\xE0-\xFE])*?))}xms,
1009             'informixv6als' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFD]+\z).*?|.*?[^\x81-\x9F\xE0-\xFD](?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|\xFD[\xA1-\xFE][\x00-\xFF])*?))}xms,
1010             'eucjp' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
1011             'euctw' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x8E\xA1-\xFE]+\z).*?|.*?[^\x8E\xA1-\xFE](?>\x8E[\xA1-\xB0][\xA1-\xFE][\x00-\xFF]|[\xA1-\xFE][\xA1-\xFE])*?))}xms,
1012             'gbk' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1013             'uhc' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1014             'big5' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1015             'big5hkscs' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1016             'gb18030' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
1017 0   0     0 }->{$script_encoding} || die;
1018             }
1019             else {
1020 0         0 ${mb::_anchor} = qr{(?:$x)*?}xms;
1021             }
1022              
1023             # codepoint class shortcuts in qq-like regular expression
1024 277         3509 @{mb::_dot} = "(?>$over_ascii|.)"; # supports /s modifier by /./
1025 277         904 @{mb::_B} = "(?:(?
1026 277         1071 @{mb::_D} = "(?:(?![0-9])$x)";
1027 277         731 @{mb::_H} = "(?:(?![\\x09\\x20])$x)";
1028 277         734 @{mb::_N} = "(?:(?!\\n)$x)";
1029 277         554 @{mb::_R} = "(?>\\r\\n|[\\x0A\\x0B\\x0C\\x0D])";
1030 277         727 @{mb::_S} = "(?:(?![\\t\\n\\f\\r\\x20])$x)";
1031 277         719 @{mb::_V} = "(?:(?![\\x0A\\x0B\\x0C\\x0D])$x)";
1032 277         718 @{mb::_W} = "(?:(?![A-Za-z0-9_])$x)";
1033 277         1574 @{mb::_b} = "(?:(?
1034 277         567 @{mb::_d} = "[0-9]";
1035 277         475 @{mb::_h} = "[\\x09\\x20]";
1036 277         457 @{mb::_s} = "[\\t\\n\\f\\r\\x20]";
1037 277         453 @{mb::_v} = "[\\x0A\\x0B\\x0C\\x0D]";
1038 277         672 @{mb::_w} = "[A-Za-z0-9_]";
1039             }
1040              
1041             #---------------------------------------------------------------------
1042             # get script encoding name
1043             sub mb::get_script_encoding () {
1044 726762     726765 0 2915368 return $script_encoding;
1045             }
1046              
1047             #---------------------------------------------------------------------
1048             # get old package name
1049             sub mb::get_old_package () {
1050             return {qw(
1051             sjis Sjis::
1052             hp15 HP15::
1053             informixv6als INFORMIXV6ALS::
1054             gbk GBK::
1055             uhc UHC::
1056             big5 Big5::
1057             big5hkscs Big5HKSCS::
1058             eucjp EUCJP::
1059             euctw EUCTW::
1060             gb18030 GB18030::
1061             rfc2279 RFC2279::
1062             utf8 UTF2::
1063             wtf8 WTF8::
1064 726748   50 726751 0 4332074 )}->{mb::get_script_encoding()} || die;
1065             }
1066              
1067             #---------------------------------------------------------------------
1068             # substr() for MBCS encoding
1069             BEGIN {
1070 162 50 100 162 0 359622 CORE::eval sprintf <<'END', ($] >= 5.014) ? ':lvalue' : '';
  127 100   3   5402  
  127 100   130   489  
  2 100       7  
  125 50       282  
  16 100       30  
  16 50       25  
  16 100       29  
  101 100       380  
  101 100       333  
  101         280  
  101         574  
  8         20  
  8         48  
1071             # VV------------------------AAAAAAA
1072             sub mb::substr ($$;$$) %s {
1073             my @x = $_[0] =~ /\G$x/g;
1074              
1075             # If the substring is beyond either end of the string, substr() returns the undefined
1076             # value and produces a warning. When used as an lvalue, specifying a substring that
1077             # is entirely outside the string raises an exception.
1078             # http://perldoc.perl.org/functions/substr.html
1079              
1080             # A return with no argument returns the scalar value undef in scalar context,
1081             # an empty list () in list context, and (naturally) nothing at all in void
1082             # context.
1083              
1084             if (($_[1] < (-1 * scalar(@x))) or (+1 * scalar(@x) < $_[1])) {
1085             return;
1086             }
1087              
1088             # substr($string,$offset,$length,$replacement)
1089             if (@_ == 4) {
1090             my $substr = join '', splice @x, $_[1], $_[2], $_[3];
1091             $_[0] = join '', @x;
1092             $substr; # "return $substr" doesn't work, don't write "return"
1093             }
1094              
1095             # substr($string,$offset,$length)
1096             elsif (@_ == 3) {
1097             local $SIG{__WARN__} = sub {}; # avoid: Use of uninitialized value in join or string at here
1098             my $octet_offset =
1099             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
1100             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
1101             0;
1102             my $octet_length =
1103             ($_[2] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[2]+1 .. $#x]) :
1104             ($_[2] > 0) ? CORE::length(join '', @x[$_[1] .. $_[1]+$_[2]-1]) :
1105             0;
1106             CORE::substr($_[0], $octet_offset, $octet_length);
1107             }
1108              
1109             # substr($string,$offset)
1110             else {
1111             my $octet_offset =
1112             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
1113             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
1114             0;
1115             CORE::substr($_[0], $octet_offset);
1116             }
1117             }
1118             END
1119             }
1120              
1121             #---------------------------------------------------------------------
1122             # tr/// and y/// for MBCS encoding
1123             sub mb::tr ($$$;$) {
1124 2530     2533 0 409025 my @x = $_[0] =~ /\G($x)/xmsg;
1125 2530         10148 my @search = list_all_ASCII_by_hyphen($_[1] =~ /\G(\\-|$x)/xmsg);
1126 2530         8465 my @replacement = list_all_ASCII_by_hyphen($_[2] =~ /\G(\\-|$x)/xmsg);
1127 2530 100       6249 my %modifier = (defined $_[3]) ? (map { $_ => 1 } CORE::split //, $_[3]) : ();
  2753         6894  
1128              
1129 2530         3494 my %tr = ();
1130 2530         3888 for (my $i=0; $i <= $#search; $i++) {
1131              
1132             # tr/AAA/123/ works as tr/A/1/
1133 3388 100       5363 if (not exists $tr{$search[$i]}) {
1134              
1135             # tr/ABC/123/ makes %tr = ('A'=>'1','B'=>'2','C'=>'3',);
1136 3328 100 66     8399 if (defined($replacement[$i]) and ($replacement[$i] ne '')) {
    100 66        
    100          
1137 3123         6486 $tr{$search[$i]} = $replacement[$i];
1138             }
1139              
1140             # tr/ABC/12/d makes %tr = ('A'=>'1','B'=>'2','C'=>'',);
1141             elsif (exists $modifier{d}) {
1142 108         178 $tr{$search[$i]} = '';
1143             }
1144              
1145             # tr/ABC/12/ makes %tr = ('A'=>'1','B'=>'2','C'=>'2',);
1146             elsif (defined($replacement[-1]) and ($replacement[-1] ne '')) {
1147 89         149 $tr{$search[$i]} = $replacement[-1];
1148             }
1149              
1150             # tr/ABC// makes %tr = ('A'=>'A','B'=>'B','C'=>'C',);
1151             else {
1152 8         14 $tr{$search[$i]} = $search[$i];
1153             }
1154             }
1155             }
1156              
1157 2530         2564 my $tr = 0;
1158 2530         2392 my $replaced = '';
1159              
1160             # has /c modifier
1161 2530 100       3298 if (exists $modifier{c}) {
1162              
1163             # has /s modifier
1164 126 100       152 if (exists $modifier{s}) {
1165 54         63 my $last_transliterated = undef;
1166 54         82 while (defined(my $x = shift @x)) {
1167              
1168             # /c modifier works here
1169 428 100       430 if (exists $tr{$x}) {
1170 252         252 $replaced .= $x;
1171 252         311 $last_transliterated = undef;
1172             }
1173             else {
1174              
1175             # /d modifier works here
1176 176 100       198 if (exists $modifier{d}) {
    50          
1177             }
1178              
1179             elsif (defined $replacement[-1]) {
1180              
1181             # /s modifier works here
1182 52 100 66     73 if (defined($last_transliterated) and ($replacement[-1] eq $last_transliterated)) {
1183             }
1184              
1185             # tr/// works here
1186             else {
1187 43         42 $replaced .= ($last_transliterated = $replacement[-1]);
1188             }
1189             }
1190 176         224 $tr++;
1191             }
1192             }
1193             }
1194              
1195             # has no /s modifier
1196             else {
1197 72         107 while (defined(my $x = shift @x)) {
1198              
1199             # /c modifier works here
1200 314 100       319 if (exists $tr{$x}) {
1201 210         282 $replaced .= $x;
1202             }
1203             else {
1204              
1205             # /d modifier works here
1206 104 100       133 if (exists $modifier{d}) {
    50          
1207             }
1208              
1209             # tr/// works here
1210             elsif (defined $replacement[-1]) {
1211 70         62 $replaced .= $replacement[-1];
1212             }
1213 104         158 $tr++;
1214             }
1215             }
1216             }
1217             }
1218              
1219             # has no /c modifier
1220             else {
1221              
1222             # has /s modifier
1223 2404 100       2510 if (exists $modifier{s}) {
1224 85         72 my $last_transliterated = undef;
1225 85         142 while (defined(my $x = shift @x)) {
1226 593 100       663 if (exists $tr{$x}) {
1227              
1228             # /d modifier works here
1229 425 100 100     701 if ($tr{$x} eq '') {
    100          
1230             }
1231              
1232             # /s modifier works here
1233             elsif (defined($last_transliterated) and ($tr{$x} eq $last_transliterated)) {
1234             }
1235              
1236             # tr/// works here
1237             else {
1238 159         174 $replaced .= ($last_transliterated = $tr{$x});
1239             }
1240 425         511 $tr++;
1241             }
1242             else {
1243 168         145 $replaced .= $x;
1244 168         211 $last_transliterated = undef;
1245             }
1246             }
1247             }
1248              
1249             # has no /s modifier
1250             else {
1251 2319         3935 while (defined(my $x = shift @x)) {
1252 2749 100       3663 if (exists $tr{$x}) {
1253 2621         3411 $replaced .= $tr{$x};
1254 2621         4611 $tr++;
1255             }
1256             else {
1257 128         168 $replaced .= $x;
1258             }
1259             }
1260             }
1261             }
1262              
1263             # /r modifier works here
1264 2530 100       2998 if (exists $modifier{r}) {
1265 2362         11864 return $replaced;
1266             }
1267              
1268             # has no /r modifier
1269             else {
1270 168         192 $_[0] = $replaced;
1271 168         456 return $tr;
1272             }
1273             }
1274              
1275             #---------------------------------------------------------------------
1276             # universal uc() for MBCS encoding
1277             sub mb::uc (;$) {
1278 54 100   57 1 470 local $_ = @_ ? $_[0] : $_;
1279             # a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
1280 54 100       754 return join '', map { {qw( a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z )}->{$_}||$_ } /\G$x/g;
  1022         6731  
1281             # a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
1282             }
1283              
1284             #---------------------------------------------------------------------
1285             # universal ucfirst() for MBCS encoding
1286             sub mb::ucfirst (;$) {
1287 2 100   5 0 127 local $_ = @_ ? $_[0] : $_;
1288 2 50       53 if (/\A($x)(.*)\z/s) {
1289 2         5 return mb::uc($1) . $2;
1290             }
1291             else {
1292 0         0 return '';
1293             }
1294             }
1295              
1296             ######################################################################
1297             # runtime routines on all operating systems (used automatically)
1298             ######################################################################
1299              
1300             #---------------------------------------------------------------------
1301             # implement of special variable $1,$2,$3,...
1302             sub mb::_CAPTURE (;$) {
1303 90 100   93   780 if ($mb::last_s_passed) {
1304 29 50       47 if (defined $_[0]) {
1305              
1306             # $1 is used for multi-byte anchoring
1307 29         1357 return CORE::eval('$' . ($_[0] + 1));
1308             }
1309             else {
1310 0         0 my @capture = ();
1311 0 0       0 if ($] >= 5.006) {
1312              
1313             # $1 is used for multi-byte anchoring in s///
1314 0         0 push @capture, map { CORE::eval('$'.$_) } 2 .. CORE::eval('$#-');
  0         0  
1315             }
1316             else {
1317              
1318             # @{^CAPTURE} doesn't work enough in perl 5.005
1319 0         0 for (my $n_th=2; defined(CORE::eval('$'.$n_th)); $n_th++) {
1320 0         0 push @capture, CORE::eval('$'.$n_th);
1321             }
1322             }
1323 0         0 return @capture;
1324             }
1325             }
1326             else {
1327 61 50       102 if (defined $_[0]) {
1328 61         3462 return CORE::eval('$' . $_[0]);
1329             }
1330             else {
1331 0         0 my @capture = ();
1332 0 0       0 if ($] >= 5.006) {
1333 0         0 push @capture, map { CORE::eval('$'.$_) } 1 .. CORE::eval('$#-');
  0         0  
1334             }
1335             else {
1336              
1337             # @{^CAPTURE} doesn't work enough in perl 5.005
1338 0         0 for (my $n_th=1; defined(CORE::eval('$'.$n_th)); $n_th++) {
1339 0         0 push @capture, CORE::eval('$'.$n_th);
1340             }
1341             }
1342 0         0 return @capture;
1343             }
1344             }
1345             }
1346              
1347             #---------------------------------------------------------------------
1348             # implement of special variable @+
1349             sub mb::_LAST_MATCH_END (@) {
1350              
1351             # perl 5.005 does not support @+, so it need CORE::eval
1352              
1353 10 100   13   32 if ($mb::last_s_passed) {
1354 5 50       8 if (scalar(@_) >= 1) {
1355 5         237 return CORE::eval q{ ($+[0], @+[2..$#-])[ @_ ] };
1356             }
1357             else {
1358 0         0 return CORE::eval q{ ($+[0], @+[2..$#-]) };
1359             }
1360             }
1361             else {
1362 5 50       11 if (scalar(@_) >= 1) {
1363 5         201 return CORE::eval q{ @+[ @_ ] };
1364             }
1365             else {
1366 0         0 return CORE::eval q{ @+ };
1367             }
1368             }
1369             }
1370              
1371             #---------------------------------------------------------------------
1372             # implement of special variable @-
1373             sub mb::_LAST_MATCH_START (@) {
1374              
1375             # perl 5.005 does not support @-, so it need CORE::eval
1376              
1377 18 100   21   32 if ($mb::last_s_passed) {
1378 9 50       12 if (scalar(@_) >= 1) {
1379 9         430 return CORE::eval q{ ($-[2], @-[2..$#-])[ @_ ] };
1380             }
1381             else {
1382 0         0 return CORE::eval q{ ($-[2], @-[2..$#-]) };
1383             }
1384             }
1385             else {
1386 9 50       14 if (scalar(@_) >= 1) {
1387 9         407 return CORE::eval q{ @-[ @_ ] };
1388             }
1389             else {
1390 0         0 return CORE::eval q{ @- };
1391             }
1392             }
1393             }
1394              
1395             #---------------------------------------------------------------------
1396             # implement of special variable $&
1397             sub mb::_MATCH () {
1398 61 50   64   576 if (defined $&) {
1399 61 100       106 if ($mb::last_s_passed) {
1400 8 50 33     48 if (defined($1) and (CORE::substr($&, 0, CORE::length($1)) eq $1)) {
1401 8         108 return CORE::substr($&, CORE::length($1));
1402             }
1403             else {
1404 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1405             }
1406             }
1407             else {
1408 53 50 33     272 if (defined($1) and (CORE::substr($&, -CORE::length($1)) eq $1)) {
1409 53         1065 return $1;
1410             }
1411             else {
1412 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1413             }
1414             }
1415             }
1416             else {
1417 0         0 return '';
1418             }
1419             }
1420              
1421             #---------------------------------------------------------------------
1422             # implement of special variable $`
1423             sub mb::_PREMATCH () {
1424 15 50   18   132 if (defined $&) {
1425 15 100       22 if ($mb::last_s_passed) {
1426 8         147 return $1;
1427             }
1428             else {
1429 7 50 33     41 if (defined($1) and (CORE::substr($&,-CORE::length($1)) eq $1)) {
1430 7         101 return CORE::substr($&, 0, -CORE::length($1));
1431             }
1432             else {
1433 0         0 confess 'Use of "$`", $PREMATCH, and ${^PREMATCH} need to /( capture all )/ in regexp';
1434             }
1435             }
1436             }
1437             else {
1438 0         0 return '';
1439             }
1440             }
1441              
1442             #---------------------------------------------------------------------
1443             # flag off if last m// was pass
1444             sub mb::_m_passed () {
1445 126822     126825   580532 $mb::last_s_passed = 0;
1446 126822         24591931 return '';
1447             }
1448              
1449             #---------------------------------------------------------------------
1450             # flag on if last s/// was pass
1451             sub mb::_s_passed () {
1452 85     88   117311 $mb::last_s_passed = 1;
1453 85         8282 return '';
1454             }
1455              
1456             #---------------------------------------------------------------------
1457             # ignore space of m/[here]/xx, qr/[here]/xx, s/[here]//xx
1458             sub mb::_ignore_space ($) {
1459 33     36   37 my($has_space) = @_;
1460 33         39 my $has_no_space = '';
1461              
1462             # parse into elements
1463 33         405 while ($has_space =~ /\G (
1464             \(\? \^? [a-z]* [:\)] | # cloister (?^x) (?^x: ...
1465             \(\? \^? [a-z]*-[a-z]+ [:\)] | # cloister (?^x-y) (?^x-y: ...
1466             \[ ((?: \\@{mb::_dot} | @{mb::_dot} )+?) \] |
1467             \\x\{ [0-9A-Fa-f]{2} \} |
1468             \\o\{ [0-7]{3} \} |
1469             \\x [0-9A-Fa-f]{2} |
1470             \\ [0-7]{3} |
1471             \\@{mb::_dot} |
1472             @{mb::_dot}
1473             ) /xmsgc) {
1474 424         555 my($element, $classmate) = ($1, $2);
1475              
1476             # in codepoint class
1477 424 100       393 if (defined $classmate) {
1478 33         32 $has_no_space .= '[';
1479 33         231 while ($classmate =~ /\G (
1480             \\x\{ [0-9A-Fa-f]{2} \} |
1481             \\o\{ [0-7]{3} \} |
1482             \\x [0-9A-Fa-f]{2} |
1483             \\ [0-7]{3} |
1484             \\@{mb::_dot} |
1485             @{mb::_dot}
1486             ) /xmsgc) {
1487 693         777 my $element = $1;
1488 693 100       1527 if ($element !~ /\A[$bare_s]\z/) {
1489 559         1699 $has_no_space .= $element;
1490             }
1491             }
1492 33         172 $has_no_space .= ']';
1493             }
1494              
1495             # out of codepoint class
1496             else {
1497 391         1797 $has_no_space .= $element;
1498             }
1499             }
1500 33         58 return $has_no_space;
1501             }
1502              
1503             #---------------------------------------------------------------------
1504             # ignore case of m//i, qr//i, s///i
1505             sub mb::_ignorecase ($) {
1506 64     67   439 my($has_case) = @_;
1507 64         78 my $has_no_case = '';
1508              
1509             # parse into elements
1510 64         1722 while ($has_case =~ /\G (
1511             \(\? \^? [a-z]* [:\)] | # cloister (?^x) (?^x: ...
1512             \(\? \^? [a-z]*-[a-z]+ [:\)] | # cloister (?^x-y) (?^x-y: ...
1513             \[ ((?: \\@{mb::_dot} | @{mb::_dot} )+?) \] |
1514             \\x\{ [0-9A-Fa-f]{2} \} |
1515             \\o\{ [0-7]{3} \} |
1516             \\x [0-9A-Fa-f]{2} |
1517             \\ [0-7]{3} |
1518             \\@{mb::_dot} |
1519             @{mb::_dot}
1520             ) /xmsgc) {
1521 512         820 my($element, $classmate) = ($1, $2);
1522              
1523             # in codepoint class
1524 512 100       527 if (defined $classmate) {
1525 60         50 $has_no_case .= '[';
1526 60         272 while ($classmate =~ /\G (
1527             \\x\{ [0-9A-Fa-f]{2} \} |
1528             \\o\{ [0-7]{3} \} |
1529             \\x [0-9A-Fa-f]{2} |
1530             \\ [0-7]{3} |
1531             \\@{mb::_dot} |
1532             @{mb::_dot}
1533             ) /xmsgc) {
1534 192         196 my $element = $1;
1535             $has_no_case .= {qw(
1536             A Aa a Aa
1537             B Bb b Bb
1538             C Cc c Cc
1539             D Dd d Dd
1540             E Ee e Ee
1541             F Ff f Ff
1542             G Gg g Gg
1543             H Hh h Hh
1544             I Ii i Ii
1545             J Jj j Jj
1546             K Kk k Kk
1547             L Ll l Ll
1548             M Mm m Mm
1549             N Nn n Nn
1550             O Oo o Oo
1551             P Pp p Pp
1552             Q Qq q Qq
1553             R Rr r Rr
1554             S Ss s Ss
1555             T Tt t Tt
1556             U Uu u Uu
1557             V Vv v Vv
1558             W Ww w Ww
1559             X Xx x Xx
1560             Y Yy y Yy
1561             Z Zz z Zz
1562 192   66     3159 )}->{$element} || $element;
1563             }
1564 60         299 $has_no_case .= ']';
1565             }
1566              
1567             # out of codepoint class
1568             else {
1569             $has_no_case .= {qw(
1570             A [Aa] a [Aa]
1571             B [Bb] b [Bb]
1572             C [Cc] c [Cc]
1573             D [Dd] d [Dd]
1574             E [Ee] e [Ee]
1575             F [Ff] f [Ff]
1576             G [Gg] g [Gg]
1577             H [Hh] h [Hh]
1578             I [Ii] i [Ii]
1579             J [Jj] j [Jj]
1580             K [Kk] k [Kk]
1581             L [Ll] l [Ll]
1582             M [Mm] m [Mm]
1583             N [Nn] n [Nn]
1584             O [Oo] o [Oo]
1585             P [Pp] p [Pp]
1586             Q [Qq] q [Qq]
1587             R [Rr] r [Rr]
1588             S [Ss] s [Ss]
1589             T [Tt] t [Tt]
1590             U [Uu] u [Uu]
1591             V [Vv] v [Vv]
1592             W [Ww] w [Ww]
1593             X [Xx] x [Xx]
1594             Y [Yy] y [Yy]
1595             Z [Zz] z [Zz]
1596 452   66     9146 )}->{$element} || $element;
1597             }
1598             }
1599 64         618 return qr{$has_no_case};
1600             }
1601              
1602             #---------------------------------------------------------------------
1603             # custom codepoint class in qq-like regular expression
1604             sub mb::_cc ($) {
1605 126590     126593   1002532 my($classmate) = @_;
1606 126590 100       315766 if ($classmate =~ s{\A \^ }{}xms) {
1607 63125         121633 return '(?:(?!' . parse_re_codepoint_class($classmate) . ")$x)";
1608             }
1609             else {
1610 63465         119548 return '(?:(?=' . parse_re_codepoint_class($classmate) . ")$x)";
1611             }
1612             }
1613              
1614             #---------------------------------------------------------------------
1615             # makes clustered codepoint from string
1616             sub mb::_clustered_codepoint ($) {
1617 22 100   25   198 if (my @codepoint = $_[0] =~ /\G($x)/xmsgc) {
1618 10 100       20 if (CORE::length($codepoint[$#codepoint]) == 1) {
1619 5         81 return $_[0];
1620             }
1621             else {
1622 5         105 return join '', @codepoint[ 0 .. $#codepoint-1 ], "(?:$codepoint[$#codepoint])";
1623             }
1624             }
1625             else {
1626 12         217 return '';
1627             }
1628             }
1629              
1630             #---------------------------------------------------------------------
1631             # open for append -- returns glob-name string on success, "" on failure.
1632             # Works on Perl 5.005_03 and all later versions.
1633             # Always uses a unique numbered package glob (mb::FH::H) so that
1634             # concurrent callers each get their own IO slot.
1635             sub mb::_open_a ($) {
1636 0     3   0 $mb::_fh_seq++;
1637 0         0 my $fhn = "mb::FH::H$mb::_fh_seq";
1638 162 0   162   1166 { no strict 'refs'; open($fhn, ">> $_[0]") or return "" }
  162         353  
  162         15951  
  0         0  
  0         0  
1639 0         0 return $fhn;
1640             }
1641              
1642             #---------------------------------------------------------------------
1643             # open for read -- returns glob-name string on success, "" on failure.
1644             sub mb::_open_r ($) {
1645 15     18   20 $mb::_fh_seq++;
1646 15         33 my $fhn = "mb::FH::H$mb::_fh_seq";
1647 162 50   162   762 { no strict 'refs'; open($fhn, "< $_[0]") or return "" }
  162         311  
  162         14124  
  15         18  
  15         679  
1648 15         60 return $fhn;
1649             }
1650              
1651             #---------------------------------------------------------------------
1652             # open for write -- returns glob-name string on success, "" on failure.
1653             sub mb::_open_w ($) {
1654 10     13   14 $mb::_fh_seq++;
1655 10         20 my $fhn = "mb::FH::H$mb::_fh_seq";
1656 162 50   162   701 { no strict 'refs'; open($fhn, "> $_[0]") or return "" }
  162         363  
  162         4736181  
  10         11  
  10         940  
1657 10         45 return $fhn;
1658             }
1659              
1660             #---------------------------------------------------------------------
1661             # split() runtime function (UTF8::R2 compatible)
1662             #
1663             # This is the runtime entry point that a path-3 user calls directly as
1664             # mb::split(...). It mirrors UTF8::R2::split so that scripts ported from the
1665             # UTF8::R2 environment behave identically. The transpiler does NOT use this;
1666             # transpiled "split" is rewritten to mb::_split() below, which is a separate,
1667             # more elaborate implementation tuned for the filter/modulino paths.
1668             #
1669             # Note: mb::qr() returns a plain regular-expression STRING (not a qr// object,
1670             # which matters on perl 5.005_03; see _r2_qr), so the pattern is interpolated
1671             # into a fresh qr{...} before it is handed to CORE::split.
1672             sub mb::split (;$$$) {
1673 56 100 100 59 0 925 if (defined($_[0]) and (($_[0] eq '') or ($_[0] =~ /\A \( \? \^? [-a-z]* : \) \z/x))) {
    100 66        
    50          
    0          
1674 38 100       390 my @x = (defined($_[1]) ? $_[1] : $_) =~ /\G$x/g;
1675 38 100 100     77 if (defined($_[2]) and ($_[2] > 0) and (scalar(@x) > $_[2])) {
      100        
1676 12         36 @x = (@x[0..$_[2]-1-1], join('', @x[$_[2]-1..$#x]));
1677             }
1678 38 100       44 if (wantarray) {
1679 26         61 return @x;
1680             }
1681             else {
1682 12 50       15 if ($] < 5.012) {
1683 0 0       0 warn "Use of implicit split to \@_ is deprecated" if $^W;
1684 0         0 @_ = @x; # unlike camel book and perldoc saying, can return only scalar(@_), cannot @_
1685             }
1686 12         19 return scalar @x;
1687             }
1688             }
1689             elsif (@_ == 3) {
1690 12         10 return CORE::split qr{@{[mb::qr($_[0])]}}, $_[1], $_[2];
  12         24  
1691             }
1692             elsif (@_ == 2) {
1693 6         8 return CORE::split qr{@{[mb::qr($_[0])]}}, $_[1];
  6         10  
1694             }
1695             elsif (@_ == 1) {
1696 0         0 return CORE::split qr{@{[mb::qr($_[0])]}};
  0         0  
1697             }
1698             else {
1699 0         0 return CORE::split;
1700             }
1701             }
1702              
1703             #---------------------------------------------------------------------
1704             # split() for MBCS encoding
1705             sub mb::_split (;$$$) {
1706 336 100   339   9328 my $pattern = defined($_[0]) ? $_[0] : ' ';
1707 336 100       650 my $string = defined($_[1]) ? $_[1] : $_;
1708 336         449 my @split = ();
1709              
1710             # split's first argument is more consistently interpreted
1711             #
1712             # After some changes earlier in v5.17, split's behavior has been simplified:
1713             # if the PATTERN argument evaluates to a string containing one space, it is
1714             # treated the way that a literal string containing one space once was.
1715             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#split's_first_argument_is_more_consistently_interpreted
1716             # if $pattern is also omitted or is the literal space, " ", the function splits
1717             # on whitespace, /\s+/, after skipping any leading whitespace
1718              
1719 336 100       725 if ($pattern eq ' ') {
1720 108         313 $pattern = qr/\s+/;
1721 108         367 $string =~ s{\A \s+ }{}xms;
1722             }
1723              
1724             # count '(' in pattern
1725 336         418 my @parsed = ();
1726 336         455 my $modifier = '';
1727 336 100 100     2497 if ((($modifier) = $pattern =~ /\A \(\?\^? (.+?) [\)\-\:] /xms) and ($modifier =~ /x/xms)) {
1728 34         1194 @parsed = $pattern =~ m{ \G (
1729             \\ $x |
1730             \# .*? $ | # comment on /x modifier
1731             \(\?\# (?:$x)*? \) |
1732             \[ (?:$x)+? \] |
1733             \(\? |
1734             \(\+ |
1735             \(\* |
1736             $x |
1737             [\x00-\xFF]
1738             ) }xgc;
1739             }
1740             else {
1741 302         4462 @parsed = $pattern =~ m{ \G (
1742             \\ $x |
1743             \(\?\# (?:$x)*? \) |
1744             \[ (?:$x)+? \] |
1745             \(\? |
1746             \(\+ |
1747             \(\* |
1748             $x |
1749             [\x00-\xFF]
1750             ) }xgc;
1751             }
1752             my $last_match_no =
1753             1 + # first '(' is for substring
1754 336         703 scalar(grep { $_ eq '(' } @parsed); # other '(' are for pattern of split()
  2398         3221  
1755              
1756             # Repeated Patterns Matching a Zero-length Substring
1757             # https://perldoc.perl.org/perlre.html#Repeated-Patterns-Matching-a-Zero-length-Substring
1758 336 100       2808 my $substring_quantifier = ('' =~ / \A $pattern \z /xms) ? '+?' : '*?';
1759              
1760             # if $_[2] specified and positive
1761 336 100 100     825 if (defined($_[2]) and ($_[2] >= 1)) {
1762 21         26 my $limit = $_[2];
1763              
1764 21         1487 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
1765              
1766             # gets substrings by repeat chopping by pattern
1767 21   100     578 while ((--$limit > 0) and ($string =~ s<\A((?:$x)$substring_quantifier)$pattern><>)) {
1768 42         101 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1769 42         1720 push @split, CORE::eval('$'.$n_th);
1770             }
1771             }
1772             }
1773              
1774             # if $_[2] is omitted or zero or negative
1775             else {
1776 315     5   20609 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
  5     5   35  
  5         8  
  5         212  
  5         31  
  5         6  
  5         195  
1777              
1778             # gets substrings by repeat chopping by pattern
1779 315         9053 while ($string =~ s<\A((?:$x)$substring_quantifier)$pattern><>) {
1780 740         1793 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1781 792         30816 push @split, CORE::eval('$'.$n_th);
1782             }
1783             }
1784             }
1785              
1786             # get last substring
1787 336 100 100     821 if (CORE::length($string) > 0) {
    100          
1788 303         463 push @split, $string;
1789             }
1790             elsif (defined($_[2]) and ($_[2] >= 1)) {
1791 6 50       14 if (scalar(@split) < $_[2]) {
1792 6         16 push @split, ('') x ($_[2] - scalar(@split));
1793             }
1794             }
1795              
1796             # if $_[2] is omitted or zero, trailing null fields are stripped from the result
1797 336 100 100     835 if ((not defined $_[2]) or ($_[2] == 0)) {
1798 309   33     1182 while ((scalar(@split) >= 1) and ($split[-1] eq '')) {
1799 0         0 pop @split;
1800             }
1801             }
1802              
1803             # old days, split had write its result to @_ on scalar context,
1804             # but this usage is no longer supported
1805              
1806 336 100       534 if (wantarray) {
1807 203         1285 return @split;
1808             }
1809             else {
1810 133         672 return scalar @split;
1811             }
1812             }
1813              
1814             ######################################################################
1815             # runtime routines for MSWin32 (used automatically)
1816             ######################################################################
1817              
1818             #---------------------------------------------------------------------
1819             # chdir() for MSWin32
1820             sub mb::_chdir (;$) {
1821              
1822             # not on MSWin32 or UTF-8
1823 2 50 33 5   13 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | informixv6als | hp15 | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1824 2 50       4 if (@_ == 0) {
1825 0         0 return CORE::chdir;
1826             }
1827             else {
1828 2         39 return CORE::chdir $_[0];
1829             }
1830             }
1831              
1832             # on MSWin32
1833 0 0 0     0 if (@_ == 0) {
    0 0        
    0 0        
    0          
1834 0         0 return CORE::chdir;
1835             }
1836             elsif (($script_encoding =~ /\A (?: sjis | informixv6als ) \z/xms) and ($_[0] =~ /\A $x* [\x81-\x9F\xE0-\xFC][\x5C] \z/xms)) {
1837 0 0       0 if (defined wantarray) {
1838 0         0 return 0;
1839             }
1840             else {
1841 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1842             }
1843             }
1844             elsif (($script_encoding =~ /\A (?: hp15 ) \z/xms) and ($_[0] =~ /\A $x* [\x80-\xA0\xE0-\xFE][\x5C] \z/xms)) {
1845 0 0       0 if (defined wantarray) {
1846 0         0 return 0;
1847             }
1848             else {
1849 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1850             }
1851             }
1852             elsif (($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and ($_[0] =~ /\A $x* [\x81-\xFE][\x5C] \z/xms)) {
1853 0 0       0 if (defined wantarray) {
1854 0         0 return 0;
1855             }
1856             else {
1857 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1858             }
1859             }
1860             else {
1861 0         0 return CORE::chdir $_[0];
1862             }
1863             }
1864              
1865             #---------------------------------------------------------------------
1866             # stackable filetest -X -Y -Z for MSWin32
1867             sub mb::_filetest {
1868 11209     11212   51084 my @filetest = map { /(-[A-Za-z])/g } @{ shift(@_) };
  11217         53636  
  11209         23976  
1869 11209 0       21878 local $_ = @_ ? shift : (($filetest[-1] eq '-t') ? \*STDIN : $_);
    50          
1870 11209 50 33     19263 confess "Too many arguments for filetest @filetest" if @_ and not wantarray;
1871              
1872             # testee has "\x5C" octet at end
1873 11209 0 33     17837 if (
      33        
1874             ($OSNAME =~ /MSWin32/) and
1875             ($script_encoding =~ /\A (?: sjis | informixv6als | hp15 | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and
1876             /[\x5C]\z/
1877             ) {
1878 0         0 $_ = qq{$_.};
1879             }
1880              
1881             # supports stackable filetest
1882 11209         10486 my $result;
1883 11209         15044 my $filetest = pop @filetest;
1884 11209 100       471285 if ($result = CORE::eval($filetest . ' $_')) { # '$_' at 1st time, and ...
1885             }
1886             else {
1887 2043 50       22154 return wantarray ? ($result, @_) : $result;
1888             }
1889 9166         35010 for my $filetest (CORE::reverse @filetest) {
1890 7 50       225 if ($result = CORE::eval($filetest . ' _')) { # '_' at 2nd time or later
1891             }
1892             else {
1893 0 0       0 return wantarray ? ($result, @_) : $result;
1894             }
1895             }
1896 9166 50       82444 return wantarray ? ($result, @_) : $result;
1897             }
1898              
1899             #---------------------------------------------------------------------
1900             # lstat() for MSWin32
1901             sub mb::_lstat (;$) {
1902 3 50   6   48 local $_ = @_ ? $_[0] : $_;
1903 3 50       5 if ($_ eq '_') {
1904 0         0 confess qq{lstat doesn't support '_'\n};
1905             }
1906              
1907             # testee has "\x5C" octet at end
1908 3 0 33     7 if (
      33        
1909             ($OSNAME =~ /MSWin32/) and
1910             ($script_encoding =~ /\A (?: sjis | informixv6als | hp15 | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and
1911             /[\x5C]\z/
1912             ) {
1913 0         0 $_ = qq{$_.};
1914             }
1915              
1916 3         34 return CORE::lstat $_;
1917             }
1918              
1919             #---------------------------------------------------------------------
1920             # opendir() for MSWin32
1921             sub mb::_opendir ($$) {
1922 7 100   10   45 if (not defined $_[0]) {
1923 3         3 $_[0] = \do { local *_ };
  3         11  
1924             }
1925              
1926             # works on MSWin32 only
1927 7 50 33     18 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | informixv6als | hp15 | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
    0          
    0          
1928 7         197 return CORE::opendir $_[0], $_[1];
1929             }
1930             elsif (-d $_[1]) {
1931 0         0 return CORE::opendir $_[0], $_[1];
1932             }
1933             elsif (-d qq{$_[1].}) {
1934 0         0 return CORE::opendir $_[0], qq{$_[1].};
1935             }
1936 0         0 return undef;
1937             }
1938              
1939             #---------------------------------------------------------------------
1940             # stat() for MSWin32
1941             sub mb::_stat (;$) {
1942 9 50   12   238 local $_ = @_ ? $_[0] : $_;
1943              
1944             # testee has "\x5C" octet at end
1945 9 0 33     23 if (
      33        
1946             ($OSNAME =~ /MSWin32/) and
1947             ($script_encoding =~ /\A (?: sjis | informixv6als | hp15 | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and
1948             /[\x5C]\z/
1949             ) {
1950 0         0 $_ = qq{$_.};
1951             }
1952              
1953 9         58 return CORE::stat $_;
1954             }
1955              
1956             #---------------------------------------------------------------------
1957             # unlink() for MSWin32
1958             sub mb::_unlink (@) {
1959              
1960             # works on MSWin32 only
1961 10222 50 33 10225   57348 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | informixv6als | hp15 | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1962 10222 50       630196 return CORE::unlink(@_ ? @_ : $_);
1963             }
1964              
1965 0         0 my $unlink = 0;
1966 0 0       0 for (@_ ? @_ : $_) {
1967 0 0       0 if (CORE::unlink) {
    0          
1968 0         0 $unlink++;
1969             }
1970             elsif (CORE::unlink qq{$_.}) {
1971 0         0 $unlink++;
1972             }
1973             }
1974 0         0 return $unlink;
1975             }
1976              
1977             ######################################################################
1978             # source code filter
1979             ######################################################################
1980              
1981             #---------------------------------------------------------------------
1982             # detect system encoding any of big5, big5hkscs, eucjp, euctw, gb18030, gbk, sjis, uhc, utf8
1983             # (hp15, informixv6als, rfc2279, and wtf8 are never auto-detected: no operating
1984             # system ships a system locale under those names; rfc2279/wtf8 scripts run
1985             # under the utf8 default, hp15/informixv6als must be selected with -e)
1986             sub detect_system_encoding {
1987              
1988             # running on Microsoft Windows
1989 196 50   199 0 1266 if ($OSNAME =~ /MSWin32/) {
    100          
    100          
    100          
1990 0 0       0 if (my($codepage) = qx{chcp} =~ m/[^0123456789](932|936|949|950|951|20932|54936)\Z/) {
1991              
1992             # "Code Page Identifiers" (Microsoft Learn)
1993             # https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
1994             return {
1995             '932' => 'sjis', # ANSI/OEM Japanese; Japanese (Shift-JIS)
1996             '936' => 'gbk', # ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312), GBK since Windows 95
1997             '949' => 'uhc', # ANSI/OEM Korean (Unified Hangul Code)
1998             '950' => 'big5', # ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
1999             '951' => 'big5hkscs', # Big5-HKSCS variant of 950 installed by the HKSCS support update; not listed on the Code Page Identifiers page
2000             '20932' => 'eucjp', # Japanese (JIS 0208-1990 and 0212-1990), EUC-JP
2001             '54936' => 'gb18030', # Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
2002 0         0 }->{$codepage};
2003             }
2004             else {
2005 0         0 return 'utf8';
2006             }
2007             }
2008              
2009             # running on Oracle Solaris
2010             elsif ($OSNAME =~ /solaris/) {
2011             my $LANG =
2012             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
2013             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
2014 10 50       33 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    100          
2015             '';
2016              
2017             # "International Language Environments Guide" (Solaris 9), Chapter 4 Supported Asian Locales
2018             # https://docs.oracle.com/cd/E19683-01/806-6642/new-27777/index.html
2019             # "International Language Environments Guide for Oracle Solaris 11.3"
2020             # https://docs.oracle.com/cd/E53394_01/pdf/E54757.pdf
2021             # "Chinese: Simplified and Traditional" (Solaris 7)
2022             # https://docs.oracle.com/cd/E19620-01/805-4123/new-71/index.html
2023             return {
2024             'ja_JP.PCK' => 'sjis', # PC-Kanji code (known as Shift_JIS), Solaris 9 ILE guide
2025             'ja' => 'eucjp', # Japanese EUC, traditional specification, Solaris 9 ILE guide
2026             'japanese' => 'eucjp', # Japanese EUC, legacy SunOS 4.x alias of ja (no surviving official manual)
2027             'ja_JP.eucJP' => 'eucjp', # Japanese EUC, UI-OSF Ver 1.1, Solaris 9 ILE guide
2028             'zh' => 'gbk', # EUC-encoded GB2312-80, handled as its GBK superset, Solaris 9 ILE guide
2029             'zh.GBK' => 'gbk', # GBK codeset, Solaris 9 ILE guide
2030             'zh_CN.GBK' => 'gbk', # GBK codeset, Solaris 11.3 ILE guide
2031             'zh_CN.EUC' => 'gbk', # EUC-encoded GB2312, handled as its GBK superset, Solaris 11.3 ILE guide
2032             'zh_CN.GB18030' => 'gb18030', # GB18030-2000 codeset, Solaris 9 9/04 and later
2033             'ko' => 'uhc', # EUC-encoded KS X 1001, handled as its UHC superset, Solaris 9 ILE guide
2034             'ko_KR.EUC' => 'uhc', # EUC-encoded KS X 1001, handled as its UHC superset, Solaris 11.3 ILE guide
2035             'zh_TW' => 'euctw', # EUC-encoded CNS 11643.1992 codeset, Solaris 7 guide
2036             'zh_TW.EUC' => 'euctw', # EUC-encoded CNS11643.1992 codeset, Solaris 9 and 11.3 ILE guides
2037             'zh_TW.BIG5' => 'big5', # Big5 codeset, Solaris 9 and 11.3 ILE guides
2038             'zh_HK.BIG5HK' => 'big5hkscs', # Big5-HKSCS codeset, Solaris 9 and 11.3 ILE guides
2039 10   100     77 }->{$LANG} || 'utf8';
2040             }
2041              
2042             # running on HP HP-UX
2043             elsif ($OSNAME =~ /hpux/) {
2044             my $LANG =
2045             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
2046             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
2047 8 50       17 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    100          
2048             '';
2049              
2050             # "Configuring HP-UX for Different Languages" (UXL10N-90302), Appendix A Locale Names
2051             # https://community.hpe.com/hpeb/attachments/hpeb/itrc-156/211158/1/198250.pdf
2052             return {
2053             'japanese' => 'sjis', # legacy pre-11.0 HP-UX locale name (no surviving official manual)
2054             'ja_JP.SJIS' => 'sjis', # Shift-JIS, UXL10N-90302 Table A-1
2055             'japanese.euc' => 'eucjp', # legacy pre-11.0 HP-UX locale name (no surviving official manual)
2056             'ja_JP.eucJP' => 'eucjp', # Japanese EUC, UXL10N-90302 Table A-1
2057             'zh_CN.hp15CN' => 'gbk', # HP-15CN Simplified Chinese, handled as GBK, UXL10N-90302 Table A-1
2058             'zh_CN.gb18030' => 'gb18030', # GB18030, HP-UX 11i (patch PHCO_26453 and later, in 11.31 locale -a)
2059             'ko_KR.eucKR' => 'uhc', # Korean EUC, handled as its UHC superset, UXL10N-90302 Table A-1
2060             'zh_TW.eucTW' => 'euctw', # Taiwanese EUC, UXL10N-90302 Table A-1
2061             'zh_TW.big5' => 'big5', # Big5, UXL10N-90302 Table A-1
2062             'zh_HK.big5' => 'big5hkscs', # kept for compatibility (not in UXL10N-90302; HP-UX ships zh_HK.hkbig5)
2063             'zh_HK.hkbig5' => 'big5hkscs', # Big5-HKSCS, HP-UX 11i (patch PHCO_26453 and later, in 11.31 locale -a)
2064 8   100     50 }->{$LANG} || 'utf8';
2065             }
2066              
2067             # running on IBM AIX
2068             elsif ($OSNAME =~ /aix/) {
2069             my $LANG =
2070             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
2071             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
2072 8 50       21 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    100          
2073             '';
2074              
2075             # "Supported languages and locales" (IBM AIX documentation)
2076             # https://www.ibm.com/docs/en/aix/7.2.0?topic=globalization-supported-languages-locales
2077             # (the language / territory / code set / locale table; AIX locale
2078             # lookups are case-sensitive: zh_* is EUC, Zh_* is the PC code set)
2079             return {
2080             'Ja_JP' => 'sjis', # code set IBM-943 (Shift-JIS)
2081             'Ja_JP.IBM-943' => 'sjis', # code set IBM-943 (Shift-JIS)
2082             'ja_JP' => 'eucjp', # code set IBM-eucJP
2083             'ja_JP.IBM-eucJP' => 'eucjp', # code set IBM-eucJP
2084             'zh_CN' => 'gbk', # code set IBM-eucCN, handled as its GBK superset
2085             'zh_CN.IBM-eucCN' => 'gbk', # code set IBM-eucCN, handled as its GBK superset
2086             'Zh_CN' => 'gb18030', # code set GB18030
2087             'Zh_CN.GB18030' => 'gb18030', # code set GB18030
2088             'ko_KR' => 'uhc', # code set IBM-eucKR, handled as its UHC superset
2089             'ko_KR.IBM-eucKR' => 'uhc', # code set IBM-eucKR, handled as its UHC superset
2090             'zh_TW' => 'euctw', # code set IBM-eucTW
2091             'zh_TW.IBM-eucTW' => 'euctw', # code set IBM-eucTW
2092             'Zh_TW' => 'big5', # code set big5
2093             'Zh_TW.big-5' => 'big5', # code set big5
2094             'Zh_HK' => 'big5hkscs', # code set BIG5-HKSCS
2095             'Zh_HK.BIG5-HKSCS' => 'big5hkscs', # code set BIG5-HKSCS
2096 8   100     53 }->{$LANG} || 'utf8';
2097             }
2098              
2099             # running on Other Systems
2100             else {
2101             my $LANG =
2102             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
2103             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
2104 170 100       918 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    50          
2105             '';
2106              
2107             # GNU libc localedata/SUPPORTED (locale/codeset list for Linux and other glibc systems)
2108             # https://github.com/bminor/glibc/blob/master/localedata/SUPPORTED
2109             # (a bare zh_TW is intentionally NOT mapped here: it is Big5 on glibc
2110             # but EUC-encoded CNS 11643 on the Solaris lineage, so guessing
2111             # either encoding on an unknown system would be wrong half the time)
2112             return {
2113             'japanese' => 'sjis', # legacy vendor UNIX locale name (no surviving official manual)
2114             'ja_JP.SJIS' => 'sjis', # Shift-JIS (shipped by some glibc distributions and HP-UX)
2115             'ja_JP.mscode' => 'sjis', # legacy vendor UNIX locale name (no surviving official manual)
2116             'ja' => 'eucjp', # Japanese EUC, Solaris-style short name
2117             'japan' => 'eucjp', # legacy vendor UNIX locale name (no surviving official manual)
2118             'japanese.euc' => 'eucjp', # legacy vendor UNIX locale name (no surviving official manual)
2119             'Japanese-EUC' => 'eucjp', # legacy vendor UNIX locale name (no surviving official manual)
2120             'ja_JP' => 'eucjp', # Japanese EUC, glibc SUPPORTED: ja_JP/EUC-JP
2121             'ja_JP.ujis' => 'eucjp', # Japanese EUC, legacy alias (ujis)
2122             'ja_JP.eucJP' => 'eucjp', # Japanese EUC, HP-UX/Solaris-style spelling
2123             'ja_JP.EUC-JP' => 'eucjp', # Japanese EUC, glibc SUPPORTED: ja_JP.EUC-JP/EUC-JP
2124             'ja_JP.AJEC' => 'eucjp', # Japanese EUC, legacy vendor UNIX locale name (no surviving official manual)
2125             'ja_JP.EUC' => 'eucjp', # Japanese EUC, legacy vendor UNIX locale name (no surviving official manual)
2126             'Jp_JP' => 'eucjp', # legacy vendor UNIX locale name (no surviving official manual)
2127             'zh_CN' => 'gbk', # glibc SUPPORTED: zh_CN/GB2312, handled as its GBK superset
2128             'zh_CN.EUC' => 'gbk', # EUC-encoded GB2312, handled as its GBK superset
2129             'zh_CN.GB2312' => 'gbk', # GB2312, handled as its GBK superset
2130             'zh_CN.GBK' => 'gbk', # glibc SUPPORTED: zh_CN.GBK/GBK
2131             'zh_CN.hp15CN' => 'gbk', # HP-15CN Simplified Chinese, handled as GBK (HP-UX name, UXL10N-90302 Table A-1)
2132             'zh_SG' => 'gbk', # glibc SUPPORTED: zh_SG/GB2312, handled as its GBK superset
2133             'zh_SG.GBK' => 'gbk', # glibc SUPPORTED: zh_SG.GBK/GBK
2134             'zh_CN.gb18030' => 'gb18030', # GB18030, HP-UX-style spelling
2135             'zh_CN.GB18030' => 'gb18030', # GB18030, glibc SUPPORTED: zh_CN.GB18030/GB18030
2136             'ko_KR.eucKR' => 'uhc', # Korean EUC, handled as its UHC superset, HP-UX-style spelling
2137             'ko_KR.EUC-KR' => 'uhc', # Korean EUC, handled as its UHC superset, glibc SUPPORTED: ko_KR.EUC-KR/EUC-KR
2138             'zh_TW.eucTW' => 'euctw', # Taiwanese EUC, HP-UX-style spelling (UXL10N-90302 Table A-1; also Tru64 UNIX Chinese(5))
2139             'zh_TW.EUC-TW' => 'euctw', # EUC-TW, glibc SUPPORTED: zh_TW.EUC-TW/EUC-TW
2140             'zh_TW.Big5' => 'big5', # Big5, legacy spelling
2141             'zh_TW.big5' => 'big5', # Big5, HP-UX-style spelling (UXL10N-90302 Table A-1)
2142             'zh_HK' => 'big5hkscs', # glibc SUPPORTED: zh_HK/BIG5-HKSCS
2143             'zh_HK.big5' => 'big5hkscs', # kept for compatibility (Big5 locale of Hong Kong handled as Big5-HKSCS)
2144             'zh_HK.BIG5-HKSCS' => 'big5hkscs', # Big5-HKSCS, glibc SUPPORTED: zh_HK.BIG5-HKSCS/BIG5-HKSCS
2145 170   100     4153 }->{$LANG} || 'utf8';
2146             }
2147             }
2148              
2149             my @here_document_delimiter = ();
2150              
2151             #---------------------------------------------------------------------
2152             # parse script
2153             sub parse {
2154 145103 100   145106 0 5655449 local $_ = @_ ? $_[0] : $_;
2155              
2156             # Yes, I studied study yesterday, once again.
2157 145103         204461 study $_; # acts between perl 5.005 to perl 5.014
2158              
2159 145103         194769 @here_document_delimiter = ();
2160              
2161             # transpile JPerl script to Perl script
2162 145103         207773 my $parsed_script = '';
2163 145103         491604 while (not /\G \z /xmsgc) {
2164 722249         991841 $parsed_script .= parse_expr();
2165             }
2166              
2167             # return octet-oriented Perl script
2168 145103         14051897 return $parsed_script;
2169             }
2170              
2171             #---------------------------------------------------------------------
2172             # Perl 5.42 introduces source::encoding and automatically enables
2173             # ASCII-only checking for "use v5.41" and later.
2174             #
2175             # mb transpiles scripts to mostly US-ASCII, but it intentionally keeps
2176             # comments and POD as-is. Those may contain multibyte characters.
2177             #
2178             # source::encoding is only activated when "use v5.41" or later appears
2179             # in the script. We append "no source::encoding;" on the same line as
2180             # the "use VERSION" statement (replacing any trailing semicolon first)
2181             # to avoid introducing extra lines that would shift line numbers in
2182             # error messages.
2183             sub _insert_source_encoding_unimport {
2184 70     73   481 my($script) = @_;
2185              
2186             # append "no source::encoding;" on the same line as "use v5.41" or later,
2187             # before any trailing comment, to avoid line number shifts in error messages.
2188             # matches: use v5.41; use v5.42; use 5.041; use 5.042; etc.
2189 70         276 $script =~ s{
2190             ( \buse \s+
2191             (?: v5\. (?:4[1-9]|[5-9]\d|\d{3,}) # use v5.41 and later
2192             | 5\.0(?:4[1-9]|[5-9]\d|\d{3,}) # use 5.041 and later
2193             )
2194             [^\n#;]* # rest of statement (no # or ;)
2195             )
2196             ;? # consume trailing semicolon
2197             ( [^\n]* ) # trailing comment (if any)
2198             ( (?:\r\n|\r|\n) ) # line ending
2199             }{$1; no source::encoding;$2$3}xmsg;
2200              
2201 70         226 return $script;
2202             }
2203              
2204             #---------------------------------------------------------------------
2205             # parse ambiguous characters
2206             sub parse_ambiguous_char {
2207 294626     294629 0 342458 my $parsed = '';
2208              
2209             # Ambiguous characters
2210             # --------------------------------------------------------
2211             # Character Operator Term
2212             # --------------------------------------------------------
2213             # % modulo %hash
2214             # & &, && &subroutine
2215             # ' package 'string'
2216             # * multiplication *typeglob
2217             # + addition unary plus
2218             # - subtraction unary minus
2219             # . concatenation .3333
2220             # / division /pattern/
2221             # < less than <>, ,
2222             # << left shift <>
2223             # ? ?: ?pattern?
2224             # --------------------------------------------------------
2225              
2226             # any term then operator
2227 294626 100       605555 if (m{\G ( \s* (?:
2228              
2229             # 12345 | 12345 | 12345 | 12345 | 12345 | 12345 |
2230             %= | % | # "\x25" [%] PERCENT SIGN (U+0025)
2231             &&= | && | &\.= | &\. | &= | & | # "\x26" [&] AMPERSAND (U+0026)
2232             \*\*= | \*\* | \*= | \* | # "\x2A" [*] ASTERISK (U+002A)
2233             \.\.\.| \.\. | \.= | \. | # "\x2E" [.] FULL STOP (U+002E)
2234             \/\/= | \/\/ | \/= | \/ | # "\x2F" [/] SOLIDUS (U+002F)
2235             <=> | << | <= | < | # "\x3C" [<] LESS-THAN SIGN (U+003C)
2236             \? # "\x3F" [?] QUESTION MARK (U+003F)
2237             )) }xmsgc) {
2238 129         193 $parsed .= $1;
2239             }
2240              
2241 294626         449628 return $parsed;
2242             }
2243              
2244             #---------------------------------------------------------------------
2245             # parse expression in script
2246             sub parse_expr {
2247 726619     726622 0 818881 my $parsed = '';
2248 726619         1032101 my $old_package = mb::get_old_package();
2249              
2250             # __END__ or __DATA__
2251 726619 100       13343995 if (/\G ^ ( (?: __END__ | __DATA__ ) $R .* ) \z/xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
    50          
    0          
2252 17         34 $parsed .= $1;
2253             }
2254              
2255             # =pod ... =cut
2256             elsif (/\G ^ ( = [A-Za-z_][A-Za-z_0-9]* [\x00-\xFF]*? $R =cut \b [^\n]* $R ) /xmsgc) {
2257 1         3 $parsed .= $1;
2258             }
2259              
2260             # "\r\n", "\r", "\n"
2261             elsif (/\G (?= $R ) /xmsgc) {
2262 8747         15930 while (my $here_document_delimiter = shift @here_document_delimiter) {
2263 23         22 my($delimiter, $quote_type) = @{$here_document_delimiter};
  23         31  
2264 23 100       35 if ($quote_type eq 'qq') {
    50          
2265 14         18 $parsed .= parse_heredocument_as_qq_endswith($delimiter);
2266             }
2267             elsif ($quote_type eq 'q') {
2268              
2269             # perlop > Quote-Like Operators > < Single Quotes
2270             #
2271             # Single quotes indicate the text is to be treated literally
2272             # with no interpolation of its content. This is similar to
2273             # single quoted strings except that backslashes have no special
2274             # meaning, with \\ being treated as two backslashes and not
2275             # one as they would in every other quoting construct.
2276             # https://perldoc.perl.org/perlop.html#Quote-Like-Operators
2277              
2278 9         15 $parsed .= parse_heredocument_as_q_endswith($delimiter);
2279             }
2280             else {
2281 0         0 die "$0(@{[__LINE__]}): $ARGV[0] here document delimiter '$delimiter' not found.\n";
  0         0  
2282             }
2283             }
2284             }
2285              
2286             # "\t"
2287             # "\x20" [ ] SPACE (U+0020)
2288             elsif (/\G ( [\t ]+ ) /xmsgc) {
2289 274455         475351 $parsed .= $1;
2290             }
2291              
2292             # "\x3B" [;] SEMICOLON (U+003B)
2293             elsif (/\G ( ; ) /xmsgc) {
2294 5285         8706 $parsed .= $1;
2295             }
2296              
2297             # balanced brackets
2298             # "\x28" [(] LEFT PARENTHESIS (U+0028)
2299             # "\x7B" [{] LEFT CURLY BRACKET (U+007B)
2300             # "\x5B" [[] LEFT SQUARE BRACKET (U+005B)
2301             elsif (/\G ( [(\{\[] ) /xmsgc) {
2302 652         1022 $parsed .= parse_expr_balanced($1);
2303 652         835 $parsed .= parse_ambiguous_char();
2304             }
2305              
2306             # version string
2307             # v102.111.111
2308             # 102.111.111
2309             elsif (/\G (
2310             v [0-9]+ (?: \.[0-9]+ ){1,} \b |
2311             [0-9]+ (?: \.[0-9]+ ){2,} \b
2312             ) /xmsgc) {
2313 2         4 my $v_string = $1;
2314 2         9 $parsed .= join('.', map { "mb::chr($_)" } ($v_string =~ /[0-9]+/g));
  8         14  
2315 2         4 $parsed .= parse_ambiguous_char();
2316             }
2317              
2318             # version string
2319             # v9786
2320             elsif (/\G v ( [0-9]+ ) \b (?! \s* => ) /xmsgc) {
2321 1         3 $parsed .= "mb::chr($1)";
2322 1         2 $parsed .= parse_ambiguous_char();
2323             }
2324              
2325             # numbers
2326             # "\x2E" [.] [0-9]
2327             # "\x30" [0] DIGIT ZERO (U+0030)
2328             # "\x31" [1] DIGIT ONE (U+0031)
2329             # "\x32" [2] DIGIT TWO (U+0032)
2330             # "\x33" [3] DIGIT THREE (U+0033)
2331             # "\x34" [4] DIGIT FOUR (U+0034)
2332             # "\x35" [5] DIGIT FIVE (U+0035)
2333             # "\x36" [6] DIGIT SIX (U+0036)
2334             # "\x37" [7] DIGIT SEVEN (U+0037)
2335             # "\x38" [8] DIGIT EIGHT (U+0038)
2336             # "\x39" [9] DIGIT NINE (U+0039)
2337             elsif (m{\G (
2338              
2339             # since Perl v5.22 adds hexadecimal floating point literals
2340             # https://perldoc.perl.org/perl5220delta#Floating-point-parsing-has-been-improved
2341             # https://perldoc.perl.org/5.32.0/perldata#Scalar-value-constructors
2342              
2343             # https://qiita.com/mod_poppo/items/3fa4cdc35f9bfb352ad5
2344             # https://qiita.com/mod_poppo/items/3fa4cdc35f9bfb352ad5#perl
2345             #
2346             # $ perl -l -e 'print(0x1.23); print(0x1.23p0)'
2347             # makes ==> 123
2348             # makes ==> 1.13671875
2349              
2350             0[Xx] [0-9A-Fa-f_]+ \. [0-9A-Fa-f_]* [Pp] [+-]? [0-9_]+ |
2351             0[Xx] \. [0-9A-Fa-f_]+ [Pp] [+-]? [0-9_]+ |
2352             0[Xx] [0-9A-Fa-f_]+ |
2353              
2354             # since perl v5.33.5 Core Enhancements New octal syntax 0oddddd
2355              
2356             0[Oo] [0-7_]+ |
2357             0 [0-7_]* |
2358              
2359             0[Bb] [01_]+ |
2360              
2361             [1-9] [0-9_]* \. [0-9_]* [Ee] [+-]? [0-9_]+ |
2362             [1-9] [0-9_]* |
2363             \. [0-9_]+ [Ee] [+-]? [0-9_]+ |
2364             \. [0-9_]+
2365              
2366             ) }xmsgc) {
2367 971         1524 $parsed .= $1;
2368 971         1158 $parsed .= parse_ambiguous_char();
2369             }
2370              
2371             # file test operators on MSWin32
2372             # "\x2D" [-] HYPHEN-MINUS (U+002D)
2373              
2374             # -X -Y -Z 'file' --> mb::_filetest [qw( -X -Y -Z )], 'file'
2375             # -X -Y -Z "file" --> mb::_filetest [qw( -X -Y -Z )], "file"
2376             # -X -Y -Z `file` --> mb::_filetest [qw( -X -Y -Z )], `file`
2377             # -X -Y -Z $file --> mb::_filetest [qw( -X -Y -Z )], $file
2378             # ..., and filetest any word except file handle or directory handle
2379             # -X -Y -Z m// --> mb::_filetest [qw( -X -Y -Z )], m//
2380             # -X -Y -Z q// --> mb::_filetest [qw( -X -Y -Z )], q//
2381             # -X -Y -Z qq// --> mb::_filetest [qw( -X -Y -Z )], qq//
2382             # -X -Y -Z qr// --> mb::_filetest [qw( -X -Y -Z )], qr//
2383             # -X -Y -Z qw// --> mb::_filetest [qw( -X -Y -Z )], qw//
2384             # -X -Y -Z qx// --> mb::_filetest [qw( -X -Y -Z )], qx//
2385             # -X -Y -Z s/// --> mb::_filetest [qw( -X -Y -Z )], s///
2386             # -X -Y -Z tr/// --> mb::_filetest [qw( -X -Y -Z )], tr///
2387             # -X -Y -Z y/// --> mb::_filetest [qw( -X -Y -Z )], y///
2388             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2389             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2390             elsif (/\G ( (?: -[ABCMORSTWXbcdefgkloprstuwxz] \s* )+ \b ) (?= (?: \( \s* )* (?: ' | " | ` | \$ | (?: (?: m | q | qq | qr | qw | qx | s | tr | y ) \b )) ) /xmsgc) {
2391 0         0 $parsed .= "mb::_filetest [qw( $1 )], ";
2392             }
2393              
2394             # filetest file handle or directory handle
2395             # -X -Y -Z _ --> mb::_filetest [qw( -X -Y -Z )], \*_
2396             # -X -Y -Z FILE --> mb::_filetest [qw( -X -Y -Z )], \*FILE
2397             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2398             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvv
2399             elsif (/\G ( (?: -[ABCMORSTWXbcdefgkloprstuwxz] \s* )+ \b ) (?= [A-Za-z_][A-Za-z0-9_]* ) /xmsgc) {
2400 2828         8419 $parsed .= "mb::_filetest [qw( $1)], ";
2401 2828         3530 $parsed .= '\\*';
2402             }
2403              
2404             # -X -Y -Z ... --> mb::_filetest [qw( -X -Y -Z )], ...
2405             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2406             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2407             elsif (/\G ( (?: -[ABCMORSTWXbcdefgkloprstuwxz] \s* )+ \b ) /xmsgc) {
2408 8409         26917 $parsed .= "mb::_filetest [qw( $1)]";
2409 8409 50       14289 if (my $ambiguous_char = parse_ambiguous_char()) {
2410 0         0 $parsed .= $ambiguous_char;
2411             }
2412             else {
2413 8409         11577 $parsed .= ', ';
2414             }
2415             }
2416              
2417             # yada-yada or triple-dot operator
2418             elsif (/\G ( \.\.\. ) /xmsgc) {
2419 1         2 $parsed .= $1;
2420             }
2421              
2422             # -> and any method
2423             elsif (/\G ( -> \s* [A-Za-z_][A-Za-z_0-9]* ) /xmsgc) {
2424 1         2 $parsed .= $1;
2425             }
2426              
2427             # symbolic operators
2428             elsif (/\G (
2429              
2430             # 12345 | 12345 | 12345 | 12345 | 12345 | 12345 |
2431             != | !~ | ! | # "\x21" [!] EXCLAMATION MARK (U+0021)
2432             \+\+ | \+= | \+ | # "\x2B" [+] PLUS SIGN (U+002B)
2433             , | # "\x2C" [,] COMMA (U+002C)
2434             -- | -= | -> | - | # "\x2D" [-] HYPHEN-MINUS (U+002D)
2435             == | => | =~ | = | # "\x3D" [=] EQUALS SIGN (U+003D)
2436             >> | >= | > | # "\x3E" [>] GREATER-THAN SIGN (U+003E)
2437             \\ | # "\x5C" [\] REVERSE SOLIDUS (U+005C)
2438             \^\^= | \^\^ | \^\.= | \^\. | \^= | \^ | # "\x5E" [^] CIRCUMFLEX ACCENT (U+005E)
2439             \|\|= | \|\| | \|\.= | \|\. | \|= | \| | # "\x7C" [|] VERTICAL LINE (U+007C)
2440             ~~ | ~\. | ~= | ~ # "\x7E" [~] TILDE (U+007E)
2441              
2442             ) /xmsgc) {
2443 130251         248914 $parsed .= $1;
2444             }
2445              
2446             # named operators
2447             elsif (/\G ( (?: and | cmp | eq | ge | gt | isa | le | lt | ne | not | or | x | x= | xor ) \b ) /xmsgc) {
2448 2431         3268 $parsed .= $1;
2449             }
2450              
2451             # $` --> mb::_PREMATCH()
2452             # ${`} --> mb::_PREMATCH()
2453             # $PREMATCH --> mb::_PREMATCH()
2454             # ${PREMATCH} --> mb::_PREMATCH()
2455             # ${^PREMATCH} --> mb::_PREMATCH()
2456             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
2457 20         28 $parsed .= 'mb::_PREMATCH()';
2458 20         40 $parsed .= parse_ambiguous_char();
2459             }
2460              
2461             # $& --> mb::_MATCH()
2462             # ${&} --> mb::_MATCH()
2463             # $MATCH --> mb::_MATCH()
2464             # ${MATCH} --> mb::_MATCH()
2465             # ${^MATCH} --> mb::_MATCH()
2466             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
2467 68         95 $parsed .= 'mb::_MATCH()';
2468 68         76 $parsed .= parse_ambiguous_char();
2469             }
2470              
2471             # $1 --> mb::_CAPTURE(1)
2472             # $2 --> mb::_CAPTURE(2)
2473             # $3 --> mb::_CAPTURE(3)
2474             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
2475 55         114 $parsed .= "mb::_CAPTURE($1)";
2476 55         91 $parsed .= parse_ambiguous_char();
2477             }
2478              
2479             # @{^CAPTURE} --> mb::_CAPTURE()
2480             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
2481 3         4 $parsed .= 'mb::_CAPTURE()';
2482 3         4 $parsed .= parse_ambiguous_char();
2483             }
2484              
2485             # ${^CAPTURE}[0] --> mb::_CAPTURE(1)
2486             # ${^CAPTURE}[1] --> mb::_CAPTURE(2)
2487             # ${^CAPTURE}[2] --> mb::_CAPTURE(3)
2488             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
2489 3         6 my $n_th = quotee_of(parse_expr_balanced($1));
2490 3         4 $parsed .= "mb::_CAPTURE($n_th+1)";
2491 3         4 $parsed .= parse_ambiguous_char();
2492             }
2493              
2494             # @- --> mb::_LAST_MATCH_START()
2495             # @LAST_MATCH_START --> mb::_LAST_MATCH_START()
2496             # @{LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2497             # @{^LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2498             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
2499 12         17 $parsed .= 'mb::_LAST_MATCH_START()';
2500 12         16 $parsed .= parse_ambiguous_char();
2501             }
2502              
2503             # $-[1] --> mb::_LAST_MATCH_START(1)
2504             # $LAST_MATCH_START[1] --> mb::_LAST_MATCH_START(1)
2505             # ${LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2506             # ${^LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2507             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
2508 22         36 my $n_th = quotee_of(parse_expr_balanced($1));
2509 22         33 $parsed .= "mb::_LAST_MATCH_START($n_th)";
2510 22         25 $parsed .= parse_ambiguous_char();
2511             }
2512              
2513             # @+ --> mb::_LAST_MATCH_END()
2514             # @LAST_MATCH_END --> mb::_LAST_MATCH_END()
2515             # @{LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2516             # @{^LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2517             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
2518 12         19 $parsed .= 'mb::_LAST_MATCH_END()';
2519 12         15 $parsed .= parse_ambiguous_char();
2520             }
2521              
2522             # $+[1] --> mb::_LAST_MATCH_END(1)
2523             # $LAST_MATCH_END[1] --> mb::_LAST_MATCH_END(1)
2524             # ${LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2525             # ${^LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2526             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
2527 14         30 my $n_th = quotee_of(parse_expr_balanced($1));
2528 14         18 $parsed .= "mb::_LAST_MATCH_END($n_th)";
2529 14         17 $parsed .= parse_ambiguous_char();
2530             }
2531              
2532             # CORE::do { block } --> CORE::do { block }
2533             # CORE::eval { block } --> CORE::eval { block }
2534             # CORE::try { block } --> CORE::try { block }
2535             # CORE::finally { block } --> CORE::finally { block }
2536             elsif (/\G ( CORE:: (?: do | eval | try | finally ) \s* ) ( \{ ) /xmsgc) {
2537 11         20 $parsed .= $1;
2538 11         15 $parsed .= parse_expr_balanced($2);
2539 11         12 $parsed .= parse_ambiguous_char();
2540             }
2541              
2542             # mb::do { block } --> do { block }
2543             # mb::eval { block } --> eval { block }
2544             # mb::try { block } --> try { block }
2545             # mb::finally { block } --> finally { block }
2546             # do { block } --> do { block }
2547             # eval { block } --> eval { block }
2548             # try { block } --> try { block }
2549             # finally { block } --> finally { block }
2550             elsif (/\G (?: mb:: | $old_package )? ( (?: do | eval | try | finally ) \s* ) ( \{ ) /xmsgc) {
2551 30         44 $parsed .= $1;
2552 30         36 $parsed .= parse_expr_balanced($2);
2553 30         33 $parsed .= parse_ambiguous_char();
2554             }
2555              
2556             # $#{}, ${}, @{}, %{}, &{}, *{}, defer {}, sub {}
2557             # "\x24" [$] DOLLAR SIGN (U+0024)
2558             elsif (/\G ((?: \$[#] | [\$\@%&*] | defer | sub ) \s* ) ( \{ ) /xmsgc) {
2559 281         409 $parsed .= $1;
2560 281         386 $parsed .= parse_expr_balanced($2);
2561 281         300 $parsed .= parse_ambiguous_char();
2562             }
2563              
2564             # mb::do --> mb::do
2565             # CORE::do --> CORE::do
2566             # do --> do
2567             elsif (/\G ( (?: mb:: | CORE:: )? do ) \b /xmsgc) {
2568 3         4 $parsed .= $1;
2569             }
2570              
2571             # mb::eval --> mb::eval
2572             # CORE::eval --> CORE::eval
2573             # eval --> eval
2574             elsif (/\G ( (?: mb:: | CORE:: )? eval ) \b /xmsgc) {
2575 3         4 $parsed .= $1;
2576 3         4 $parsed .= parse_ambiguous_char();
2577             }
2578              
2579             # last index of array
2580             elsif (/\G ( [\$] [#] (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2581 3         5 $parsed .= $1;
2582 3         3 $parsed .= parse_ambiguous_char();
2583             }
2584              
2585             # scalar variable
2586             elsif (/\G ( [\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | ^\{[A-Za-z_][A-Za-z_0-9]*\} | [0-9]+ | [!"#\$%&'()+,\-.\/:;<=>?\@\[\\\]\^_`|~] ) (?: \s* (?: \+\+ | -- ) )? ) /xmsgc) {
2587 5158         10139 $parsed .= $1;
2588 5158         6931 $parsed .= parse_ambiguous_char();
2589             }
2590              
2591             # array variable
2592             # "\x40" [@] COMMERCIAL AT (U+0040)
2593             elsif (/\G ( [\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [_] ) ) /xmsgc) {
2594 198         343 $parsed .= $1;
2595 198         249 $parsed .= parse_ambiguous_char();
2596             }
2597              
2598             # hash variable
2599             elsif (/\G ( [\%\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [!+\-] ) ) /xmsgc) {
2600 11         18 $parsed .= $1;
2601 11         13 $parsed .= parse_ambiguous_char();
2602             }
2603              
2604             # user subroutine call
2605             # type glob
2606             elsif (/\G ( [&*] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2607 220         396 $parsed .= $1;
2608 220         287 $parsed .= parse_ambiguous_char();
2609             }
2610              
2611             # comment
2612             # "\x23" [#] NUMBER SIGN (U+0023)
2613             elsif (/\G ( [#] [^\n]* ) /xmsgc) {
2614 47         76 $parsed .= $1;
2615             }
2616              
2617             # 2-quotes
2618              
2619             # '...'
2620             # "\x27" ['] APOSTROPHE (U+0027)
2621             elsif (m{\G ( ' ) }xmsgc) {
2622 5865         9817 $parsed .= parse_q__like_endswith($1);
2623 5865         8404 $parsed .= parse_ambiguous_char();
2624             }
2625              
2626             # "...", `...`
2627             # "\x22" ["] QUOTATION MARK (U+0022)
2628             # "\x60" [`] GRAVE ACCENT (U+0060)
2629             elsif (m{\G ( ["`] ) }xmsgc) {
2630 134553         325026 $parsed .= parse_qq_like_endswith($1);
2631 134553         256244 $parsed .= parse_ambiguous_char();
2632             }
2633              
2634             # /.../
2635             elsif (m{\G ( [/] ) }xmsgc) {
2636 126385         282116 my $regexp = parse_re_endswith('m',$1);
2637 126385         201568 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2638              
2639             # /xx modifier
2640 126385 100       296137 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2641 28         46 $regexp = mb::_ignore_space($regexp);
2642             }
2643              
2644             # /i modifier
2645 126385 100       167729 if ($modifier_i) {
2646 23         38 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2647             }
2648             else {
2649 126362         191089 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2650             }
2651 126385         179056 $parsed .= parse_ambiguous_char();
2652             }
2653              
2654             # ?...?
2655             elsif (m{\G ( [?] ) }xmsgc) {
2656 1         2 my $regexp = parse_re_endswith('m',$1);
2657 1         2 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2658              
2659             # /xx modifier
2660 1 50       2 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2661 0         0 $regexp = mb::_ignore_space($regexp);
2662             }
2663              
2664             # /i modifier
2665 1 50       3 if ($modifier_i) {
2666 0         0 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2667             }
2668             else {
2669 1         2 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2670             }
2671 1         2 $parsed .= parse_ambiguous_char();
2672             }
2673              
2674             # <<>> double-diamond operator
2675             elsif (/\G ( <<>> ) /xmsgc) {
2676 1         2 $parsed .= $1;
2677 1         2 $parsed .= parse_ambiguous_char();
2678             }
2679              
2680             # diamond operator
2681             # <${file}>
2682             # <$file>
2683             #
2684             elsif (/\G (<) ((?:(?!\s)$x)*?) (>) /xmsgc) {
2685 5         13 my($open_bracket, $quotee, $close_bracket) = ($1, $2, $3);
2686 5         5 $parsed .= $open_bracket;
2687 5         56 while ($quotee =~ /\G ($x) /xmsgc) {
2688 25         25 $parsed .= escape_qq($1, $close_bracket);
2689             }
2690 5         5 $parsed .= $close_bracket;
2691 5         6 $parsed .= parse_ambiguous_char();
2692             }
2693              
2694             # qw/.../, q/.../
2695             elsif (/\G ( qw | q ) \b /xmsgc) {
2696 174         279 $parsed .= $1;
2697 174 100       563 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
  2 100       4  
    100          
    100          
    100          
    50          
2698 2         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2699 48         111 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); }
2700 6         11 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); }
2701 48         53 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2702 68         73 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2703 68         134 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2704 4         9 $parsed .= $1;
2705             }
2706 68 100       184 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
  6 100       8  
    100          
    100          
    50          
2707 2         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2708 8         9 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); }
2709 2         41 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); }
2710 50         82 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2711 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2712             }
2713 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2714 174         241 $parsed .= parse_ambiguous_char();
2715             }
2716              
2717             # qq/.../
2718             elsif (/\G ( qq ) \b /xmsgc) {
2719 69         102 $parsed .= $1;
2720 69 100       255 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  1 100       3  
    100          
    100          
    100          
    50          
2721 1         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); } # qq'...' works as "..."
2722 6         13 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2723 3         7 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2724 24         35 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2725 34         37 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2726 34         63 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2727 2         5 $parsed .= $1;
2728             }
2729 34 100       97 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  3 100       5  
    100          
    100          
    50          
2730 1         2 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); } # qq'...' works as "..."
2731 4         7 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2732 1         1 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2733 25         36 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2734 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2735             }
2736 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2737 69         95 $parsed .= parse_ambiguous_char();
2738             }
2739              
2740             # qx/.../
2741             elsif (/\G ( qx ) \b /xmsgc) {
2742 67         136 $parsed .= $1;
2743 67 100       233 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  1 100       3  
    100          
    100          
    100          
    50          
2744 1         2 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2745 4         6 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2746 3         7 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2747 24         34 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2748 34         36 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2749 34         60 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2750 2         5 $parsed .= $1;
2751             }
2752 34 100       128 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  3 100       4  
    100          
    100          
    50          
2753 1         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2754 4         6 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2755 1         2 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2756 25         31 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2757 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2758             }
2759 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2760 67         116 $parsed .= parse_ambiguous_char();
2761             }
2762              
2763             # m/.../, qr/.../
2764             elsif (/\G ( m | qr ) \b /xmsgc) {
2765 1655         2723 $parsed .= $1;
2766 1655         1734 my $regexp = '';
2767 1655 100       4405 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr#...#
  2 100       3  
    100          
    100          
    100          
    100          
    50          
2768 643         1030 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr'...'
2769 8         12 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr{...}
2770 360         609 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr/.../
2771 530         723 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # qr@...@
2772 44         64 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr?...?
2773 68         65 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # qr SPACE ...
  68         71  
2774 68         116 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2775 4         9 $parsed .= $1;
2776             }
2777 68 100       218 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE A...A
  6 100       9  
    100          
    100          
    100          
    50          
2778 2         4 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr SPACE '...'
2779 8         10 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr SPACE {...}
2780 2         5 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE /.../
2781 4         5 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # qr SPACE @...@
2782 46         62 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE ?...?
2783 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2784             }
2785 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2786              
2787 1655         2414 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2788              
2789             # /xx modifier
2790 1655 100       2949 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2791 2         4 $regexp = mb::_ignore_space($regexp);
2792             }
2793              
2794             # /i modifier
2795 1655 100       2087 if ($modifier_i) {
2796 37         58 $parsed .= sprintf('{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2797             }
2798             else {
2799 1618         2035 $parsed .= sprintf('{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2800             }
2801 1655         2077 $parsed .= parse_ambiguous_char();
2802             }
2803              
2804             # 3-quotes
2805              
2806             # s/.../.../
2807             elsif (/\G ( s ) \b /xmsgc) {
2808 1713         2882 $parsed .= $1;
2809 1713         1721 my $regexp = '';
2810 1713         1523 my $comment = '';
2811 1713         1777 my @replacement = ();
2812 1713 100       5462 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s#...#...#
  1 100       3  
  1 100       3  
    100          
    100          
    100          
    50          
2813 286         457 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s'...'...'
  286         502  
2814 240         367 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s{...}...
2815 240 50       887 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2816 4         10 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}'...'
2817 16         23 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{}{...}
2818 4         9 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}/.../
2819 96         145 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}?...?
2820 120         126 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s{} SPACE ...
2821 120         246 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2822 0         0 $comment .= $1;
2823             }
2824 120 50       415 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2825 4         9 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE '...'
2826 16         25 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{} SPACE {...}
2827 4         11 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE /.../
2828 96         142 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE ?...?
2829 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2830             }
2831 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2832             }
2833 354         549 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s/.../.../
  354         594  
2834 528         823 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('s',$1)) . '`');
2835 528         767 @replacement = parse_qq_like_endswith($1); } # s@...@...@
2836 22         34 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s?...?...?
  22         44  
2837 282         306 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # s SPACE ...
  282         273  
2838 282         561 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2839 12         26 $parsed .= $1;
2840             }
2841 282 100       749 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE A...A...A
  12 100       19  
  12 100       19  
    100          
    100          
    50          
2842 1         3 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE '...'...'
  1         3  
2843 244         374 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s SPACE {...}...
2844 244 100       961 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}#...#
  1 100       3  
    100          
    100          
    100          
    50          
2845 4         10 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}'...'
2846 17         23 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {}{...}
2847 4         15 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}/.../
2848 96         173 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}?...?
2849 122         132 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s SPACE {} SPACE ...
2850 122         228 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2851 8         16 $comment .= $1;
2852             }
2853 122 50       387 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2854 4         41 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE '...'
2855 18         38 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {} SPACE {...}
2856 4         10 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE /.../
2857 96         147 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE ?...?
2858 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2859             }
2860 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2861             }
2862 1         3 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE /.../.../
  1         2  
2863 2         4 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('s',$1)) . '`');
2864 2         5 @replacement = parse_qq_like_endswith($1); } # s SPACE @...@...@
2865 22         37 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE ?...?...?
  22         34  
2866 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2867             }
2868 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2869              
2870 1713         2384 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2871 1713         1947 my $replacement = '';
2872 1713         1606 my $eval = '';
2873              
2874             # has /e modifier
2875 1713 100       4143 if (my $e = $modifier_cegr =~ tr/e//d) {
    100          
    100          
2876 9         9 $replacement = 'q'. $replacement[1]; # q-type quotee
2877 9         15 $eval = 'mb::eval ' x $e;
2878             }
2879              
2880             # s''q-quotee'
2881             elsif ($replacement[0] =~ /\A ' /xms) {
2882 300         347 $replacement = $replacement[1]; # q-type quotee
2883             }
2884              
2885             # s##qq-quotee#
2886             elsif ($replacement[0] =~ /\A [#] /xms) {
2887 2         15 $replacement = 'qq' . $replacement[0]; # qq-type quotee
2888             }
2889              
2890             # s//qq-quotee/
2891             else {
2892 1402         1796 $replacement = 'qq ' . $replacement[0]; # qq-type quotee
2893             }
2894              
2895             # /xx modifier
2896 1713 100       2459 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2897 1         3 $regexp = mb::_ignore_space($regexp);
2898             }
2899              
2900             # /i modifier
2901 1713 100       2049 if ($modifier_i) {
2902 18         31 $parsed .= sprintf('{(\\G${mb::_anchor})@{[mb::_ignorecase(qr%s%s)]}@{[mb::_s_passed()]}}%s{$1 . %s%s}e%s', $regexp, $modifier_not_cegir, $comment, $eval, $replacement, $modifier_cegr);
2903             }
2904             else {
2905 1695         2452 $parsed .= sprintf('{(\\G${mb::_anchor})@{[' . 'qr%s%s ]}@{[mb::_s_passed()]}}%s{$1 . %s%s}e%s', $regexp, $modifier_not_cegir, $comment, $eval, $replacement, $modifier_cegr);
2906             }
2907 1713         2128 $parsed .= parse_ambiguous_char();
2908             }
2909              
2910             # tr/.../.../, y/.../.../
2911             elsif (/\G (?: tr | y ) \b /xmsgc) {
2912 2159         3380 $parsed .= 's'; # not 'tr'
2913 2159         2399 my $search = '';
2914 2159         1931 my $comment = '';
2915 2159         2318 my $replacement = '';
2916 2159 100       7955 if (/\G ( [#] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr#...#...#
  4 100       10  
  4 100       8  
    100          
    100          
    50          
2917 4         9 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr'...'...'
  4         6  
2918 912         1591 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_tr_like_balanced($1); # tr{...}...
2919 912 50       3536 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2920 16         22 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}'...'
2921 64         82 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr{}{...}
2922 16         22 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}/.../
2923 360         455 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}?...?
2924 456         670 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr{} SPACE ...
2925 456         958 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2926 0         0 $comment .= $1;
2927             }
2928 456 50       1359 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2929 16         23 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE '...'
2930 64         111 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr{} SPACE {...}
2931 16         24 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE /.../
2932 360         458 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE ?...?
2933 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2934             }
2935 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2936             }
2937 98         166 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr/.../.../
  98         185  
2938 131         202 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr?...?...?
  131         194  
2939 1010         1655 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; # tr SPACE ...
2940 1010         2305 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2941 0         0 $parsed .= $1;
2942             }
2943 1010 50       2640 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE A...A...A
  0 100       0  
  0 100       0  
    100          
    50          
2944 4         10 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE '...'...'
  4         8  
2945 912         1489 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_tr_like_balanced($1); # tr SPACE {...}...
2946 912 50       3675 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2947 16         26 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}'...'
2948 64         88 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr SPACE {}{...}
2949 16         23 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}/.../
2950 360         436 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}?...?
2951 456         572 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr SPACE {} SPACE ...
2952 456         913 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2953 0         0 $comment .= $1;
2954             }
2955 456 50       1434 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2956 16         26 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE '...'
2957 64         85 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr SPACE {} SPACE {...}
2958 16         20 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE /.../
2959 360         431 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE ?...?
2960 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2961             }
2962 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2963             }
2964 4         9 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE /.../.../
  4         10  
2965 90         150 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE ?...?...?
  90         113  
2966 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2967             }
2968 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2969              
2970             # modifier
2971 2159         3755 my($modifier_not_r, $modifier_r) = parse_tr_modifier();
2972 2159 50       3986 if ($modifier_r) {
    100          
2973 0         0 $parsed .= sprintf(q<{[\x00-\xFF]*}%s{mb::tr($&,q%s,q%s,'%sr')}ser>, $comment, $search, $replacement, $modifier_not_r);
2974             }
2975             elsif ($modifier_not_r =~ /s/) {
2976              
2977             # this implementation cannot return right count of codepoints replaced.
2978             # if you want right count, you can call mb::tr() yourself.
2979 28         44 $parsed .= sprintf(q<{[\x00-\xFF]+}%s{mb::tr($&,q%s,q%s,'%sr')}se>, $comment, $search, $replacement, $modifier_not_r);
2980             }
2981             else {
2982              
2983             # $parsed .= sprintf(q<{@{mb::_dot}}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $comment, $search, $replacement, $modifier_not_r);
2984             #------------------------------------------------------------------------------------------------------------------------------------------------
2985             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (9,111222DE1)
2986             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (9,111222DE1)
2987             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (9,11122DE1)
2988             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (9,11122DE1)
2989             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (9,AAABBC22A)
2990             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (9,AAABBC22A)
2991             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (9,AAABBCA)
2992             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (9,AAABBCA)
2993              
2994             # $parsed .= sprintf(q<{[\x00-\xFF]*}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $comment, $search, $replacement, $modifier_not_r);
2995             #------------------------------------------------------------------------------------------------------------------------------------------------
2996             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (2,111222DE1)
2997             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (2,12DE1)
2998             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (2,11122DE1)
2999             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (2,12DE1)
3000             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (2,AAABBC22A)
3001             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (2,AAABBC2A)
3002             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (2,AAABBCA)
3003             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (2,AAABBCA)
3004              
3005             # if ($modifier_not_r =~ /c/) {
3006             # $parsed .= sprintf(q<{@{[mb::_cc(q[^%s])]}}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $search, $comment, $search, $replacement, $modifier_not_r);
3007             # }
3008             # else {
3009             # $parsed .= sprintf(q<{@{[mb::_cc(q[%s])]}}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $search, $comment, $search, $replacement, $modifier_not_r);
3010             # }
3011             #------------------------------------------------------------------------------------------------------------------------------------------------
3012             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (7,111222DE1)
3013             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (7,111222DE1)
3014             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (7,11122DE1)
3015             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (7,11122DE1)
3016             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (2,AAABBC22A)
3017             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (2,AAABBC22A)
3018             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (2,AAABBCA)
3019             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (2,AAABBCA)
3020              
3021             # better idea of mine
3022 2131 100       2419 if ($modifier_not_r =~ /c/) {
3023 16         21 $parsed .= sprintf(q<{(\\G${mb::_anchor})((?!%s)@{mb::_dot})}%s{$1.mb::tr($2,q%s,q%s,'%sr')}sge>, codepoint_tr($search), $comment, $search, $replacement, $modifier_not_r);
3024             }
3025             else {
3026 2115         2611 $parsed .= sprintf(q<{(\\G${mb::_anchor})((?=%s)@{mb::_dot})}%s{$1.mb::tr($2,q%s,q%s,'%sr')}sge>, codepoint_tr($search), $comment, $search, $replacement, $modifier_not_r);
3027             }
3028             #------------------------------------------------------------------------------------------------------------------------------------------------
3029             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (7,111222DE1)
3030             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (1,12DE1)
3031             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (7,11122DE1)
3032             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (1,12DE1)
3033             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (2,AAABBC22A)
3034             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (1,AAABBC2A)
3035             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (2,AAABBCA)
3036             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (1,AAABBCA)
3037             }
3038 2159         3183 $parsed .= parse_ambiguous_char();
3039             }
3040              
3041             # indented here document
3042             elsif (/\G ( <<~ ) /xmsgc) {
3043 11         17 $parsed .= $1;
3044 11 100       43 if (/\G ( ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  1 100       2  
  1 100       5  
    100          
    50          
3045 1         2 elsif (/\G ( \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; }
  1         4  
3046 3         5 elsif (/\G ( [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; }
  3         8  
3047 3         4 elsif (/\G ( [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  3         6  
3048 3         4 elsif (/\G ( [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  3         6  
3049 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
3050 11         14 $parsed .= parse_ambiguous_char();
3051             }
3052              
3053             # here document
3054             elsif (/\G ( << ) /xmsgc) {
3055 12         19 $parsed .= $1;
3056 12 100       71 if (/\G ( ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  1 100       1  
  1 100       4  
    100          
    50          
3057 1         2 elsif (/\G ( \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; }
  1         2  
3058 4         9 elsif (/\G ( [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; }
  4         15  
3059 3         4 elsif (/\G ( [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  3         7  
3060 3         5 elsif (/\G ( [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  3         4  
3061 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
3062 12         19 $parsed .= parse_ambiguous_char();
3063             }
3064              
3065             # sub subroutine();
3066             elsif (/\G ( sub \s+ [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* \s* ) /xmsgc) {
3067 32         66 $parsed .= $1;
3068             }
3069              
3070             # while (<<>>)
3071             elsif (/\G ( while \s* \( \s* ) ( <<>> ) ( \s* \) ) /xmsgc) {
3072 2         4 $parsed .= $1;
3073 2         3 $parsed .= $2;
3074 2         3 $parsed .= $3;
3075             }
3076              
3077             # while (<${file}>)
3078             # while (<$file>)
3079             # while ()
3080             # while ()
3081             elsif (/\G ( while \s* \( \s* ) (<) ((?:(?!\s)$x)*?) (>) ( \s* \) ) /xmsgc) {
3082 9         15 $parsed .= $1;
3083 9         64 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
3084 9         13 my $close_bracket2 = $5;
3085 9         11 $parsed .= $open_bracket;
3086 9         189 while ($quotee =~ /\G ($x) /xmsgc) {
3087 54         64 $parsed .= escape_qq($1, $close_bracket);
3088             }
3089 9         10 $parsed .= $close_bracket;
3090 9         13 $parsed .= $close_bracket2;
3091             }
3092              
3093             # while <<>>
3094             elsif (/\G ( while \s* ) ( <<>> ) /xmsgc) {
3095 0         0 $parsed .= $1;
3096 0         0 $parsed .= $2;
3097             }
3098              
3099             # while <${file}>
3100             # while <$file>
3101             # while
3102             # while
3103             elsif (/\G ( while \s* ) (<) ((?:(?!\s)$x)*?) (>) /xmsgc) {
3104 0         0 $parsed .= $1;
3105 0         0 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
3106 0         0 $parsed .= $open_bracket;
3107 0         0 while ($quotee =~ /\G ($x) /xmsgc) {
3108 0         0 $parsed .= escape_qq($1, $close_bracket);
3109             }
3110 0         0 $parsed .= $close_bracket;
3111             }
3112              
3113             # if (expr)
3114             # elsif (expr)
3115             # unless (expr)
3116             # while (expr)
3117             # until (expr)
3118             # given (expr)
3119             # when (expr)
3120             # CORE::catch (expr)
3121             # catch (expr)
3122             elsif (/\G ( (?: if | elsif | unless | while | until | given | when | (?: CORE:: )? catch ) \s* ) ( \( ) /xmsgc) {
3123 25         37 $parsed .= $1;
3124              
3125             # outputs expr
3126 25         31 my $expr = parse_expr_balanced($2);
3127 25         25 $parsed .= $expr;
3128             }
3129              
3130             # mb::catch (expr) --> catch (expr)
3131             elsif (/\G mb:: ( catch \s* ) ( \( ) /xmsgc) {
3132 4         6 $parsed .= $1;
3133              
3134             # outputs expr
3135 4         6 my $expr = parse_expr_balanced($2);
3136 4         4 $parsed .= $expr;
3137             }
3138              
3139             # else
3140             elsif (/\G ( else ) \b /xmsgc) {
3141 1         3 $parsed .= $1;
3142             }
3143              
3144             # ... if expr;
3145             # ... unless expr;
3146             # ... while expr;
3147             # ... until expr;
3148             elsif (/\G ( if | unless | while | until ) \b /xmsgc) {
3149 13         24 $parsed .= $1;
3150             }
3151              
3152             # foreach my $var (expr) --> foreach my $var (expr)
3153             # for my $var (expr) --> for my $var (expr)
3154             elsif (/\G ( (?: foreach | for ) \s+ my \s* [\$] [A-Za-z_][A-Za-z_0-9]* ) ( \( ) /xmsgc) {
3155 0         0 $parsed .= $1;
3156 0         0 $parsed .= parse_expr_balanced($2);
3157             }
3158              
3159             # foreach $var (expr) --> foreach $var (expr)
3160             # for $var (expr) --> for $var (expr)
3161             elsif (/\G ( (?: foreach | for ) \s* [\$] [\$]* (?: \{[A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)*\} | [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]* ) ) ) ( \( ) /xmsgc) {
3162 0         0 $parsed .= $1;
3163 0         0 $parsed .= parse_expr_balanced($2);
3164             }
3165              
3166             # foreach (expr1; expr2; expr3) --> foreach (expr1; expr2; expr3)
3167             # foreach (expr) --> foreach (expr)
3168             # for (expr1; expr2; expr3) --> for (expr1; expr2; expr3)
3169             # for (expr) --> for (expr)
3170             elsif (/\G ( (?: foreach | for ) \s* ) ( \( ) /xmsgc) {
3171 4         10 $parsed .= $1;
3172 4         6 $parsed .= parse_expr_balanced($2);
3173             }
3174              
3175             # CORE::split --> mb::_split
3176             # mb::split --> mb::_split
3177             # split --> mb::_split
3178             elsif (/\G (?: CORE:: | mb:: | $old_package )? ( split ) \b /xmsgc) {
3179 679         821 $parsed .= "mb::_split";
3180              
3181             # parse \s and '('
3182 679         547 while (1) {
3183 1364 100       2847 if (/\G ( \s+ ) /xmsgc) {
    100          
    100          
3184 296         402 $parsed .= $1;
3185             }
3186             elsif (/\G ( \( ) /xmsgc) {
3187 389         523 $parsed .= $1;
3188             }
3189             elsif (/\G ( \# .* \n ) /xmgc) {
3190 16         18 $parsed .= $1;
3191 16         17 last;
3192             }
3193             else {
3194 663         757 last;
3195             }
3196             }
3197 679         705 my $regexp = '';
3198              
3199             # split /^/ --> mb::_split qr/^/m
3200             # split /.../ --> mb::_split qr/.../
3201 679 100       1618 if (m{\G ( [/] ) }xmsgc) {
    100          
3202 24         18 $parsed .= "qr";
3203 24         40 $regexp = parse_re_endswith('m',$1); # split /.../
3204 24         32 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
3205              
3206             # P.794 29.2.161. split
3207             # in Chapter 29: Functions
3208             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
3209              
3210             # P.951 split
3211             # in Chapter 27: Functions
3212             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
3213              
3214             # said "The //m modifier is assumed when you split on the pattern /^/",
3215             # but perl5.008 is not so. Therefore, this software adds //m.
3216             # (and so on)
3217              
3218 24 100       39 if ($modifier_not_cegir !~ /m/xms) {
3219 18         21 $modifier_not_cegir .= 'm';
3220             }
3221              
3222             # /xx modifier
3223 24 100       43 if (($modifier_not_cegir =~ tr/x//) >= 2) {
3224 1         2 $regexp = mb::_ignore_space($regexp);
3225             }
3226              
3227             # /i modifier
3228 24 100       29 if ($modifier_i) {
3229 6         10 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
3230             }
3231             else {
3232 18         26 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
3233             }
3234             }
3235              
3236             # split m/^/ --> mb::_split qr/^/m
3237             # split m/.../ --> mb::_split qr/.../
3238             elsif (/\G ( m | qr ) \b /xmsgc) {
3239 611         583 $parsed .= "qr";
3240              
3241 611 100       2153 if (/\G ( [#] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr#...#
  8 100       13  
    100          
    100          
    100          
    100          
    50          
3242 8         15 elsif (/\G ( ['] ) /xmsgc) { $regexp = parse_re_as_q_endswith('m',$1); } # split qr'...'
3243 32         51 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp = parse_re_balanced('m',$1); } # split qr{...}
3244 83         145 elsif (m{\G( [/] ) }xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr/.../
3245 16         25 elsif (/\G ( [:\@] ) /xmsgc) { $regexp = ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # split qr@...@
3246 184         283 elsif (/\G ( [\S] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr?...?
3247 280         351 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp = $1; # split qr SPACE ...
  280         316  
3248 280         498 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3249 32         55 $parsed .= $1;
3250             }
3251 280 100       897 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE A...A
  24 100       32  
    100          
    100          
    100          
    50          
3252 8         12 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # split qr SPACE '...'
3253 32         67 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # split qr SPACE {...}
3254 8         12 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE /.../
3255 16         26 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # split qr SPACE @...@
3256 192         283 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE ?...?
3257 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
3258             }
3259 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
3260              
3261 611         843 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
3262              
3263 611 100       912 if ($modifier_not_cegir !~ /m/xms) {
3264 607         528 $modifier_not_cegir .= 'm';
3265             }
3266              
3267             # /xx modifier
3268 611 100       973 if (($modifier_not_cegir =~ tr/x//) >= 2) {
3269 1         2 $regexp = mb::_ignore_space($regexp);
3270             }
3271              
3272             # /i modifier
3273 611 100       687 if ($modifier_i) {
3274 16         30 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
3275             }
3276             else {
3277 595         670 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
3278             }
3279             }
3280              
3281 679         795 $parsed .= parse_ambiguous_char();
3282             }
3283              
3284             # provides bare Perl and JPerl compatible functions
3285             elsif (/\G ( (?: lc | lcfirst | uc | ucfirst ) ) \b /xmsgc) {
3286 15         38 $parsed .= "mb::$1";
3287 15         26 $parsed .= parse_ambiguous_char();
3288             }
3289              
3290             # CORE::require, mb::require, require
3291             elsif (/\G ( (?: CORE:: | mb:: )? require ) /xmsgc) {
3292 3         6 $parsed .= $1;
3293 3         5 $parsed .= parse_ambiguous_char();
3294             }
3295              
3296             # mb::use --> BEGIN { mb::require ... }
3297             # mb::no --> BEGIN { mb::require ... }
3298             elsif (/\G ( mb::use | mb::no ) \b /xmsgc) {
3299 42   50     185 my $method = { 'mb::use'=>'import', 'mb::no'=>'unimport' }->{$1} || die;
3300 42         76 $parsed .= "BEGIN { mb::require";
3301 42         110 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3302 58         134 $parsed .= $1;
3303             }
3304 42 50       114 if (/\G ( [A-Za-z_][A-Za-z_0-9]* (?: ::[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
3305 42         64 my $module = $1;
3306 42         45 $parsed .= qq{'$module';};
3307 42         73 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3308 54         101 $parsed .= $1;
3309             }
3310 42 100       106 if (/\G ( [0-9]+ (?: \.[0-9]+)* ) /xmsgc) {
3311 26         55 my $version = $1;
3312 26         30 $parsed .= qq{$module->VERSION($version);};
3313 26         50 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3314 46         97 $parsed .= $1;
3315             }
3316             }
3317 42         115 my $list = parse_expr_endswith(qr< [;\}] | \z >xms);
3318 42 100       1704 if ($list eq '') {
    100          
3319 12         21 $parsed .= qq{ $module->$method; };
3320             }
3321             elsif (scalar(CORE::eval("()=$list")) == 0) {
3322             }
3323             else {
3324 22         44 $parsed .= qq{ $module->$method($list); };
3325             }
3326             }
3327 42         98 $parsed .= "}";
3328             }
3329              
3330             # mb::getc() --> mb::getc()
3331             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3332             # vvvvvvvvvvvv
3333             elsif (/\G ( mb::getc ) (?= (?: \s* \( )+ \s* \) ) /xmsgc) {
3334 1         3 $parsed .= $1;
3335             }
3336              
3337             # mb::getc($fh) --> mb::getc($fh)
3338             # mb::getc $fh --> mb::getc $fh
3339             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3340             # vvvvvvvvvvvv
3341             elsif (/\G ( mb::getc ) (?= (?: \s* \( )* \s* \$ ) /xmsgc) {
3342 2         4 $parsed .= $1;
3343             }
3344              
3345             # mb::getc(FILE) --> mb::getc(\*FILE)
3346             # mb::getc FILE --> mb::getc \*FILE
3347             # vvvvvvvvvvvvvvvvvvvvv
3348             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3349             elsif (/\G ( mb::getc ) \b ( (?: \s* \( )* \s* ) (?= [A-Za-z_][A-Za-z0-9_]* \b ) /xmsgc) {
3350 2         3 $parsed .= $1;
3351 2         3 $parsed .= $2;
3352 2         2 $parsed .= '\\*';
3353             }
3354              
3355             # mb::getc --> mb::getc
3356             elsif (/\G ( mb::getc ) /xmsgc) {
3357 1         3 $parsed .= $1;
3358 1         2 $parsed .= parse_ambiguous_char();
3359             }
3360              
3361             # CORE::functions that allow zero parameters
3362             # mb::functions that allow zero parameters
3363             elsif (/\G ( (?: CORE:: | mb:: )? (?:
3364             chop |
3365             chr |
3366             getc |
3367             lc |
3368             lcfirst |
3369             length |
3370             ord |
3371             uc |
3372             ucfirst
3373             ) ) \b /xmsgc) {
3374 28         46 $parsed .= $1;
3375 28         33 $parsed .= parse_ambiguous_char();
3376             }
3377              
3378             # CORE::functions that must parameters
3379             # mb::functions that must parameters
3380             elsif (/\G ( (?: CORE:: | mb:: )? (?:
3381             index |
3382             reverse |
3383             rindex |
3384             substr
3385             ) ) \b /xmsgc) {
3386 26         46 $parsed .= $1;
3387             }
3388              
3389             # mb::subroutines
3390             elsif (/\G ( mb:: (?: index_byte | rindex_byte ) ) \b /xmsgc) {
3391 2         6 $parsed .= $1;
3392             }
3393              
3394             # CORE::functions that allow zero parameters
3395             # functions that allow zero parameters
3396             elsif (/\G ( (?: CORE:: )? (?:
3397             _ |
3398             abs |
3399             chomp |
3400             cos |
3401             exp |
3402             fc |
3403             hex |
3404             int |
3405             __LINE__ |
3406             log |
3407             oct |
3408             pop |
3409             pos |
3410             quotemeta |
3411             rand |
3412             rmdir |
3413             shift |
3414             sin |
3415             sqrt |
3416             tell |
3417             time |
3418             umask |
3419             wantarray
3420             ) ) \b /xmsgc) {
3421 2885         6101 $parsed .= $1;
3422 2885         4120 $parsed .= parse_ambiguous_char();
3423             }
3424              
3425             # lstat(), stat() on MSWin32
3426              
3427             # lstat() --> mb::_lstat()
3428             # stat() --> mb::_stat()
3429             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3430             # vvvvvvvvvvvv
3431             elsif (/\G ( lstat | stat ) (?= (?: \s* \( )+ \s* \) ) /xmsgc) {
3432 2         5 $parsed .= "mb::_$1";
3433             }
3434              
3435             # lstat(...) --> mb::_lstat(...)
3436             # stat(...) --> mb::_stat(...)
3437             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3438             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3439             elsif (/\G ( lstat | stat ) (?= (?: \s* \( )* \b (?: ' | " | ` | m | q | qq | qr | qw | qx | s | tr | y | \$ ) \b ) /xmsgc) {
3440 18         46 $parsed .= "mb::_$1";
3441             }
3442              
3443             # lstat(FILE) --> mb::_lstat(\*FILE)
3444             # lstat FILE --> mb::_lstat \*FILE
3445             # stat(FILE) --> mb::_stat(\*FILE)
3446             # stat FILE --> mb::_stat \*FILE
3447             # vvvvvvvvvvvvvvvvvvvvv
3448             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3449             elsif (/\G ( lstat | stat ) \b ( (?: \s* \( )* \s* ) (?= [A-Za-z_][A-Za-z0-9_]* \b ) /xmsgc) {
3450 10         26 $parsed .= "mb::_$1";
3451 10         12 $parsed .= $2;
3452 10         11 $parsed .= '\\*';
3453             }
3454              
3455             # opendir(DIR, ...) --> mb::_opendir(\*DIR, ...)
3456             # opendir DIR, ... --> mb::_opendir \*DIR, ...
3457             # vvvvvvvvvvvvvvvvvvvvv
3458             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3459             elsif (/\G ( opendir ) \b ( (?: \s* \( )* \s* ) (?= [A-Za-z_][A-Za-z0-9_]* \s* , ) /xmsgc) {
3460 4         13 $parsed .= "mb::_$1";
3461 4         6 $parsed .= $2;
3462 4         4 $parsed .= '\\*';
3463             }
3464              
3465             # function --> mb::subroutine on MSWin32
3466             # implements run on any systems by transpiling once
3467             elsif (/\G ( chdir | lstat | stat | unlink ) \b /xmsgc) {
3468 32         76 $parsed .= "mb::_$1";
3469 32         45 $parsed .= parse_ambiguous_char();
3470             }
3471             elsif (/\G ( opendir ) \b /xmsgc) {
3472 4         12 $parsed .= "mb::_$1";
3473             }
3474              
3475             # Carp::carp <
3476             # Carp::cluck <
3477             # Carp::confess <
3478             # Carp::croak <
3479             # carp <
3480             # cluck <
3481             # confess <
3482             # croak <
3483             # die <
3484             # print <
3485             # printf <
3486             # say <
3487             # warn <
3488             elsif (/\G (
3489             Carp::carp |
3490             Carp::cluck |
3491             Carp::confess |
3492             Carp::croak |
3493             carp |
3494             cluck |
3495             confess |
3496             croak |
3497             die |
3498             print |
3499             printf |
3500             say |
3501             warn
3502             ) (?= (?: \s+ | [#] .* )* << ) /xgc) {
3503 0         0 $parsed .= $1;
3504             # without $parsed .= parse_ambiguous_char();
3505             }
3506              
3507             # printf FILEHANDLE <
3508             # print FILEHANDLE <
3509             # say FILEHANDLE <
3510             elsif (/\G (
3511             (?: printf | print | say )
3512             (?: \s+ | [#] .* )*
3513             (?! [a-z]+ ) # lowercase is considered to be function
3514             (?: \b [A-Za-z_][A-Za-z_0-9]*(?: :: [A-Za-z_][A-Za-z_0-9]*)* |
3515             \$ [A-Za-z_][A-Za-z_0-9]*(?: :: [A-Za-z_][A-Za-z_0-9]*)*
3516             )
3517             ) /xgc) {
3518 28         71 $parsed .= $1;
3519             # without $parsed .= parse_ambiguous_char();
3520             }
3521              
3522             # printf {FILEHANDLE} <
3523             # print {FILEHANDLE} <
3524             # say {FILEHANDLE} <
3525             elsif (/\G (
3526             (?: printf | print | say )
3527             (?: \s+ | [#] .* )*
3528             ) (\{)
3529             /xgc) {
3530 0         0 $parsed .= $1;
3531 0         0 $parsed .= parse_expr_balanced($2);
3532             # without $parsed .= parse_ambiguous_char();
3533             }
3534              
3535             # return
3536             elsif (/\G ( return ) /xmsgc) {
3537 14         30 $parsed .= $1;
3538             }
3539              
3540             # any word
3541             # "\x5F" [_] LOW LINE (U+005F)
3542             # "\x41" [A] LATIN CAPITAL LETTER A (U+0041)
3543             # "\x42" [B] LATIN CAPITAL LETTER B (U+0042)
3544             # "\x43" [C] LATIN CAPITAL LETTER C (U+0043)
3545             # "\x44" [D] LATIN CAPITAL LETTER D (U+0044)
3546             # "\x45" [E] LATIN CAPITAL LETTER E (U+0045)
3547             # "\x46" [F] LATIN CAPITAL LETTER F (U+0046)
3548             # "\x47" [G] LATIN CAPITAL LETTER G (U+0047)
3549             # "\x48" [H] LATIN CAPITAL LETTER H (U+0048)
3550             # "\x49" [I] LATIN CAPITAL LETTER I (U+0049)
3551             # "\x4A" [J] LATIN CAPITAL LETTER J (U+004A)
3552             # "\x4B" [K] LATIN CAPITAL LETTER K (U+004B)
3553             # "\x4C" [L] LATIN CAPITAL LETTER L (U+004C)
3554             # "\x4D" [M] LATIN CAPITAL LETTER M (U+004D)
3555             # "\x4E" [N] LATIN CAPITAL LETTER N (U+004E)
3556             # "\x4F" [O] LATIN CAPITAL LETTER O (U+004F)
3557             # "\x50" [P] LATIN CAPITAL LETTER P (U+0050)
3558             # "\x51" [Q] LATIN CAPITAL LETTER Q (U+0051)
3559             # "\x52" [R] LATIN CAPITAL LETTER R (U+0052)
3560             # "\x53" [S] LATIN CAPITAL LETTER S (U+0053)
3561             # "\x54" [T] LATIN CAPITAL LETTER T (U+0054)
3562             # "\x55" [U] LATIN CAPITAL LETTER U (U+0055)
3563             # "\x56" [V] LATIN CAPITAL LETTER V (U+0056)
3564             # "\x57" [W] LATIN CAPITAL LETTER W (U+0057)
3565             # "\x58" [X] LATIN CAPITAL LETTER X (U+0058)
3566             # "\x59" [Y] LATIN CAPITAL LETTER Y (U+0059)
3567             # "\x5A" [Z] LATIN CAPITAL LETTER Z (U+005A)
3568             # "\x61" [a] LATIN SMALL LETTER A (U+0061)
3569             # "\x62" [b] LATIN SMALL LETTER B (U+0062)
3570             # "\x63" [c] LATIN SMALL LETTER C (U+0063)
3571             # "\x64" [d] LATIN SMALL LETTER D (U+0064)
3572             # "\x65" [e] LATIN SMALL LETTER E (U+0065)
3573             # "\x66" [f] LATIN SMALL LETTER F (U+0066)
3574             # "\x67" [g] LATIN SMALL LETTER G (U+0067)
3575             # "\x68" [h] LATIN SMALL LETTER H (U+0068)
3576             # "\x69" [i] LATIN SMALL LETTER I (U+0069)
3577             # "\x6A" [j] LATIN SMALL LETTER J (U+006A)
3578             # "\x6B" [k] LATIN SMALL LETTER K (U+006B)
3579             # "\x6C" [l] LATIN SMALL LETTER L (U+006C)
3580             # "\x6D" [m] LATIN SMALL LETTER M (U+006D)
3581             # "\x6E" [n] LATIN SMALL LETTER N (U+006E)
3582             # "\x6F" [o] LATIN SMALL LETTER O (U+006F)
3583             # "\x70" [p] LATIN SMALL LETTER P (U+0070)
3584             # "\x71" [q] LATIN SMALL LETTER Q (U+0071)
3585             # "\x72" [r] LATIN SMALL LETTER R (U+0072)
3586             # "\x73" [s] LATIN SMALL LETTER S (U+0073)
3587             # "\x74" [t] LATIN SMALL LETTER T (U+0074)
3588             # "\x75" [u] LATIN SMALL LETTER U (U+0075)
3589             # "\x76" [v] LATIN SMALL LETTER V (U+0076)
3590             # "\x77" [w] LATIN SMALL LETTER W (U+0077)
3591             # "\x78" [x] LATIN SMALL LETTER X (U+0078)
3592             # "\x79" [y] LATIN SMALL LETTER Y (U+0079)
3593             # "\x7A" [z] LATIN SMALL LETTER Z (U+007A)
3594             elsif (/\G ( [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
3595 675         1382 $parsed .= $1;
3596 675         932 $parsed .= parse_ambiguous_char();
3597             }
3598              
3599             # any right parenthesis
3600             # "\x29" [)] RIGHT PARENTHESIS (U+0029)
3601             # "\x7D" [}] RIGHT CURLY BRACKET (U+007D)
3602             # "\x5D" []] RIGHT SQUARE BRACKET (U+005D)
3603             elsif (/\G ([\)\}\]]) /xmsgc) {
3604 396         710 $parsed .= $1;
3605 396         442 $parsed .= parse_ambiguous_char();
3606             }
3607              
3608             # any US-ASCII
3609             # "\x3A" [:] COLON (U+003A)
3610             elsif (/\G ([\x00-\x7F]) /xmsgc) {
3611 8764         14458 $parsed .= $1;
3612             }
3613              
3614             # otherwise
3615             elsif (/\G ($x) /xmsgc) {
3616 0         0 die "$0(@{[__LINE__]}): can't parse not US-ASCII '$1'.\n";
  0         0  
3617             }
3618              
3619 726619         1948153 return $parsed;
3620             }
3621              
3622             #---------------------------------------------------------------------
3623             # parse expression in balanced blackets
3624             sub parse_expr_balanced {
3625 1046     1049 0 1631 my($open_bracket) = @_;
3626 1046   50     3385 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3627 1046         1658 my $parsed = $open_bracket;
3628 1046         1013 my $nest_bracket = 1;
3629 1046         977 while (1) {
3630              
3631             # open bracket
3632 5460 100       29112 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
3633 37         60 $parsed .= $1;
3634 37         63 $nest_bracket++;
3635             }
3636              
3637             # close bracket
3638             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3639 1083         1304 $parsed .= $1;
3640 1083         1217 $parsed .= parse_ambiguous_char();
3641 1083 100       1640 if (--$nest_bracket <= 0) {
3642 1046         1140 last;
3643             }
3644             }
3645              
3646             # otherwise
3647             else {
3648 4340         10128 $parsed .= parse_expr();
3649             }
3650             }
3651 1046         1574 return $parsed;
3652             }
3653              
3654             #---------------------------------------------------------------------
3655             # parse expression that ends with a regexp
3656             sub parse_expr_endswith {
3657 42     45 0 56 my($endswith) = @_;
3658 42         39 my $parsed = '';
3659 42         37 while (1) {
3660 72 100       260 if (/\G (?= $endswith ) /xmsgc) {
3661 42         41 last;
3662             }
3663             else {
3664 30         223 $parsed .= parse_expr();
3665             }
3666             }
3667 42         61 return $parsed;
3668             }
3669              
3670             #---------------------------------------------------------------------
3671             # parse <<'HERE_DOCUMENT' as q-like
3672             sub parse_heredocument_as_q_endswith {
3673 9     12 0 13 my($endswith) = @_;
3674 9         7 my $parsed = '';
3675 9         10 while (1) {
3676 465 100       1460 if (/\G ( $R $endswith ) /xmsgc) {
    50          
3677 9         14 $parsed .= $1;
3678 9         13 last;
3679             }
3680             elsif (/\G ($x) /xmsgc) {
3681 456         457 $parsed .= $1;
3682             }
3683              
3684             # something wrong happened
3685             else {
3686 0         0 die sprintf(<
3687 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3688             ------------------------------------------------------------------------------
3689             %s
3690             ------------------------------------------------------------------------------
3691             END
3692             }
3693             }
3694 9         25 return $parsed;
3695             }
3696              
3697             #---------------------------------------------------------------------
3698             # parse <<"HERE_DOCUMENT" as qq-like
3699             sub parse_heredocument_as_qq_endswith {
3700 14     17 0 15 my($endswith) = @_;
3701 14         11 my $parsed = '';
3702 14         13 my $nest_escape = 0;
3703 14         10 while (1) {
3704 14 50       143 if (/\G ( $R $endswith ) /xmsgc) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3705 14         20 $parsed .= ('>)]}' x $nest_escape);
3706 14         60 $parsed .= $1;
3707 14         13 last;
3708             }
3709              
3710             # \L\u --> \u\L
3711             elsif (/\G \\L \\u /xmsgc) {
3712 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3713 0         0 $parsed .= '@{[mb::lc(qq<';
3714 0         0 $nest_escape++;
3715 0         0 $nest_escape++;
3716             }
3717              
3718             # \U\l --> \l\U
3719             elsif (/\G \\U \\l /xmsgc) {
3720 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3721 0         0 $parsed .= '@{[mb::uc(qq<';
3722 0         0 $nest_escape++;
3723 0         0 $nest_escape++;
3724             }
3725              
3726             # \L
3727             elsif (/\G \\L /xmsgc) {
3728 0         0 $parsed .= '@{[mb::lc(qq<';
3729 0         0 $nest_escape++;
3730             }
3731              
3732             # \U
3733             elsif (/\G \\U /xmsgc) {
3734 0         0 $parsed .= '@{[mb::uc(qq<';
3735 0         0 $nest_escape++;
3736             }
3737              
3738             # \l
3739             elsif (/\G \\l /xmsgc) {
3740 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3741 0         0 $nest_escape++;
3742             }
3743              
3744             # \u
3745             elsif (/\G \\u /xmsgc) {
3746 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3747 0         0 $nest_escape++;
3748             }
3749              
3750             # \Q
3751             elsif (/\G \\Q /xmsgc) {
3752 0         0 $parsed .= '@{[quotemeta(qq<';
3753 0         0 $nest_escape++;
3754             }
3755              
3756             # \E
3757             elsif (/\G \\E /xmsgc) {
3758 0         0 $parsed .= ('>)]}' x $nest_escape);
3759 0         0 $nest_escape = 0;
3760             }
3761              
3762             # \o{...}
3763             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3764 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), '\\');
3765             }
3766              
3767             # \x{...}
3768             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3769 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), '\\');
3770             }
3771              
3772             # \any
3773             elsif (/\G (\\) ($x) /xmsgc) {
3774 0         0 $parsed .= ($1 . escape_qq($2, '\\'));
3775             }
3776              
3777             # $` --> @{[mb::_PREMATCH()]}
3778             # ${`} --> @{[mb::_PREMATCH()]}
3779             # $PREMATCH --> @{[mb::_PREMATCH()]}
3780             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3781             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3782             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3783 0         0 $parsed .= '@{[mb::_PREMATCH()]}';
3784             }
3785              
3786             # $& --> @{[mb::_MATCH()]}
3787             # ${&} --> @{[mb::_MATCH()]}
3788             # $MATCH --> @{[mb::_MATCH()]}
3789             # ${MATCH} --> @{[mb::_MATCH()]}
3790             # ${^MATCH} --> @{[mb::_MATCH()]}
3791             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3792 0         0 $parsed .= '@{[mb::_MATCH()]}';
3793             }
3794              
3795             # $1 --> @{[mb::_CAPTURE(1)]}
3796             # $2 --> @{[mb::_CAPTURE(2)]}
3797             # $3 --> @{[mb::_CAPTURE(3)]}
3798             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
3799 0         0 $parsed .= "\@{[mb::_CAPTURE($1)]}";
3800             }
3801              
3802             # @{^CAPTURE} --> @{[mb::_CAPTURE()]}
3803             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
3804 0         0 $parsed .= '@{[mb::_CAPTURE()]}';
3805             }
3806              
3807             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3808             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3809             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3810             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
3811 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3812 0         0 $parsed .= "\@{[mb::_CAPTURE($n_th+1)]}";
3813             }
3814              
3815             # @- --> @{[mb::_LAST_MATCH_START()]}
3816             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3817             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3818             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3819             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3820 0         0 $parsed .= '@{[mb::_LAST_MATCH_START()]}';
3821             }
3822              
3823             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3824             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3825             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3826             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3827             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3828 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3829 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3830             }
3831              
3832             # @+ --> @{[mb::_LAST_MATCH_END()]}
3833             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3834             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3835             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3836             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3837 0         0 $parsed .= '@{[mb::_LAST_MATCH_END()]}';
3838             }
3839              
3840             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3841             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3842             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3843             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3844             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3845 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3846 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3847             }
3848              
3849             # any
3850             elsif (/\G ($x) /xmsgc) {
3851 0         0 $parsed .= escape_qq($1, '\\');
3852             }
3853              
3854             # something wrong happened
3855             else {
3856 0         0 die sprintf(<
3857 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3858             ------------------------------------------------------------------------------
3859             %s
3860             ------------------------------------------------------------------------------
3861             END
3862             }
3863             }
3864 14         32 return $parsed;
3865             }
3866              
3867             #---------------------------------------------------------------------
3868             # parse q{string} in balanced blackets
3869             sub parse_q__like_balanced {
3870 56     59 0 358 my($open_bracket) = @_;
3871 56   50     312 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3872 56         179 my $parsed = $open_bracket;
3873 56         56 my $nest_bracket = 1;
3874 56         56 while (1) {
3875 276 50       1546 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
3876 0         0 $parsed .= $1;
3877 0         0 $nest_bracket++;
3878             }
3879             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3880 56         128 $parsed .= $1;
3881 56 50       105 if (--$nest_bracket <= 0) {
3882 56         75 last;
3883             }
3884             }
3885             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3886 0         0 $parsed .= $1;
3887             }
3888             else {
3889 220         324 $parsed .= parse_q__like($close_bracket);
3890             }
3891             }
3892 56         95 return $parsed;
3893             }
3894              
3895             #---------------------------------------------------------------------
3896             # parse q/string/ that ends with a character
3897             sub parse_q__like_endswith {
3898 5985     5988 0 11330 my($endswith) = @_;
3899 5985         6928 my $parsed = $endswith;
3900 5985         5817 while (1) {
3901 14698 100       44148 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
3902 5985         8312 $parsed .= $1;
3903 5985         6795 last;
3904             }
3905             elsif (/\G (\\ \Q$endswith\E) /xmsgc) {
3906 0         0 $parsed .= $1;
3907             }
3908             else {
3909 8713         11310 $parsed .= parse_q__like($endswith);
3910             }
3911             }
3912 5985         8326 return $parsed;
3913             }
3914              
3915             #---------------------------------------------------------------------
3916             # parse q/string/ common routine
3917             sub parse_q__like {
3918 8933     8936 0 10289 my($closewith) = @_;
3919 8933 100       30631 if (/\G (\\\\) /xmsgc) {
    50          
3920 13         41 return $1;
3921             }
3922             elsif (/\G ($x) /xmsgc) {
3923 8920         13893 return escape_q($1, $closewith);
3924             }
3925              
3926             # something wrong happened
3927             else {
3928 0         0 die sprintf(<
3929 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3930             ------------------------------------------------------------------------------
3931             %s
3932             ------------------------------------------------------------------------------
3933             END
3934             }
3935             }
3936              
3937             #---------------------------------------------------------------------
3938             # parse qq{string} in balanced blackets
3939             sub parse_qq_like_balanced {
3940 85     88 0 116 my($open_bracket) = @_;
3941 85   50     286 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3942 85         123 my $parsed_as_q = $open_bracket;
3943 85         82 my $parsed_as_qq = $open_bracket;
3944 85         77 my $nest_bracket = 1;
3945 85         76 my $nest_escape = 0;
3946 85         79 while (1) {
3947              
3948             # blackets
3949 317 50       3556 if (/\G (\\ \Q$open_bracket\E) /xmsgc) {
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3950 0         0 $parsed_as_q .= $1;
3951 0         0 $parsed_as_qq .= $1;
3952             }
3953             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3954 0         0 $parsed_as_q .= $1;
3955 0         0 $parsed_as_qq .= $1;
3956             }
3957             elsif (/\G (\Q$open_bracket\E) /xmsgc) {
3958 0         0 $parsed_as_q .= $1;
3959 0         0 $parsed_as_qq .= $1;
3960 0         0 $nest_bracket++;
3961             }
3962             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3963 85 50       117 if (--$nest_bracket <= 0) {
3964 85         107 $parsed_as_q .= $1;
3965 85         99 $parsed_as_qq .= ('>)]}' x $nest_escape);
3966 85         81 $parsed_as_qq .= $1;
3967 85         90 last;
3968             }
3969             else {
3970 0         0 $parsed_as_q .= $1;
3971 0         0 $parsed_as_qq .= $1;
3972             }
3973             }
3974              
3975             # \L\u --> \u\L
3976             elsif (/\G (\\L \\u) /xmsgc) {
3977 0         0 $parsed_as_q .= $1;
3978 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3979 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3980 0         0 $nest_escape++;
3981 0         0 $nest_escape++;
3982             }
3983              
3984             # \U\l --> \l\U
3985             elsif (/\G (\\U \\l) /xmsgc) {
3986 0         0 $parsed_as_q .= $1;
3987 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3988 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3989 0         0 $nest_escape++;
3990 0         0 $nest_escape++;
3991             }
3992              
3993             # \L
3994             elsif (/\G (\\L) /xmsgc) {
3995 0         0 $parsed_as_q .= $1;
3996 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3997 0         0 $nest_escape++;
3998             }
3999              
4000             # \U
4001             elsif (/\G (\\U) /xmsgc) {
4002 0         0 $parsed_as_q .= $1;
4003 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
4004 0         0 $nest_escape++;
4005             }
4006              
4007             # \l
4008             elsif (/\G (\\l) /xmsgc) {
4009 0         0 $parsed_as_q .= $1;
4010 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
4011 0         0 $nest_escape++;
4012             }
4013              
4014             # \u
4015             elsif (/\G (\\u) /xmsgc) {
4016 0         0 $parsed_as_q .= $1;
4017 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
4018 0         0 $nest_escape++;
4019             }
4020              
4021             # \Q
4022             elsif (/\G (\\Q) /xmsgc) {
4023 0         0 $parsed_as_q .= $1;
4024 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
4025 0         0 $nest_escape++;
4026             }
4027              
4028             # \E
4029             elsif (/\G (\\E) /xmsgc) {
4030 0         0 $parsed_as_q .= $1;
4031 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
4032 0         0 $nest_escape = 0;
4033             }
4034              
4035             else {
4036 232         357 my($as_qq, $as_q) = parse_qq_like($close_bracket);
4037 232         222 $parsed_as_q .= $as_q;
4038 232         231 $parsed_as_qq .= $as_qq;
4039             }
4040             }
4041              
4042             # return qq-like and q-like quotee
4043 85 100       91 if (wantarray) {
4044 67         141 return ($parsed_as_qq, $parsed_as_q);
4045             }
4046             else {
4047 18         27 return $parsed_as_qq;
4048             }
4049             }
4050              
4051             #---------------------------------------------------------------------
4052             # parse qq/string/ that ends with a character
4053             sub parse_qq_like_endswith {
4054 136315     136318 0 366878 my($endswith) = @_;
4055 136315         168981 my $parsed_as_q = $endswith;
4056 136315         166955 my $parsed_as_qq = $endswith;
4057 136315         167321 my $nest_escape = 0;
4058 136315         145272 while (1) {
4059              
4060             # ends with
4061 705944 50       3684267 if (/\G (\\ \Q$endswith\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
4062 0         0 $parsed_as_q .= $1;
4063 0         0 $parsed_as_qq .= $1;
4064             }
4065             elsif (/\G (\Q$endswith\E) /xmsgc) {
4066 136315         283381 $parsed_as_q .= $1;
4067 136315         239089 $parsed_as_qq .= ('>)]}' x $nest_escape);
4068 136315 50       312084 $parsed_as_qq .= "\n" if CORE::length($1) >= 2; # here document
4069 136315         194272 $parsed_as_qq .= $1;
4070 136315         209449 last;
4071             }
4072              
4073             # \L\u --> \u\L
4074             elsif (/\G (\\L \\u) /xmsgc) {
4075 0         0 $parsed_as_q .= $1;
4076 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
4077 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
4078 0         0 $nest_escape++;
4079 0         0 $nest_escape++;
4080             }
4081              
4082             # \U\l --> \l\U
4083             elsif (/\G (\\U \\l) /xmsgc) {
4084 0         0 $parsed_as_q .= $1;
4085 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
4086 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
4087 0         0 $nest_escape++;
4088 0         0 $nest_escape++;
4089             }
4090              
4091             # \L
4092             elsif (/\G (\\L) /xmsgc) {
4093 0         0 $parsed_as_q .= $1;
4094 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
4095 0         0 $nest_escape++;
4096             }
4097              
4098             # \U
4099             elsif (/\G (\\U) /xmsgc) {
4100 0         0 $parsed_as_q .= $1;
4101 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
4102 0         0 $nest_escape++;
4103             }
4104              
4105             # \l
4106             elsif (/\G (\\l) /xmsgc) {
4107 0         0 $parsed_as_q .= $1;
4108 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
4109 0         0 $nest_escape++;
4110             }
4111              
4112             # \u
4113             elsif (/\G (\\u) /xmsgc) {
4114 0         0 $parsed_as_q .= $1;
4115 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
4116 0         0 $nest_escape++;
4117             }
4118              
4119             # \Q
4120             elsif (/\G (\\Q) /xmsgc) {
4121 0         0 $parsed_as_q .= $1;
4122 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
4123 0         0 $nest_escape++;
4124             }
4125              
4126             # \E
4127             elsif (/\G (\\E) /xmsgc) {
4128 0         0 $parsed_as_q .= $1;
4129 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
4130 0         0 $nest_escape = 0;
4131             }
4132              
4133             else {
4134 569629         683838 my($as_qq, $as_q) = parse_qq_like($endswith);
4135 569629         585998 $parsed_as_q .= $as_q;
4136 569629         574331 $parsed_as_qq .= $as_qq;
4137             }
4138             }
4139              
4140             # return qq-like and q-like quotee
4141 136315 100       202699 if (wantarray) {
4142 1646         2791 return ($parsed_as_qq, $parsed_as_q);
4143             }
4144             else {
4145 134669         291423 return $parsed_as_qq;
4146             }
4147             }
4148              
4149             #---------------------------------------------------------------------
4150             # parse qq/string/ common routine
4151             sub parse_qq_like {
4152 569861     569864 0 611736 my($closewith) = @_;
4153 569861         560966 my $parsed_as_q = '';
4154 569861         526580 my $parsed_as_qq = '';
4155              
4156             # \o{...}
4157 569861 50       4011526 if (/\G ( \\o\{ (.*?) \} ) /xmsgc) {
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
4158 0         0 $parsed_as_q .= $1;
4159 0         0 $parsed_as_qq .= escape_to_hex(mb::chr(oct $2), $closewith);
4160             }
4161              
4162             # \x{...}
4163             elsif (/\G ( \\x\{ (.*?) \} ) /xmsgc) {
4164 1         3 $parsed_as_q .= $1;
4165 1         6 $parsed_as_qq .= escape_to_hex(mb::chr(hex $2), $closewith);
4166             }
4167              
4168             # \any
4169             elsif (/\G ( (\\) ($x) ) /xmsgc) {
4170 278         471 $parsed_as_q .= $1;
4171 278         552 $parsed_as_qq .= ($2 . escape_qq($3, $closewith));
4172             }
4173              
4174             # $` --> @{[mb::_PREMATCH()]}
4175             # ${`} --> @{[mb::_PREMATCH()]}
4176             # $PREMATCH --> @{[mb::_PREMATCH()]}
4177             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
4178             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
4179             elsif (/\G ( \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
4180 2         4 $parsed_as_q .= $1;
4181 2         4 $parsed_as_qq .= '@{[mb::_PREMATCH()]}';
4182             }
4183              
4184             # $& --> @{[mb::_MATCH()]}
4185             # ${&} --> @{[mb::_MATCH()]}
4186             # $MATCH --> @{[mb::_MATCH()]}
4187             # ${MATCH} --> @{[mb::_MATCH()]}
4188             # ${^MATCH} --> @{[mb::_MATCH()]}
4189             elsif (/\G ( \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
4190 2         2 $parsed_as_q .= $1;
4191 2         3 $parsed_as_qq .= '@{[mb::_MATCH()]}';
4192             }
4193              
4194             # $1 --> @{[mb::_CAPTURE(1)]}
4195             # $2 --> @{[mb::_CAPTURE(2)]}
4196             # $3 --> @{[mb::_CAPTURE(3)]}
4197             elsif (/\G ( \$ ([1-9][0-9]*) ) /xmsgc) {
4198 23         35 $parsed_as_q .= $1;
4199 23         41 $parsed_as_qq .= "\@{[mb::_CAPTURE($2)]}";
4200             }
4201              
4202             # @{^CAPTURE} --> @{[mb::_CAPTURE()]}
4203             elsif (/\G ( \@\{\^CAPTURE\} ) /xmsgc) {
4204 0         0 $parsed_as_q .= $1;
4205 0         0 $parsed_as_qq .= '@{[mb::_CAPTURE()]}';
4206             }
4207              
4208             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
4209             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
4210             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
4211             elsif (/\G (\$\{\^CAPTURE\}) \s* (\[) /xmsgc) {
4212 0         0 my $indexing = parse_expr_balanced($2);
4213 0         0 $parsed_as_q .= ($1 . $indexing);
4214 0         0 my $n_th = quotee_of($indexing);
4215 0         0 $parsed_as_qq .= "\@{[mb::_CAPTURE($n_th)]}";
4216             }
4217              
4218             # @- --> @{[mb::_LAST_MATCH_START()]}
4219             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
4220             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
4221             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
4222             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
4223 0         0 $parsed_as_q .= $&;
4224 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_START()]}';
4225             }
4226              
4227             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
4228             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
4229             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
4230             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
4231             elsif (/\G ( \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
4232 0         0 my $indexing = parse_expr_balanced($2);
4233 0         0 $parsed_as_q .= ($1 . $indexing);
4234 0         0 my $n_th = quotee_of($indexing);
4235 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
4236             }
4237              
4238             # @+ --> @{[mb::_LAST_MATCH_END()]}
4239             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
4240             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
4241             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
4242             elsif (/\G ( \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
4243 0         0 $parsed_as_q .= $1;
4244 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_END()]}';
4245             }
4246              
4247             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
4248             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
4249             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
4250             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
4251             elsif (/\G ( \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
4252 0         0 my $indexing = parse_expr_balanced($2);
4253 0         0 $parsed_as_q .= ($1 . $indexing);
4254 0         0 my $n_th = quotee_of($indexing);
4255 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
4256             }
4257              
4258             # any
4259             elsif (/\G ($x) /xmsgc) {
4260 569555         771039 $parsed_as_q .= escape_q ($1, $closewith);
4261 569555         718032 $parsed_as_qq .= escape_qq($1, $closewith);
4262             }
4263              
4264             # something wrong happened
4265             else {
4266 0         0 die sprintf(<
4267 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4268             ------------------------------------------------------------------------------
4269             %s
4270             ------------------------------------------------------------------------------
4271             END
4272             }
4273              
4274             # return qq-like and q-like quotee
4275 569861 50       703807 if (wantarray) {
4276 569861         951729 return ($parsed_as_qq, $parsed_as_q);
4277             }
4278             else {
4279 0         0 return $parsed_as_qq;
4280             }
4281             }
4282              
4283             #---------------------------------------------------------------------
4284             # tr/A-C/1-3/ for US-ASCII codepoint
4285             sub list_all_ASCII_by_hyphen {
4286 5060     5063 0 7800 my @hyphened = @_;
4287 5060         5144 my @list_all = ();
4288 5060         8846 for (my $i=0; $i <= $#hyphened; ) {
4289 6417 100 100     12765 if (
      100        
4290             ($i+1 < $#hyphened) and
4291             ($hyphened[$i+1] eq '-') and
4292             1) {
4293 95 100       127 $hyphened[$i+0] = ($hyphened[$i+0] eq '\\-') ? '-' : $hyphened[$i+0];
4294 95 100       131 $hyphened[$i+2] = ($hyphened[$i+2] eq '\\-') ? '-' : $hyphened[$i+2];
4295 95 50       259 if (0) { }
    50          
    50          
4296 0         0 elsif ($hyphened[$i+0] !~ m/\A [\x00-\x7F] \z/xms) {
4297 0         0 confess sprintf(qq{@{[__FILE__]}: "$hyphened[$i+0]-$hyphened[$i+2]" in tr/// is not US-ASCII});
  0         0  
4298             }
4299             elsif ($hyphened[$i+2] !~ m/\A [\x00-\x7F] \z/xms) {
4300 0         0 confess sprintf(qq{@{[__FILE__]}: "$hyphened[$i+0]-$hyphened[$i+2]" in tr/// is not US-ASCII});
  0         0  
4301             }
4302             elsif ($hyphened[$i+0] gt $hyphened[$i+2]) {
4303 0         0 confess sprintf(qq{@{[__FILE__]}: "$hyphened[$i+0]-$hyphened[$i+2]" in tr/// is not "$hyphened[$i+0]" le "$hyphened[$i+2]"});
  0         0  
4304             }
4305             else {
4306 95         148 push @list_all, map { CORE::chr($_) } (CORE::ord($hyphened[$i+0]) .. CORE::ord($hyphened[$i+2]));
  297         438  
4307 95         142 $i += 3;
4308             }
4309             }
4310             else {
4311 6322 100       8488 if ($hyphened[$i] eq '\\-') {
4312 19         36 push @list_all, '-';
4313             }
4314             else {
4315 6303         7618 push @list_all, $hyphened[$i];
4316             }
4317 6322         8585 $i++;
4318             }
4319             }
4320 5060         9111 return @list_all;
4321             }
4322              
4323             #---------------------------------------------------------------------
4324             # parse tr{here}{here} in balanced blackets
4325             sub parse_tr_like_balanced {
4326 2080     2083 0 3235 my($open_bracket) = @_;
4327 2080   50     8885 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
4328 2080         4089 my @x = ();
4329 2080         2208 my $nest_bracket = 1;
4330 2080         1703 while (1) {
4331              
4332             # blackets
4333 4160 50       66098 if (/\G (\\ \Q$open_bracket\E) /xmsgc) {
    50          
    50          
    100          
    50          
4334 0         0 push @x, $1;
4335             }
4336             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
4337 0         0 push @x, $1;
4338             }
4339             elsif (/\G (\Q$open_bracket\E) /xmsgc) {
4340 0         0 push @x, $1;
4341 0         0 $nest_bracket++;
4342             }
4343             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
4344 2080 50       3368 if (--$nest_bracket <= 0) {
4345 2080         2326 last;
4346             }
4347 0         0 push @x, $1;
4348             }
4349              
4350             # \-
4351             elsif (/\G (\\ -) /xmsgc) {
4352 0         0 push @x, $1;
4353             }
4354              
4355             else {
4356 2080         3916 push @x, parse_tr_like($close_bracket);
4357             }
4358             }
4359 2080         5473 return join('', $open_bracket, @x, $close_bracket);
4360             }
4361              
4362             #---------------------------------------------------------------------
4363             # parse tr/here/here/ that ends with a character
4364             sub parse_tr_like_endswith {
4365 2238     2241 0 3087 my($endswith) = @_;
4366 2238         2231 my $openwith = $endswith;
4367 2238         2659 my @x = ();
4368 2238         1968 while (1) {
4369 4800 50       16474 if (/\G (\\ \Q$endswith\E) /xmsgc) {
    100          
    100          
4370 0         0 push @x, $1;
4371             }
4372             elsif (/\G (\Q$endswith\E) /xmsgc) {
4373 2238         2338 last;
4374             }
4375              
4376             # \-
4377             elsif (/\G (\\ -) /xmsgc) {
4378 9         15 push @x, $1;
4379             }
4380              
4381             else {
4382 2553         3199 push @x, parse_tr_like($endswith);
4383             }
4384             }
4385 2238         4778 return join('', $openwith, @x, $endswith);
4386             }
4387              
4388             #---------------------------------------------------------------------
4389             # parse tr/here/here/ common routine
4390             sub parse_tr_like {
4391 4633     4636 0 5348 my($closewith) = @_;
4392              
4393 4633 100       23054 if (0) {
    100          
    100          
    100          
    100          
    100          
    100          
    50          
4394             }
4395              
4396             # https://perldoc.perl.org/perlop#Interpolation
4397             # tr///, y///
4398             # No variable interpolation occurs.
4399             # String modifying combinations for case and quoting such as \Q, \U, and \E are not recognized.
4400             # The other escape sequences such as \200 and \t and backslashed characters such as \\ and \- are converted to appropriate literals.
4401             # The character "-" is treated specially and therefore \- is treated as a literal "-".
4402              
4403             # \ddd
4404 0         0 elsif (/\G \\ ( [0-3][0-7][0-7] | [0-7][0-7] | [0-7] ) /xmsgc) {
4405 4         19 return escape_tr(mb::chr(oct $1), $closewith);
4406             }
4407              
4408             # \oddd
4409             elsif (/\G \\o ( [0-3][0-7][0-7] | [0-7][0-7] | [0-7] ) /xmsgc) {
4410 4         13 return escape_tr(mb::chr(oct $1), $closewith);
4411             }
4412              
4413             # \o{...}
4414             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
4415 4         11 return escape_tr(mb::chr(oct $1), $closewith);
4416             }
4417              
4418             # \xhh
4419             elsif (/\G \\x ( [0-9A-Fa-f][0-9A-Fa-f] | [0-9A-Fa-f] ) /xmsgc) {
4420 3         9 return escape_tr(mb::chr(hex $1), $closewith);
4421             }
4422              
4423             # \x{...}
4424             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
4425 3         7 return escape_tr(mb::chr(hex $1), $closewith);
4426             }
4427              
4428             # \cX
4429             elsif (/\G ( \\c [\@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]^_?] ) /xmsgc) {
4430             return {
4431             '\\c@' => "\c@",
4432             '\\cA' => "\cA",
4433             '\\cB' => "\cB",
4434             '\\cC' => "\cC",
4435             '\\cD' => "\cD",
4436             '\\cE' => "\cE",
4437             '\\cF' => "\cF",
4438             '\\cG' => "\cG",
4439             '\\cH' => "\cH",
4440             '\\cI' => "\cI",
4441             '\\cJ' => "\cJ",
4442             '\\cK' => "\cK",
4443             '\\cL' => "\cL",
4444             '\\cM' => "\cM",
4445             '\\cN' => "\cN",
4446             '\\cO' => "\cO",
4447             '\\cP' => "\cP",
4448             '\\cQ' => "\cQ",
4449             '\\cR' => "\cR",
4450             '\\cS' => "\cS",
4451             '\\cT' => "\cT",
4452             '\\cU' => "\cU",
4453             '\\cV' => "\cV",
4454             '\\cW' => "\cW",
4455             '\\cX' => "\cX",
4456             '\\cY' => "\cY",
4457             '\\cZ' => "\cZ",
4458             '\\c[' => "\c[",
4459             '\\c\\' => CORE::chr(0x1C),
4460             '\\c]' => "\c]",
4461             '\\c^' => "\c^",
4462             '\\c_' => "\c_",
4463             '\\c?' => CORE::chr(0x7F),
4464 9   50     166 }->{$1} || die;
4465             }
4466              
4467             # \\ \a \b \e \f \n \r \t \E \l \L \u \U \Q
4468             elsif (/\G ( \\ ([\\abefnrtElLuUQ]) ) /xmsgc) {
4469             return {
4470             "\x5C\x5C" => "\x5C\x5C",
4471             '\a' => "\a",
4472             '\b' => "\b",
4473             '\e' => "\e",
4474             '\f' => "\f",
4475             '\n' => "\n",
4476             '\r' => "\r",
4477             '\t' => "\t",
4478 16   66     185 }->{$1} || $2;
4479             }
4480              
4481             # any
4482             elsif (/\G ($x) /xmsgc) {
4483 4590         6185 return escape_tr($1, $closewith);
4484             }
4485              
4486             # something wrong happened
4487             else {
4488 0         0 die sprintf(<
4489 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4490             ------------------------------------------------------------------------------
4491             %s
4492             ------------------------------------------------------------------------------
4493             END
4494             }
4495             }
4496              
4497             #---------------------------------------------------------------------
4498             # qr/ [A-Z] / for Shift_JIS-like encoding
4499             sub list_all_by_hyphen_sjis_like {
4500 8435     8438 0 12518 my($a, $b) = @_;
4501 8435         24776 my @a = (undef, unpack 'C*', $a);
4502 8435         13570 my @b = (undef, unpack 'C*', $b);
4503              
4504 8435 100       18332 if (0) { }
    50          
4505 0         0 elsif (CORE::length($a) == 1) {
4506 2995 100       6015 if (0) { }
    50          
4507 0         0 elsif (CORE::length($b) == 1) {
4508             return (
4509 435 50 100     2807 (($a[1] <= 0x80) and (0xA0 <= $b[1])) ?
    100          
4510             sprintf(join('', qw( [\x%02x-\x80\xA0-\x%02x] )), $a[1],
4511             $b[1]) :
4512             $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4513             $b[1]) : (),
4514             );
4515             }
4516             elsif (CORE::length($b) == 2) {
4517             return (
4518 2560 100       19013 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
    50          
    50          
    100          
4519             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4520             $a[1] <= 0x80 ? sprintf(join('', qw( [\x%02x-\x80\xA0-\xDF] )), $a[1]) :
4521             $a[1] < 0xA0 ? () :
4522             $a[1] <= 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] )), $a[1]) : (),
4523             );
4524             }
4525             }
4526             elsif (CORE::length($a) == 2) {
4527 5440 50       8993 if (0) { }
4528 0         0 elsif (CORE::length($b) == 2) {
4529 5440 100       25694 my $lower_limit = join('|',
4530             $a[1] < 0xFC ? sprintf(join('', qw( [\x%02x-\xFC] [\x00-\xFF ] )), $a[1]+1 ) : (),
4531             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4532             );
4533 5440 100       16143 my $upper_limit = join('|',
4534             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4535             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4536             );
4537 5440         17313 return qq{(?=$lower_limit)(?=$upper_limit)};
4538             }
4539             }
4540              
4541             # over range of codepoint
4542 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4543             }
4544              
4545             #---------------------------------------------------------------------
4546             # the one-octet universe of INFORMIX V6 ALS, intersected with [$from,$to]
4547             # (when $to is omitted it defaults to \xFF, the top of the universe), as a
4548             # regex alternation. \xFD is ambiguous as a bare byte value: it is a genuine
4549             # one-octet character only when NOT followed by \xA1-\xFE (otherwise it is
4550             # the lead of the three-octet plane), so it needs a negative lookahead rather
4551             # than a plain byte-range member; \xE0-\xFC are never one-octet (always a
4552             # two-octet lead) and are excluded entirely; every other byte in \xA0-\xFF is
4553             # an unambiguous one-octet character. This helper is the single source of the
4554             # one-octet set: every branch that needs "the valid single octets in a range"
4555             # calls it, so the \xFD guard and the \xE0-\xFC exclusion cannot drift.
4556             sub _informixv6als_onebyte_sweep {
4557 2761     2764   3327 my ($from, $to) = @_;
4558 2761 100       4353 $to = 0xFF unless defined $to;
4559 2761         2823 my @piece = ();
4560              
4561             # contiguous single sub-range [\x00-\x80] intersected with [$from,$to]
4562 2761 100       3320 my $lo1 = ($from > 0x00) ? $from : 0x00;
4563 2761 100       3184 my $hi1 = ($to < 0x80) ? $to : 0x80;
4564 2761 100       4184 if ($lo1 <= $hi1) {
4565 1261 100       3464 push @piece, ($lo1 == $hi1) ? sprintf('\x%02x', $lo1)
4566             : sprintf('[\x%02x-\x%02x]', $lo1, $hi1);
4567             }
4568              
4569             # contiguous single sub-range [\xA0-\xDF] intersected with [$from,$to]
4570 2761 100       3214 my $lo2 = ($from > 0xA0) ? $from : 0xA0;
4571 2761 100       3166 my $hi2 = ($to < 0xDF) ? $to : 0xDF;
4572 2761 100       3240 if ($lo2 <= $hi2) {
4573 1770 100       3942 push @piece, ($lo2 == $hi2) ? sprintf('\x%02x', $lo2)
4574             : sprintf('[\x%02x-\x%02x]', $lo2, $hi2);
4575             }
4576              
4577             # \xFD is a genuine one-octet character only when NOT the lead of the
4578             # three-octet plane (i.e. when NOT followed by \xA1-\xFE), so it needs the
4579             # negative lookahead rather than a bare byte-range member.
4580 2761 100 100     6378 if (($from <= 0xFD) and (0xFD <= $to)) {
4581 1800         2258 push @piece, '\xFD(?![\xA1-\xFE])';
4582             }
4583 2761 100 100     5142 if (($from <= 0xFE) and (0xFE <= $to)) {
4584 1890         1914 push @piece, '\xFE';
4585             }
4586 2761 100 66     5042 if (($from <= 0xFF) and (0xFF <= $to)) {
4587 1920         2246 push @piece, '\xFF';
4588             }
4589              
4590 2761         9373 return join('|', @piece);
4591             }
4592              
4593             #---------------------------------------------------------------------
4594             # qr/ [A-Z] / for INFORMIX V6 ALS-like encoding
4595             #
4596             # INFORMIX V6 ALS codepoint structure (all in byte form):
4597             # 1 octet US-ASCII plus the non-lead high bytes [\x00-\x80\xA0-\xDF\xFD-\xFF]
4598             # 2 octets Shift_JIS-compatible core (== sjis) [\x81-\x9F\xE0-\xFC][\x00-\xFF]
4599             # 3 octets \xFD user-defined plane \xFD[\xA1-\xFE][\x00-\xFF]
4600             # The 1- and 2-octet cases are byte-for-byte the same as sjis (see
4601             # list_all_by_hyphen_sjis_like) and are reused verbatim here; only the cases
4602             # that touch the 3-octet \xFD plane are new. mb orders codepoints length-first
4603             # (every one-octet unit before every two-octet unit before every three-octet
4604             # unit), the same order list_all_by_hyphen_sjis_like assumes.
4605             sub list_all_by_hyphen_informixv6als_like {
4606 3601     3604 0 4871 my($a, $b) = @_;
4607 3601         9457 my @a = (undef, unpack 'C*', $a);
4608 3601         5961 my @b = (undef, unpack 'C*', $b);
4609              
4610 3601 100       5758 if (0) { }
    100          
    50          
4611 0         0 elsif (CORE::length($a) == 1) {
4612 2761 100       4295 if (0) { }
    100          
    50          
4613 0         0 elsif (CORE::length($b) == 1) {
4614             # the valid single octets in [$a[1],$b[1]]; the sweep excludes the
4615             # \xE0-\xFC two-octet leads and guards \xFD against being read as a
4616             # three-octet lead, so a range whose top reaches \xFD-\xFF cannot
4617             # wrongly match the lead byte of a \xFD-plane character.
4618 1081         1679 my $body = _informixv6als_onebyte_sweep($a[1], $b[1]);
4619 1081 50       2607 return ($body eq '') ? () : ($body);
4620             }
4621             elsif (CORE::length($b) == 2) {
4622             return (
4623 1200 100       5066 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4624             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4625             # length 1: a .. the top of the one-octet universe (incl. \xFD-\xFF)
4626             _informixv6als_onebyte_sweep($a[1]),
4627             );
4628             }
4629             elsif (CORE::length($b) == 3) {
4630             return (
4631             # length 3: \xFD\xA1\x00 .. b
4632 480 100       2151 sprintf(join('', qw( \xFD \x%02x [\x00-\x%02x] )), $b[2], $b[3]),
4633             0xA1 < $b[2] ? sprintf(join('', qw( \xFD [\xA1-\x%02x] [\x00-\xFF ] )), $b[2]-1 ) : (),
4634              
4635             # length 2: the full sjis-core two-octet universe
4636             sprintf(join('', qw( [\x81-\x9F\xE0-\xFC][\x00-\xFF] )), ),
4637              
4638             # length 1: a .. the top of the one-octet universe
4639             _informixv6als_onebyte_sweep($a[1]),
4640             );
4641             }
4642             }
4643             elsif (CORE::length($a) == 2) {
4644 750 100       1198 if (0) { }
    50          
4645 0         0 elsif (CORE::length($b) == 2) {
4646 450 100       2027 my $lower_limit = join('|',
4647             $a[1] < 0xFC ? sprintf(join('', qw( [\x%02x-\xFC] [\x00-\xFF ] )), $a[1]+1 ) : (),
4648             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4649             );
4650 450 100       1188 my $upper_limit = join('|',
4651             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4652             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4653             );
4654 450         1306 return qq{(?=$lower_limit)(?=$upper_limit)};
4655             }
4656             elsif (CORE::length($b) == 3) {
4657             return (
4658             # length 3: \xFD\xA1\x00 .. b
4659 300 100       2248 sprintf(join('', qw( \xFD \x%02x [\x00-\x%02x] )), $b[2], $b[3]),
    100          
4660             0xA1 < $b[2] ? sprintf(join('', qw( \xFD [\xA1-\x%02x] [\x00-\xFF ] )), $b[2]-1 ) : (),
4661             # length 2: a .. \xFC\xFF (top of the two-octet universe)
4662             $a[1] < 0xFC ? sprintf(join('', qw( [\x%02x-\xFC] [\x00-\xFF ] )), $a[1]+1 ) : (),
4663             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4664             );
4665             }
4666             }
4667             elsif (CORE::length($a) == 3) {
4668 90 50       125 if (0) { }
4669 0         0 elsif (CORE::length($b) == 3) {
4670 90 100       389 my $lower_limit = join('|',
4671             $a[2] < 0xFE ? sprintf(join('', qw( \xFD [\x%02x-\xFE] [\x00-\xFF ] )), $a[2]+1 ) : (),
4672             sprintf(join('', qw( \xFD \x%02x [\x%02x-\xFF] )), $a[2], $a[3]),
4673             );
4674 90 100       263 my $upper_limit = join('|',
4675             sprintf(join('', qw( \xFD \x%02x [\x00-\x%02x] )), $b[2], $b[3]),
4676             0xA1 < $b[2] ? sprintf(join('', qw( \xFD [\xA1-\x%02x] [\x00-\xFF ] )), $b[2]-1 ) : (),
4677             );
4678 90         274 return qq{(?=$lower_limit)(?=$upper_limit)};
4679             }
4680             }
4681              
4682             # over range of codepoint
4683 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4684             }
4685              
4686             #---------------------------------------------------------------------
4687             # qr/ [A-Z] / for EUC-JP-like encoding
4688             sub list_all_by_hyphen_eucjp_like {
4689 253     256 0 299 my($a, $b) = @_;
4690 253         665 my @a = (undef, unpack 'C*', $a);
4691 253         408 my @b = (undef, unpack 'C*', $b);
4692              
4693 253 100       433 if (0) { }
    50          
4694 0         0 elsif (CORE::length($a) == 1) {
4695 133 100       219 if (0) { }
    50          
4696 0         0 elsif (CORE::length($b) == 1) {
4697             return (
4698 37 50       193 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4699             $b[1]) : (),
4700             );
4701             }
4702             elsif (CORE::length($b) == 2) {
4703             return (
4704 96 100       602 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4705             0xA1 < $b[1] ? sprintf(join('', qw( [\xA1-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4706             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4707             );
4708             }
4709             }
4710             elsif (CORE::length($a) == 2) {
4711 120 50       182 if (0) { }
4712 0         0 elsif (CORE::length($b) == 2) {
4713 120 100       546 my $lower_limit = join('|',
4714             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\x00-\xFF ] )), $a[1]+1 ) : (),
4715             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4716             );
4717 120 100       323 my $upper_limit = join('|',
4718             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4719             0xA1 < $b[1] ? sprintf(join('', qw( [\xA1-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4720             );
4721 120         325 return qq{(?=$lower_limit)(?=$upper_limit)};
4722             }
4723             }
4724              
4725             # over range of codepoint
4726 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4727             }
4728              
4729             #---------------------------------------------------------------------
4730             # qr/ [A-Z] / for EUC-TW-like encoding
4731             #
4732             # EUC-TW codepoint structure (all in byte form):
4733             # 1 octet US-ASCII [\x00-\x7F]
4734             # 2 octets CNS 11643 plane 1 [\xA1-\xFE][\xA1-\xFE]
4735             # 4 octets SS2 planes 2..16 \x8E[\xA1-\xB0][\xA1-\xFE][\x00-\xFF]
4736             # (there is no 3-octet form). Range semantics follow the legacy Char-EUCTW
4737             # Eeuctw _charlist: ordering is length-first (every 1-octet char < every
4738             # 2-octet char < every 4-octet char), so [A-B] is the union, over each length
4739             # L in length(A)..length(B), of: A..max(L) for the shortest length, all of L
4740             # for an intermediate length, and min(L)..B for the longest length. The
4741             # non-existent 3-octet length is skipped (as the gb18030 helper skips it).
4742             # Every branch is consumed by the enclosing (?=...)$x / (?!...)$x wrapper, so a
4743             # branch only has to assert the in-range octets and $x consumes the character.
4744             sub list_all_by_hyphen_euctw_like {
4745 1106     1109 0 1440 my($a, $b) = @_;
4746 1106         2997 my @a = (undef, unpack 'C*', $a);
4747 1106         1805 my @b = (undef, unpack 'C*', $b);
4748              
4749 1106 100       2221 if (0) { }
    100          
    50          
4750 0         0 elsif (CORE::length($a) == 1) {
4751 384 100       726 if (0) { }
    100          
    50          
4752 0         0 elsif (CORE::length($b) == 1) {
4753             return (
4754 61 50       285 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1], $b[1]) : (),
4755             );
4756             }
4757             elsif (CORE::length($b) == 2) {
4758             return (
4759             # length 2: \xA1\xA1 .. b
4760 160 100       1090 sprintf(join('', qw( \x%02x [\xA1-\x%02x] )), $b[1], $b[2]),
4761             0xA1 < $b[1] ? sprintf(join('', qw( [\xA1-\x%02x] [\xA1-\xFE ] )), $b[1]-1 ) : (),
4762             # length 1: a .. \x7F
4763             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4764             );
4765             }
4766             elsif (CORE::length($b) == 4) {
4767             return (
4768             # length 4: \x8E\xA1\xA1\x00 .. b (lead is always \x8E)
4769 163 100       1153 sprintf(join('', qw( \x8E \x%02x \x%02x [\x00-\x%02x] )), $b[2], $b[3], $b[4]),
    100          
4770             0xA1 < $b[3] ? sprintf(join('', qw( \x8E \x%02x [\xA1-\x%02x] [\x00-\xFF ] )), $b[2], $b[3]-1 ) : (),
4771             0xA1 < $b[2] ? sprintf(join('', qw( \x8E [\xA1-\x%02x] [\xA1-\xFE ] [\x00-\xFF ] )), $b[2]-1 ) : (),
4772             # length 2: all two-octet chars
4773             sprintf(join('', qw( [\xA1-\xFE] [\xA1-\xFE] )), ),
4774             # length 1: a .. \x7F
4775             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4776             );
4777             }
4778             }
4779             elsif (CORE::length($a) == 2) {
4780 521 100       916 if (0) { }
    50          
4781 0         0 elsif (CORE::length($b) == 2) {
4782 200 100       887 my $lower_limit = join('|',
4783             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\xA1-\xFE ] )), $a[1]+1 ) : (),
4784             sprintf(join('', qw( \x%02x [\x%02x-\xFE] )), $a[1], $a[2]),
4785             );
4786 200 100       560 my $upper_limit = join('|',
4787             sprintf(join('', qw( \x%02x [\xA1-\x%02x] )), $b[1], $b[2]),
4788             0xA1 < $b[1] ? sprintf(join('', qw( [\xA1-\x%02x] [\xA1-\xFE ] )), $b[1]-1 ) : (),
4789             );
4790 200         576 return qq{(?=$lower_limit)(?=$upper_limit)};
4791             }
4792             elsif (CORE::length($b) == 4) {
4793             return (
4794             # length 4: \x8E\xA1\xA1\x00 .. b
4795 321 100       2472 sprintf(join('', qw( \x8E \x%02x \x%02x [\x00-\x%02x] )), $b[2], $b[3], $b[4]),
    100          
    100          
4796             0xA1 < $b[3] ? sprintf(join('', qw( \x8E \x%02x [\xA1-\x%02x] [\x00-\xFF ] )), $b[2], $b[3]-1 ) : (),
4797             0xA1 < $b[2] ? sprintf(join('', qw( \x8E [\xA1-\x%02x] [\xA1-\xFE ] [\x00-\xFF ] )), $b[2]-1 ) : (),
4798             # length 2: a .. \xFE\xFE
4799             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\xA1-\xFE ] )), $a[1]+1 ) : (),
4800             sprintf(join('', qw( \x%02x [\x%02x-\xFE] )), $a[1], $a[2]),
4801             );
4802             }
4803             }
4804             elsif (CORE::length($a) == 4) {
4805 201 50       325 if (0) { }
4806 0         0 elsif (CORE::length($b) == 4) {
4807 201 100       1156 my $lower_limit = join('|',
    100          
4808             # >= a, lead is always \x8E
4809             $a[2] < 0xB0 ? sprintf(join('', qw( \x8E [\x%02x-\xB0] [\xA1-\xFE ] [\x00-\xFF ] )), $a[2]+1 ) : (),
4810             $a[3] < 0xFE ? sprintf(join('', qw( \x8E \x%02x [\x%02x-\xFE] [\x00-\xFF ] )), $a[2], $a[3]+1 ) : (),
4811             sprintf(join('', qw( \x8E \x%02x \x%02x [\x%02x-\xFF] )), $a[2], $a[3], $a[4]),
4812             );
4813 201 100       705 my $upper_limit = join('|',
    100          
4814             sprintf(join('', qw( \x8E \x%02x \x%02x [\x00-\x%02x] )), $b[2], $b[3], $b[4]),
4815             0xA1 < $b[3] ? sprintf(join('', qw( \x8E \x%02x [\xA1-\x%02x] [\x00-\xFF ] )), $b[2], $b[3]-1 ) : (),
4816             0xA1 < $b[2] ? sprintf(join('', qw( \x8E [\xA1-\x%02x] [\xA1-\xFE ] [\x00-\xFF ] )), $b[2]-1 ) : (),
4817             );
4818 201         613 return qq{(?=$lower_limit)(?=$upper_limit)};
4819             }
4820             }
4821              
4822             # over range of codepoint
4823 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4824             }
4825              
4826             #---------------------------------------------------------------------
4827             # qr/ [A-Z] / for Big5-like encoding
4828             sub list_all_by_hyphen_big5_like {
4829 256     258 0 364 my($a, $b) = @_;
4830 256         664 my @a = (undef, unpack 'C*', $a);
4831 256         387 my @b = (undef, unpack 'C*', $b);
4832              
4833 256 100       487 if (0) { }
    50          
4834 0         0 elsif (CORE::length($a) == 1) {
4835 136 100       216 if (0) { }
    50          
4836 0         0 elsif (CORE::length($b) == 1) {
4837             return (
4838 40 50       188 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4839             $b[1]) : (),
4840             );
4841             }
4842             elsif (CORE::length($b) == 2) {
4843             return (
4844 96 100       549 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4845             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4846             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4847             );
4848             }
4849             }
4850             elsif (CORE::length($a) == 2) {
4851 120 50       148 if (0) { }
4852 0         0 elsif (CORE::length($b) == 2) {
4853 120 100       506 my $lower_limit = join('|',
4854             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\x00-\xFF ] )), $a[1]+1 ) : (),
4855             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4856             );
4857 120 100       361 my $upper_limit = join('|',
4858             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4859             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4860             );
4861 120         372 return qq{(?=$lower_limit)(?=$upper_limit)};
4862             }
4863             }
4864              
4865             # over range of codepoint
4866 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4867             }
4868              
4869             #---------------------------------------------------------------------
4870             # qr/ [A-Z] / for HP-15-like encoding
4871             #
4872             # HP-15 has a discontinuous two-octet lead [\x80-\xA0\xE0-\xFE] with the
4873             # single-octet JIS X 0201 katakana [\xA1-\xDF] sitting between the two lead
4874             # ranges and the single octet \xFF above them (verified against the legacy
4875             # Ehp15 %range_tr). So a codepoint-class range that touches the high bytes
4876             # must intersect [lo,hi] with the exact single-octet set and the exact lead
4877             # set rather than emit one contiguous class (as the contiguous-lead sjis/big5
4878             # helpers do). mb orders codepoints length-first (every one-octet unit sorts
4879             # before every two-octet unit), the same order list_all_by_hyphen_sjis_like
4880             # assumes.
4881             sub list_all_by_hyphen_hp15_like {
4882 3601     3601 0 4697 my($a, $b) = @_;
4883 3601         9438 my @a = (undef, unpack 'C*', $a);
4884 3601         5551 my @b = (undef, unpack 'C*', $b);
4885              
4886             # HP-15 valid single-octet units and valid lead octets
4887 3601         7419 my @single_ranges = ([0x00,0x7F],[0xA1,0xDF],[0xFF,0xFF]);
4888 3601         6246 my @lead_ranges = ([0x80,0xA0],[0xE0,0xFE]);
4889              
4890             # class body for the intersection of [$lo,$hi] with @{$_[2]} ('' if empty)
4891             my $isect = sub {
4892 6751     6751   8510 my($lo, $hi, $ranges) = @_;
4893 6751         6453 my $body = '';
4894 6751         6158 for my $r (@{$ranges}) {
  6751         10030  
4895 15453 100       19026 my $x = ($r->[0] > $lo) ? $r->[0] : $lo;
4896 15453 100       17141 my $y = ($r->[1] < $hi) ? $r->[1] : $hi;
4897 15453 100       19812 next if $x > $y;
4898 9811 100       22982 $body .= ($x == $y) ? sprintf('\x%02x', $x)
4899             : sprintf('\x%02x-\x%02x', $x, $y);
4900             }
4901 6751         9932 return $body;
4902 3601         14732 };
4903              
4904 3601 100       7290 if (0) { }
    50          
4905 0         0 elsif (CORE::length($a) == 1) {
4906 1951 100       3435 if (0) { }
    50          
4907 0         0 elsif (CORE::length($b) == 1) {
4908 451         722 my $body = $isect->($a[1], $b[1], \@single_ranges);
4909 451 50       3429 return ($body eq '') ? () : ("[$body]");
4910             }
4911             elsif (CORE::length($b) == 2) {
4912 1500         1701 my @out = ();
4913              
4914             # every valid single octet >= $a[1] (all sort before any two-octet $b)
4915 1500         2480 my $sbody = $isect->($a[1], 0xFF, \@single_ranges);
4916 1500 50       3702 push @out, "[$sbody]" if $sbody ne '';
4917              
4918             # two-octet units whose lead is a valid lead below $b[1] (full trail)
4919 1500         2580 my $lbody = $isect->(0x80, $b[1]-1, \@lead_ranges);
4920 1500 100       2918 push @out, sprintf('[%s][\x00-\xFF]', $lbody) if $lbody ne '';
4921              
4922             # two-octet units with lead == $b[1] and trail <= $b[2]
4923 1500         2751 push @out, sprintf('\x%02x[\x00-\x%02x]', $b[1], $b[2]);
4924 1500         11367 return @out;
4925             }
4926             }
4927             elsif (CORE::length($a) == 2) {
4928 1650 50       2460 if (0) { }
4929 0         0 elsif (CORE::length($b) == 2) {
4930 1650         1587 my @lower = ();
4931 1650         5444 push @lower, sprintf('\x%02x[\x%02x-\xFF]', $a[1], $a[2]);
4932 1650         3218 my $lo_leads = $isect->($a[1]+1, 0xFE, \@lead_ranges);
4933 1650 100       3974 push @lower, sprintf('[%s][\x00-\xFF]', $lo_leads) if $lo_leads ne '';
4934              
4935 1650         1536 my @upper = ();
4936 1650         2996 push @upper, sprintf('\x%02x[\x00-\x%02x]', $b[1], $b[2]);
4937 1650         2570 my $up_leads = $isect->(0x80, $b[1]-1, \@lead_ranges);
4938 1650 100       3182 push @upper, sprintf('[%s][\x00-\xFF]', $up_leads) if $up_leads ne '';
4939              
4940 1650         2744 my $lower_limit = join('|', @lower);
4941 1650         2332 my $upper_limit = join('|', @upper);
4942 1650         12514 return qq{(?=$lower_limit)(?=$upper_limit)};
4943             }
4944             }
4945              
4946             # over range of codepoint
4947 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4948             }
4949              
4950             #---------------------------------------------------------------------
4951             # qr/ [A-Z] / for GB18030-like encoding
4952             sub list_all_by_hyphen_gb18030_like {
4953 18253     18253 0 24785 my($a, $b) = @_;
4954 18253         50728 my @a = (undef, unpack 'C*', $a);
4955 18253         28572 my @b = (undef, unpack 'C*', $b);
4956              
4957 18253 100       43828 if (0) { }
    100          
    50          
4958 0         0 elsif (CORE::length($a) == 1) {
4959 2653 100       5712 if (0) { }
    100          
    50          
4960 0         0 elsif (CORE::length($b) == 1) {
4961             return (
4962 157 50       777 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4963             $b[1]) : (),
4964             );
4965             }
4966             elsif (CORE::length($b) == 2) {
4967             return (
4968 832 100       5362 sprintf(join('', qw( \x%02x [\x00-\x2F\x3A-\x%02x] )), $b[1], $b[2]),
4969             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [^\x30-\x39 ] )), $b[1]-1 ) : (),
4970             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4971             );
4972             }
4973             elsif (CORE::length($b) == 4) {
4974             return (
4975 1664 100       15089 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x30-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
4976             0x81 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x81-\x%02x] [\x30-\x39 ] )), $b[1], $b[2], $b[3]-1 ) : (),
4977             0x30 < $b[2] ? sprintf(join('', qw( \x%02x [\x30-\x%02x] [\x81-\xFE ] [\x30-\x39 ] )), $b[1], $b[2]-1 ) : (),
4978             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $b[1]-1 ) : (),
4979             sprintf(join('', qw( [\x81-\xFE ] [^\x30-\x39 ] )), ),
4980             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4981             );
4982             }
4983             }
4984             elsif (CORE::length($a) == 2) {
4985 8528 100       17564 if (0) { }
    50          
4986 0         0 elsif (CORE::length($b) == 2) {
4987 1872 100       8948 my $lower_limit = join('|',
4988             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [^\x30-\x39 ] )), $a[1]+1 ) : (),
4989             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4990             );
4991 1872 100       6130 my $upper_limit = join('|',
4992             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4993             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [^\x30-\x39 ] )), $b[1]-1 ) : (),
4994             );
4995 1872         5947 return qq{(?=$lower_limit)(?=$upper_limit)};
4996             }
4997             elsif (CORE::length($b) == 4) {
4998             return (
4999 6656 100       63810 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x30-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
    100          
5000             0x81 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x81-\x%02x] [\x30-\x39 ] )), $b[1], $b[2], $b[3]-1 ) : (),
5001             0x30 < $b[2] ? sprintf(join('', qw( \x%02x [\x30-\x%02x] [\x81-\xFE ] [\x30-\x39 ] )), $b[1], $b[2]-1 ) : (),
5002             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $b[1]-1 ) : (),
5003             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [^\x30-\x39 ] )), $a[1]+1 ) : (),
5004             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2] ),
5005             );
5006             }
5007             }
5008             elsif (CORE::length($a) == 4) {
5009 7072 50       11566 if (0) { }
5010 0         0 elsif (CORE::length($b) == 4) {
5011 7072 100       48109 my $lower_limit = join('|',
    100          
    100          
5012             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $a[1]+1 ) : (),
5013             $a[2] < 0x39 ? sprintf(join('', qw( \x%02x [\x%02x-\x39] [\x81-\xFE ] [\x30-\x39 ] )), $a[1], $a[2]+1 ) : (),
5014             $a[3] < 0xFE ? sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xFE] [\x30-\x39 ] )), $a[1], $a[2], $a[3]+1 ) : (),
5015             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x%02x-\x39] )), $a[1], $a[2], $a[3], $a[4]),
5016             );
5017 7072 100       33608 my $upper_limit = join('|',
    100          
    100          
5018             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x30-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
5019             0x81 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x81-\x%02x] [\x30-\x39 ] )), $b[1], $b[2], $b[3]-1 ) : (),
5020             0x30 < $b[2] ? sprintf(join('', qw( \x%02x [\x30-\x%02x] [\x81-\xFE ] [\x30-\x39 ] )), $b[1], $b[2]-1 ) : (),
5021             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $b[1]-1 ) : (),
5022             );
5023 7072         24066 return qq{(?=$lower_limit)(?=$upper_limit)};
5024             }
5025             }
5026              
5027             # over range of codepoint
5028 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
5029             }
5030              
5031             #---------------------------------------------------------------------
5032             # qr/ [A-Z] / for UTF-8-like encoding
5033             sub list_all_by_hyphen_utf8_like {
5034 90127     90127 0 124137 my($a, $b) = @_;
5035 90127         260642 my @a = (undef, unpack 'C*', $a);
5036 90127         140509 my @b = (undef, unpack 'C*', $b);
5037              
5038 90127 100       272910 if (0) { }
    100          
    100          
    50          
5039 0         0 elsif (CORE::length($a) == 1) {
5040 9737 100       23738 if (0) { }
    100          
    100          
    50          
5041 0         0 elsif (CORE::length($b) == 1) {
5042             return (
5043 425 50       2008 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
5044             $b[1]) : (),
5045             );
5046             }
5047             elsif (CORE::length($b) == 2) {
5048             return (
5049 816 100       4962 sprintf(join('', qw( \x%02x [\x80-\x%02x] )), $b[1], $b[2]),
5050             0xC2 < $b[1] ? sprintf(join('', qw( [\xC2-\x%02x] [\x80-\xBF ] )), $b[1]-1 ) : (),
5051             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
5052             );
5053             }
5054             elsif (CORE::length($b) == 3) {
5055             return (
5056 3376 100       25705 sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3]),
    100          
5057             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5058             0xE0 < $b[1] ? sprintf(join('', qw( [\xE0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5059             sprintf(join('', qw( [\xC2-\xDF ] [\x80-\xBF ] )), ),
5060             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
5061             );
5062             }
5063             elsif (CORE::length($b) == 4) {
5064             return (
5065 5120 100       42937 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
5066             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
5067             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5068             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5069             sprintf(join('', qw( [\xE0-\xEF ] [\x80-\xBF ] [\x80-\xBF ] )), ),
5070             sprintf(join('', qw( [\xC2-\xDF ] [\x80-\xBF ] )), ),
5071             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
5072             );
5073             }
5074             }
5075             elsif (CORE::length($a) == 2) {
5076 12692 100       28214 if (0) { }
    100          
    50          
5077 0         0 elsif (CORE::length($b) == 2) {
5078 868 100       3692 my $lower_limit = join('|',
5079             $a[1] < 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] [\x80-\xBF ] )), $a[1]+1 ) : (),
5080             sprintf(join('', qw( \x%02x [\x%02x-\xBF] )), $a[1], $a[2]),
5081             );
5082 868 100       2381 my $upper_limit = join('|',
5083             sprintf(join('', qw( \x%02x [\x80-\x%02x] )), $b[1], $b[2]),
5084             0xC2 < $b[1] ? sprintf(join('', qw( [\xC2-\x%02x] [\x80-\xBF ] )), $b[1]-1 ) : (),
5085             );
5086 868         2719 return qq{(?=$lower_limit)(?=$upper_limit)};
5087             }
5088             elsif (CORE::length($b) == 3) {
5089             return (
5090 6448 100       61297 sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3] ),
    100          
    100          
5091             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5092             0xE0 < $b[1] ? sprintf(join('', qw( [\xE0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5093             $a[1] < 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] [\x80-\xBF ] )), $a[1]+1 ) : (),
5094             sprintf(join('', qw( \x%02x [\x%02x-\xBF] )), $a[1], $a[2] ),
5095             );
5096             }
5097             elsif (CORE::length($b) == 4) {
5098             return (
5099 5376 100       49469 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
    100          
5100             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
5101             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5102             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5103             sprintf(join('', qw( [\xE0-\xEF ] [\x80-\xBF ] [\x80-\xBF ] )), ),
5104             $a[1] < 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] [\x80-\xBF ] )), $a[1]+1 ) : (),
5105             sprintf(join('', qw( \x%02x [\x%02x-\xBF] )), $a[1], $a[2] ),
5106             );
5107             }
5108             }
5109             elsif (CORE::length($a) == 3) {
5110 27378 100       46812 if (0) { }
    50          
5111 0         0 elsif (CORE::length($b) == 3) {
5112 19442 100       109787 my $lower_limit = join('|',
    100          
5113             $a[1] < 0xEF ? sprintf(join('', qw( [\x%02x-\xEF] [\x80-\xBF ] [\x80-\xBF ] )), $a[1]+1 ) : (),
5114             $a[2] < 0xBF ? sprintf(join('', qw( \x%02x [\x%02x-\xBF] [\x80-\xBF ] )), $a[1], $a[2]+1 ) : (),
5115             sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xBF] )), $a[1], $a[2], $a[3]),
5116             );
5117 19442 100       72560 my $upper_limit = join('|',
    100          
5118             sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3]),
5119             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5120             0xE0 < $b[1] ? sprintf(join('', qw( [\xE0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5121             );
5122 19442         65787 return qq{(?=$lower_limit)(?=$upper_limit)};
5123             }
5124             elsif (CORE::length($b) == 4) {
5125             return (
5126 7936 100       79173 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
    100          
    100          
5127             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
5128             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5129             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5130             $a[1] < 0xEF ? sprintf(join('', qw( [\x%02x-\xEF] [\x80-\xBF ] [\x80-\xBF ] )), $a[1]+1 ) : (),
5131             $a[2] < 0xBF ? sprintf(join('', qw( \x%02x [\x%02x-\xBF] [\x80-\xBF ] )), $a[1], $a[2]+1 ) : (),
5132             sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xBF] )), $a[1], $a[2], $a[3] ),
5133             );
5134             }
5135             }
5136             elsif (CORE::length($a) == 4) {
5137 40320 50       60027 if (0) { }
5138 0         0 elsif (CORE::length($b) == 4) {
5139 40320 100       274591 my $lower_limit = join('|',
    100          
    100          
5140             $a[1] < 0xF4 ? sprintf(join('', qw( [\x%02x-\xF4] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $a[1]+1 ) : (),
5141             $a[2] < 0xBF ? sprintf(join('', qw( \x%02x [\x%02x-\xBF] [\x80-\xBF ] [\x80-\xBF ] )), $a[1], $a[2]+1 ) : (),
5142             $a[3] < 0xBF ? sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xBF] [\x80-\xBF ] )), $a[1], $a[2], $a[3]+1 ) : (),
5143             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x%02x-\xBF] )), $a[1], $a[2], $a[3], $a[4]),
5144             );
5145 40320 100       194013 my $upper_limit = join('|',
    100          
    100          
5146             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
5147             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
5148             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
5149             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
5150             );
5151 40320         135481 return qq{(?=$lower_limit)(?=$upper_limit)};
5152             }
5153             }
5154              
5155             # over range of codepoint
5156 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
5157             }
5158             #---------------------------------------------------------------------
5159             # qr// for UTF-8 codepoint string at runtime (used by $mb{qr/.../})
5160             # ported from UTF8::R2::qr; uses mb::chr and list_all_by_hyphen_utf8_like
5161             sub _r2_qr ($) {
5162              
5163             # Local STRING form of the one-codepoint matcher, used throughout this
5164             # subroutine in place of the file-scoped qr// object $x.
5165             #
5166             # The file-scoped $x is a qr// object ($x = qr/(?>$over_ascii|...)/). On
5167             # perl 5.005_03 a qr// object loses its body when interpolated into
5168             # another pattern ("$qr" becomes "(?-xism:)" with the contents dropped),
5169             # so an embedded $x would silently degrade to a match-anything sub-pattern
5170             # in BOTH the parsing regexes below and the generated output. That makes
5171             # negative codepoint classes, hyphen-range boundaries, quantifier shortfall
5172             # and "." (without /s) over-match on old perl. A plain string interpolates
5173             # losslessly on every perl from 5.005_03 onward, so build one here.
5174             #
5175             # It is kept STRICT (ASCII tail is [\x00-\x7F], not [\x00-\xFF]): leniency
5176             # is deliberately not introduced. $over_ascii is itself a plain string.
5177             # The file-scoped qr// $x is left untouched for mb's transpile path.
5178 45     45   55 my $x = "(?>$over_ascii|[\\x00-\\x7F])";
5179              
5180             # Work on a stringified, writable copy of the argument. The caller passes
5181             # either a qr// object (from $mb{qr/.../}) or a plain string. On perl
5182             # 5.005_03 a destructive s/// applied directly to a qr// argument (or to a
5183             # read-only literal) fails ("Modification of a read-only value") or yields
5184             # an empty body, so copy "$_[0]" into a lexical first.
5185 45         57 my $source = "$_[0]";
5186              
5187 45         42 my $modifiers = '';
5188 45 50       163 if (my($m) = $source =~ /\A \( \? \^? (.*?) : /x) {
5189 45         40 $modifiers = $m;
5190 45         50 $modifiers =~ s/-.*//;
5191             }
5192              
5193 45         42 my @after = ();
5194 45         1283 while ($source =~ s! \A (
5195             (?> \[ (?: \[:[^:]+?:\] | \\x\{[0123456789ABCDEFabcdef]+\} | \\c[\x00-\xFF] | (?>\\$x) | $x )+? \] ) |
5196             \\x\{[0123456789ABCDEFabcdef]+\} | \\c[\x00-\xFF] | (?>\\$x) | $x
5197             ) !!x) {
5198 336         382 my $before = $1;
5199              
5200             # [^...] or [...]
5201 336 100       2416 if (my($negative, $class) = $before =~ /\A \[ (\^?) ((?>\\$x|$x)+?) \] \z/x) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    100          
    50          
    100          
    100          
    50          
5202 12         282 my @classmate = $class =~ /\G (?: \[:.+?:\] | \\x\{[0123456789ABCDEFabcdef]+\} | (?>\\$x) | $x ) /xg;
5203 12         16 my @sbcs = ();
5204 12         11 my @xbcs = ();
5205              
5206 12         33 for (my $i=0; $i <= $#classmate; ) {
5207 15         29 my $classmate = $classmate[$i];
5208              
5209             # hyphen of [A-Z] or [^A-Z]
5210 15 100 66     43 if (($i < $#classmate) and ($classmate[$i+1] eq '-')) {
5211 13 50       23 my $a = ($classmate[$i+0] =~ /\A \\x \{ ([0123456789ABCDEFabcdef]+) \} \z/x) ? mb::chr(hex $1) : $classmate[$i+0];
5212 13 50       16 my $b = ($classmate[$i+2] =~ /\A \\x \{ ([0123456789ABCDEFabcdef]+) \} \z/x) ? mb::chr(hex $1) : $classmate[$i+2];
5213 13         23 push @xbcs, list_all_by_hyphen_utf8_like($a, $b);
5214 13         20 $i += 3;
5215             }
5216              
5217             # any "one"
5218             else {
5219              
5220             # \x{UTF8hex}
5221 2 50       34 if ($classmate =~ /\A \\x \{ ([0123456789ABCDEFabcdef]+) \} \z/x) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5222 0         0 push @xbcs, mb::chr(hex $1);
5223             }
5224              
5225             # \any
5226 0         0 elsif ($classmate eq '\D' ) { push @xbcs, "(?:(?![$bare_d])$x)" }
5227 0         0 elsif ($classmate eq '\H' ) { push @xbcs, "(?:(?![$bare_h])$x)" }
5228             # elsif ($classmate eq '\N' ) { push @xbcs, "(?:(?!\\n)$x)" } # \N in a character class must be a named character: \N{...} in regex
5229             # elsif ($classmate eq '\R' ) { push @xbcs, "(?>\\r\\n|[$bare_v])" } # Unrecognized escape \R in character class passed through in regex
5230 0         0 elsif ($classmate eq '\S' ) { push @xbcs, "(?:(?![$bare_s])$x)" }
5231 0         0 elsif ($classmate eq '\V' ) { push @xbcs, "(?:(?![$bare_v])$x)" }
5232 0         0 elsif ($classmate eq '\W' ) { push @xbcs, "(?:(?![$bare_w])$x)" }
5233 0         0 elsif ($classmate eq '\b' ) { push @sbcs, $bare_backspace }
5234 0         0 elsif ($classmate eq '\d' ) { push @sbcs, $bare_d }
5235 0         0 elsif ($classmate eq '\h' ) { push @sbcs, $bare_h }
5236 0         0 elsif ($classmate eq '\s' ) { push @sbcs, $bare_s }
5237 0         0 elsif ($classmate eq '\v' ) { push @sbcs, $bare_v }
5238 0         0 elsif ($classmate eq '\w' ) { push @sbcs, $bare_w }
5239              
5240             # [:POSIX:]
5241 0         0 elsif ($classmate eq '[:alnum:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x61-\x7A'; }
5242 1         1 elsif ($classmate eq '[:alpha:]' ) { push @sbcs, '\x41-\x5A\x61-\x7A'; }
5243 0         0 elsif ($classmate eq '[:ascii:]' ) { push @sbcs, '\x00-\x7F'; }
5244 0         0 elsif ($classmate eq '[:blank:]' ) { push @sbcs, '\x09\x20'; }
5245 0         0 elsif ($classmate eq '[:cntrl:]' ) { push @sbcs, '\x00-\x1F\x7F'; }
5246 1         2 elsif ($classmate eq '[:digit:]' ) { push @sbcs, '\x30-\x39'; }
5247 0         0 elsif ($classmate eq '[:graph:]' ) { push @sbcs, '\x21-\x7F'; }
5248 0         0 elsif ($classmate eq '[:lower:]' ) { push @sbcs, '\x61-\x7A'; } # /i modifier requires 'a' to 'z' literally
5249 0         0 elsif ($classmate eq '[:print:]' ) { push @sbcs, '\x20-\x7F'; }
5250 0         0 elsif ($classmate eq '[:punct:]' ) { push @sbcs, '\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E'; }
5251 0         0 elsif ($classmate eq '[:space:]' ) { push @sbcs, '\s\x0B'; } # "\s" and vertical tab ("\cK")
5252 0         0 elsif ($classmate eq '[:upper:]' ) { push @sbcs, '\x41-\x5A'; } # /i modifier requires 'A' to 'Z' literally
5253 0         0 elsif ($classmate eq '[:word:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x5F\x61-\x7A'; }
5254 0         0 elsif ($classmate eq '[:xdigit:]' ) { push @sbcs, '\x30-\x39\x41-\x46\x61-\x66'; }
5255              
5256             # [:^POSIX:]
5257 0         0 elsif ($classmate eq '[:^alnum:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x61-\\x7A])$x)"; }
5258 0         0 elsif ($classmate eq '[:^alpha:]' ) { push @xbcs, "(?:(?![\\x41-\\x5A\\x61-\\x7A])$x)"; }
5259 0         0 elsif ($classmate eq '[:^ascii:]' ) { push @xbcs, "(?:(?![\\x00-\\x7F])$x)"; }
5260 0         0 elsif ($classmate eq '[:^blank:]' ) { push @xbcs, "(?:(?![\\x09\\x20])$x)"; }
5261 0         0 elsif ($classmate eq '[:^cntrl:]' ) { push @xbcs, "(?:(?![\\x00-\\x1F\\x7F])$x)"; }
5262 0         0 elsif ($classmate eq '[:^digit:]' ) { push @xbcs, "(?:(?![\\x30-\\x39])$x)"; }
5263 0         0 elsif ($classmate eq '[:^graph:]' ) { push @xbcs, "(?:(?![\\x21-\\x7F])$x)"; }
5264 0         0 elsif ($classmate eq '[:^lower:]' ) { push @xbcs, "(?:(?![\\x61-\\x7A])$x)"; } # /i modifier requires 'a' to 'z' literally
5265 0         0 elsif ($classmate eq '[:^print:]' ) { push @xbcs, "(?:(?![\\x20-\\x7F])$x)"; }
5266 0         0 elsif ($classmate eq '[:^punct:]' ) { push @xbcs, "(?:(?![\\x21-\\x2F\\x3A-\\x3F\\x40\\x5B-\\x5F\\x60\\x7B-\\x7E])$x)"; }
5267 0         0 elsif ($classmate eq '[:^space:]' ) { push @xbcs, "(?:(?![\\s\\x0B])$x)"; } # "\s" and vertical tab ("\cK")
5268 0         0 elsif ($classmate eq '[:^upper:]' ) { push @xbcs, "(?:(?![\\x41-\\x5A])$x)"; } # /i modifier requires 'A' to 'Z' literally
5269 0         0 elsif ($classmate eq '[:^word:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x5F\\x61-\\x7A])$x)"; }
5270 0         0 elsif ($classmate eq '[:^xdigit:]') { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x46\\x61-\\x66])$x)"; }
5271              
5272             # other all
5273 0         0 elsif (CORE::length($classmate)==1) { push @sbcs, $classmate }
5274 0         0 else { push @xbcs, $classmate }
5275 2         4 $i += 1;
5276             }
5277             }
5278              
5279             # [^...]
5280 12 100       26 if ($negative eq q[^]) {
    50          
5281 2 0 33     25 push @after,
    50 33        
    50 0        
5282             ( @sbcs and @xbcs) ? '(?:(?!' . join('|', @xbcs, '['.join('', @sbcs).']') . ")$x)" :
5283             (!@sbcs and @xbcs) ? '(?:(?!' . join('|', @xbcs ) . ")$x)" :
5284             ( @sbcs and !@xbcs) ? '(?:(?!' . '['.join('', @sbcs).']' . ")$x)" :
5285             '';
5286             }
5287              
5288             # [...] on Perl 5.006
5289             elsif ($] =~ /\A5\.006/) {
5290 0 0 0     0 push @after,
    0 0        
    0 0        
5291             ( @sbcs and @xbcs) ? '(?:' . join('|', @xbcs, '['.join('', @sbcs).']') . ')' :
5292             (!@sbcs and @xbcs) ? '(?:' . join('|', @xbcs ) . ')' :
5293             ( @sbcs and !@xbcs) ? '['.join('', @sbcs).']' :
5294             '';
5295             }
5296              
5297             # [...]
5298             else {
5299 10 50 66     115 push @after,
    100 66        
    50 33        
5300             ( @sbcs and @xbcs) ? '(?:(?=' . join('|', @xbcs, '['.join('', @sbcs).']') . ")$x)" :
5301             (!@sbcs and @xbcs) ? '(?:(?=' . join('|', @xbcs ) . ")$x)" :
5302             ( @sbcs and !@xbcs) ? '['.join('', @sbcs).']' :
5303             '';
5304             }
5305             }
5306              
5307             # \any or /./
5308 4 100       19 elsif ($before eq '.' ) { push @after, ($modifiers =~ /s/) ? $x : "(?:(?!\\n)$x)" }
5309 0         0 elsif ($before eq '\B') { push @after, "(?:(?
5310 0         0 elsif ($before eq '\D') { push @after, "(?:(?![$bare_d])$x)" }
5311 0         0 elsif ($before eq '\H') { push @after, "(?:(?![$bare_h])$x)" }
5312 0         0 elsif ($before eq '\N') { push @after, "(?:(?!\\n)$x)" }
5313 0         0 elsif ($before eq '\R') { push @after, "(?>\\r\\n|[$bare_v])" }
5314 0         0 elsif ($before eq '\S') { push @after, "(?:(?![$bare_s])$x)" }
5315 0         0 elsif ($before eq '\V') { push @after, "(?:(?![$bare_v])$x)" }
5316 0         0 elsif ($before eq '\W') { push @after, "(?:(?![$bare_w])$x)" }
5317 0         0 elsif ($before eq '\b') { push @after, "(?:(?
5318 1         6 elsif ($before eq '\d') { push @after, "[$bare_d]" }
5319 0         0 elsif ($before eq '\h') { push @after, "[$bare_h]" }
5320 1         5 elsif ($before eq '\s') { push @after, "[$bare_s]" }
5321 0         0 elsif ($before eq '\v') { push @after, "[$bare_v]" }
5322 1         5 elsif ($before eq '\w') { push @after, "[$bare_w]" }
5323              
5324             # quantifiers ? + * {n} {n,} {n,m}
5325             elsif ($before =~ /\A[?+*{]\z/) {
5326 52 50       143 if (0) { }
    50          
    100          
    100          
5327 0         0 elsif ($after[-1] =~ /\A \\c [\x00-\xFF] \z/x) { } # \c) \c} \c] \cX
5328             elsif ($after[-1] =~ /\A \\ [\x00-\xFF] \z/x) { } # \) \} \] \" \0 \1 \D \E \F \G \H \K \L \N \Q \R \S \U \V \W \\ \a \d \e \f \h \l \n \r \s \t \u \v \w
5329             elsif ($after[-1] =~ /\A [\x00-\xFF] \z/x) { } # (a) a{1} [a] a . \012 \x12 \o{12} \g{1}
5330             elsif ($after[-1] =~ / [\x00-\xFF] [)}\]] \z/x) { } # (any) any{1} [any]
5331             else { # XBCS
5332 4         4 $after[-1] = '(?:' . $after[-1] . ')';
5333             }
5334 52         203 push @after, $before;
5335             }
5336              
5337             # \x{UTF8hex}
5338             elsif ($before =~ /\A \\x \{ ([0123456789ABCDEFabcdef]+) \} \z/x) {
5339 0         0 push @after, mb::chr(hex $1);
5340             }
5341              
5342             # else
5343             else {
5344 265         1143 push @after, $before;
5345             }
5346             }
5347              
5348 45         68 my $after = join '', @after;
5349              
5350             # Return a plain regular-expression STRING, not a qr// object.
5351             #
5352             # On perl 5.005_03 a qr// object, when interpolated into another pattern
5353             # (for example m<\G$mb{qr/.../}>g or s<$mb{qr/.../}><...> or even a
5354             # second =~ // after stringification) loses its body: "$qr" becomes
5355             # "(?-xism:)" with the contents dropped, so the pattern then matches
5356             # anything. A plain string interpolates losslessly on every perl from
5357             # 5.005_03 onward. The (?modifiers:...) wrapper preserves the i/m/s/x
5358             # flags that were present on the original qr/.../ token.
5359 45 100       54 if ($modifiers ne '') {
5360 2         122 return "(?$modifiers:$after)";
5361             }
5362             else {
5363 43         2664 return "(?:$after)";
5364             }
5365             }
5366              
5367             #---------------------------------------------------------------------
5368             # mb::qr() - functional form of the runtime UTF-8 codepoint regex builder.
5369             # This is the same engine as $mb{qr/.../} (the tie FETCH), exposed as a
5370             # named subroutine for UTF8::R2 source compatibility:
5371             # $_ =~ mb::qr(qr/.../) is equivalent to $_ =~ $mb{qr/.../}
5372             # It returns a plain regular-expression string (see _r2_qr above for why a
5373             # string and not a qr// object, which matters on perl 5.005_03).
5374             sub mb::qr ($) {
5375 18     18 0 23 return _r2_qr($_[0]);
5376             }
5377              
5378             #---------------------------------------------------------------------
5379             # parse codepoint class
5380             sub parse_re_codepoint_class {
5381 126590     126590 0 167397 my($codepoint_class) = @_;
5382 126590         159275 my @sbcs = ();
5383 126590         122993 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
5384              
5385             # get members from class
5386 126590         118696 my @classmate = ();
5387 126590         302746 while ($codepoint_class !~ /\G \z /xmsgc) {
5388 378280 50       2058260 if (0) { }
    50          
    100          
    100          
    50          
5389 0         0 elsif ($codepoint_class =~ /\G\\o\{([01234567]+)\}/xmsgc) {
5390 0         0 push @classmate, mb::chr(oct $1);
5391             }
5392             elsif ($codepoint_class =~ /\G\\x\{([0123456789ABCDEFabcdef]+)\}/xmsgc) {
5393 0         0 push @classmate, mb::chr(hex $1);
5394             }
5395             elsif ($codepoint_class =~ /\G(\[:.+?:\])/xmsgc) {
5396 100         316 push @classmate, $1;
5397             }
5398             elsif ($codepoint_class =~ /\G((?>\\$x))/xmsgc) {
5399 562         1886 push @classmate, $1;
5400             }
5401             elsif ($codepoint_class =~ /\G($x)/xmsgc) {
5402 377618         830360 push @classmate, $1;
5403             }
5404             else {
5405 0         0 confess qq{@{[__FILE__]}: codepoint_class=($codepoint_class), classmate=(@classmate)};
  0         0  
5406             }
5407             }
5408              
5409             # get regular expression for MBCS codepoint class
5410 126590         271430 for (my $i=0; $i <= $#classmate; $i++) {
5411 127042         181501 my $classmate = $classmate[$i];
5412              
5413             # hyphen of [A-Z] or [^A-Z]
5414 127042 100 100     438669 if (($i < $#classmate) and ($classmate[$i+1] eq '-')) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
5415 125619         128365 my $a = $classmate[$i];
5416 125619         141176 my $b = $classmate[$i+2];
5417 125619 100       599430 if (0) { }
    100          
    100          
    100          
    100          
    100          
    100          
    50          
5418 0         0 elsif ($script_encoding =~ /\A (?: sjis ) \z/xms) {
5419 8435         18942 push @xbcs, list_all_by_hyphen_sjis_like ($a, $b);
5420             }
5421             elsif ($script_encoding =~ /\A (?: informixv6als ) \z/xms) {
5422 3601         6363 push @xbcs, list_all_by_hyphen_informixv6als_like($a, $b);
5423             }
5424             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
5425 253         435 push @xbcs, list_all_by_hyphen_eucjp_like ($a, $b);
5426             }
5427             elsif ($script_encoding =~ /\A (?: euctw ) \z/xms) {
5428 1106         2269 push @xbcs, list_all_by_hyphen_euctw_like ($a, $b);
5429             }
5430             elsif ($script_encoding =~ /\A (?: hp15 ) \z/xms) {
5431 3601         6611 push @xbcs, list_all_by_hyphen_hp15_like ($a, $b);
5432             }
5433             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
5434 256         486 push @xbcs, list_all_by_hyphen_big5_like ($a, $b);
5435             }
5436             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
5437 18253         37112 push @xbcs, list_all_by_hyphen_gb18030_like ($a, $b);
5438             }
5439             elsif ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
5440 90114         164279 push @xbcs, list_all_by_hyphen_utf8_like ($a, $b);
5441             }
5442             else {
5443 0         0 push @sbcs, "$a-$b";
5444             }
5445 125619         305523 $i += 2;
5446             }
5447              
5448             # classic perl codepoint class shortcuts
5449 34         110 elsif ($classmate eq '\\D') { push @xbcs, "(?:(?![$bare_d])$x)"; }
5450 10         36 elsif ($classmate eq '\\H') { push @xbcs, "(?:(?![$bare_h])$x)"; }
5451             # elsif ($classmate eq '\\N') { push @xbcs, "(?:(?!\\n)$x)"; } # \N in a codepoint class must be a named character: \N{...} in regex
5452             # elsif ($classmate eq '\\R') { push @xbcs, "(?>\\r\\n|[$bare_v])"; } # Unrecognized escape \R in codepoint class passed through in regex
5453 19         61 elsif ($classmate eq '\\S') { push @xbcs, "(?:(?![$bare_s])$x)"; }
5454 16         53 elsif ($classmate eq '\\V') { push @xbcs, "(?:(?![$bare_v])$x)"; }
5455 193         701 elsif ($classmate eq '\\W') { push @xbcs, "(?:(?![$bare_w])$x)"; }
5456 6         15 elsif ($classmate eq '\\b') { push @sbcs, $bare_backspace; }
5457 34         70 elsif ($classmate eq '\\d') { push @sbcs, $bare_d; }
5458 10         659 elsif ($classmate eq '\\h') { push @sbcs, $bare_h; }
5459 19         54 elsif ($classmate eq '\\s') { push @sbcs, $bare_s; }
5460 16         33 elsif ($classmate eq '\\v') { push @sbcs, $bare_v; }
5461 193         454 elsif ($classmate eq '\\w') { push @sbcs, $bare_w; }
5462              
5463             # [:POSIX:]
5464 19         34 elsif ($classmate eq '[:alnum:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x61-\x7A'; }
5465 3         9 elsif ($classmate eq '[:alpha:]' ) { push @sbcs, '\x41-\x5A\x61-\x7A'; }
5466 3         8 elsif ($classmate eq '[:ascii:]' ) { push @sbcs, '\x00-\x7F'; }
5467 3         8 elsif ($classmate eq '[:blank:]' ) { push @sbcs, '\x09\x20'; }
5468 3         6 elsif ($classmate eq '[:cntrl:]' ) { push @sbcs, '\x00-\x1F\x7F'; }
5469 3         10 elsif ($classmate eq '[:digit:]' ) { push @sbcs, '\x30-\x39'; }
5470 3         9 elsif ($classmate eq '[:graph:]' ) { push @sbcs, '\x21-\x7F'; }
5471 3         7 elsif ($classmate eq '[:lower:]' ) { push @sbcs, 'abcdefghijklmnopqrstuvwxyz'; } # /i modifier requires 'a' to 'z' literally
5472 3         7 elsif ($classmate eq '[:print:]' ) { push @sbcs, '\x20-\x7F'; }
5473 3         9 elsif ($classmate eq '[:punct:]' ) { push @sbcs, '\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E'; }
5474 3         9 elsif ($classmate eq '[:space:]' ) { push @sbcs, '\s\x0B'; } # "\s" and vertical tab ("\cK")
5475 3         9 elsif ($classmate eq '[:upper:]' ) { push @sbcs, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; } # /i modifier requires 'A' to 'Z' literally
5476 3         7 elsif ($classmate eq '[:word:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x5F\x61-\x7A'; }
5477 3         8 elsif ($classmate eq '[:xdigit:]') { push @sbcs, '\x30-\x39\x41-\x46\x61-\x66'; }
5478              
5479             # [:^POSIX:]
5480 3         17 elsif ($classmate eq '[:^alnum:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x61-\\x7A])$x)"; }
5481 3         14 elsif ($classmate eq '[:^alpha:]' ) { push @xbcs, "(?:(?![\\x41-\\x5A\\x61-\\x7A])$x)"; }
5482 3         13 elsif ($classmate eq '[:^ascii:]' ) { push @xbcs, "(?:(?![\\x00-\\x7F])$x)"; }
5483 3         12 elsif ($classmate eq '[:^blank:]' ) { push @xbcs, "(?:(?![\\x09\\x20])$x)"; }
5484 3         13 elsif ($classmate eq '[:^cntrl:]' ) { push @xbcs, "(?:(?![\\x00-\\x1F\\x7F])$x)"; }
5485 3         15 elsif ($classmate eq '[:^digit:]' ) { push @xbcs, "(?:(?![\\x30-\\x39])$x)"; }
5486 3         11 elsif ($classmate eq '[:^graph:]' ) { push @xbcs, "(?:(?![\\x21-\\x7F])$x)"; }
5487 3         11 elsif ($classmate eq '[:^lower:]' ) { push @xbcs, "(?:(?![abcdefghijklmnopqrstuvwxyz])$x)"; } # /i modifier requires 'a' to 'z' literally
5488 3         13 elsif ($classmate eq '[:^print:]' ) { push @xbcs, "(?:(?![\\x20-\\x7F])$x)"; }
5489 3         47 elsif ($classmate eq '[:^punct:]' ) { push @xbcs, "(?:(?![\\x21-\\x2F\\x3A-\\x3F\\x40\\x5B-\\x5F\\x60\\x7B-\\x7E])$x)"; }
5490 3         13 elsif ($classmate eq '[:^space:]' ) { push @xbcs, "(?:(?![\\s\\x0B])$x)"; } # "\s" and vertical tab ("\cK")
5491 3         15 elsif ($classmate eq '[:^upper:]' ) { push @xbcs, "(?:(?![ABCDEFGHIJKLMNOPQRSTUVWXYZ])$x)"; } # /i modifier requires 'A' to 'Z' literally
5492 3         11 elsif ($classmate eq '[:^word:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x5F\\x61-\\x7A])$x)"; }
5493 3         12 elsif ($classmate eq '[:^xdigit:]') { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x46\\x61-\\x66])$x)"; }
5494              
5495             # \any
5496             elsif ($classmate =~ /\G (\\) ($x) /xmsgc) {
5497 12 50       22 if (CORE::length($2) == 1) {
5498 12         33 push @sbcs, ($1 . $2);
5499             }
5500             else {
5501 0         0 push @xbcs, '(?:' . $1 . escape_to_hex($2, ']') . ')';
5502             }
5503             }
5504              
5505             # any
5506             elsif ($classmate =~ /\G ($x) /xmsgc) {
5507 761 100       1114 if (CORE::length($1) == 1) {
5508 417         807 push @sbcs, $1;
5509             }
5510             else {
5511 344         487 push @xbcs, '(?:' . escape_to_hex($1, ']') . ')';
5512             }
5513             }
5514              
5515             # something wrong happened
5516             else {
5517 0         0 die sprintf(<
5518 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5519             ------------------------------------------------------------------------------
5520             %s
5521             ------------------------------------------------------------------------------
5522             END
5523             }
5524             }
5525              
5526             # return codepoint class
5527 126590 50 100     498757 my $parsed =
    100 66        
    100 33        
5528             ( @sbcs and @xbcs) ? join('|', @xbcs, '['.join('',@sbcs).']') :
5529             (!@sbcs and @xbcs) ? join('|', @xbcs ) :
5530             ( @sbcs and !@xbcs) ? '['.join('',@sbcs).']' :
5531             die;
5532 126590         22750204 return $parsed;
5533             }
5534              
5535             #---------------------------------------------------------------------
5536             # parse qr'regexp' as q-like
5537             sub parse_re_as_q_endswith {
5538 948     948 0 1926 my($operator, $endswith) = @_;
5539 948         1118 my $parsed = $endswith;
5540 948         1000 while (1) {
5541 1956 100       8700 if (/\G (\Q$endswith\E) /xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
5542 948         1235 $parsed .= $1;
5543 948         850 last;
5544             }
5545              
5546             # get codepoint class
5547             elsif (/\G \[ /xmsgc) {
5548 566         655 my $classmate = '';
5549 566         562 while (1) {
5550 1766 100       5348 if (/\G \] /xmsgc) {
    100          
    100          
    50          
5551 566         658 last;
5552             }
5553             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
5554 28         37 $classmate .= $1;
5555             }
5556             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
5557 44         56 $classmate .= $1;
5558             }
5559             elsif (/\G ($x) /xmsgc) {
5560 1128         1350 $classmate .= $1;
5561             }
5562              
5563             # something wrong happened
5564             else {
5565 0         0 die sprintf(<
5566 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5567             ------------------------------------------------------------------------------
5568             %s
5569             ------------------------------------------------------------------------------
5570             END
5571             }
5572             }
5573              
5574             # parse codepoint class
5575 566         835 $parsed .= mb::_cc($classmate);
5576             }
5577              
5578             # /./ or \any
5579 2         6 elsif (/\G \. /xmsgc) { $parsed .= "(?:$over_ascii|.)"; } # after $over_ascii, /s modifier wants "." (not [\x00-\xFF])
5580 2         6 elsif (/\G \\B /xmsgc) { $parsed .= "(?:(?
5581 12         42 elsif (/\G \\D /xmsgc) { $parsed .= "(?:(?![$bare_d])$x)"; }
5582 4         11 elsif (/\G \\H /xmsgc) { $parsed .= "(?:(?![$bare_h])$x)"; }
5583 2         4 elsif (/\G \\N /xmsgc) { $parsed .= "(?:(?!\\n)$x)"; }
5584 2         4 elsif (/\G \\R /xmsgc) { $parsed .= "(?>\\r\\n|[$bare_v])"; }
5585 7         20 elsif (/\G \\S /xmsgc) { $parsed .= "(?:(?![$bare_s])$x)"; }
5586 6         15 elsif (/\G \\V /xmsgc) { $parsed .= "(?:(?![$bare_v])$x)"; }
5587 65         177 elsif (/\G \\W /xmsgc) { $parsed .= "(?:(?![$bare_w])$x)"; }
5588 2         4 elsif (/\G \\b /xmsgc) { $parsed .= "(?:(?
5589 12         19 elsif (/\G \\d /xmsgc) { $parsed .= "[$bare_d]"; }
5590 4         7 elsif (/\G \\h /xmsgc) { $parsed .= "[$bare_h]"; }
5591 7         10 elsif (/\G \\s /xmsgc) { $parsed .= "[$bare_s]"; }
5592 6         8 elsif (/\G \\v /xmsgc) { $parsed .= "[$bare_v]"; }
5593 65         95 elsif (/\G \\w /xmsgc) { $parsed .= "[$bare_w]"; }
5594              
5595             # \o{...}
5596             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
5597 0         0 $parsed .= '(?:';
5598 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $endswith);
5599 0         0 $parsed .= ')';
5600             }
5601              
5602             # \x{...}
5603             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
5604 0         0 $parsed .= '(?:';
5605 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $endswith);
5606 0         0 $parsed .= ')';
5607             }
5608              
5609             # \0... octal escape
5610             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
5611 0         0 $parsed .= $1;
5612             }
5613              
5614             # \100...\x377 octal escape
5615             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
5616 0         0 $parsed .= $1;
5617             }
5618              
5619             # \1...\99, ... n-th previously captured string (decimal)
5620             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
5621 0         0 $parsed .= $1;
5622 0 0       0 if ($operator eq 's') {
5623 0         0 $parsed .= ($2 + 1);
5624             }
5625             else {
5626 0         0 $parsed .= $2;
5627             }
5628             }
5629              
5630             # any
5631             elsif (/\G ($x) /xmsgc) {
5632 244 100       374 if (CORE::length($1) == 1) {
5633 99         139 $parsed .= $1;
5634             }
5635             else {
5636 145         140 $parsed .= '(?:';
5637 145         228 $parsed .= escape_to_hex($1, $endswith);
5638 145         183 $parsed .= ')';
5639             }
5640             }
5641              
5642             # something wrong happened
5643             else {
5644 0         0 die sprintf(<
5645 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5646             ------------------------------------------------------------------------------
5647             %s
5648             ------------------------------------------------------------------------------
5649             END
5650             }
5651             }
5652 948         1287 return $parsed;
5653             }
5654              
5655             #---------------------------------------------------------------------
5656             # parse qr{regexp} in balanced blackets
5657             sub parse_re_balanced {
5658 564     564 0 1107 my($operator, $open_bracket) = @_;
5659 564   50     2059 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
5660 564         932 my $parsed = $open_bracket;
5661 564         554 my $nest_bracket = 1;
5662 564         517 my $nest_escape = 0;
5663 564         511 while (1) {
5664 1133 50       7948 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
5665 0         0 $parsed .= $1;
5666 0         0 $nest_bracket++;
5667             }
5668             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
5669 564 50       787 if (--$nest_bracket <= 0) {
5670 564         654 $parsed .= ('>)]}' x $nest_escape);
5671 564         585 $parsed .= $1;
5672 564         613 last;
5673             }
5674             else {
5675 0         0 $parsed .= $1;
5676             }
5677             }
5678              
5679             # \L\u --> \u\L
5680             elsif (/\G \\L \\u /xmsgc) {
5681 0         0 $parsed .= '@{[mb::ucfirst(qq<';
5682 0         0 $parsed .= '@{[mb::lc(qq<';
5683 0         0 $nest_escape++;
5684 0         0 $nest_escape++;
5685             }
5686              
5687             # \U\l --> \l\U
5688             elsif (/\G \\U \\l /xmsgc) {
5689 0         0 $parsed .= '@{[mb::lcfirst(qq<';
5690 0         0 $parsed .= '@{[mb::uc(qq<';
5691 0         0 $nest_escape++;
5692 0         0 $nest_escape++;
5693             }
5694              
5695             # \L
5696             elsif (/\G \\L /xmsgc) {
5697 0         0 $parsed .= '@{[mb::lc(qq<';
5698 0         0 $nest_escape++;
5699             }
5700              
5701             # \U
5702             elsif (/\G \\U /xmsgc) {
5703 0         0 $parsed .= '@{[mb::uc(qq<';
5704 0         0 $nest_escape++;
5705             }
5706              
5707             # \l
5708             elsif (/\G \\l /xmsgc) {
5709 0         0 $parsed .= '@{[mb::lcfirst(qq<';
5710 0         0 $nest_escape++;
5711             }
5712              
5713             # \u
5714             elsif (/\G \\u /xmsgc) {
5715 0         0 $parsed .= '@{[mb::ucfirst(qq<';
5716 0         0 $nest_escape++;
5717             }
5718              
5719             # \Q
5720             elsif (/\G \\Q /xmsgc) {
5721 0         0 $parsed .= '@{[quotemeta(qq<';
5722 0         0 $nest_escape++;
5723             }
5724              
5725             # \E
5726             elsif (/\G \\E /xmsgc) {
5727 0         0 $parsed .= ('>)]}' x $nest_escape);
5728 0         0 $nest_escape = 0;
5729             }
5730              
5731             else {
5732 569         859 $parsed .= parse_re($operator, $open_bracket);
5733             }
5734             }
5735 564         783 return $parsed;
5736             }
5737              
5738             #---------------------------------------------------------------------
5739             # parse qr/regexp/ that ends with a character
5740             sub parse_re_endswith {
5741 128877     128877 0 345299 my($operator, $endswith) = @_;
5742 128877         166028 my $parsed = $endswith;
5743 128877         135114 my $nest_escape = 0;
5744 128877         129234 while (1) {
5745 259220 100       992903 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
5746 128877         171064 $parsed .= ('>)]}' x $nest_escape);
5747 128877         171769 $parsed .= $1;
5748 128877         123598 last;
5749             }
5750              
5751             # \L\u --> \u\L
5752             elsif (/\G \\L \\u /xmsgc) {
5753 0         0 $parsed .= '@{[mb::ucfirst(qq<';
5754 0         0 $parsed .= '@{[mb::lc(qq<';
5755 0         0 $nest_escape++;
5756 0         0 $nest_escape++;
5757             }
5758              
5759             # \U\l --> \l\U
5760             elsif (/\G \\U \\l /xmsgc) {
5761 0         0 $parsed .= '@{[mb::lcfirst(qq<';
5762 0         0 $parsed .= '@{[mb::uc(qq<';
5763 0         0 $nest_escape++;
5764 0         0 $nest_escape++;
5765             }
5766              
5767             # \L
5768             elsif (/\G \\L /xmsgc) {
5769 0         0 $parsed .= '@{[mb::lc(qq<';
5770 0         0 $nest_escape++;
5771             }
5772              
5773             # \U
5774             elsif (/\G \\U /xmsgc) {
5775 0         0 $parsed .= '@{[mb::uc(qq<';
5776 0         0 $nest_escape++;
5777             }
5778              
5779             # \l
5780             elsif (/\G \\l /xmsgc) {
5781 0         0 $parsed .= '@{[mb::lcfirst(qq<';
5782 0         0 $nest_escape++;
5783             }
5784              
5785             # \u
5786             elsif (/\G \\u /xmsgc) {
5787 0         0 $parsed .= '@{[mb::ucfirst(qq<';
5788 0         0 $nest_escape++;
5789             }
5790              
5791             # \Q
5792             elsif (/\G \\Q /xmsgc) {
5793 0         0 $parsed .= '@{[quotemeta(qq<';
5794 0         0 $nest_escape++;
5795             }
5796              
5797             # \E
5798             elsif (/\G \\E /xmsgc) {
5799 0         0 $parsed .= ('>)]}' x $nest_escape);
5800 0         0 $nest_escape = 0;
5801             }
5802              
5803             else {
5804 130343         219913 $parsed .= parse_re($operator, $endswith);
5805             }
5806             }
5807 128877         205078 return $parsed;
5808             }
5809              
5810             #---------------------------------------------------------------------
5811             # parse qr/regexp/ common routine
5812             sub parse_re {
5813 130912     130912 0 170299 my($operator, $closewith) = @_;
5814 130912         132437 my $parsed = '';
5815              
5816             # codepoint class
5817 130912 100       264470 if (/\G \[ /xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
5818 127158         130368 my $classmate = '';
5819 127158         111660 while (1) {
5820 570087 100       2042248 if (/\G \] /xmsgc) {
    100          
    100          
    100          
    50          
5821 127158         145047 last;
5822             }
5823             elsif (/\G (\\) /xmsgc) {
5824 510         804 $classmate .= "\\$1";
5825             }
5826             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
5827 98         129 $classmate .= $1;
5828             }
5829             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
5830 114         140 $classmate .= $1;
5831             }
5832             elsif (/\G ($x) /xmsgc) {
5833 442207         523999 $classmate .= escape_qq($1, ']');
5834             }
5835              
5836             # something wrong happened
5837             else {
5838 0         0 die sprintf(<
5839 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5840             ------------------------------------------------------------------------------
5841             %s
5842             ------------------------------------------------------------------------------
5843             END
5844             }
5845             }
5846              
5847             # quote by (?: ... ) to avoid syntax error: Can't coerce array into hash at ...
5848             #
5849             # [ABC]{3} --> @{[mb::_cc(qq[ABC])]}{3} # makes: Can't coerce array into hash at ...
5850             # [ABC]{3} --> (?:@{[mb::_cc(qq[ABC])]}){3} # ok
5851              
5852 127158         208495 $parsed .= "(?:\@{[mb::_cc(qq[$classmate])]})";
5853             }
5854              
5855             # /./ or \any
5856 44         64 elsif (/\G \. /xmsgc) { $parsed .= '(?:@{[@mb::_dot]})'; }
5857 7         15 elsif (/\G \\B /xmsgc) { $parsed .= '(?:@{[@mb::_B]})'; }
5858 18         29 elsif (/\G \\D /xmsgc) { $parsed .= '(?:@{[@mb::_D]})'; }
5859 10         16 elsif (/\G \\H /xmsgc) { $parsed .= '(?:@{[@mb::_H]})'; }
5860 8         10 elsif (/\G \\N /xmsgc) { $parsed .= '(?:@{[@mb::_N]})'; }
5861 12         15 elsif (/\G \\R /xmsgc) { $parsed .= '(?:@{[@mb::_R]})'; }
5862 14         21 elsif (/\G \\S /xmsgc) { $parsed .= '(?:@{[@mb::_S]})'; }
5863 12         22 elsif (/\G \\V /xmsgc) { $parsed .= '(?:@{[@mb::_V]})'; }
5864 71         98 elsif (/\G \\W /xmsgc) { $parsed .= '(?:@{[@mb::_W]})'; }
5865 7         8 elsif (/\G \\b /xmsgc) { $parsed .= '(?:@{[@mb::_b]})'; }
5866 17         26 elsif (/\G \\d /xmsgc) { $parsed .= '(?:@{[@mb::_d]})'; }
5867 10         15 elsif (/\G \\h /xmsgc) { $parsed .= '(?:@{[@mb::_h]})'; }
5868 18         22 elsif (/\G \\s /xmsgc) { $parsed .= '(?:@{[@mb::_s]})'; }
5869 14         23 elsif (/\G \\v /xmsgc) { $parsed .= '(?:@{[@mb::_v]})'; }
5870 70         102 elsif (/\G \\w /xmsgc) { $parsed .= '(?:@{[@mb::_w]})'; }
5871              
5872             # \o{...}
5873             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
5874 0         0 $parsed .= '(?:';
5875 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $closewith);
5876 0         0 $parsed .= ')';
5877             }
5878              
5879             # \x{...}
5880             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
5881 0         0 $parsed .= '(?:';
5882 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $closewith);
5883 0         0 $parsed .= ')';
5884             }
5885              
5886             # \0... octal escape
5887             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
5888 0         0 $parsed .= $1;
5889             }
5890              
5891             # \100...\x377 octal escape
5892             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
5893 0         0 $parsed .= $1;
5894             }
5895              
5896             # \1...\99, ... n-th previously captured string (decimal)
5897             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
5898 24         30 $parsed .= $1;
5899 24 50       38 if ($operator eq 's') {
5900 0         0 $parsed .= ($2 + 1);
5901             }
5902             else {
5903 24         32 $parsed .= $2;
5904             }
5905             }
5906              
5907             # \any
5908             elsif (/\G (\\) ($x) /xmsgc) {
5909 8 50       20 if (CORE::length($2) == 1) {
5910 8         15 $parsed .= ($1 . $2);
5911             }
5912             else {
5913 0         0 $parsed .= ('(?:' . $1 . escape_qq($2, $closewith) . ')');
5914             }
5915             }
5916              
5917             # $` --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5918             # ${`} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5919             # $PREMATCH --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5920             # ${PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5921             # ${^PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5922             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
5923 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_PREMATCH())]}';
5924             }
5925              
5926             # $& --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5927             # ${&} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5928             # $MATCH --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5929             # ${MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5930             # ${^MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5931             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
5932 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_MATCH())]}';
5933             }
5934              
5935             # $1 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
5936             # $2 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
5937             # $3 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
5938             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
5939 24         47 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($1))]}";
5940             }
5941              
5942             # ${^CAPTURE}[0] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
5943             # ${^CAPTURE}[1] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
5944             # ${^CAPTURE}[2] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
5945             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
5946 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
5947 0         0 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($n_th+1))]}";
5948             }
5949              
5950             # @- --> @{[mb::_LAST_MATCH_START()]}
5951             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
5952             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
5953             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
5954             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
5955 0         0 $parsed .= '@{[mb::_LAST_MATCH_START()]}';
5956             }
5957              
5958             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
5959             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
5960             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
5961             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
5962             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
5963 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
5964 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
5965             }
5966              
5967             # @+ --> @{[mb::_LAST_MATCH_END()]}
5968             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
5969             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
5970             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
5971             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
5972 0         0 $parsed .= '@{[mb::_LAST_MATCH_END()]}';
5973             }
5974              
5975             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
5976             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
5977             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
5978             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
5979             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
5980 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
5981 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
5982             }
5983              
5984             # any
5985             elsif (/\G ($x) /xmsgc) {
5986 3366 100       4982 if (CORE::length($1) == 1) {
5987 2803         3313 $parsed .= $1;
5988             }
5989             else {
5990 563         860 $parsed .= ('(?:' . escape_qq($1, $closewith) . ')');
5991             }
5992             }
5993              
5994             # something wrong happened
5995             else {
5996 0         0 die sprintf(<
5997 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5998             ------------------------------------------------------------------------------
5999             %s
6000             ------------------------------------------------------------------------------
6001             END
6002             }
6003 130912         232703 return $parsed;
6004             }
6005              
6006             #---------------------------------------------------------------------
6007             # parse modifiers of qr///here
6008             sub parse_re_modifier {
6009 130389     130389 0 139699 my $modifier_i = '';
6010 130389         130419 my $modifier_not_cegir = '';
6011 130389         131728 my $modifier_cegr = '';
6012 130389         109209 while (1) {
6013 130724 50       295606 if (/\G [adlpu] /xmsgc) {
    100          
    100          
    100          
6014             # drop modifiers
6015             }
6016             elsif (/\G ([i]) /xmsgc) {
6017 100         121 $modifier_i .= $1;
6018             }
6019             elsif (/\G ([cegr]) /xmsgc) {
6020 70         86 $modifier_cegr .= $1;
6021             }
6022             elsif (/\G ([a-z]) /xmsgc) {
6023 165         198 $modifier_not_cegir .= $1;
6024             }
6025             else {
6026 130389         116547 last;
6027             }
6028             }
6029 130389         267398 return ($modifier_i, $modifier_not_cegir, $modifier_cegr);
6030             }
6031              
6032             #---------------------------------------------------------------------
6033             # parse modifiers of tr///here
6034             sub parse_tr_modifier {
6035 2159     2159 0 2109 my $modifier_not_r = '';
6036 2159         1935 my $modifier_r = '';
6037 2159         1717 while (1) {
6038 2247 50       4240 if (/\G ([r]) /xmsgc) {
    100          
6039 0         0 $modifier_r .= $1;
6040             }
6041             elsif (/\G ([a-z]) /xmsgc) {
6042 88         119 $modifier_not_r .= $1;
6043             }
6044             else {
6045 2159         1960 last;
6046             }
6047             }
6048 2159         4046 return ($modifier_not_r, $modifier_r);
6049             }
6050              
6051             #---------------------------------------------------------------------
6052             # makes codepoint class from string
6053             sub codepoint_tr {
6054 2131     2131 0 3175 my $searchlist = quotee_of($_[0]);
6055              
6056 2131         2196 my @sbcs = ();
6057 2131         2034 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
6058 2131         4085 while ($searchlist !~ /\G \z /xmsgc) {
6059              
6060             # \-
6061 3267 100       15186 if ($searchlist =~ /\G (\\-) /xmsgc) {
    100          
    100          
    50          
6062 9         19 push @sbcs, $1;
6063             }
6064              
6065             # -
6066             elsif ($searchlist =~ /\G (-) /xmsgc) {
6067 31         58 push @sbcs, $1;
6068             }
6069              
6070             # any qq escapee
6071             elsif ($searchlist =~ /\G ([$escapee_in_qq_like]) /xmsgc) {
6072 1036         2740 push @sbcs, "\\$1";
6073             }
6074              
6075             # any
6076             elsif ($searchlist =~ /\G ($x) /xmsgc) {
6077 2191 100       3382 if (CORE::length($1) == 1) {
6078 1160         3035 push @sbcs, $1;
6079             }
6080             else {
6081 1031         1282 push @xbcs, escape_qq($1, '\\');
6082             }
6083             }
6084              
6085             # something wrong happened
6086             else {
6087 0         0 die sprintf(<
6088 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
6089             ------------------------------------------------------------------------------
6090             %s
6091             ------------------------------------------------------------------------------
6092             END
6093             }
6094             }
6095              
6096             # return codepoint class
6097             return
6098 2131 50 100     15230 ( @sbcs and @xbcs) ? join('|', @xbcs, '['.join('',@sbcs).']') :
    100 66        
    100 33        
6099             (!@sbcs and @xbcs) ? join('|', @xbcs ) :
6100             ( @sbcs and !@xbcs) ? '['.join('',@sbcs).']' :
6101             die;
6102             }
6103              
6104             #---------------------------------------------------------------------
6105             # get quotee from quoted "quotee"
6106             sub quotee_of {
6107 3266 50   3266 0 4510 if (CORE::length($_[0]) >= 2) {
6108 3266         5723 return CORE::substr($_[0],1,-1);
6109             }
6110             else {
6111 0         0 die;
6112             }
6113             }
6114              
6115             #---------------------------------------------------------------------
6116             # escape q/string/ as q-like quote
6117             sub escape_q {
6118 578475     578475 0 801746 my($codepoint, $endswith) = @_;
6119 578475 50       1695837 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
6120 0         0 return "$1\\$2";
6121             }
6122             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ($escapee_in_q__like) \z/xms) {
6123 2712         8659 return "$1\\$2";
6124             }
6125             else {
6126 575763         819478 return $codepoint;
6127             }
6128             }
6129              
6130             #---------------------------------------------------------------------
6131             # escape qq/string/ as qq-like quote
6132             sub escape_qq {
6133 1013713     1013713 0 1311868 my($codepoint, $endswith) = @_;
6134              
6135             # m@`@ --> m`\x60`
6136             # qr@`@ --> qr`\x60`
6137             # s@`@``@ --> s`\x60`\x60\x60`
6138             # m:`: --> m`\x60`
6139             # qr:`: --> qr`\x60`
6140             # s:`:``: --> s`\x60`\x60\x60`
6141 1013713 50       8827819 if ($codepoint eq '`') {
    100          
    100          
6142 0         0 return '\\x60';
6143             }
6144             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
6145 1032         2858 return "$1\\$2";
6146             }
6147             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
6148 21723         74028 return "$1\\$2";
6149             }
6150             else {
6151 990958         1518782 return $codepoint;
6152             }
6153             }
6154              
6155             #---------------------------------------------------------------------
6156             # escape tr/here/here/ as tr-like quote
6157             sub escape_tr {
6158 4608     4608 0 6483 my($codepoint, $endswith) = @_;
6159 4608 50       81206 if ($codepoint =~ /\A (\Q$endswith\E) \z/xms) {
    50          
    100          
6160 0         0 return "\\$1";
6161             }
6162             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
6163 0         0 return "$1\\$2";
6164             }
6165             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ($escapee_in_q__like) \z/xms) {
6166 1988         6814 return "$1\\$2";
6167             }
6168             else {
6169 2620         6602 return $codepoint;
6170             }
6171             }
6172              
6173             #---------------------------------------------------------------------
6174             # escape qq/string/ or qr/regexp/ to hex
6175             sub escape_to_hex {
6176 490     490 0 680 my($codepoint, $endswith) = @_;
6177 490 100       2675 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
6178 28         87 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
6179             }
6180              
6181             # in qr'...', $escapee_in_qq_like is right, not $escapee_in_q__like
6182             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
6183 82         371 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
6184             }
6185             else {
6186 380         932 return $codepoint;
6187             }
6188             }
6189              
6190             #---------------------------------------------------------------------
6191             # compatible routines for %mb of UTF8::R2 module
6192             #
6193             # tie my %mb, 'mb';
6194             # $result = $_ =~ $mb{qr/$utf8regex/imsxo}
6195             # $result = $_ =~ m<\G$mb{qr/$utf8regex/imsxo}>gc
6196             # $result = $_ =~ s<$mb{qr/before/imsxo}>egr
6197              
6198 130     130   451 sub TIEHASH { bless { }, $_[0] }
6199 27     27   666 sub FETCH { _r2_qr($_[1]) }
6200       0     sub STORE { }
6201       129     sub FIRSTKEY { }
6202       0     sub NEXTKEY { }
6203       0     sub EXISTS { }
6204       0     sub DELETE { }
6205       0     sub CLEAR { }
6206       0     sub UNTIE { }
6207       0     sub DESTROY { }
6208       0     sub SCALAR { }
6209              
6210             #---------------------------------------------------------------------
6211              
6212             1;
6213              
6214             __END__