File Coverage

lib/mb.pm
Criterion Covered Total %
statement 1320 1736 76.0
branch 1087 1614 67.3
condition 97 220 44.0
subroutine 107 107 100.0
pod 6 49 12.2
total 2617 3726 70.2


line stmt bran cond sub pod time code
1             package mb;
2             ######################################################################
3             #
4             # mb - run Perl script in MBCS encoding (not only CJK ;-)
5             #
6             # https://metacpan.org/release/mb
7             #
8             # Copyright (c) 2020 INABA Hitoshi in a CPAN
9             ######################################################################
10              
11 99     99   404861 use 5.00503; # Universal Consensus 1998 for primetools
  99         943  
12             # use 5.008001; # Lancaster Consensus 2013 for toolchains
13              
14             $VERSION = '0.07';
15             $VERSION = $VERSION;
16              
17             # internal use
18             $mb::last_s_passed = 0; # last s/// status (1 if s/// passed)
19              
20 99 50   99   3717 BEGIN { pop @INC if $INC[-1] eq '.' } # CVE-2016-1238: Important unsafe module load path flaw
21 99     99   676 use strict;
  99         222  
  99         4861  
22 99 50   99   2788 BEGIN { $INC{'warnings.pm'} = '' if $] < 5.006 } use warnings; local $^W=1;
  99     98   675  
  99         346  
  99         3686  
23 99     98   45911 use Symbol ();
  99         82816  
  98         533192  
24              
25             # set OSNAME
26             my $OSNAME = $^O;
27              
28             # encoding name of MBCS script
29             my $script_encoding = undef;
30              
31             # over US-ASCII
32             ${mb::over_ascii} = undef;
33              
34             # supports qr/./ in MBCS script
35             ${mb::x} = undef;
36              
37             # supports [\b] \d \h \s \v \w in MBCS script
38             ${mb::bare_backspace} = '\x08';
39             ${mb::bare_d} = '0123456789';
40             ${mb::bare_h} = '\x09\x20';
41             ${mb::bare_s} = '\t\n\f\r\x20';
42             ${mb::bare_v} = '\x0A\x0B\x0C\x0D';
43             ${mb::bare_w} = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';
44              
45             # as many escapes as possible to avoid perl's feature
46             my $escapee_in_qq_like = join('', map {"\\$_"} grep( ! /[A-Za-z0-9_]/, map { CORE::chr } 0x21..0x7E));
47              
48             # as less escapes as possible to avoid over-escaping
49             my $escapee_in_q__like = '\\' . "\x5C";
50              
51             # generic linebreak
52             my $R = '(?>\\r\\n|\\r|\\n)';
53              
54             # check running perl interpreter
55             if ($^X =~ /jperl/i) {
56             die "script '@{[__FILE__]}' can run on only perl, not JPerl\n";
57             }
58              
59             # this file is used as command on command line
60             if ($0 eq __FILE__) {
61             main();
62             }
63              
64             ######################################################################
65             # main program
66             ######################################################################
67              
68             #---------------------------------------------------------------------
69             # running as module, runtime routines
70             sub import {
71 98     98   1315 my $self = shift @_;
72              
73             # confirm version
74 98 50 33     602 if (defined($_[0]) and ($_[0] =~ /\A [0-9] /xms)) {
75 3 0       6 if ($_[0] ne $mb::VERSION) {
76 3         66 die "@{[__FILE__]} just $_[0] required--but this is version $mb::VERSION, stopped";
  3         19  
77             }
78 3         6 shift @_;
79             }
80              
81             # set script encoding
82 98 50       487 if (defined $_[0]) {
83 3         20 my $encoding = $_[0];
84 3 0       6 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | sjis | uhc | utf8 ) \z/xms) {
85 3         70 set_script_encoding($encoding);
86             }
87             else {
88 3         20 die "@{[__FILE__]} script_encoding '$encoding' not supported.\n";
  3         6  
89             }
90             }
91             else {
92 98         433 set_script_encoding(detect_system_encoding());
93             }
94              
95             # $^X($EXECUTABLE_NAME) for execute MBCS Perl script
96 98         371 $mb::PERL = qq{$^X @{[__FILE__]}};
  98         453  
97 98         299 $mb::PERL = $mb::PERL; # to avoid: Name "mb::PERL" used only once: possible typo at ...
98              
99             # original $0($PROGRAM_NAME) before transpile
100 98         492 ($mb::ORIG_PROGRAM_NAME = $0) =~ s/\.oo(\.[^.]+)\z/$1/;
101 98         6026 $mb::ORIG_PROGRAM_NAME = $mb::ORIG_PROGRAM_NAME; # to avoid: Name "mb::ORIG_PROGRAM_NAME" used only once: possible typo at ...
102             }
103              
104             #---------------------------------------------------------------------
105             # running as command
106             sub main {
107              
108             # usage
109 3 0   3 0 70 if (scalar(@ARGV) == 0) {
110 3         21 die <
111             usage:
112              
113             perl mb.pm MBCS_Perl_script.pl
114             perl mb.pm -e big5 MBCS_Perl_script.pl
115             perl mb.pm -e big5hkscs MBCS_Perl_script.pl
116             perl mb.pm -e eucjp MBCS_Perl_script.pl
117             perl mb.pm -e gb18030 MBCS_Perl_script.pl
118             perl mb.pm -e gbk MBCS_Perl_script.pl
119             perl mb.pm -e sjis MBCS_Perl_script.pl
120             perl mb.pm -e uhc MBCS_Perl_script.pl
121             perl mb.pm -e utf8 MBCS_Perl_script.pl
122              
123             END
124             }
125              
126             # set script encoding from command line
127 3         6 my $encoding = '';
128 3 0       98 if (($encoding) = $ARGV[0] =~ /\A -e ( .+ ) \z/xms) {
    0          
129 3 0       30 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | sjis | uhc | utf8 ) \z/xms) {
130 3         24 set_script_encoding($encoding);
131 3         76 shift @ARGV;
132             }
133             else {
134 3         22 die "script_encoding '$encoding' not supported.\n";
135             }
136             }
137             elsif ($ARGV[0] =~ /\A -e \z/xms) {
138 3         6 $encoding = $ARGV[1];
139 3 0       68 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | sjis | uhc | utf8 ) \z/xms) {
140 3         21 set_script_encoding($encoding);
141 3         6 shift @ARGV;
142 3         68 shift @ARGV;
143             }
144             else {
145 3         20 die "script_encoding '$encoding' not supported.\n";
146             }
147             }
148             else {
149 3         7 set_script_encoding(detect_system_encoding());
150             }
151              
152             # poor "make"
153 3         67 (my $script_oo = $ARGV[0]) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
154 3 0 0     20 if (
      0        
155             (not -e $script_oo) or
156             (-M $script_oo <= -M $ARGV[0]) or
157             (-M $script_oo <= -M __FILE__)
158             ) {
159              
160             # read application script
161 3 0       7 mb::_open_r(my $fh, $ARGV[0]) or die "$0(@{[__LINE__]}): cant't open file: $ARGV[0]\n";
  3         69  
162 3         19 local $_ = CORE::do { local $/; <$fh> };
  3         6  
  3         66  
163 3         20 close $fh;
164              
165             # poor file locking
166 3     3   6 local $SIG{__DIE__} = sub { rmdir("$ARGV[0].lock"); };
  3         70  
167 3 0       23 if (mkdir("$ARGV[0].lock", 0755)) {
168 3 0       5 mb::_open_w(my $fh, ">$script_oo") or die "$0(@{[__LINE__]}): cant't open file: $script_oo\n";
  3         68  
169 3         20 print {$fh} mb::parse();
  3         5  
170 3         82 close $fh;
171 3         19 rmdir("$ARGV[0].lock");
172             }
173             else {
174 3         7 die "$0(@{[__LINE__]}): cant't mkdir: $ARGV[0].lock\n";
  3         102  
175             }
176             }
177              
178             # run octet-oriented script
179 3         19 my $module_path = '';
180 3         7 my $module_name = '';
181 3         67 my $quote = '';
182 3 0       19 if ($OSNAME =~ /MSWin32/) {
183 3 0       6 if ($0 =~ m{ ([^\/\\]+)\.pm \z}xmsi) {
184 3         67 ($module_path, $module_name) = ($`, $1);
185 3   0     21 $module_path ||= '.';
186 3         5 $module_path =~ s{ [\/\\] \z}{}xms;
187             }
188             else {
189 3         107 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         21  
190             }
191 3         6 $quote = q{"};
192             }
193             else {
194 3 0       68 if ($0 =~ m{ ([^\/]+)\.pm \z}xmsi) {
195 3         22 ($module_path, $module_name) = ($`, $1);
196 3   0     7 $module_path ||= '.';
197 3         68 $module_path =~ s{ / \z}{}xms;
198             }
199             else {
200 3         28 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         9  
201             }
202 3         98 $quote = q{'};
203             }
204              
205             # run octet-oriented script
206 3         22 $| = 1;
207 3 0       6 system($^X, "-I$module_path", "-M$module_name=$mb::VERSION,$script_encoding", map { / / ? "$quote$_$quote" : $_ } $script_oo, @ARGV[1..$#ARGV]);
  3         67  
208 3         20 exit($? >> 8);
209             }
210              
211             #---------------------------------------------------------------------
212             # cluck() for MBCS encoding
213             sub cluck {
214 3     3 0 5 my $i = 0;
215 3         67 my @cluck = ();
216 3         19 while (my($package,$filename,$line,$subroutine) = caller($i)) {
217 3         7 push @cluck, "[$i] $filename($line) $package::$subroutine\n";
218 3         66 $i++;
219             }
220 3         21 print STDERR CORE::reverse @cluck;
221 3         6 print STDERR "\n";
222 3         80 print STDERR @_;
223             }
224              
225             #---------------------------------------------------------------------
226             # confess() for MBCS encoding
227             sub confess {
228 3     3 0 22 my $i = 0;
229 3         6 my @confess = ();
230 3         67 while (my($package,$filename,$line,$subroutine) = caller($i)) {
231 3         19 push @confess, "[$i] $filename($line) $package::$subroutine\n";
232 3         7 $i++;
233             }
234 3         117 print STDERR CORE::reverse @confess;
235 3         29 print STDERR "\n";
236 3         6 print STDERR @_;
237 3         65 die "\n";
238             }
239              
240             ######################################################################
241             # subroutines for MBCS application programmers
242             ######################################################################
243              
244             #---------------------------------------------------------------------
245             # chop() for MBCS encoding
246             sub mb::chop {
247 21     21 0 629 my $chop = '';
248 21 100       46 for (@_ ? @_ : $_) {
249 29 100       209 if (my @x = /\G${mb::x}/g) {
250 23         48 $chop = pop @x;
251 23         46 $_ = join '', @x;
252             }
253             }
254 21         100 return $chop;
255             }
256              
257             #---------------------------------------------------------------------
258             # chr() for MBCS encoding
259             sub mb::chr {
260 7 100   7 0 268 local $_ = shift if @_;
261 7         12 my @octet = ();
262 7         72 CORE::do {
263 9         30 unshift @octet, ($_ % 0x100);
264 9         19 $_ = int($_ / 0x100);
265             } while ($_ > 0);
266 7         83 return pack 'C*', @octet;
267             }
268              
269             #---------------------------------------------------------------------
270             # do FILE for MBCS encoding
271             sub mb::do {
272 8     8 0 1005 my($file) = @_;
273 8         19 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  53         151  
274 8 50       85 if (-f $prefix_file) {
275              
276             # poor "make"
277 8         67 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
278 8 0 33     192 if (
      33        
279             (not -e $prefix_file_oo) or
280             (-M $prefix_file_oo <= -M $prefix_file) or
281             (-M $prefix_file_oo <= -M __FILE__)
282             ) {
283 8 50       39 mb::_open_r(my $fh, $prefix_file) or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file\n";
  3         6  
284 8         74 local $_ = CORE::do { local $/; <$fh> };
  8         36  
  8         100  
285 8         105 close $fh;
286              
287             # poor file locking
288 8     3   57 local $SIG{__DIE__} = sub { rmdir("$prefix_file.lock"); };
  3         16  
289 8 50       317 if (mkdir("$prefix_file.lock", 0755)) {
290 8 50       52 mb::_open_w(my $fh, ">$prefix_file_oo") or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file_oo\n";
  3         6  
291 8         78 print {$fh} mb::parse();
  8         40  
292 8         136 close $fh;
293 8         309 rmdir("$prefix_file.lock");
294             }
295             else {
296 3         23 confess "$0(@{[__LINE__]}): cant't mkdir: $prefix_file.lock\n";
  3         6  
297             }
298             }
299 8         90 $INC{$file} = $prefix_file_oo;
300              
301             # run as Perl script
302             # must use CORE::do to use , because CORE::eval cannot do it
303             # moreover "goto &CORE::do" doesn't work
304 8         288 return CORE::eval sprintf(<<'END', (caller)[0]);
305             package %s;
306             CORE::do "$prefix_file_oo";
307             END
308             }
309             }
310 3         6 confess "Can't find $file in \@INC";
311             }
312              
313             #---------------------------------------------------------------------
314             # DOS-like glob() for MBCS encoding
315             sub mb::dosglob {
316 11 50   11 0 723 my $expr = @_ ? $_[0] : $_;
317 11         37 my @glob = ();
318              
319             # works on not MSWin32
320 11 50       22 if ($OSNAME !~ /MSWin32/) {
321 11         3019 @glob = CORE::glob($expr);
322             }
323              
324             # works on MSWin32
325             else {
326              
327             # gets pattern
328 3         20 while ($expr =~ s{\A [\x20]* ( "(?:${mb::x})+?" | (?:(?!["\x20])${mb::x})+ ) }{}xms) {
329 3         6 my $pattern = $1;
330              
331             # avoids command injection
332 3 0       64 next if $pattern =~ /\G${mb::_anchor} \& /xms;
333 3 0       22 next if $pattern =~ /\G${mb::_anchor} \( /xms;
334 3 0       14 next if $pattern =~ /\G${mb::_anchor} \) /xms;
335 3 0       65 next if $pattern =~ /\G${mb::_anchor} \< /xms;
336 3 0       20 next if $pattern =~ /\G${mb::_anchor} \> /xms;
337 3 0       5 next if $pattern =~ /\G${mb::_anchor} \^ /xms;
338 3 0       65 next if $pattern =~ /\G${mb::_anchor} \| /xms;
339              
340             # makes globbing result
341 3         18 mb::tr($pattern, '/', "\x5C");
342 3 0       6 if (my($dir) = $pattern =~ m{\A (${mb::x}*) \\ }xms) {
343 3         66 push @glob, map { "$dir\\$_" } CORE::split /\n/, `DIR /B $pattern 2>NUL`;
  3         20  
344             }
345             else {
346 3         6 push @glob, CORE::split /\n/, `DIR /B $pattern 2>NUL`;
347             }
348             }
349             }
350              
351             # returns globbing result
352 11         102 my %glob = map { $_ => 1 } @glob;
  27         79  
353 11 50       46 return sort { (mb::uc($a) cmp mb::uc($b)) || ($a cmp $b) } keys %glob;
  22         123  
354             }
355              
356             #---------------------------------------------------------------------
357             # eval STRING for MBCS encoding
358             sub mb::eval {
359 1626 100   1626 0 4197307 local $_ = shift if @_;
360              
361             # run as Perl script
362 1626         3721 return CORE::eval mb::parse();
363             }
364              
365             #---------------------------------------------------------------------
366             # getc() for MBCS encoding
367             sub mb::getc (;*@) {
368 6 50   6 0 400 my $fh = @_ ? Symbol::qualify_to_ref(shift @_,caller()) : \*STDIN;
369 6 50 33     103 confess 'Too many arguments for mb::getc' if @_ and not wantarray;
370 6         51 my $getc = CORE::getc $fh;
371 6 50       84 if ($script_encoding =~ /\A (?: sjis ) \z/xms) {
    0          
    0          
    0          
    0          
372 6 100       30 if ($getc =~ /\A [\x81-\x9F\xE0-\xFC] \z/xms) {
373 5         11 $getc .= CORE::getc $fh;
374             }
375             }
376             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
377 3 0       65 if ($getc =~ /\A [\xA1-\xFE] \z/xms) {
378 3         17 $getc .= CORE::getc $fh;
379             }
380             }
381             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
382 3 0       11 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
383 3         67 $getc .= CORE::getc $fh;
384             }
385             }
386             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
387 3 0       19 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
388 3         5 $getc .= CORE::getc $fh;
389 3 0       66 if ($getc =~ /\A [\x81-\xFE] [\x30-\x39] \z/xms) {
390 3         19 $getc .= CORE::getc $fh;
391 3         6 $getc .= CORE::getc $fh;
392             }
393             }
394             }
395             elsif ($script_encoding =~ /\A (?: utf8 ) \z/xms) {
396 3 0       65 if ($getc =~ /\A [\xC2-\xDF] \z/xms) {
    0          
    0          
397 3         19 $getc .= CORE::getc $fh;
398             }
399             elsif ($getc =~ /\A [\xE0-\xEF] \z/xms) {
400 3         167 $getc .= CORE::getc $fh;
401 3         90 $getc .= CORE::getc $fh;
402             }
403             elsif ($getc =~ /\A [\xF0-\xF4] \z/xms) {
404 3         20 $getc .= CORE::getc $fh;
405 3         5 $getc .= CORE::getc $fh;
406 3         65 $getc .= CORE::getc $fh;
407             }
408             }
409 6 50       32 return wantarray ? ($getc,@_) : $getc;
410             }
411              
412             #---------------------------------------------------------------------
413             # index() for MBCS encoding
414             sub mb::index {
415 11     11 0 437 my $index = 0;
416 11 100       91 if (@_ == 3) {
417 7         114 $index = mb::index_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
418             }
419             else {
420 7         15 $index = mb::index_byte($_[0], $_[1]);
421             }
422 11 100       85 if ($index == -1) {
423 7         31 return -1;
424             }
425             else {
426 7         30 return mb::length(CORE::substr $_[0], 0, $index);
427             }
428             }
429              
430             #---------------------------------------------------------------------
431             # JPerl like index() for MBCS encoding
432             sub mb::index_byte {
433 19     19 0 475 my($str,$substr,$position) = @_;
434 19   100     75 $position ||= 0;
435 19         26 my $pos = 0;
436 19         101 while ($pos < CORE::length($str)) {
437 181 100       358 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
438 15 100       31 if ($pos >= $position) {
439 11         88 return $pos;
440             }
441             }
442 173 50       549 if (CORE::substr($str,$pos) =~ /\A(${mb::x})/oxms) {
443 173         327 $pos += CORE::length($1);
444             }
445             else {
446 3         69 $pos += 1;
447             }
448             }
449 11         40 return -1;
450             }
451              
452             #---------------------------------------------------------------------
453             # universal lc() for MBCS encoding
454             sub mb::lc {
455 14 100   14 1 405 local $_ = shift if @_;
456             # 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
457 14 100       330 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${mb::x}/g;
  122         1461  
458             # 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
459             }
460              
461             #---------------------------------------------------------------------
462             # universal lcfirst() for MBCS encoding
463             sub mb::lcfirst {
464 5 100   5 1 231 local $_ = shift if @_;
465 5 50       123 if (/\A(${mb::x})(.*)\z/s) {
466 5         25 return mb::lc($1) . $2;
467             }
468             else {
469 3         6 return '';
470             }
471             }
472              
473             #---------------------------------------------------------------------
474             # length() for MBCS encoding
475             sub mb::length {
476 19 100   19 0 488 local $_ = shift if @_;
477 19         241 return scalar(() = /\G${mb::x}/g);
478             }
479              
480             #---------------------------------------------------------------------
481             # ord() for MBCS encoding
482             sub mb::ord {
483 7 100   7 0 304 local $_ = shift if @_;
484 7         89 my $ord = 0;
485 7 50       74 if (/\A(${mb::x})/) {
486 7         25 for my $octet (unpack 'C*', $1) {
487 9         78 $ord = $ord * 0x100 + $octet;
488             }
489             }
490 7         33 return $ord;
491             }
492              
493             #---------------------------------------------------------------------
494             # require for MBCS encoding
495             sub mb::require {
496 8 50   8 0 1165 local $_ = shift if @_;
497              
498             # require perl version
499 8 50       87 if (/^[0-9]/) {
500 3 0       21 if ($] < $_) {
501 3         6 confess "Perl $_ required--this is only version $], stopped";
502             }
503             else {
504 3         69 return 1;
505             }
506             }
507              
508             # require expr
509             else {
510 8 100       37 if (exists $INC{$_}) {
511 4 50       13 return 1 if $INC{$_};
512 3         70 confess "Compilation failed in require";
513             }
514              
515             # find expr in @INC
516 7         27 my $file = $_;
517 7         19 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  43         144  
518 7 50       81 if (-f $prefix_file) {
519              
520             # poor "make"
521 7         62 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
522 7 0 33     149 if (
      33        
523             (not -e $prefix_file_oo) or
524             (-M $prefix_file_oo <= -M $prefix_file) or
525             (-M $prefix_file_oo <= -M __FILE__)
526             ) {
527 7 50       41 mb::_open_r(my $fh, $prefix_file) or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file\n";
  3         6  
528 7         108 local $_ = CORE::do { local $/; <$fh> };
  7         48  
  7         99  
529 7         105 close $fh;
530              
531             # poor file locking
532 7     3   60 local $SIG{__DIE__} = sub { rmdir("$prefix_file.lock"); };
  3         6  
533 7 50       297 if (mkdir("$prefix_file.lock", 0755)) {
534 7 50       51 mb::_open_w(my $fh, ">$prefix_file_oo") or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file_oo\n";
  3         4  
535 7         107 print {$fh} mb::parse();
  7         44  
536 7         137 close $fh;
537 7         313 rmdir("$prefix_file.lock");
538             }
539             else {
540 3         20 confess "$0(@{[__LINE__]}): cant't mkdir: $prefix_file.lock\n";
  3         7  
541             }
542             }
543 7         84 $INC{$_} = $prefix_file_oo;
544              
545             # run as Perl script
546             # must use CORE::do to use , because CORE::eval cannot do it.
547 7         24 local $@;
548 7         274 my $result = CORE::eval sprintf(<<'END', (caller)[0]);
549             package %s;
550             CORE::do "$prefix_file_oo";
551             END
552              
553             # return result
554 7 50       99 if ($@) {
    50          
555 3         20 $INC{$_} = undef;
556 3         6 confess $@;
557             }
558             elsif (not $result) {
559 3         65 delete $INC{$_};
560 3         34 confess "$_ did not return true value";
561             }
562             else {
563 7         30 return $result;
564             }
565             }
566             }
567 3         70 confess "Can't find $_ in \@INC";
568             }
569             }
570              
571             #---------------------------------------------------------------------
572             # reverse() for MBCS encoding
573             sub mb::reverse {
574 7 100   7 0 264 if (wantarray) {
575 5         14 return CORE::reverse @_;
576             }
577             else {
578 5         124 return join '', CORE::reverse(join('',@_) =~ /\G${mb::x}/g);
579             }
580             }
581              
582             #---------------------------------------------------------------------
583             # rindex() for MBCS encoding
584             sub mb::rindex {
585 11     11 0 447 my $rindex = 0;
586 11 100       38 if (@_ == 3) {
587 7         168 $rindex = mb::rindex_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
588             }
589             else {
590 7         32 $rindex = mb::rindex_byte($_[0], $_[1]);
591             }
592 11 100       24 if ($rindex == -1) {
593 7         77 return -1;
594             }
595             else {
596 7         35 return mb::length(CORE::substr $_[0], 0, $rindex);
597             }
598             }
599              
600             #---------------------------------------------------------------------
601             # JPerl like rindex() for MBCS encoding
602             sub mb::rindex_byte {
603 19     19 0 430 my($str,$substr,$position) = @_;
604 19   66     141 $position ||= CORE::length($str) - 1;
605 19         41 my $pos = 0;
606 19         31 my $rindex = -1;
607 19   100     150 while (($pos < CORE::length($str)) and ($pos <= $position)) {
608 233 100       453 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
609 23         32 $rindex = $pos;
610             }
611 233 50       723 if (CORE::substr($str,$pos) =~ /\A(${mb::x})/oxms) {
612 233         690 $pos += CORE::length($1);
613             }
614             else {
615 3         5 $pos += 1;
616             }
617             }
618 19         101 return $rindex;
619             }
620              
621             #---------------------------------------------------------------------
622             # set OSNAME
623             sub mb::set_OSNAME {
624 3     3 0 19 $OSNAME = $_[0];
625             }
626              
627             #---------------------------------------------------------------------
628             # set script encoding name and more
629             sub mb::set_script_encoding {
630 193     193 0 1645 $script_encoding = $_[0];
631              
632             # over US-ASCII
633             ${mb::over_ascii} = {
634             'sjis' => '(?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|[\x80-\xFF])', # shift_jis ANSI/OEM Japanese; Japanese (Shift-JIS)
635             'gbk' => '(?>[\x81-\xFE][\x00-\xFF])', # gb2312 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
636             'uhc' => '(?>[\x81-\xFE][\x00-\xFF])', # ks_c_5601-1987 ANSI/OEM Korean (Unified Hangul Code)
637             'big5' => '(?>[\x81-\xFE][\x00-\xFF])', # big5 ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
638             'big5hkscs' => '(?>[\x81-\xFE][\x00-\xFF])', # HKSCS support on top of traditional Chinese Windows
639             'eucjp' => '(?>[\xA1-\xFE][\x00-\xFF])', # EUC-JP Japanese (JIS 0208-1990 and 0121-1990)
640             '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)
641             # 'utf8' => '(?>[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF])', # utf-8 Unicode (UTF-8) RFC2279
642             '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
643 193   50     2207 }->{$script_encoding} || '[\x80-\xFF]';
644              
645             # supports qr/./ in MBCS script
646 193         16478 ${mb::x} = qr/(?>${mb::over_ascii}|[\x00-\x7F])/;
647              
648             # regexp of multi-byte anchoring
649              
650             # Quantifiers
651             # {n,m} --- Match at least n but not more than m times
652             #
653             # n and m are limited to non-negative integral values less than a
654             # preset limit defined when perl is built. This is usually 32766 on
655             # the most common platforms.
656             #
657             # The following code is an attempt to solve the above limitations
658             # in a multi-byte anchoring.
659             #
660             # avoid "Segmentation fault" and "Error: Parse exception"
661             #
662             # perl5101delta
663             # http://perldoc.perl.org/perl5101delta.html
664             # In 5.10.0, the * quantifier in patterns was sometimes treated as {0,32767}
665             # [RT #60034, #60464]. For example, this match would fail:
666             # ("ab" x 32768) =~ /^(ab)*$/
667             #
668             # SEE ALSO
669             #
670             # Complex regular subexpression recursion limit
671             # http://www.perlmonks.org/?node_id=810857
672             #
673             # regexp iteration limits
674             # http://www.nntp.perl.org/group/perl.perl5.porters/2009/02/msg144065.html
675             #
676             # latest Perl won't match certain regexes more than 32768 characters long
677             # http://stackoverflow.com/questions/26226630/latest-perl-wont-match-certain-regexes-more-than-32768-characters-long
678             #
679             # Break through the limitations of regular expressions of Perl
680             # http://d.hatena.ne.jp/gfx/20110212/1297512479
681              
682 193 100       2044 if ($script_encoding =~ /\A (?: utf8 ) \z/xms) {
    50          
    50          
683 98         408 ${mb::_anchor} = qr{.*?}xms;
684             }
685             elsif ($] >= 5.030000) {
686             ${mb::_anchor} = {
687             'sjis' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
688             'eucjp' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
689             'gbk' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
690             'uhc' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
691             'big5' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
692             'big5hkscs' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
693             'gb18030' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
694 3   0     21 }->{$script_encoding} || die;
695             }
696             elsif ($] >= 5.010001) {
697             ${mb::_anchor} = {
698             'sjis' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
699             'eucjp' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
700             'gbk' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
701             'uhc' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
702             'big5' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
703             'big5hkscs' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
704             'gb18030' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
705 98   50     35200 }->{$script_encoding} || die;
706             }
707             else {
708 3         102 ${mb::_anchor} = qr{(?:${mb::x})*?}xms;
709             }
710              
711             # codepoint class shortcuts in qq-like regular expression
712 193         2605 @{mb::_dot} = "(?>${mb::over_ascii}|.)";
713 193         1361 @{mb::_B} = "(?:(?
714 193         904 @{mb::_D} = "(?:(?![0-9])${mb::x})";
715 193         778 @{mb::_H} = "(?:(?![\\x09\\x20])${mb::x})";
716 193         730 @{mb::_N} = "(?:(?!\\n)${mb::x})";
717 193         563 @{mb::_R} = "(?>\\r\\n|[\\x0A\\x0B\\x0C\\x0D])";
718 193         718 @{mb::_S} = "(?:(?![\\t\\n\\f\\r\\x20])${mb::x})";
719 193         682 @{mb::_V} = "(?:(?![\\x0A\\x0B\\x0C\\x0D])${mb::x})";
720 193         806 @{mb::_W} = "(?:(?![A-Za-z0-9_])${mb::x})";
721 193         1096 @{mb::_b} = "(?:(?
722 193         506 @{mb::_d} = "[0-9]";
723 193         507 @{mb::_h} = "[\\x09\\x20]";
724 193         452 @{mb::_s} = "[\\t\\n\\f\\r\\x20]";
725 193         469 @{mb::_v} = "[\\x0A\\x0B\\x0C\\x0D]";
726 193         2024 @{mb::_w} = "[A-Za-z0-9_]";
727             }
728              
729             #---------------------------------------------------------------------
730             # substr() for MBCS encoding
731             BEGIN {
732 98 50 100 98 1 2579416 CORE::eval sprintf <<'END', ($] >= 5.014) ? ':lvalue' : '';
  53 100   3   5229  
  53 100   53   251  
  5 100       85  
  51 50       161  
  19 100       55  
  19 50       104  
  19 100       64  
  27 100       149  
  27 100       168  
  26         121  
  26         261  
  10         79  
  8         72  
733             # VV--------------------------------AAAAAAA
734             sub mb::substr %s {
735             my @x = $_[0] =~ /\G${mb::x}/g;
736              
737             # If the substring is beyond either end of the string, substr() returns the undefined
738             # value and produces a warning. When used as an lvalue, specifying a substring that
739             # is entirely outside the string raises an exception.
740             # http://perldoc.perl.org/functions/substr.html
741              
742             # A return with no argument returns the scalar value undef in scalar context,
743             # an empty list () in list context, and (naturally) nothing at all in void
744             # context.
745              
746             if (($_[1] < (-1 * scalar(@x))) or (+1 * scalar(@x) < $_[1])) {
747             return;
748             }
749              
750             # substr($string,$offset,$length,$replacement)
751             if (@_ == 4) {
752             my $substr = join '', splice @x, $_[1], $_[2], $_[3];
753             $_[0] = join '', @x;
754             $substr; # "return $substr" doesn't work, don't write "return"
755             }
756              
757             # substr($string,$offset,$length)
758             elsif (@_ == 3) {
759             local $SIG{__WARN__} = sub {}; # avoid: Use of uninitialized value in join or string at here
760             my $octet_offset =
761             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
762             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
763             0;
764             my $octet_length =
765             ($_[2] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[2]+1 .. $#x]) :
766             ($_[2] > 0) ? CORE::length(join '', @x[$_[1] .. $_[1]+$_[2]-1]) :
767             0;
768             CORE::substr($_[0], $octet_offset, $octet_length);
769             }
770              
771             # substr($string,$offset)
772             else {
773             my $octet_offset =
774             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
775             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
776             0;
777             CORE::substr($_[0], $octet_offset);
778             }
779             }
780             END
781             }
782              
783             #---------------------------------------------------------------------
784             # tr/// and y/// for MBCS encoding
785             sub mb::tr {
786 248     251 1 14163 my @x = $_[0] =~ /\G${mb::x}/g;
787 248         1155 my @search = $_[1] =~ /\G${mb::x}/g;
788 248         909 my @replacement = $_[2] =~ /\G${mb::x}/g;
789 248 100       777 my %modifier = (defined $_[3]) ? (map { $_ => 1 } CORE::split //, $_[3]) : ();
  388         896  
790              
791 248         417 my %tr = ();
792 248         660 for (my $i=0; $i <= $#search; $i++) {
793              
794             # tr/AAA/123/ works as tr/A/1/
795 548 100       1058 if (not exists $tr{$search[$i]}) {
796              
797             # tr/ABC/123/ makes %tr = ('A'=>'1','B'=>'2','C'=>'3',);
798 504 100 66     1497 if (defined $replacement[$i] and ($replacement[$i] ne '')) {
    100 66        
    100          
799 404         1130 $tr{$search[$i]} = $replacement[$i];
800             }
801              
802             # tr/ABC/12/d makes %tr = ('A'=>'1','B'=>'2','C'=>'',);
803             elsif (exists $modifier{d}) {
804 64         161 $tr{$search[$i]} = '';
805             }
806              
807             # tr/ABC/12/ makes %tr = ('A'=>'1','B'=>'2','C'=>'2',);
808             elsif (defined $replacement[-1] and ($replacement[-1] ne '')) {
809 28         76 $tr{$search[$i]} = $replacement[-1];
810             }
811              
812             # tr/ABC// makes %tr = ('A'=>'A','B'=>'B','C'=>'C',);
813             else {
814 8         25 $tr{$search[$i]} = $search[$i];
815             }
816             }
817             }
818              
819 248         318 my $tr = 0;
820 248         321 my $replaced = '';
821              
822             # has /c modifier
823 248 100       380 if (exists $modifier{c}) {
824              
825             # has /s modifier
826 98 100       162 if (exists $modifier{s}) {
827 44         59 my $last_transliterated = undef;
828 44         90 while (defined(my $x = shift @x)) {
829              
830             # /c modifier works here
831 348 100       494 if (exists $tr{$x}) {
832 192         221 $replaced .= $x;
833 192         345 $last_transliterated = undef;
834             }
835             else {
836              
837             # /d modifier works here
838 156 100       232 if (exists $modifier{d}) {
    50          
839             }
840              
841             elsif (defined $replacement[-1]) {
842              
843             # /s modifier works here
844 42 100 66     94 if (defined($last_transliterated) and ($replacement[-1] eq $last_transliterated)) {
845             }
846              
847             # tr/// works here
848             else {
849 38         49 $replaced .= ($last_transliterated = $replacement[-1]);
850             }
851             }
852 156         274 $tr++;
853             }
854             }
855             }
856              
857             # has no /s modifier
858             else {
859 54         106 while (defined(my $x = shift @x)) {
860              
861             # /c modifier works here
862 282 100       381 if (exists $tr{$x}) {
863 198         354 $replaced .= $x;
864             }
865             else {
866              
867             # /d modifier works here
868 84 100       144 if (exists $modifier{d}) {
    50          
869             }
870              
871             # tr/// works here
872             elsif (defined $replacement[-1]) {
873 60         71 $replaced .= $replacement[-1];
874             }
875 84         156 $tr++;
876             }
877             }
878             }
879             }
880              
881             # has no /c modifier
882             else {
883              
884             # has /s modifier
885 150 100       224 if (exists $modifier{s}) {
886 76         105 my $last_transliterated = undef;
887 76         163 while (defined(my $x = shift @x)) {
888 516 100       721 if (exists $tr{$x}) {
889              
890             # /d modifier works here
891 368 100 100     815 if ($tr{$x} eq '') {
    100          
892             }
893              
894             # /s modifier works here
895             elsif (defined($last_transliterated) and ($tr{$x} eq $last_transliterated)) {
896             }
897              
898             # tr/// works here
899             else {
900 140         206 $replaced .= ($last_transliterated = $tr{$x});
901             }
902 368         664 $tr++;
903             }
904             else {
905 148         175 $replaced .= $x;
906 148         254 $last_transliterated = undef;
907             }
908             }
909             }
910              
911             # has no /s modifier
912             else {
913 74         148 while (defined(my $x = shift @x)) {
914 490 100       991 if (exists $tr{$x}) {
915 366         506 $replaced .= $tr{$x};
916 366         664 $tr++;
917             }
918             else {
919 124         275 $replaced .= $x;
920             }
921             }
922             }
923             }
924              
925             # /r modifier works here
926 248 100       409 if (exists $modifier{r}) {
927 88         955 return $replaced;
928             }
929              
930             # has no /r modifier
931             else {
932 160         209 $_[0] = $replaced;
933 160         626 return $tr;
934             }
935             }
936              
937             #---------------------------------------------------------------------
938             # universal uc() for MBCS encoding
939             sub mb::uc {
940 44 100   47 1 472 local $_ = shift if @_;
941             # 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
942 44 100       777 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${mb::x}/g;
  832         7818  
943             # 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
944             }
945              
946             #---------------------------------------------------------------------
947             # universal ucfirst() for MBCS encoding
948             sub mb::ucfirst {
949 2 100   5 1 187 local $_ = shift if @_;
950 2 50       52 if (/\A(${mb::x})(.*)\z/s) {
951 2         7 return mb::uc($1) . $2;
952             }
953             else {
954 0         0 return '';
955             }
956             }
957              
958             ######################################################################
959             # runtime routines on all operating systems (used automatically)
960             ######################################################################
961              
962             #---------------------------------------------------------------------
963             # implement of special variable $1,$2,$3,...
964             sub mb::_CAPTURE {
965 90 100   93   376 if ($mb::last_s_passed) {
966 29 50       56 if (defined $_[0]) {
967              
968             # $1 is used for multi-byte anchoring
969 29         1214 return CORE::eval '$' . ($_[0] + 1);
970             }
971             else {
972 0         0 my @capture = ();
973 0 0       0 if ($] >= 5.006) {
974              
975             # $1 is used for multi-byte anchoring in s///
976 0         0 push @capture, map { CORE::eval('$'.$_) } 2 .. CORE::eval('$#-');
  0         0  
977             }
978             else {
979              
980             # @{^CAPTURE} doesn't work enough in perl 5.005
981 0         0 for (my $n_th=2; defined(CORE::eval('$'.$n_th)); $n_th++) {
982 0         0 push @capture, CORE::eval('$'.$n_th);
983             }
984             }
985 0         0 return @capture;
986             }
987             }
988             else {
989 61 50       280 if (defined $_[0]) {
990 61         2505 return CORE::eval '$' . $_[0];
991             }
992             else {
993 0         0 my @capture = ();
994 0 0       0 if ($] >= 5.006) {
995 0         0 push @capture, map { CORE::eval('$'.$_) } 1 .. CORE::eval('$#-');
  0         0  
996             }
997             else {
998              
999             # @{^CAPTURE} doesn't work enough in perl 5.005
1000 0         0 for (my $n_th=1; defined(CORE::eval('$'.$n_th)); $n_th++) {
1001 0         0 push @capture, CORE::eval('$'.$n_th);
1002             }
1003             }
1004 0         0 return @capture;
1005             }
1006             }
1007             }
1008              
1009             #---------------------------------------------------------------------
1010             # implement of special variable @+
1011             sub mb::_LAST_MATCH_END {
1012              
1013             # perl 5.005 does not support @+, so it need CORE::eval
1014              
1015 10 100   13   30 if ($mb::last_s_passed) {
1016 5 50       10 if (scalar(@_) >= 1) {
1017 5         273 return CORE::eval q{ ($+[0], @+[2..$#-])[ @_ ] };
1018             }
1019             else {
1020 0         0 return CORE::eval q{ ($+[0], @+[2..$#-]) };
1021             }
1022             }
1023             else {
1024 5 50       12 if (scalar(@_) >= 1) {
1025 5         182 return CORE::eval q{ @+[ @_ ] };
1026             }
1027             else {
1028 0         0 return CORE::eval q{ @+ };
1029             }
1030             }
1031             }
1032              
1033             #---------------------------------------------------------------------
1034             # implement of special variable @-
1035             sub mb::_LAST_MATCH_START {
1036              
1037             # perl 5.005 does not support @-, so it need CORE::eval
1038              
1039 18 100   21   50 if ($mb::last_s_passed) {
1040 9 50       17 if (scalar(@_) >= 1) {
1041 9         526 return CORE::eval q{ ($-[2], @-[2..$#-])[ @_ ] };
1042             }
1043             else {
1044 0         0 return CORE::eval q{ ($-[2], @-[2..$#-]) };
1045             }
1046             }
1047             else {
1048 9 50       17 if (scalar(@_) >= 1) {
1049 9         381 return CORE::eval q{ @-[ @_ ] };
1050             }
1051             else {
1052 0         0 return CORE::eval q{ @- };
1053             }
1054             }
1055             }
1056              
1057             #---------------------------------------------------------------------
1058             # implement of special variable $&
1059             sub mb::_MATCH {
1060 61 50   64   155 if (defined($&)) {
1061 61 100       96 if ($mb::last_s_passed) {
1062 8 50 33     70 if (defined($1) and (CORE::substr($&, 0, CORE::length($1)) eq $1)) {
1063 8         138 return CORE::substr($&, CORE::length($1));
1064             }
1065             else {
1066 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1067             }
1068             }
1069             else {
1070 53 50 33     292 if (defined($1) and (CORE::substr($&, -CORE::length($1)) eq $1)) {
1071 53         762 return $1;
1072             }
1073             else {
1074 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1075             }
1076             }
1077             }
1078             else {
1079 0         0 return '';
1080             }
1081             }
1082              
1083             #---------------------------------------------------------------------
1084             # implement of special variable $`
1085             sub mb::_PREMATCH {
1086 15 50   18   50 if (defined($&)) {
1087 15 100       31 if ($mb::last_s_passed) {
1088 8         126 return $1;
1089             }
1090             else {
1091 7 50 33     47 if (defined($1) and (CORE::substr($&,-CORE::length($1)) eq $1)) {
1092 7         103 return CORE::substr($&, 0, -CORE::length($1));
1093             }
1094             else {
1095 0         0 confess 'Use of "$`", $PREMATCH, and ${^PREMATCH} need to /( capture all )/ in regexp';
1096             }
1097             }
1098             }
1099             else {
1100 0         0 return '';
1101             }
1102             }
1103              
1104             #---------------------------------------------------------------------
1105             # flag off if last m// was pass
1106             sub mb::_m_passed {
1107 1089     1092   3057 $mb::last_s_passed = 0;
1108 1089         98641 return '';
1109             }
1110              
1111             #---------------------------------------------------------------------
1112             # flag on if last s/// was pass
1113             sub mb::_s_passed {
1114 83     86   129 $mb::last_s_passed = 1;
1115 83         7061 return '';
1116             }
1117              
1118             #---------------------------------------------------------------------
1119             # ignore case of m//i, qr//i, s///i
1120             sub mb::_ignorecase {
1121 40     43   137 local($_) = @_;
1122 40         64 my $regexp = '';
1123              
1124             # parse into elements
1125 40         1042 while (/\G (
1126             \(\? \^? [a-z]* [:\)] | # cloister (?^x) (?^x: ...
1127             \(\? \^? [a-z]*-[a-z]+ [:\)] | # cloister (?^x-y) (?^x-y: ...
1128             \[ ((?: \\${mb::x} | ${mb::x} )+?) \] |
1129             \\x\{ [0-9A-Fa-f]{2} \} |
1130             \\o\{ [0-7]{3} \} |
1131             \\x [0-9A-Fa-f]{2} |
1132             \\ [0-7]{3} |
1133             \\@{mb::_dot} |
1134             @{mb::_dot}
1135             ) /xmsgc) {
1136 160         466 my($element, $classmate) = ($1, $2);
1137              
1138             # in codepoint class
1139 160 50       267 if (defined $classmate) {
1140 0         0 $regexp .= '[';
1141 0         0 while ($classmate =~ /\G (
1142             \\x\{ [0-9A-Fa-f]{2} \} |
1143             \\o\{ [0-7]{3} \} |
1144             \\x [0-9A-Fa-f]{2} |
1145             \\ [0-7]{3} |
1146             \\@{mb::_dot} |
1147             @{mb::_dot}
1148             ) /xmsgc) {
1149 0         0 my $element = $1;
1150             $regexp .= {qw(
1151             A Aa a Aa
1152             B Bb b Bb
1153             C Cc c Cc
1154             D Dd d Dd
1155             E Ee e Ee
1156             F Ff f Ff
1157             G Gg g Gg
1158             H Hh h Hh
1159             I Ii i Ii
1160             J Jj j Jj
1161             K Kk k Kk
1162             L Ll l Ll
1163             M Mm m Mm
1164             N Nn n Nn
1165             O Oo o Oo
1166             P Pp p Pp
1167             Q Qq q Qq
1168             R Rr r Rr
1169             S Ss s Ss
1170             T Tt t Tt
1171             U Uu u Uu
1172             V Vv v Vv
1173             W Ww w Ww
1174             X Xx x Xx
1175             Y Yy y Yy
1176             Z Zz z Zz
1177 0   0     0 )}->{$element} || $element;
1178             }
1179 0         0 $regexp .= ']';
1180             }
1181              
1182             # out of codepoint class
1183             else {
1184             $regexp .= {qw(
1185             A [Aa] a [Aa]
1186             B [Bb] b [Bb]
1187             C [Cc] c [Cc]
1188             D [Dd] d [Dd]
1189             E [Ee] e [Ee]
1190             F [Ff] f [Ff]
1191             G [Gg] g [Gg]
1192             H [Hh] h [Hh]
1193             I [Ii] i [Ii]
1194             J [Jj] j [Jj]
1195             K [Kk] k [Kk]
1196             L [Ll] l [Ll]
1197             M [Mm] m [Mm]
1198             N [Nn] n [Nn]
1199             O [Oo] o [Oo]
1200             P [Pp] p [Pp]
1201             Q [Qq] q [Qq]
1202             R [Rr] r [Rr]
1203             S [Ss] s [Ss]
1204             T [Tt] t [Tt]
1205             U [Uu] u [Uu]
1206             V [Vv] v [Vv]
1207             W [Ww] w [Ww]
1208             X [Xx] x [Xx]
1209             Y [Yy] y [Yy]
1210             Z [Zz] z [Zz]
1211 160   66     4415 )}->{$element} || $element;
1212             }
1213             }
1214 40         719 return qr{$regexp};
1215             }
1216              
1217             #---------------------------------------------------------------------
1218             # custom codepoint class in qq-like regular expression
1219             sub mb::_cc {
1220 350     353   717 my($classmate) = @_;
1221 350 100       1232 if ($classmate =~ s{\A \^ }{}xms) {
1222 174         384 return '(?:(?!' . parse_re_codepoint_class($classmate) . ")${mb::x})";
1223             }
1224             else {
1225 176         364 return '(?:(?=' . parse_re_codepoint_class($classmate) . ")${mb::x})";
1226             }
1227             }
1228              
1229             #---------------------------------------------------------------------
1230             # makes clustered code point from string
1231             sub mb::_clustered_codepoint {
1232 22 100   25   177 if (my @codepoint = $_[0] =~ /\G(${mb::x})/xmsgc) {
1233 10 100       25 if (CORE::length($codepoint[$#codepoint]) == 1) {
1234 5         181 return $_[0];
1235             }
1236             else {
1237 5         145 return join '', @codepoint[ 0 .. $#codepoint-1 ], "(?:$codepoint[$#codepoint])";
1238             }
1239             }
1240             else {
1241 12         301 return '';
1242             }
1243             }
1244              
1245             #---------------------------------------------------------------------
1246             # open for append by undefined filehandle
1247             sub mb::_open_a {
1248 0     3   0 $_[0] = Symbol::gensym();
1249 0         0 return open($_[0], ">>$_[1]");
1250             }
1251              
1252             #---------------------------------------------------------------------
1253             # open for read by undefined filehandle
1254             sub mb::_open_r {
1255 9     12   26 $_[0] = Symbol::gensym();
1256 9         386 return open($_[0], $_[1]);
1257             }
1258              
1259             #---------------------------------------------------------------------
1260             # open for write by undefined filehandle
1261             sub mb::_open_w {
1262 9     12   25 $_[0] = Symbol::gensym();
1263 9         547 return open($_[0], $_[1]);
1264             }
1265              
1266             #---------------------------------------------------------------------
1267             # split() for MBCS encoding
1268             # sub mb::_split (;$$$) {
1269             sub mb::_split {
1270 332 100   335   16195 my $pattern = defined($_[0]) ? $_[0] : ' ';
1271 332 100       659 my $string = defined($_[1]) ? $_[1] : $_;
1272 332         512 my @split = ();
1273              
1274             # split's first argument is more consistently interpreted
1275             #
1276             # After some changes earlier in v5.17, split's behavior has been simplified:
1277             # if the PATTERN argument evaluates to a string containing one space, it is
1278             # treated the way that a literal string containing one space once was.
1279             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#split's_first_argument_is_more_consistently_interpreted
1280             # if $pattern is also omitted or is the literal space, " ", the function splits
1281             # on whitespace, /\s+/, after skipping any leading whitespace
1282              
1283 332 100       778 if ($pattern eq ' ') {
1284 108         367 $pattern = qr/\s+/;
1285 108         379 $string =~ s{\A \s+ }{}xms;
1286             }
1287              
1288             # count '(' in pattern
1289 332         465 my @parsed = ();
1290 332         465 my $modifier = '';
1291 332 100 100     2465 if ((($modifier) = $pattern =~ /\A \(\?\^? (.+?) [\)\-\:] /xms) and ($modifier =~ /x/xms)) {
1292 30         745 @parsed = $pattern =~ m{ \G (
1293             \\ ${mb::x} |
1294             \# .*? $ | # comment on /x modifier
1295             \(\?\# (?:${mb::x})*? \) |
1296             \[ (?:${mb::x})+? \] |
1297             \(\? |
1298             \(\+ |
1299             \(\* |
1300             ${mb::x} |
1301             [\x00-\xFF]
1302             ) }xgc;
1303             }
1304             else {
1305 302         4368 @parsed = $pattern =~ m{ \G (
1306             \\ ${mb::x} |
1307             \(\?\# (?:${mb::x})*? \) |
1308             \[ (?:${mb::x})+? \] |
1309             \(\? |
1310             \(\+ |
1311             \(\* |
1312             ${mb::x} |
1313             [\x00-\xFF]
1314             ) }xgc;
1315             }
1316             my $last_match_no =
1317             1 + # first '(' is for substring
1318 332         797 scalar(grep { $_ eq '(' } @parsed); # other '(' are for pattern of split()
  2254         3625  
1319              
1320             # Repeated Patterns Matching a Zero-length Substring
1321             # https://perldoc.perl.org/perlre.html#Repeated-Patterns-Matching-a-Zero-length-Substring
1322 332 100       2273 my $substring_quantifier = ('' =~ / \A $pattern \z /xms) ? '+?' : '*?';
1323              
1324             # if $_[2] specified and positive
1325 332 100 100     937 if (defined($_[2]) and ($_[2] >= 1)) {
1326 21         33 my $limit = $_[2];
1327              
1328 21         1170 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
1329              
1330             # gets substrings by repeat chopping by pattern
1331 21   100     476 while ((--$limit > 0) and ($string =~ s<\A((?:${mb::x})$substring_quantifier)$pattern><>)) {
1332 42         128 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1333 42         1636 push @split, CORE::eval('$'.$n_th);
1334             }
1335             }
1336             }
1337              
1338             # if $_[2] is omitted or zero or negative
1339             else {
1340 311     7   17001 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
  4     7   31  
  4     3   7  
  4     3   167  
  4     3   29  
  4     3   8  
  4     3   94  
        3      
        3      
        3      
        3      
        3      
        3      
        3      
        2      
1341              
1342             # gets substrings by repeat chopping by pattern
1343 311         6484 while ($string =~ s<\A((?:${mb::x})$substring_quantifier)$pattern><>) {
1344 734         2113 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1345 786         29002 push @split, CORE::eval('$'.$n_th);
1346             }
1347             }
1348             }
1349              
1350             # get last substring
1351 332 100 100     1025 if (CORE::length($string) > 0) {
    100          
1352 299         546 push @split, $string;
1353             }
1354             elsif (defined($_[2]) and ($_[2] >= 1)) {
1355 6 50       19 if (scalar(@split) < $_[2]) {
1356 6         19 push @split, ('') x ($_[2] - scalar(@split));
1357             }
1358             }
1359              
1360             # if $_[2] is omitted or zero, trailing null fields are stripped from the result
1361 332 100 100     904 if ((not defined $_[2]) or ($_[2] == 0)) {
1362 305   33     1302 while ((scalar(@split) >= 1) and ($split[-1] eq '')) {
1363 0         0 pop @split;
1364             }
1365             }
1366              
1367             # old days, split had write its result to @_ on scalar context,
1368             # but this usage is no longer supported
1369              
1370 332 100       648 if (wantarray) {
1371 199         2304 return @split;
1372             }
1373             else {
1374 133         1306 return scalar @split;
1375             }
1376             }
1377              
1378             ######################################################################
1379             # runtime routines for MSWin32 (used automatically)
1380             ######################################################################
1381              
1382             #---------------------------------------------------------------------
1383             # filetest -B for MSWin32
1384             sub mb::_B (;*@) {
1385 16 50   19   52 local $_ = shift if @_;
1386 16 50 33     36 confess 'Too many arguments for -B (mb::_B)' if @_ and not wantarray;
1387 16 100 33     47 if ($_ eq '_') {
    50          
    100          
    50          
1388 8 50       568 return wantarray ? (-B _,@_) : -B _;
1389             }
1390             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1391 0 0       0 return wantarray ? (-B $fh,@_) : -B $fh;
1392             }
1393             elsif (-B $_) {
1394 4 50       321 return wantarray ? (1,@_) : 1;
1395             }
1396             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1397 0 0       0 if (-B qq{$_.}) {
1398 0 0       0 return wantarray ? (1,@_) : 1;
1399             }
1400             }
1401 4 50       255 return wantarray ? (undef,@_) : undef;
1402             }
1403              
1404             #---------------------------------------------------------------------
1405             # filetest -C for MSWin32
1406             sub mb::_C (;*@) {
1407 32 50   35   179 local $_ = shift if @_;
1408 32 50 33     71 confess 'Too many arguments for -C (mb::_C)' if @_ and not wantarray;
1409 32 100 33     94 if ($_ eq '_') {
    50          
    100          
    50          
1410 16 50       208 return wantarray ? (-C _,@_) : -C _;
1411             }
1412             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1413 0 0       0 return wantarray ? (-C $fh,@_) : -C $fh;
1414             }
1415             elsif (-e $_) {
1416 10 50       566 return wantarray ? (-C $_,@_) : -C $_;
1417             }
1418             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1419 0 0       0 if (-e qq{$_.}) {
1420 0 0       0 return wantarray ? (-C qq{$_.},@_) : -C qq{$_.};
1421             }
1422             }
1423 6 50       408 return wantarray ? (undef,@_) : undef;
1424             }
1425              
1426             #---------------------------------------------------------------------
1427             # filetest -M for MSWin32
1428             sub mb::_M (;*@) {
1429 32 50   35   195 local $_ = shift if @_;
1430 32 50 33     76 confess 'Too many arguments for -M (mb::_M)' if @_ and not wantarray;
1431 32 100 33     106 if ($_ eq '_') {
    50          
    100          
    50          
1432 16 50       221 return wantarray ? (-M _,@_) : -M _;
1433             }
1434             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1435 0 0       0 return wantarray ? (-M $fh,@_) : -M $fh;
1436             }
1437             elsif (-e $_) {
1438 10 50       575 return wantarray ? (-M $_,@_) : -M $_;
1439             }
1440             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1441 0 0       0 if (-e qq{$_.}) {
1442 0 0       0 return wantarray ? (-M qq{$_.},@_) : -M qq{$_.};
1443             }
1444             }
1445 6 50       430 return wantarray ? (undef,@_) : undef;
1446             }
1447              
1448             #---------------------------------------------------------------------
1449             # filetest -T for MSWin32
1450             sub mb::_T (;*@) {
1451 16 50   19   48 local $_ = shift if @_;
1452 16 50 33     34 confess 'Too many arguments for -T (mb::_T)' if @_ and not wantarray;
1453 16 100 33     54 if ($_ eq '_') {
    50          
    100          
    50          
1454 8 50       542 return wantarray ? (-T _,@_) : -T _;
1455             }
1456             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1457 0 0       0 return wantarray ? (-T $fh,@_) : -T $fh;
1458             }
1459             elsif (-T $_) {
1460 2 50       148 return wantarray ? (1,@_) : 1;
1461             }
1462             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1463 0 0       0 if (-T qq{$_.}) {
1464 0 0       0 return wantarray ? (1,@_) : 1;
1465             }
1466             }
1467 6 50       371 return wantarray ? (undef,@_) : undef;
1468             }
1469              
1470             #---------------------------------------------------------------------
1471             # chdir() for MSWin32
1472             sub mb::_chdir {
1473              
1474             # works on MSWin32 only
1475 2 50 33 5   8 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1476 2         53 return CORE::chdir $_[0];
1477             }
1478              
1479 0 0 0     0 if (@_ == 0) {
    0 0        
    0          
1480 0         0 return CORE::chdir;
1481             }
1482             elsif (($script_encoding =~ /\A (?: sjis ) \z/xms) and ($_[0] =~ /\A ${mb::x}* [\x81-\x9F\xE0-\xFC][\x5C] \z/xms)) {
1483 0 0       0 if (defined wantarray) {
1484 0         0 return 0;
1485             }
1486             else {
1487 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1488             }
1489             }
1490             elsif (($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and ($_[0] =~ /\A ${mb::x}* [\x81-\xFE][\x5C] \z/xms)) {
1491 0 0       0 if (defined wantarray) {
1492 0         0 return 0;
1493             }
1494             else {
1495 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1496             }
1497             }
1498             else {
1499 0         0 return CORE::chdir $_[0];
1500             }
1501             }
1502              
1503             #---------------------------------------------------------------------
1504             # filetest -d for MSWin32
1505             sub mb::_d (;*@) {
1506 16 50   19   47 local $_ = shift if @_;
1507 16 50 33     32 confess 'Too many arguments for -d (mb::_d)' if @_ and not wantarray;
1508 16 100 33     205 if ($_ eq '_') {
    100          
    50          
1509 8 50       344 return wantarray ? (-d _,@_) : -d _;
1510             }
1511             elsif (-d $_) {
1512 2 50       12 return wantarray ? (1,@_) : 1;
1513             }
1514             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1515 0 0       0 if (-d qq{$_.}) {
1516 0 0       0 return wantarray ? (1,@_) : 1;
1517             }
1518             }
1519 6 50       29 return wantarray ? (undef,@_) : undef;
1520             }
1521              
1522             #---------------------------------------------------------------------
1523             # filetest -e for MSWin32
1524             sub mb::_e (;*@) {
1525 19 50   22   65 local $_ = shift if @_;
1526 19 50 33     45 confess 'Too many arguments for -e (mb::_e)' if @_ and not wantarray;
1527 19 100 33     65 if ($_ eq '_') {
    50          
    100          
    50          
1528 8 50       311 return wantarray ? (-e _,@_) : -e _;
1529             }
1530             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1531 0 0       0 return wantarray ? (-e $fh,@_) : -e $fh;
1532             }
1533             elsif (-e $_) {
1534 9 50       438 return wantarray ? (1,@_) : 1;
1535             }
1536             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1537 0 0       0 if (-e qq{$_.}) {
1538 0 0       0 return wantarray ? (1,@_) : 1;
1539             }
1540             }
1541 2 50       129 return wantarray ? (undef,@_) : undef;
1542             }
1543              
1544             #---------------------------------------------------------------------
1545             # filetest -f for MSWin32
1546             sub mb::_f (;*@) {
1547 16 50   19   51 local $_ = shift if @_;
1548 16 50 33     36 confess 'Too many arguments for -f (mb::_f)' if @_ and not wantarray;
1549 16 100 33     42 if ($_ eq '_') {
    50          
    100          
    50          
1550 8 50       354 return wantarray ? (-f _,@_) : -f _;
1551             }
1552             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1553 0 0       0 return wantarray ? (-f $fh,@_) : -f $fh;
1554             }
1555             elsif (-f $_) {
1556 5 50       219 return wantarray ? (1,@_) : 1;
1557             }
1558             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1559 0 0       0 if (-f qq{$_.}) {
1560 0 0       0 return wantarray ? (1,@_) : 1;
1561             }
1562             }
1563 3 50       141 return wantarray ? (undef,@_) : undef;
1564             }
1565              
1566             #---------------------------------------------------------------------
1567             # lstat() for MSWin32
1568             sub mb::_lstat (;*) {
1569 5 50   8   170 local $_ = shift if @_;
1570 5 50 33     21 if ($_ eq '_') {
    50          
    100          
    50          
1571 0         0 confess qq{lstat doesn't support '_'\n};
1572             }
1573             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1574 0         0 return CORE::stat $fh; # not CORE::lstat
1575             }
1576             elsif (-e $_) {
1577 2         127 return CORE::stat _; # not CORE::lstat
1578             }
1579             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1580 0 0       0 if (-e qq{$_.}) {
1581 0         0 return CORE::stat _; # not CORE::lstat
1582             }
1583             }
1584 3 50       148 return wantarray ? () : undef;
1585             }
1586              
1587             #---------------------------------------------------------------------
1588             # opendir() for MSWin32
1589             sub mb::_opendir (*$) {
1590 2     5   4 my $dh;
1591 2 50       5 if (defined $_[0]) {
1592 2         11 $dh = Symbol::qualify_to_ref($_[0], caller());
1593             }
1594             else {
1595 0         0 $dh = $_[0] = \do { local *_ };
  0         0  
1596             }
1597              
1598             # works on MSWin32 only
1599 2 50 33     64 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
    0          
    0          
1600 2         90 return CORE::opendir $dh, $_[1];
1601             }
1602             elsif (-d $_[1]) {
1603 0         0 return CORE::opendir $dh, $_[1];
1604             }
1605             elsif (-d qq{$_[1].}) {
1606 0         0 return CORE::opendir $dh, qq{$_[1].};
1607             }
1608 0         0 return undef;
1609             }
1610              
1611             #---------------------------------------------------------------------
1612             # filetest -r for MSWin32
1613             sub mb::_r (;*@) {
1614 32 50   35   103 local $_ = shift if @_;
1615 32 50 33     78 confess 'Too many arguments for -r (mb::_r)' if @_ and not wantarray;
1616 32 100 33     103 if ($_ eq '_') {
    50          
    100          
    50          
1617 16 50       617 return wantarray ? (-r _,@_) : -r _;
1618             }
1619             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1620 0 0       0 return wantarray ? (-r $fh,@_) : -r $fh;
1621             }
1622             elsif (-r $_) {
1623 10 50       471 return wantarray ? (1,@_) : 1;
1624             }
1625             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1626 0 0       0 if (-r qq{$_.}) {
1627 0 0       0 return wantarray ? (1,@_) : 1;
1628             }
1629             }
1630 6 50       280 return wantarray ? (undef,@_) : undef;
1631             }
1632              
1633             #---------------------------------------------------------------------
1634             # filetest -s for MSWin32
1635             sub mb::_s (;*@) {
1636 16 50   19   53 local $_ = shift if @_;
1637 16 50 33     33 confess 'Too many arguments for -s (mb::_s)' if @_ and not wantarray;
1638 16 100 33     46 if ($_ eq '_') {
    50          
    100          
    50          
1639 8 50       131 return wantarray ? (-s _,@_) : -s _;
1640             }
1641             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1642 0 0       0 return wantarray ? (-s $fh,@_) : -s $fh;
1643             }
1644             elsif (-e $_) {
1645 5 50       250 return wantarray ? (-s $_,@_) : -s $_;
1646             }
1647             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1648 0 0       0 if (-e qq{$_.}) {
1649 0 0       0 return wantarray ? (-s qq{$_.},@_) : -s qq{$_.};
1650             }
1651             }
1652 3 50       137 return wantarray ? (undef,@_) : undef;
1653             }
1654              
1655             #---------------------------------------------------------------------
1656             # stat() for MSWin32
1657             sub mb::_stat (;*) {
1658 8 50   11   176 local $_ = shift if @_;
1659 8 100 33     25 if ($_ eq '_') {
    50          
    100          
    50          
1660 3 100       19 if (-e _) {
1661 2         33 return CORE::stat _;
1662             }
1663             }
1664             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1665 0         0 return CORE::stat $fh;
1666             }
1667             elsif (-e $_) {
1668 4         203 return CORE::stat _;
1669             }
1670             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1671 0 0       0 if (-e qq{$_.}) {
1672 0         0 return CORE::stat _;
1673             }
1674             }
1675 2 50       91 return wantarray ? () : undef;
1676             }
1677              
1678             #---------------------------------------------------------------------
1679             # unlink() for MSWin32
1680             sub mb::_unlink {
1681              
1682             # works on MSWin32 only
1683 89 50 33 92   703 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1684 89 50       6839 return CORE::unlink(@_ ? @_ : $_);
1685             }
1686              
1687 0         0 my $unlink = 0;
1688 0 0       0 for (@_ ? @_ : $_) {
1689 0 0       0 if (CORE::unlink) {
    0          
1690 0         0 $unlink++;
1691             }
1692             elsif (CORE::unlink qq{$_.}) {
1693 0         0 $unlink++;
1694             }
1695             }
1696 0         0 return $unlink;
1697             }
1698              
1699             #---------------------------------------------------------------------
1700             # filetest -w for MSWin32
1701             sub mb::_w (;*@) {
1702 32 50   35   106 local $_ = shift if @_;
1703 32 50 33     72 confess 'Too many arguments for -w (mb::_w)' if @_ and not wantarray;
1704 32 100 33     88 if ($_ eq '_') {
    50          
    100          
    50          
1705 16 50       696 return wantarray ? (-w _,@_) : -w _;
1706             }
1707             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1708 0 0       0 return wantarray ? (-w $fh,@_) : -w $fh;
1709             }
1710             elsif (-w $_) {
1711 10 50       472 return wantarray ? (1,@_) : 1;
1712             }
1713             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1714 0 0       0 if (-w qq{$_.}) {
1715 0 0       0 return wantarray ? (1,@_) : 1;
1716             }
1717             }
1718 6 50       288 return wantarray ? (undef,@_) : undef;
1719             }
1720              
1721             #---------------------------------------------------------------------
1722             # filetest -x for MSWin32
1723             sub mb::_x (;*@) {
1724 36 50   39   108 local $_ = shift if @_;
1725 36 50 33     87 confess 'Too many arguments for -x (mb::_x)' if @_ and not wantarray;
1726 36 100 33     108 if ($_ eq '_') {
    50          
    50          
    50          
1727 12 50       461 return wantarray ? (-x _,@_) : -x _;
1728             }
1729             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1730 0 0       0 return wantarray ? (-x $fh,@_) : -x $fh;
1731             }
1732             elsif (-x $_) {
1733 0 0       0 return wantarray ? (1,@_) : 1;
1734             }
1735             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1736 0 0       0 if (-x qq{$_.}) {
1737 0 0       0 return wantarray ? (1,@_) : 1;
1738             }
1739             }
1740 24 50       1260 return wantarray ? (undef,@_) : undef;
1741             }
1742              
1743             #---------------------------------------------------------------------
1744             # filetest -z for MSWin32
1745             sub mb::_z (;*@) {
1746 16 50   19   61 local $_ = shift if @_;
1747 16 50 33     37 confess 'Too many arguments for -z (mb::_z)' if @_ and not wantarray;
1748 16 100 33     43 if ($_ eq '_') {
    50          
    100          
    50          
1749 8 50       294 return wantarray ? (-z _,@_) : -z _;
1750             }
1751             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1752 0 0       0 return wantarray ? (-z $fh,@_) : -z $fh;
1753             }
1754             elsif (-e $_) {
1755 5 50       258 return wantarray ? (-z $_,@_) : -z $_;
1756             }
1757             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1758 0 0       0 if (-e qq{$_.}) {
1759 0 0       0 return wantarray ? (-z qq{$_.},@_) : -z qq{$_.};
1760             }
1761             }
1762 3 50       129 return wantarray ? (undef,@_) : undef;
1763             }
1764              
1765             ######################################################################
1766             # source code filter
1767             ######################################################################
1768              
1769             #---------------------------------------------------------------------
1770             # detect system encoding any of big5, big5hkscs, eucjp, gb18030, gbk, sjis, uhc, utf8
1771             sub detect_system_encoding {
1772              
1773             # running on Microsoft Windows
1774 95 50   98 0 819 if ($OSNAME =~ /MSWin32/) {
    50          
    50          
    50          
1775 0 0       0 if (my($codepage) = qx{chcp} =~ m/[^0123456789](932|936|949|950|951|20932|54936)\Z/) {
1776             return {qw(
1777             932 sjis
1778             936 gbk
1779             949 uhc
1780             950 big5
1781             951 big5hkscs
1782             20932 eucjp
1783             54936 gb18030
1784 0         0 )}->{$codepage};
1785             }
1786             else {
1787 0         0 return 'utf8';
1788             }
1789             }
1790              
1791             # running on Oracle Solaris
1792             elsif ($OSNAME =~ /solaris/) {
1793             my $LANG =
1794             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1795             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1796 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1797             '';
1798             return {qw(
1799             ja_JP.PCK sjis
1800             ja eucjp
1801             japanese eucjp
1802             ja_JP.eucJP eucjp
1803             zh gbk
1804             zh.GBK gbk
1805             zh_CN.GBK gbk
1806             zh_CN.EUC gbk
1807             zh_CN.GB18030 gb18030
1808             ko uhc
1809             ko_KR.EUC uhc
1810             zh_TW.BIG5 big5
1811             zh_HK.BIG5HK big5hkscs
1812 0   0     0 )}->{$LANG} || 'utf8';
1813             }
1814              
1815             # running on HP HP-UX
1816             elsif ($OSNAME =~ /hpux/) {
1817             my $LANG =
1818             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1819             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1820 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1821             '';
1822             return {qw(
1823             japanese sjis
1824             ja_JP.SJIS sjis
1825             japanese.euc eucjp
1826             ja_JP.eucJP eucjp
1827             zh_CN.hp15CN gbk
1828             zh_CN.gb18030 gb18030
1829             ko_KR.eucKR uhc
1830             zh_TW.big5 big5
1831             zh_HK.big5 big5hkscs
1832             zh_HK.hkbig5 big5hkscs
1833 0   0     0 )}->{$LANG} || 'utf8';
1834             }
1835              
1836             # running on IBM AIX
1837             elsif ($OSNAME =~ /aix/) {
1838             my $LANG =
1839             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1840             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1841 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1842             '';
1843             return {qw(
1844             Ja_JP sjis
1845             Ja_JP.IBM-943 sjis
1846             ja_JP eucjp
1847             ja_JP.IBM-eucJP eucjp
1848             zh_CN gbk
1849             zh_CN.IBM-eucCN gbk
1850             Zh_CN gb18030
1851             Zh_CN.GB18030 gb18030
1852             ko_KR uhc
1853             ko_KR.IBM-eucKR uhc
1854             Zh_TW big5
1855             Zh_TW.big-5 big5
1856             Zh_HK big5hkscs
1857             Zh_HK.BIG5-HKSCS big5hkscs
1858 0   0     0 )}->{$LANG} || 'utf8';
1859             }
1860              
1861             # running on Other Systems
1862             else {
1863             my $LANG =
1864             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1865             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1866 95 50       827 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    50          
1867             '';
1868             return {qw(
1869             japanese sjis
1870             ja_JP.SJIS sjis
1871             ja_JP.mscode sjis
1872             ja eucjp
1873             japan eucjp
1874             japanese.euc eucjp
1875             Japanese-EUC eucjp
1876             ja_JP eucjp
1877             ja_JP.ujis eucjp
1878             ja_JP.eucJP eucjp
1879             ja_JP.AJEC eucjp
1880             ja_JP.EUC eucjp
1881             Jp_JP eucjp
1882             zh_CN.EUC gbk
1883             zh_CN.GB2312 gbk
1884             zh_CN.hp15CN gbk
1885             zh_CN.gb18030 gb18030
1886             ko_KR.eucKR uhc
1887             zh_TW.Big5 big5
1888             zh_TW.big5 big5
1889             zh_HK.big5 big5hkscs
1890 95   50     3102 )}->{$LANG} || 'utf8';
1891             }
1892             }
1893              
1894             my $term = 0;
1895             my @here_document_delimiter = ();
1896              
1897             #---------------------------------------------------------------------
1898             # parse script
1899             sub parse {
1900 7164 100   7167 0 340162 local $_ = shift if @_;
1901              
1902 7164         9872 $term = 0;
1903 7164         11401 @here_document_delimiter = ();
1904              
1905             # transpile JPerl script to Perl script
1906 7164         9846 my $parsed_script = '';
1907 7164         24700 while (not /\G \z /xmsgc) {
1908 35580         56980 $parsed_script .= parse_expr();
1909             }
1910              
1911             # return octet-oriented Perl script
1912 7164         183588 return $parsed_script;
1913             }
1914              
1915             #---------------------------------------------------------------------
1916             # parse expression in script
1917             sub parse_expr {
1918 38317     38320 0 48548 my $parsed = '';
1919              
1920             # __END__ or __DATA__
1921 38317 100 100     802299 if (/\G ^ ( (?: __END__ | __DATA__ ) $R .* ) \z/xmsgc) {
    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          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    50          
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    0          
1922 2         7 $parsed .= $1;
1923             }
1924              
1925             # =pod ... =cut
1926             elsif (/\G ^ ( = [A-Za-z_][A-Za-z_0-9]* [\x00-\xFF]*? $R =cut \b [^\n]* $R ) /xmsgc) {
1927 1         5 $parsed .= $1;
1928             }
1929              
1930             # \r\n, \r, \n
1931             elsif (/\G (?= $R ) /xmsgc) {
1932 8545         22207 while (my $here_document_delimiter = shift @here_document_delimiter) {
1933 23         23 my($delimiter, $quote_type) = @{$here_document_delimiter};
  23         38  
1934 23 100       48 if ($quote_type eq 'qq') {
    50          
1935 14         23 $parsed .= parse_heredocument_as_qq_endswith($delimiter);
1936             }
1937             elsif ($quote_type eq 'q') {
1938              
1939             # perlop > Quote-Like Operators > < Single Quotes
1940             #
1941             # Single quotes indicate the text is to be treated literally
1942             # with no interpolation of its content. This is similar to
1943             # single quoted strings except that backslashes have no special
1944             # meaning, with \\ being treated as two backslashes and not
1945             # one as they would in every other quoting construct.
1946             # https://perldoc.perl.org/perlop.html#Quote-Like-Operators
1947              
1948 9         19 $parsed .= parse_heredocument_as_q_endswith($delimiter);
1949             }
1950             else {
1951 0         0 die "$0(@{[__LINE__]}): $ARGV[0] here document delimiter '$delimiter' not found.\n";
  0         0  
1952             }
1953             }
1954             }
1955              
1956             # \t
1957             # "\x20" [ ] SPACE (U+0020)
1958             elsif (/\G ( [\t ]+ ) /xmsgc) {
1959 5860         11190 $parsed .= $1;
1960             }
1961              
1962             # "\x3B" [;] SEMICOLON (U+003B)
1963             elsif (/\G ( ; ) /xmsgc) {
1964 1009         2064 $parsed .= $1;
1965 1009         1300 $term = 0;
1966             }
1967              
1968             # balanced bracket
1969             # "\x28" [(] LEFT PARENTHESIS (U+0028)
1970             # "\x7B" [{] LEFT CURLY BRACKET (U+007B)
1971             # "\x5B" [[] LEFT SQUARE BRACKET (U+005B)
1972             elsif (/\G ( [(\{\[] ) /xmsgc) {
1973 464         1110 $parsed .= parse_expr_balanced($1);
1974 464         656 $term = 1;
1975             }
1976              
1977             # number
1978             # "\x30" [0] DIGIT ZERO (U+0030)
1979             # "\x31" [1] DIGIT ONE (U+0031)
1980             # "\x32" [2] DIGIT TWO (U+0032)
1981             # "\x33" [3] DIGIT THREE (U+0033)
1982             # "\x34" [4] DIGIT FOUR (U+0034)
1983             # "\x35" [5] DIGIT FIVE (U+0035)
1984             # "\x36" [6] DIGIT SIX (U+0036)
1985             # "\x37" [7] DIGIT SEVEN (U+0037)
1986             # "\x38" [8] DIGIT EIGHT (U+0038)
1987             # "\x39" [9] DIGIT NINE (U+0039)
1988             elsif (/\G (
1989             0x [0-9A-Fa-f_]+ |
1990             0b [01_]+ |
1991             0 [0-7_]* |
1992             [1-9] [0-9_]* (?: \.[0-9_]* )? (?: [Ee] [0-9_]+ )?
1993             ) /xmsgc) {
1994 660         1508 $parsed .= $1;
1995 660         832 $term = 1;
1996             }
1997              
1998             # any term then operator
1999             # "\x25" [%] PERCENT SIGN (U+0025)
2000             # "\x26" [&] AMPERSAND (U+0026)
2001             # "\x2A" [*] ASTERISK (U+002A)
2002             # "\x2E" [.] FULL STOP (U+002E)
2003             # "\x2F" [/] SOLIDUS (U+002F)
2004             # "\x3C" [<] LESS-THAN SIGN (U+003C)
2005             # "\x3F" [?] QUESTION MARK (U+003F)
2006             elsif ($term and /\G ( %= | % | &&= | && | &\.= | &\. | &= | & | \*\*= | \*\* | \*= | \* | \.\.\. | \.\. | \.= | \. | \/\/= | \/\/ | \/= | \/ | <=> | << | <= | < | \? ) /xmsgc) {
2007 122         235 $parsed .= $1;
2008 122         173 $term = 0;
2009             }
2010              
2011             # unimplemented file test operator on MSWin32
2012             # "\x2D" [-] HYPHEN-MINUS (U+002D)
2013             elsif (/\G ( -[ASORWXbcgkloptu] ) \b /xmsgc) {
2014 15         37 $parsed .= $1;
2015 15         17 $term = 1;
2016             }
2017              
2018             # implemented file test operator on MSWin32
2019             # implements run on any systems by transpiling once
2020             elsif (/\G -([BCMTdefrswxz]) \b /xmsgc) {
2021 291         699 $parsed .= "mb::_$1";
2022 291         389 $term = 1;
2023             }
2024              
2025             # yada-yada or triple-dot operator
2026             elsif (/\G ( \.\.\. ) /xmsgc) {
2027 1         4 $parsed .= $1;
2028 1         2 $term = 0;
2029             }
2030              
2031             # any operator
2032             # "\x21" [!] EXCLAMATION MARK (U+0021)
2033             # "\x2B" [+] PLUS SIGN (U+002B)
2034             # "\x2C" [,] COMMA (U+002C)
2035             # "\x3D" [=] EQUALS SIGN (U+003D)
2036             # "\x3E" [>] GREATER-THAN SIGN (U+003E)
2037             # "\x5C" [\] REVERSE SOLIDUS (U+005C)
2038             # "\x5E" [^] CIRCUMFLEX ACCENT (U+005E)
2039             # "\x7C" [|] VERTICAL LINE (U+007C)
2040             # "\x7E" [~] TILDE (U+007E)
2041             elsif (/\G ( != | !~ | ! | \+\+ | \+= | \+ | , | -- | -= | -> | - | == | => | =~ | = | >> | >= | > | \\ | \^\.= | \^\. | \^= | \^ | (?: and | cmp | eq | ge | gt | isa | le | lt | ne | not | or | x | x= | xor ) \b | \|\|= | \|\| | \|\.= | \|\. | \|= | \| | ~~ | ~\. | ~= | ~ ) /xmsgc) {
2042 2165         4440 $parsed .= $1;
2043 2165         2790 $term = 0;
2044             }
2045              
2046             # $` --> mb::_PREMATCH()
2047             # ${`} --> mb::_PREMATCH()
2048             # $PREMATCH --> mb::_PREMATCH()
2049             # ${PREMATCH} --> mb::_PREMATCH()
2050             # ${^PREMATCH} --> mb::_PREMATCH()
2051             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
2052 20         40 $parsed .= 'mb::_PREMATCH()';
2053 20         27 $term = 1;
2054             }
2055              
2056             # $& --> mb::_MATCH()
2057             # ${&} --> mb::_MATCH()
2058             # $MATCH --> mb::_MATCH()
2059             # ${MATCH} --> mb::_MATCH()
2060             # ${^MATCH} --> mb::_MATCH()
2061             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
2062 68         118 $parsed .= 'mb::_MATCH()';
2063 68         80 $term = 1;
2064             }
2065              
2066             # $1 --> mb::_CAPTURE(1)
2067             # $2 --> mb::_CAPTURE(2)
2068             # $3 --> mb::_CAPTURE(3)
2069             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
2070 55         148 $parsed .= "mb::_CAPTURE($1)";
2071 55         72 $term = 1;
2072             }
2073              
2074             # @{^CAPTURE} --> mb::_CAPTURE()
2075             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
2076 3         45 $parsed .= 'mb::_CAPTURE()';
2077 3         5 $term = 1;
2078             }
2079              
2080             # ${^CAPTURE}[0] --> mb::_CAPTURE(1)
2081             # ${^CAPTURE}[1] --> mb::_CAPTURE(2)
2082             # ${^CAPTURE}[2] --> mb::_CAPTURE(3)
2083             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
2084 3         7 my $n_th = quotee_of(parse_expr_balanced($1));
2085 3         6 $parsed .= "mb::_CAPTURE($n_th+1)";
2086 3         4 $term = 1;
2087             }
2088              
2089             # @- --> mb::_LAST_MATCH_START()
2090             # @LAST_MATCH_START --> mb::_LAST_MATCH_START()
2091             # @{LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2092             # @{^LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2093             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
2094 12         22 $parsed .= 'mb::_LAST_MATCH_START()';
2095 12         14 $term = 1;
2096             }
2097              
2098             # $-[1] --> mb::_LAST_MATCH_START(1)
2099             # $LAST_MATCH_START[1] --> mb::_LAST_MATCH_START(1)
2100             # ${LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2101             # ${^LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2102             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
2103 22         53 my $n_th = quotee_of(parse_expr_balanced($1));
2104 22         49 $parsed .= "mb::_LAST_MATCH_START($n_th)";
2105 22         47 $term = 1;
2106             }
2107              
2108             # @+ --> mb::_LAST_MATCH_END()
2109             # @LAST_MATCH_END --> mb::_LAST_MATCH_END()
2110             # @{LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2111             # @{^LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2112             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
2113 12         24 $parsed .= 'mb::_LAST_MATCH_END()';
2114 12         13 $term = 1;
2115             }
2116              
2117             # $+[1] --> mb::_LAST_MATCH_END(1)
2118             # $LAST_MATCH_END[1] --> mb::_LAST_MATCH_END(1)
2119             # ${LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2120             # ${^LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2121             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
2122 14         33 my $n_th = quotee_of(parse_expr_balanced($1));
2123 14         32 $parsed .= "mb::_LAST_MATCH_END($n_th)";
2124 14         21 $term = 1;
2125             }
2126              
2127             # mb::do { block } --> do { block }
2128             # mb::eval { block } --> eval { block }
2129             # do { block } --> do { block }
2130             # eval { block } --> eval { block }
2131             elsif (/\G (?: mb:: )? ( (?: do | eval ) \s* ) ( \{ ) /xmsgc) {
2132 4         12 $parsed .= $1;
2133 4         9 $parsed .= parse_expr_balanced($2);
2134 4         6 $term = 1;
2135             }
2136              
2137             # $#{}, ${}, @{}, %{}, &{}, *{}, do {}, eval {}, sub {}
2138             # "\x24" [$] DOLLAR SIGN (U+0024)
2139             elsif (/\G ((?: \$[#] | [\$\@%&*] | (?:CORE::)? do | (?:CORE::)? eval | sub ) \s* ) ( \{ ) /xmsgc) {
2140 11         28 $parsed .= $1;
2141 11         19 $parsed .= parse_expr_balanced($2);
2142 11         13 $term = 1;
2143             }
2144              
2145             # mb::do --> mb::do
2146             # mb::eval --> mb::eval
2147             # do --> mb::do
2148             # eval --> mb::eval
2149             elsif (/\G (?: mb:: )? ( do | eval ) \b /xmsgc) {
2150 4         10 $parsed .= "mb::$1";
2151 4         5 $term = 1;
2152             }
2153              
2154             # CORE::do --> CORE::do
2155             # CORE::eval --> CORE::eval
2156             elsif (/\G ( CORE:: (?: do | eval ) ) \b /xmsgc) {
2157 2         5 $parsed .= $1;
2158 2         3 $term = 1;
2159             }
2160              
2161             # last index of array
2162             elsif (/\G ( [\$] [#] (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2163 3         9 $parsed .= $1;
2164 3         4 $term = 1;
2165             }
2166              
2167             # scalar variable
2168             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) {
2169 593         1441 $parsed .= $1;
2170 593         751 $term = 1;
2171             }
2172              
2173             # array variable
2174             # "\x40" [@] COMMERCIAL AT (U+0040)
2175             elsif (/\G ( [\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [_] ) ) /xmsgc) {
2176 109         276 $parsed .= $1;
2177 109         141 $term = 1;
2178             }
2179              
2180             # hash variable
2181             elsif (/\G ( [\%\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [!+\-] ) ) /xmsgc) {
2182 11         25 $parsed .= $1;
2183 11         14 $term = 1;
2184             }
2185              
2186             # user subroutine call
2187             # type glob
2188             elsif (/\G ( [&*] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2189 12         27 $parsed .= $1;
2190 12         14 $term = 1;
2191             }
2192              
2193             # comment
2194             # "\x23" [#] NUMBER SIGN (U+0023)
2195             elsif (/\G ( [#] [^\n]* ) /xmsgc) {
2196 11         32 $parsed .= $1;
2197             }
2198              
2199             # 2-quotes
2200              
2201             # '...'
2202             # "\x27" ['] APOSTROPHE (U+0027)
2203 1476         3560 elsif (m{\G ( ' ) }xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  1476         2137  
2204              
2205             # "...", `...`
2206             # "\x22" ["] QUOTATION MARK (U+0022)
2207             # "\x60" [`] GRAVE ACCENT (U+0060)
2208 740         1816 elsif (m{\G ( ["`] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  740         1165  
2209              
2210             # /.../
2211             elsif (m{\G ( [/] ) }xmsgc) {
2212 704         1555 my $regexp = parse_re_endswith('m',$1);
2213 704         1364 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2214 704 100       1321 if ($modifier_i) {
2215 15         61 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2216             }
2217             else {
2218 689         2691 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2219             }
2220 704         1195 $term = 1;
2221             }
2222              
2223             # ?...?
2224             elsif (m{\G ( [?] ) }xmsgc) {
2225 1         4 my $regexp = parse_re_endswith('m',$1);
2226 1         2 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2227 1 50       4 if ($modifier_i) {
2228 0         0 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2229             }
2230             else {
2231 1         41 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2232             }
2233 1         5 $term = 1;
2234             }
2235              
2236             # <<>> double-diamond operator
2237             elsif (/\G ( <<>> ) /xmsgc) {
2238 1         4 $parsed .= $1;
2239 1         1 $term = 1;
2240             }
2241              
2242             # diamond operator
2243             # <${file}>
2244             # <$file>
2245             #
2246             elsif (/\G (<) ((?:(?!\s)${mb::x})*?) (>) /xmsgc) {
2247 5         18 my($open_bracket, $quotee, $close_bracket) = ($1, $2, $3);
2248 5         8 $parsed .= $open_bracket;
2249 5         55 while ($quotee =~ /\G (${mb::x}) /xmsgc) {
2250 25         37 $parsed .= escape_qq($1, $close_bracket);
2251             }
2252 5         6 $parsed .= $close_bracket;
2253 5         7 $term = 1;
2254             }
2255              
2256             # qw/.../, q/.../
2257             elsif (/\G ( qw | q ) \b /xmsgc) {
2258 130         303 $parsed .= $1;
2259 130 100       574 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2 100       6  
  2 100       4  
    100          
    100          
    50          
2260 2         6 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         4  
2261 8         18 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); $term = 1; }
  8         11  
2262 2         26 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         3  
2263 48         74 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  48         59  
2264 68         89 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2265 68         144 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2266 4         12 $parsed .= $1;
2267             }
2268 68 100       232 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  6 100       13  
  6 100       10  
    100          
    50          
2269 2         6 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         3  
2270 8         18 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); $term = 1; }
  8         11  
2271 2         6 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         3  
2272 50         91 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  50         61  
2273 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2274             }
2275 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2276             }
2277              
2278             # qq/.../
2279             elsif (/\G ( qq ) \b /xmsgc) {
2280 67         168 $parsed .= $1;
2281 67 100       290 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1 100       3  
  1 100       3  
    100          
    100          
    50          
2282 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; } # qq'...' works as "..."
  1         2  
2283 6         19 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  6         10  
2284 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         2  
2285 24         43 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  24         30  
2286 34         50 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2287 34         74 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2288 2         7 $parsed .= $1;
2289             }
2290 34 100       164 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  3 100       6  
  3 100       5  
    100          
    50          
2291 1         44 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; } # qq'...' works as "..."
  1         3  
2292 4         10 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  4         6  
2293 1         6 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         3  
2294 25         42 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  25         30  
2295 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2296             }
2297 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2298             }
2299              
2300             # qx/.../
2301             elsif (/\G ( qx ) \b /xmsgc) {
2302 65         161 $parsed .= $1;
2303 65 100       305 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1 100       4  
  1 100       3  
    100          
    100          
    50          
2304 1         5 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  1         4  
2305 4         8 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  4         6  
2306 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         2  
2307 24         42 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  24         28  
2308 34         47 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2309 34         73 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2310 2         7 $parsed .= $1;
2311             }
2312 34 100       126 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  3 100       6  
  3 100       5  
    100          
    50          
2313 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  1         3  
2314 4         8 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  4         8  
2315 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         3  
2316 25         45 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  25         29  
2317 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2318             }
2319 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2320             }
2321              
2322             # m/.../, qr/.../
2323             elsif (/\G ( m | qr ) \b /xmsgc) {
2324 1597         4623 $parsed .= $1;
2325 1597         2554 my $regexp = '';
2326 1597 100       6329 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr#...#
  2 100       6  
    100          
    100          
    100          
    100          
    50          
2327 631         1379 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr'...'
2328 8         18 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr{...}
2329 314         727 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr/.../
2330 530         1465 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # qr@...@
2331 44         93 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr?...?
2332 68         96 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # qr SPACE ...
  68         64  
2333 68         149 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2334 4         10 $parsed .= $1;
2335             }
2336 68 100       235 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE A...A
  6 100       12  
    100          
    100          
    100          
    50          
2337 2         8 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr SPACE '...'
2338 8         18 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr SPACE {...}
2339 2         5 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE /.../
2340 4         8 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # qr SPACE @...@
2341 46         88 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE ?...?
2342 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2343             }
2344 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2345              
2346             # /i modifier
2347 1597         3393 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2348 1597 100       2992 if ($modifier_i) {
2349 21         85 $parsed .= sprintf('{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2350             }
2351             else {
2352 1576         5893 $parsed .= sprintf('{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2353             }
2354 1597         2789 $term = 1;
2355             }
2356              
2357             # 3-quotes
2358              
2359             # s/.../.../
2360             elsif (/\G ( s ) \b /xmsgc) {
2361 1709         4767 $parsed .= $1;
2362 1709         2750 my $regexp = '';
2363 1709         2041 my $comment = '';
2364 1709         2447 my @replacement = ();
2365 1709 100       7440 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s#...#...#
  1 100       5  
  1 100       3  
    100          
    100          
    100          
    50          
2366 286         698 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s'...'...'
  286         624  
2367 240         517 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s{...}...
2368 240 50       1215 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2369 4         14 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}'...'
2370 16         37 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{}{...}
2371 4         16 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}/.../
2372 96         232 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}?...?
2373 120         194 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s{} SPACE ...
2374 120         350 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2375 0         0 $comment .= $1;
2376             }
2377 120 50       544 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2378 4         15 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE '...'
2379 16         33 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{} SPACE {...}
2380 4         231 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE /.../
2381 96         198 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE ?...?
2382 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2383             }
2384 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2385             }
2386 350         773 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s/.../.../
  350         720  
2387 528         1125 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('s',$1)) . '`';
2388 528         1175 @replacement = parse_qq_like_endswith($1); } # s@...@...@
2389 22         48 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s?...?...?
  22         52  
2390 282         495 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # s SPACE ...
  282         376  
2391 282         819 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2392 12         40 $parsed .= $1;
2393             }
2394 282 100       1021 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       30  
  12 100       25  
    100          
    100          
    50          
2395 1         5 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE '...'...'
  1         3  
2396 244         569 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s SPACE {...}...
2397 244 100       1262 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}#...#
  1 100       4  
    100          
    100          
    100          
    50          
2398 4         17 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}'...'
2399 17         33 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {}{...}
2400 4         28 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}/.../
2401 96         204 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}?...?
2402 122         193 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s SPACE {} SPACE ...
2403 122         341 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2404 8         26 $comment .= $1;
2405             }
2406 122 50       521 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          
2407 4         15 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE '...'
2408 18         40 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {} SPACE {...}
2409 4         18 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE /.../
2410 96         203 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE ?...?
2411 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2412             }
2413 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2414             }
2415 1         5 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE /.../.../
  1         3  
2416 2         6 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('s',$1)) . '`';
2417 2         6 @replacement = parse_qq_like_endswith($1); } # s SPACE @...@...@
2418 22         58 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE ?...?...?
  22         46  
2419 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2420             }
2421 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2422              
2423 1709         3215 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2424 1709         2632 my $replacement = '';
2425 1709         2148 my $eval = '';
2426              
2427             # has /e modifier
2428 1709 100       5370 if (my $e = $modifier_cegr =~ tr/e//d) {
    100          
    100          
2429 9         15 $replacement = 'q'. $replacement[1]; # q-type quotee
2430 9         18 $eval = 'mb::eval ' x $e;
2431             }
2432              
2433             # s''q-quotee'
2434             elsif ($replacement[0] =~ /\A ' /xms) {
2435 300         460 $replacement = $replacement[1]; # q-type quotee
2436             }
2437              
2438             # s##qq-quotee#
2439             elsif ($replacement[0] =~ /\A [#] /xms) {
2440 2         3 $replacement = 'qq' . $replacement[0]; # qq-type quotee
2441             }
2442              
2443             # s//qq-quotee/
2444             else {
2445 1398         2088 $replacement = 'qq ' . $replacement[0]; # qq-type quotee
2446             }
2447              
2448             # /i modifier
2449 1709 100       2734 if ($modifier_i) {
2450 18         77 $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);
2451             }
2452             else {
2453 1691         6699 $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);
2454             }
2455 1709         3536 $term = 1;
2456             }
2457              
2458             # tr/.../.../, y/.../.../
2459             elsif (/\G (?: tr | y ) \b /xmsgc) {
2460 1250         2615 $parsed .= 's'; # not 'tr'
2461 1250         1770 my $search = '';
2462 1250         1581 my $comment = '';
2463 1250         1584 my $replacement = '';
2464 1250 100       5561 if (/\G ( [#] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr#...#...#
  2 100       10  
  2 100       8  
    100          
    100          
    50          
2465 128         289 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr'...'...'
  128         239  
2466 480         1073 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_q__like_balanced($1); # tr{...}...
2467 480 50       2811 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2468 8         29 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}'...'
2469 32         73 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr{}{...}
2470 8         31 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}/.../
2471 192         406 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}?...?
2472 240         426 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr{} SPACE ...
2473 240         692 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2474 0         0 $comment .= $1;
2475             }
2476 240 50       1121 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2477 8         35 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE '...'
2478 32         58 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr{} SPACE {...}
2479 8         26 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE /.../
2480 192         389 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE ?...?
2481 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2482             }
2483 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2484             }
2485 36         74 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr/.../.../
  36         67  
2486 48         97 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr?...?...?
  48         94  
2487 556         1425 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; # tr SPACE ...
2488 556         1557 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2489 24         82 $parsed .= $1;
2490             }
2491 556 100       2098 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE A...A...A
  16 100       74  
  16 100       30  
    100          
    50          
2492 2         9 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE '...'...'
  2         8  
2493 488         1037 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_q__like_balanced($1); # tr SPACE {...}...
2494 488 100       2987 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}#...#
  2 100       8  
    100          
    100          
    100          
    50          
2495 8         45 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}'...'
2496 34         55 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr SPACE {}{...}
2497 8         33 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}/.../
2498 192         353 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}?...?
2499 244         462 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr SPACE {} SPACE ...
2500 244         666 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2501 16         83 $comment .= $1;
2502             }
2503 244 50       1083 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2504 8         31 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE '...'
2505 36         74 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr SPACE {} SPACE {...}
2506 8         35 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE /.../
2507 192         364 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE ?...?
2508 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2509             }
2510 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2511             }
2512 2         7 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE /.../.../
  2         6  
2513 48         98 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE ?...?...?
  48         85  
2514 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2515             }
2516 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2517              
2518             # modifier
2519 1250         2643 my($modifier_not_r, $modifier_r) = parse_tr_modifier();
2520 1250 50       2682 if ($modifier_r) {
    100          
2521 0         0 $parsed .= sprintf(q<{[\x00-\xFF]*> . q<}%s{mb::tr($&,q%s,q%s,'%sr')}er>, $comment, $search, $replacement, $modifier_not_r);
2522             }
2523             elsif ($modifier_not_r =~ /s/) {
2524             # these implementations cannot return right number of codepoints replaced. if you want number, you can use mb::tr().
2525 20         94 $parsed .= sprintf(q<{[\x00-\xFF]*> . q<}%s{mb::tr($&,q%s,q%s,'%sr')}e>, $comment, $search, $replacement, $modifier_not_r);
2526             # $parsed .= sprintf(q<{(\\G${mb::_anchor})(%s+)}%s{$1.mb::tr($2,q%s,q%s,'%sr')}eg>, codepoint_tr($search, $modifier_not_r), $comment, $search, $replacement, $modifier_not_r);
2527             }
2528             else {
2529 1230         2188 $parsed .= sprintf(q<{(\\G${mb::_anchor})(%s)}%s{$1.mb::tr($2,q%s,q%s,'%sr')}eg>, codepoint_tr($search, $modifier_not_r), $comment, $search, $replacement, $modifier_not_r);
2530             }
2531 1250         2386 $term = 1;
2532             }
2533              
2534             # indented here document
2535 1         5 elsif (/\G ( <<~ ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; $term = 1; }
  1         5  
  1         3  
2536 1         4 elsif (/\G ( <<~ \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; $term = 1; }
  1         4  
  1         2  
2537 3         7 elsif (/\G ( <<~ [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; $term = 1; }
  3         11  
  3         4  
2538 3         8 elsif (/\G ( <<~ [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; $term = 1; }
  3         11  
  3         4  
2539 3         9 elsif (/\G ( <<~ [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; $term = 1; }
  3         9  
  3         6  
2540              
2541             # here document
2542 1         2 elsif (/\G ( << ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; $term = 1; }
  1         5  
  1         2  
2543 1         3 elsif (/\G ( << \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; $term = 1; }
  1         13  
  1         3  
2544 4         25 elsif (/\G ( << [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; $term = 1; }
  4         15  
  4         8  
2545 3         8 elsif (/\G ( << [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; $term = 1; }
  3         9  
  3         4  
2546 3         8 elsif (/\G ( << [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; $term = 1; }
  3         9  
  3         5  
2547              
2548             # sub subroutine();
2549             elsif (/\G ( sub \s+ [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* \s* ) /xmsgc) {
2550 10         28 $parsed .= $1;
2551 10         15 $term = 0;
2552             }
2553              
2554             # while (<<>>)
2555             elsif (/\G ( while \s* \( \s* ) ( <<>> ) ( \s* \) ) /xmsgc) {
2556 2         5 $parsed .= $1;
2557 2         4 $parsed .= $2;
2558 2         4 $parsed .= $3;
2559 2         3 $term = 0;
2560             }
2561              
2562             # while (<${file}>)
2563             # while (<$file>)
2564             # while ()
2565             # while ()
2566             elsif (/\G ( while \s* \( \s* ) (<) ((?:(?!\s)${mb::x})*?) (>) ( \s* \) ) /xmsgc) {
2567 8         23 $parsed .= $1;
2568 8         29 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2569 8         13 my $close_bracket2 = $5;
2570 8         23 $parsed .= $open_bracket;
2571 8         76 while ($quotee =~ /\G (${mb::x}) /xmsgc) {
2572 50         149 $parsed .= escape_qq($1, $close_bracket);
2573             }
2574 8         11 $parsed .= $close_bracket;
2575 8         9 $parsed .= $close_bracket2;
2576 8         13 $term = 0;
2577             }
2578              
2579             # while <<>>
2580             elsif (/\G ( while \s* ) ( <<>> ) /xmsgc) {
2581 0         0 $parsed .= $1;
2582 0         0 $parsed .= $2;
2583 0         0 $term = 0;
2584             }
2585              
2586             # while <${file}>
2587             # while <$file>
2588             # while
2589             # while
2590             elsif (/\G ( while \s* ) (<) ((?:(?!\s)${mb::x})*?) (>) /xmsgc) {
2591 0         0 $parsed .= $1;
2592 0         0 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2593 0         0 $parsed .= $open_bracket;
2594 0         0 while ($quotee =~ /\G (${mb::x}) /xmsgc) {
2595 0         0 $parsed .= escape_qq($1, $close_bracket);
2596             }
2597 0         0 $parsed .= $close_bracket;
2598 0         0 $term = 0;
2599             }
2600              
2601             # if (expr)
2602             # elsif (expr)
2603             # unless (expr)
2604             # while (expr)
2605             # until (expr)
2606             # given (expr)
2607             # when (expr)
2608             elsif (/\G ( (?: if | elsif | unless | while | until | given | when ) \s* ) ( \( ) /xmsgc) {
2609 25         265 $parsed .= $1;
2610              
2611             # outputs expr
2612 25         89 my $expr = parse_expr_balanced($2);
2613 25         527 $parsed .= $expr;
2614 25         114 $term = 0;
2615             }
2616              
2617             # else
2618             elsif (/\G ( else ) \b /xmsgc) {
2619 1         3 $parsed .= $1;
2620 1         2 $term = 0;
2621             }
2622              
2623             # ... if expr;
2624             # ... unless expr;
2625             # ... while expr;
2626             # ... until expr;
2627             elsif (/\G ( if | unless | while | until ) \b /xmsgc) {
2628 8         20 $parsed .= $1;
2629 8         13 $term = 0;
2630             }
2631              
2632             # foreach my $var (expr) --> foreach my $var (expr)
2633             # for my $var (expr) --> for my $var (expr)
2634             elsif (/\G ( (?: foreach | for ) \s+ my \s* [\$] [A-Za-z_][A-Za-z_0-9]* ) ( \( ) /xmsgc) {
2635 0         0 $parsed .= $1;
2636 0         0 $parsed .= parse_expr_balanced($2);
2637 0         0 $term = 0;
2638             }
2639              
2640             # foreach $var (expr) --> foreach $var (expr)
2641             # for $var (expr) --> for $var (expr)
2642             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) {
2643 0         0 $parsed .= $1;
2644 0         0 $parsed .= parse_expr_balanced($2);
2645 0         0 $term = 0;
2646             }
2647              
2648             # foreach (expr1; expr2; expr3) --> foreach (expr1; expr2; expr3)
2649             # foreach (expr) --> foreach (expr)
2650             # for (expr1; expr2; expr3) --> for (expr1; expr2; expr3)
2651             # for (expr) --> for (expr)
2652             elsif (/\G ( (?: foreach | for ) \s* ) ( \( ) /xmsgc) {
2653 4         12 $parsed .= $1;
2654 4         8 $parsed .= parse_expr_balanced($2);
2655 4         6 $term = 0;
2656             }
2657              
2658             # CORE::split --> CORE::split
2659             elsif (/\G ( CORE::split ) \b /xmsgc) {
2660 0         0 $parsed .= $1;
2661 0         0 $term = 1;
2662             }
2663              
2664             # split --> mb::_split by default
2665             elsif (/\G (?: mb:: )? ( split ) \b /xmsgc) {
2666 675         1363 $parsed .= "mb::_split";
2667              
2668             # parse \s and '('
2669 675         662 while (1) {
2670 1354 100       3467 if (/\G ( \s+ ) /xmsgc) {
    100          
    100          
2671 294         557 $parsed .= $1;
2672             }
2673             elsif (/\G ( \( ) /xmsgc) {
2674 385         797 $parsed .= $1;
2675             }
2676             elsif (/\G ( \# .* \n ) /xmgc) {
2677 16         24 $parsed .= $1;
2678 16         25 last;
2679             }
2680             else {
2681 659         912 last;
2682             }
2683             }
2684 675         817 my $regexp = '';
2685              
2686             # split /^/ --> mb::_split qr/^/m
2687             # split /.../ --> mb::_split qr/.../
2688 675 100       1999 if (m{\G ( [/] ) }xmsgc) {
    100          
2689 22         29 $parsed .= "qr";
2690 22         37 $regexp = parse_re_endswith('m',$1); # split /.../
2691 22         31 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2692              
2693             # P.794 29.2.161. split
2694             # in Chapter 29: Functions
2695             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2696              
2697             # P.951 split
2698             # in Chapter 27: Functions
2699             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2700              
2701             # said "The //m modifier is assumed when you split on the pattern /^/",
2702             # but perl5.008 is not so. Therefore, this software adds //m.
2703             # (and so on)
2704              
2705 22 100       49 if ($modifier_not_cegir !~ /m/xms) {
2706 16         20 $modifier_not_cegir .= 'm';
2707             }
2708              
2709             # /i modifier
2710 22 100       33 if ($modifier_i) {
2711 6         21 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2712             }
2713             else {
2714 16         49 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2715             }
2716             }
2717              
2718             # split m/^/ --> mb::_split qr/^/m
2719             # split m/.../ --> mb::_split qr/.../
2720             elsif (/\G ( m | qr ) \b /xmsgc) {
2721 609         790 $parsed .= "qr";
2722              
2723 609 100       2440 if (/\G ( [#] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr#...#
  8 100       23  
    100          
    100          
    100          
    100          
    50          
2724 8         27 elsif (/\G ( ['] ) /xmsgc) { $regexp = parse_re_as_q_endswith('m',$1); } # split qr'...'
2725 32         66 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp = parse_re_balanced('m',$1); } # split qr{...}
2726 81         190 elsif (m{\G( [/] ) }xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr/.../
2727 16         41 elsif (/\G ( [:\@] ) /xmsgc) { $regexp = '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # split qr@...@
2728 184         330 elsif (/\G ( [\S] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr?...?
2729 280         431 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp = $1; # split qr SPACE ...
  280         376  
2730 280         623 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2731 32         78 $parsed .= $1;
2732             }
2733 280 100       1203 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE A...A
  24 100       50  
    100          
    100          
    100          
    50          
2734 8         31 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # split qr SPACE '...'
2735 32         69 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # split qr SPACE {...}
2736 8         22 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE /.../
2737 16         36 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # split qr SPACE @...@
2738 192         345 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE ?...?
2739 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2740             }
2741 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2742              
2743 609         982 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2744              
2745 609 100       1148 if ($modifier_not_cegir !~ /m/xms) {
2746 605         651 $modifier_not_cegir .= 'm';
2747             }
2748              
2749             # /i modifier
2750 609 100       744 if ($modifier_i) {
2751 16         69 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2752             }
2753             else {
2754 593         1695 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2755             }
2756             }
2757              
2758 675         852 $term = 1;
2759             }
2760              
2761             # provides bare Perl and JPerl compatible functions
2762             elsif (/\G ( (?: lc | lcfirst | uc | ucfirst ) ) \b /xmsgc) {
2763 15         49 $parsed .= "mb::$1";
2764 15         20 $term = 1;
2765             }
2766              
2767             # CORE::function, mb::subroutine, function
2768             elsif (/\G (?: mb:: )? ( require ) (?= \s+ [0-9] ) /xmsgc) {
2769 0         0 $parsed .= $1;
2770 0         0 $term = 1;
2771             }
2772             elsif (/\G (?: mb:: )? ( require ) \b /xmsgc) {
2773 2         7 $parsed .= "mb::$1";
2774 2         3 $term = 1;
2775             }
2776             elsif (/\G ( CORE::require ) \b /xmsgc) {
2777 1         3 $parsed .= $1;
2778 1         2 $term = 1;
2779             }
2780             elsif (/\G ( (?: CORE:: | mb:: )? (?: chop | chr | getc | index | lc | lcfirst | length | ord | reverse | rindex | substr | uc | ucfirst ) ) \b /xmsgc) {
2781 50         123 $parsed .= $1;
2782 50         62 $term = 1;
2783             }
2784              
2785             # mb::subroutine
2786             elsif (/\G ( mb:: (?: index_byte | rindex_byte ) ) \b /xmsgc) {
2787 2         6 $parsed .= $1;
2788 2         3 $term = 1;
2789             }
2790              
2791             # CORE::function, function
2792             elsif (/\G ( (?: CORE:: )? (?: _ | abs | chomp | cos | exp | fc | hex | int | __LINE__ | log | oct | pop | pos | quotemeta | rand | rmdir | shift | sin | sqrt | tell | time | umask | wantarray ) ) \b /xmsgc) {
2793 261         708 $parsed .= $1;
2794 261         362 $term = 1;
2795             }
2796              
2797             # function --> mb::subroutine on MSWin32
2798             # implements run on any systems by transpiling once
2799             elsif (/\G ( chdir | lstat | opendir | stat | unlink ) \b /xmsgc) {
2800 184         557 $parsed .= "mb::_$1";
2801 184         270 $term = 1;
2802             }
2803              
2804             # any word
2805             # "\x5F" [_] LOW LINE (U+005F)
2806             # "\x41" [A] LATIN CAPITAL LETTER A (U+0041)
2807             # "\x42" [B] LATIN CAPITAL LETTER B (U+0042)
2808             # "\x43" [C] LATIN CAPITAL LETTER C (U+0043)
2809             # "\x44" [D] LATIN CAPITAL LETTER D (U+0044)
2810             # "\x45" [E] LATIN CAPITAL LETTER E (U+0045)
2811             # "\x46" [F] LATIN CAPITAL LETTER F (U+0046)
2812             # "\x47" [G] LATIN CAPITAL LETTER G (U+0047)
2813             # "\x48" [H] LATIN CAPITAL LETTER H (U+0048)
2814             # "\x49" [I] LATIN CAPITAL LETTER I (U+0049)
2815             # "\x4A" [J] LATIN CAPITAL LETTER J (U+004A)
2816             # "\x4B" [K] LATIN CAPITAL LETTER K (U+004B)
2817             # "\x4C" [L] LATIN CAPITAL LETTER L (U+004C)
2818             # "\x4D" [M] LATIN CAPITAL LETTER M (U+004D)
2819             # "\x4E" [N] LATIN CAPITAL LETTER N (U+004E)
2820             # "\x4F" [O] LATIN CAPITAL LETTER O (U+004F)
2821             # "\x50" [P] LATIN CAPITAL LETTER P (U+0050)
2822             # "\x51" [Q] LATIN CAPITAL LETTER Q (U+0051)
2823             # "\x52" [R] LATIN CAPITAL LETTER R (U+0052)
2824             # "\x53" [S] LATIN CAPITAL LETTER S (U+0053)
2825             # "\x54" [T] LATIN CAPITAL LETTER T (U+0054)
2826             # "\x55" [U] LATIN CAPITAL LETTER U (U+0055)
2827             # "\x56" [V] LATIN CAPITAL LETTER V (U+0056)
2828             # "\x57" [W] LATIN CAPITAL LETTER W (U+0057)
2829             # "\x58" [X] LATIN CAPITAL LETTER X (U+0058)
2830             # "\x59" [Y] LATIN CAPITAL LETTER Y (U+0059)
2831             # "\x5A" [Z] LATIN CAPITAL LETTER Z (U+005A)
2832             # "\x61" [a] LATIN SMALL LETTER A (U+0061)
2833             # "\x62" [b] LATIN SMALL LETTER B (U+0062)
2834             # "\x63" [c] LATIN SMALL LETTER C (U+0063)
2835             # "\x64" [d] LATIN SMALL LETTER D (U+0064)
2836             # "\x65" [e] LATIN SMALL LETTER E (U+0065)
2837             # "\x66" [f] LATIN SMALL LETTER F (U+0066)
2838             # "\x67" [g] LATIN SMALL LETTER G (U+0067)
2839             # "\x68" [h] LATIN SMALL LETTER H (U+0068)
2840             # "\x69" [i] LATIN SMALL LETTER I (U+0069)
2841             # "\x6A" [j] LATIN SMALL LETTER J (U+006A)
2842             # "\x6B" [k] LATIN SMALL LETTER K (U+006B)
2843             # "\x6C" [l] LATIN SMALL LETTER L (U+006C)
2844             # "\x6D" [m] LATIN SMALL LETTER M (U+006D)
2845             # "\x6E" [n] LATIN SMALL LETTER N (U+006E)
2846             # "\x6F" [o] LATIN SMALL LETTER O (U+006F)
2847             # "\x70" [p] LATIN SMALL LETTER P (U+0070)
2848             # "\x71" [q] LATIN SMALL LETTER Q (U+0071)
2849             # "\x72" [r] LATIN SMALL LETTER R (U+0072)
2850             # "\x73" [s] LATIN SMALL LETTER S (U+0073)
2851             # "\x74" [t] LATIN SMALL LETTER T (U+0074)
2852             # "\x75" [u] LATIN SMALL LETTER U (U+0075)
2853             # "\x76" [v] LATIN SMALL LETTER V (U+0076)
2854             # "\x77" [w] LATIN SMALL LETTER W (U+0077)
2855             # "\x78" [x] LATIN SMALL LETTER X (U+0078)
2856             # "\x79" [y] LATIN SMALL LETTER Y (U+0079)
2857             # "\x7A" [z] LATIN SMALL LETTER Z (U+007A)
2858             elsif (/\G ( [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
2859 278         781 $parsed .= $1;
2860 278         440 $term = 0;
2861             }
2862              
2863             # any US-ASCII
2864             # "\x3A" [:] COLON (U+003A)
2865             # "\x29" [)] RIGHT PARENTHESIS (U+0029)
2866             # "\x7D" [}] RIGHT CURLY BRACKET (U+007D)
2867             # "\x5D" []] RIGHT SQUARE BRACKET (U+005D)
2868             elsif (/\G ([\x00-\x7F]) /xmsgc) {
2869 8919         22537 $parsed .= $1;
2870 8919         11779 $term = 0;
2871             }
2872              
2873             # otherwise
2874             elsif (/\G (${mb::x}) /xmsgc) {
2875 0         0 die "$0(@{[__LINE__]}): can't parse not US-ASCII '$1'.\n";
  0         0  
2876             }
2877              
2878 38317         128902 return $parsed;
2879             }
2880              
2881             #---------------------------------------------------------------------
2882             # parse expression in balanced blackets
2883             sub parse_expr_balanced {
2884 547     550 0 1301 my($open_bracket) = @_;
2885 547   50     2729 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
2886 547         1388 my $parsed = $open_bracket;
2887 547         729 my $nest_bracket = 1;
2888 547         658 $term = 0;
2889 547         666 while (1) {
2890              
2891             # open bracket
2892 3310 100       14882 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
2893 13         24 $parsed .= $1;
2894 13         15 $term = 0;
2895 13         20 $nest_bracket++;
2896             }
2897              
2898             # close bracket
2899             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
2900 560         1160 $parsed .= $1;
2901 560         745 $term = 1;
2902 560 100       1101 if (--$nest_bracket <= 0) {
2903 547         915 last;
2904             }
2905             }
2906              
2907             # otherwise
2908             else {
2909 2737         7243 $parsed .= parse_expr();
2910             }
2911             }
2912 547         1171 return $parsed;
2913             }
2914              
2915             #---------------------------------------------------------------------
2916             # parse <<'HERE_DOCUMENT' as q-like
2917             sub parse_heredocument_as_q_endswith {
2918 9     12 0 13 my($endswith) = @_;
2919 9         13 my $parsed = '';
2920 9         10 while (1) {
2921 465 100       2136 if (/\G ( $R $endswith ) /xmsgc) {
    50          
2922 9         20 $parsed .= $1;
2923 9         15 last;
2924             }
2925             elsif (/\G (${mb::x}) /xmsgc) {
2926 456         777 $parsed .= $1;
2927             }
2928              
2929             # something wrong happened
2930             else {
2931 0         0 die sprintf(<
2932 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
2933             ------------------------------------------------------------------------------
2934             %s
2935             ------------------------------------------------------------------------------
2936             END
2937             }
2938             }
2939 9         47 return $parsed;
2940             }
2941              
2942             #---------------------------------------------------------------------
2943             # parse <<"HERE_DOCUMENT" as qq-like
2944             sub parse_heredocument_as_qq_endswith {
2945 14     17 0 16 my($endswith) = @_;
2946 14         15 my $parsed = '';
2947 14         14 my $nest_escape = 0;
2948 14         14 while (1) {
2949 14 50       138 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          
2950 14         27 $parsed .= ('>)]}' x $nest_escape);
2951 14         20 $parsed .= $1;
2952 14         18 last;
2953             }
2954              
2955             # \L\u --> \u\L
2956             elsif (/\G \\L \\u /xmsgc) {
2957 0         0 $parsed .= '@{[mb::ucfirst(qq<';
2958 0         0 $parsed .= '@{[mb::lc(qq<';
2959 0         0 $nest_escape++;
2960 0         0 $nest_escape++;
2961             }
2962              
2963             # \U\l --> \l\U
2964             elsif (/\G \\U \\l /xmsgc) {
2965 0         0 $parsed .= '@{[mb::lcfirst(qq<';
2966 0         0 $parsed .= '@{[mb::uc(qq<';
2967 0         0 $nest_escape++;
2968 0         0 $nest_escape++;
2969             }
2970              
2971             # \L
2972             elsif (/\G \\L /xmsgc) {
2973 0         0 $parsed .= '@{[mb::lc(qq<';
2974 0         0 $nest_escape++;
2975             }
2976              
2977             # \U
2978             elsif (/\G \\U /xmsgc) {
2979 0         0 $parsed .= '@{[mb::uc(qq<';
2980 0         0 $nest_escape++;
2981             }
2982              
2983             # \l
2984             elsif (/\G \\l /xmsgc) {
2985 0         0 $parsed .= '@{[mb::lcfirst(qq<';
2986 0         0 $nest_escape++;
2987             }
2988              
2989             # \u
2990             elsif (/\G \\u /xmsgc) {
2991 0         0 $parsed .= '@{[mb::ucfirst(qq<';
2992 0         0 $nest_escape++;
2993             }
2994              
2995             # \Q
2996             elsif (/\G \\Q /xmsgc) {
2997 0         0 $parsed .= '@{[quotemeta(qq<';
2998 0         0 $nest_escape++;
2999             }
3000              
3001             # \E
3002             elsif (/\G \\E /xmsgc) {
3003 0         0 $parsed .= ('>)]}' x $nest_escape);
3004 0         0 $nest_escape = 0;
3005             }
3006              
3007             # \o{...}
3008             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3009 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), '\\');
3010             }
3011              
3012             # \x{...}
3013             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3014 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), '\\');
3015             }
3016              
3017             # \any
3018             elsif (/\G (\\) (${mb::x}) /xmsgc) {
3019 0         0 $parsed .= ($1 . escape_qq($2, '\\'));
3020             }
3021              
3022             # $` --> @{[mb::_PREMATCH()]}
3023             # ${`} --> @{[mb::_PREMATCH()]}
3024             # $PREMATCH --> @{[mb::_PREMATCH()]}
3025             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3026             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3027             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3028 0         0 $parsed .= '@{[mb::_PREMATCH()]}';
3029             }
3030              
3031             # $& --> @{[mb::_MATCH()]}
3032             # ${&} --> @{[mb::_MATCH()]}
3033             # $MATCH --> @{[mb::_MATCH()]}
3034             # ${MATCH} --> @{[mb::_MATCH()]}
3035             # ${^MATCH} --> @{[mb::_MATCH()]}
3036             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3037 0         0 $parsed .= '@{[mb::_MATCH()]}';
3038             }
3039              
3040             # $1 --> @{[mb::_CAPTURE(1)]}
3041             # $2 --> @{[mb::_CAPTURE(2)]}
3042             # $3 --> @{[mb::_CAPTURE(3)]}
3043             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
3044 0         0 $parsed .= "\@{[mb::_CAPTURE($1)]}";
3045             }
3046              
3047             # @{^CAPTURE} --> @{[join $", mb::_CAPTURE()]}
3048             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
3049 0         0 $parsed .= '@{[join $", mb::_CAPTURE()]}';
3050             }
3051              
3052             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3053             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3054             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3055             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
3056 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3057 0         0 $parsed .= "\@{[mb::_CAPTURE($n_th+1)]}";
3058             }
3059              
3060             # @- --> @{[mb::_LAST_MATCH_START()]}
3061             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3062             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3063             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3064             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3065 0         0 $parsed .= '@{[mb::_LAST_MATCH_START()]}';
3066             }
3067              
3068             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3069             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3070             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3071             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3072             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3073 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3074 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3075             }
3076              
3077             # @+ --> @{[mb::_LAST_MATCH_END()]}
3078             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3079             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3080             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3081             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3082 0         0 $parsed .= '@{[mb::_LAST_MATCH_END()]}';
3083             }
3084              
3085             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3086             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3087             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3088             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3089             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3090 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3091 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3092             }
3093              
3094             # any
3095             elsif (/\G (${mb::x}) /xmsgc) {
3096 0         0 $parsed .= escape_qq($1, '\\');
3097             }
3098              
3099             # something wrong happened
3100             else {
3101 0         0 die sprintf(<
3102 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3103             ------------------------------------------------------------------------------
3104             %s
3105             ------------------------------------------------------------------------------
3106             END
3107             }
3108             }
3109 14         42 return $parsed;
3110             }
3111              
3112             #---------------------------------------------------------------------
3113             # parse q{string} in balanced blackets
3114             sub parse_q__like_balanced {
3115 1118     1121 0 2736 my($open_bracket) = @_;
3116 1118   50     5151 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3117 1118         2787 my $parsed = $open_bracket;
3118 1118         1390 my $nest_bracket = 1;
3119 1118         1292 while (1) {
3120 2266 50       14570 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
3121 0         0 $parsed .= $1;
3122 0         0 $nest_bracket++;
3123             }
3124             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3125 1118         2234 $parsed .= $1;
3126 1118 50       2277 if (--$nest_bracket <= 0) {
3127 1118         1820 last;
3128             }
3129             }
3130             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3131 0         0 $parsed .= $1;
3132             }
3133             else {
3134 1148         2240 $parsed .= parse_q__like($close_bracket);
3135             }
3136             }
3137 1118         2322 return $parsed;
3138             }
3139              
3140             #---------------------------------------------------------------------
3141             # parse q/string/ that ends with a character
3142             sub parse_q__like_endswith {
3143 2990     2993 0 6956 my($endswith) = @_;
3144 2990         4439 my $parsed = $endswith;
3145 2990         3509 while (1) {
3146 7811 100       40991 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
3147 2990         5482 $parsed .= $1;
3148 2990         4503 last;
3149             }
3150             elsif (/\G (\\ \Q$endswith\E) /xmsgc) {
3151 0         0 $parsed .= $1;
3152             }
3153             else {
3154 4821         8365 $parsed .= parse_q__like($endswith);
3155             }
3156             }
3157 2990         5475 return $parsed;
3158             }
3159              
3160             #---------------------------------------------------------------------
3161             # parse q/string/ common routine
3162             sub parse_q__like {
3163 5969     5972 0 8829 my($closewith) = @_;
3164 5969 50       26032 if (/\G (\\\\) /xmsgc) {
    50          
3165 0         0 return $1;
3166             }
3167             elsif (/\G (${mb::x}) /xmsgc) {
3168 5969         11281 return escape_q($1, $closewith);
3169             }
3170              
3171             # something wrong happened
3172             else {
3173 0         0 die sprintf(<
3174 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3175             ------------------------------------------------------------------------------
3176             %s
3177             ------------------------------------------------------------------------------
3178             END
3179             }
3180             }
3181              
3182             #---------------------------------------------------------------------
3183             # parse qq{string} in balanced blackets
3184             sub parse_qq_like_balanced {
3185 85     88 0 175 my($open_bracket) = @_;
3186 85   50     401 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3187 85         207 my $parsed_as_q = $open_bracket;
3188 85         101 my $parsed_as_qq = $open_bracket;
3189 85         95 my $nest_bracket = 1;
3190 85         99 my $nest_escape = 0;
3191 85         121 while (1) {
3192 317 50       3035 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3193 0         0 $parsed_as_q .= $1;
3194 0         0 $parsed_as_qq .= $1;
3195 0         0 $nest_bracket++;
3196             }
3197             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3198 85 50       156 if (--$nest_bracket <= 0) {
3199 85         138 $parsed_as_q .= $1;
3200 85         140 $parsed_as_qq .= ('>)]}' x $nest_escape);
3201 85         138 $parsed_as_qq .= $1;
3202 85         149 last;
3203             }
3204             else {
3205 0         0 $parsed_as_q .= $1;
3206 0         0 $parsed_as_qq .= $1;
3207             }
3208             }
3209              
3210             # \L\u --> \u\L
3211             elsif (/\G (\\L \\u) /xmsgc) {
3212 0         0 $parsed_as_q .= $1;
3213 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3214 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3215 0         0 $nest_escape++;
3216 0         0 $nest_escape++;
3217             }
3218              
3219             # \U\l --> \l\U
3220             elsif (/\G (\\U \\l) /xmsgc) {
3221 0         0 $parsed_as_q .= $1;
3222 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3223 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3224 0         0 $nest_escape++;
3225 0         0 $nest_escape++;
3226             }
3227              
3228             # \L
3229             elsif (/\G (\\L) /xmsgc) {
3230 0         0 $parsed_as_q .= $1;
3231 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3232 0         0 $nest_escape++;
3233             }
3234              
3235             # \U
3236             elsif (/\G (\\U) /xmsgc) {
3237 0         0 $parsed_as_q .= $1;
3238 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3239 0         0 $nest_escape++;
3240             }
3241              
3242             # \l
3243             elsif (/\G (\\l) /xmsgc) {
3244 0         0 $parsed_as_q .= $1;
3245 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3246 0         0 $nest_escape++;
3247             }
3248              
3249             # \u
3250             elsif (/\G (\\u) /xmsgc) {
3251 0         0 $parsed_as_q .= $1;
3252 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3253 0         0 $nest_escape++;
3254             }
3255              
3256             # \Q
3257             elsif (/\G (\\Q) /xmsgc) {
3258 0         0 $parsed_as_q .= $1;
3259 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
3260 0         0 $nest_escape++;
3261             }
3262              
3263             # \E
3264             elsif (/\G (\\E) /xmsgc) {
3265 0         0 $parsed_as_q .= $1;
3266 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
3267 0         0 $nest_escape = 0;
3268             }
3269              
3270             else {
3271 232         464 my($as_qq, $as_q) = parse_qq_like($close_bracket);
3272 232         336 $parsed_as_q .= $as_q;
3273 232         328 $parsed_as_qq .= $as_qq;
3274             }
3275             }
3276              
3277             # return qq-like and q-like quotee
3278 85 100       124 if (wantarray) {
3279 67         198 return ($parsed_as_qq, $parsed_as_q);
3280             }
3281             else {
3282 18         35 return $parsed_as_qq;
3283             }
3284             }
3285              
3286             #---------------------------------------------------------------------
3287             # parse qq/string/ that ends with a character
3288             sub parse_qq_like_endswith {
3289 2494     2497 0 5220 my($endswith) = @_;
3290 2494         3463 my $parsed_as_q = $endswith;
3291 2494         3209 my $parsed_as_qq = $endswith;
3292 2494         3116 my $nest_escape = 0;
3293 2494         2887 while (1) {
3294 10253 100       57175 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3295 2494         4478 $parsed_as_q .= $1;
3296 2494         3988 $parsed_as_qq .= ('>)]}' x $nest_escape);
3297 2494 50       5871 $parsed_as_qq .= "\n" if CORE::length($1) >= 2; # here document
3298 2494         3529 $parsed_as_qq .= $1;
3299 2494         3841 last;
3300             }
3301              
3302             # \L\u --> \u\L
3303             elsif (/\G (\\L \\u) /xmsgc) {
3304 0         0 $parsed_as_q .= $1;
3305 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3306 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3307 0         0 $nest_escape++;
3308 0         0 $nest_escape++;
3309             }
3310              
3311             # \U\l --> \l\U
3312             elsif (/\G (\\U \\l) /xmsgc) {
3313 0         0 $parsed_as_q .= $1;
3314 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3315 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3316 0         0 $nest_escape++;
3317 0         0 $nest_escape++;
3318             }
3319              
3320             # \L
3321             elsif (/\G (\\L) /xmsgc) {
3322 0         0 $parsed_as_q .= $1;
3323 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3324 0         0 $nest_escape++;
3325             }
3326              
3327             # \U
3328             elsif (/\G (\\U) /xmsgc) {
3329 0         0 $parsed_as_q .= $1;
3330 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3331 0         0 $nest_escape++;
3332             }
3333              
3334             # \l
3335             elsif (/\G (\\l) /xmsgc) {
3336 0         0 $parsed_as_q .= $1;
3337 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3338 0         0 $nest_escape++;
3339             }
3340              
3341             # \u
3342             elsif (/\G (\\u) /xmsgc) {
3343 0         0 $parsed_as_q .= $1;
3344 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3345 0         0 $nest_escape++;
3346             }
3347              
3348             # \Q
3349             elsif (/\G (\\Q) /xmsgc) {
3350 0         0 $parsed_as_q .= $1;
3351 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
3352 0         0 $nest_escape++;
3353             }
3354              
3355             # \E
3356             elsif (/\G (\\E) /xmsgc) {
3357 0         0 $parsed_as_q .= $1;
3358 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
3359 0         0 $nest_escape = 0;
3360             }
3361              
3362             else {
3363 7759         13112 my($as_qq, $as_q) = parse_qq_like($endswith);
3364 7759         11002 $parsed_as_q .= $as_q;
3365 7759         10395 $parsed_as_qq .= $as_qq;
3366             }
3367             }
3368              
3369             # return qq-like and q-like quotee
3370 2494 100       3828 if (wantarray) {
3371 1642         4510 return ($parsed_as_qq, $parsed_as_q);
3372             }
3373             else {
3374 852         1765 return $parsed_as_qq;
3375             }
3376             }
3377              
3378             #---------------------------------------------------------------------
3379             # parse qq/string/ common routine
3380             sub parse_qq_like {
3381 7991     7994 0 11399 my($closewith) = @_;
3382 7991         9819 my $parsed_as_q = '';
3383 7991         9074 my $parsed_as_qq = '';
3384              
3385             # \o{...}
3386 7991 50       72227 if (/\G ( \\o\{ (.*?) \} ) /xmsgc) {
    50          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3387 0         0 $parsed_as_q .= $1;
3388 0         0 $parsed_as_qq .= escape_to_hex(mb::chr(oct $2), $closewith);
3389             }
3390              
3391             # \x{...}
3392             elsif (/\G ( \\x\{ (.*?) \} ) /xmsgc) {
3393 0         0 $parsed_as_q .= $1;
3394 0         0 $parsed_as_qq .= escape_to_hex(mb::chr(hex $2), $closewith);
3395             }
3396              
3397             # \any
3398             elsif (/\G ( (\\) (${mb::x}) ) /xmsgc) {
3399 188         411 $parsed_as_q .= $1;
3400 188         394 $parsed_as_qq .= ($2 . escape_qq($3, $closewith));
3401             }
3402              
3403             # $` --> @{[mb::_PREMATCH()]}
3404             # ${`} --> @{[mb::_PREMATCH()]}
3405             # $PREMATCH --> @{[mb::_PREMATCH()]}
3406             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3407             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3408             elsif (/\G ( \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3409 2         6 $parsed_as_q .= $1;
3410 2         5 $parsed_as_qq .= '@{[mb::_PREMATCH()]}';
3411             }
3412              
3413             # $& --> @{[mb::_MATCH()]}
3414             # ${&} --> @{[mb::_MATCH()]}
3415             # $MATCH --> @{[mb::_MATCH()]}
3416             # ${MATCH} --> @{[mb::_MATCH()]}
3417             # ${^MATCH} --> @{[mb::_MATCH()]}
3418             elsif (/\G ( \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3419 2         6 $parsed_as_q .= $1;
3420 2         3 $parsed_as_qq .= '@{[mb::_MATCH()]}';
3421             }
3422              
3423             # $1 --> @{[mb::_CAPTURE(1)]}
3424             # $2 --> @{[mb::_CAPTURE(2)]}
3425             # $3 --> @{[mb::_CAPTURE(3)]}
3426             elsif (/\G ( \$ ([1-9][0-9]*) ) /xmsgc) {
3427 23         46 $parsed_as_q .= $1;
3428 23         44 $parsed_as_qq .= "\@{[mb::_CAPTURE($2)]}";
3429             }
3430              
3431             # @{^CAPTURE} --> @{[join $", mb::_CAPTURE()]}
3432             elsif (/\G ( \@\{\^CAPTURE\} ) /xmsgc) {
3433 0         0 $parsed_as_q .= $1;
3434 0         0 $parsed_as_qq .= '@{[join $", mb::_CAPTURE()]}';
3435             }
3436              
3437             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3438             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3439             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3440             elsif (/\G (\$\{\^CAPTURE\}) \s* (\[) /xmsgc) {
3441 0         0 my $indexing = parse_expr_balanced($2);
3442 0         0 $parsed_as_q .= ($1 . $indexing);
3443 0         0 my $n_th = quotee_of($indexing);
3444 0         0 $parsed_as_qq .= "\@{[mb::_CAPTURE($n_th)]}";
3445             }
3446              
3447             # @- --> @{[mb::_LAST_MATCH_START()]}
3448             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3449             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3450             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3451             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3452 0         0 $parsed_as_q .= $&;
3453 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_START()]}';
3454             }
3455              
3456             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3457             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3458             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3459             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3460             elsif (/\G ( \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3461 0         0 my $indexing = parse_expr_balanced($2);
3462 0         0 $parsed_as_q .= ($1 . $indexing);
3463 0         0 my $n_th = quotee_of($indexing);
3464 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3465             }
3466              
3467             # @+ --> @{[mb::_LAST_MATCH_END()]}
3468             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3469             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3470             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3471             elsif (/\G ( \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3472 0         0 $parsed_as_q .= $1;
3473 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_END()]}';
3474             }
3475              
3476             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3477             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3478             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3479             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3480             elsif (/\G ( \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3481 0         0 my $indexing = parse_expr_balanced($2);
3482 0         0 $parsed_as_q .= ($1 . $indexing);
3483 0         0 my $n_th = quotee_of($indexing);
3484 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3485             }
3486              
3487             # any
3488             elsif (/\G (${mb::x}) /xmsgc) {
3489 7776         14214 $parsed_as_q .= escape_q ($1, $closewith);
3490 7776         12994 $parsed_as_qq .= escape_qq($1, $closewith);
3491             }
3492              
3493             # something wrong happened
3494             else {
3495 0         0 die sprintf(<
3496 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3497             ------------------------------------------------------------------------------
3498             %s
3499             ------------------------------------------------------------------------------
3500             END
3501             }
3502              
3503             # return qq-like and q-like quotee
3504 7991 50       13221 if (wantarray) {
3505 7991         18713 return ($parsed_as_qq, $parsed_as_q);
3506             }
3507             else {
3508 0         0 return $parsed_as_qq;
3509             }
3510             }
3511              
3512             #---------------------------------------------------------------------
3513             # parse code point class
3514             sub parse_re_codepoint_class {
3515 912     915 0 1547 my($classmate) = @_;
3516 912         1281 my $parsed = '';
3517 912         1202 my @sbcs = ();
3518 912         1088 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
3519 912         1057 while (1) {
3520 2042 100       18136 if ($classmate =~ /\G \z /xmsgc) {
    50          
    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          
    50          
    50          
    100          
    100          
    100          
    50          
3521 912 50 100     5738 $parsed =
    100 66        
    100 33        
3522             ( @sbcs and @xbcs) ? join('|', @xbcs, '['.join('',@sbcs).']') :
3523             (!@sbcs and @xbcs) ? join('|', @xbcs ) :
3524             ( @sbcs and !@xbcs) ? '['.join('',@sbcs).']' :
3525             die;
3526 912         1584 last;
3527             }
3528             elsif ($classmate =~ /\G (\\ \]) /xmsgc) {
3529 0         0 push @sbcs, $1;
3530             }
3531             elsif ($classmate =~ /\G (\\\\) /xmsgc) {
3532 0         0 push @sbcs, $1;
3533             }
3534              
3535             # classic perl codepoint class shortcuts
3536 34         125 elsif ($classmate =~ /\G \\D /xmsgc) { push @xbcs, "(?:(?![$mb::bare_d])${mb::x})"; }
3537 10         45 elsif ($classmate =~ /\G \\H /xmsgc) { push @xbcs, "(?:(?![$mb::bare_h])${mb::x})"; }
3538             # elsif ($classmate =~ /\G \\N /xmsgc) { push @xbcs, "(?:(?!\\n)${mb::x})"; } # \N in a codepoint class must be a named character: \N{...} in regex
3539             # elsif ($classmate =~ /\G \\R /xmsgc) { push @xbcs, "(?>\\r\\n|[$mb::bare_v])"; } # Unrecognized escape \R in codepoint class passed through in regex
3540 19         74 elsif ($classmate =~ /\G \\S /xmsgc) { push @xbcs, "(?:(?![$mb::bare_s])${mb::x})"; }
3541 16         60 elsif ($classmate =~ /\G \\V /xmsgc) { push @xbcs, "(?:(?![$mb::bare_v])${mb::x})"; }
3542 193         624 elsif ($classmate =~ /\G \\W /xmsgc) { push @xbcs, "(?:(?![$mb::bare_w])${mb::x})"; }
3543 6         16 elsif ($classmate =~ /\G \\b /xmsgc) { push @sbcs, $mb::bare_backspace; }
3544 34         77 elsif ($classmate =~ /\G \\d /xmsgc) { push @sbcs, $mb::bare_d; }
3545 10         38 elsif ($classmate =~ /\G \\h /xmsgc) { push @sbcs, $mb::bare_h; }
3546 19         48 elsif ($classmate =~ /\G \\s /xmsgc) { push @sbcs, $mb::bare_s; }
3547 16         41 elsif ($classmate =~ /\G \\v /xmsgc) { push @sbcs, $mb::bare_v; }
3548 193         416 elsif ($classmate =~ /\G \\w /xmsgc) { push @sbcs, $mb::bare_w; }
3549              
3550             # [:POSIX:]
3551 18         32 elsif ($classmate =~ /\G \[:alnum:\] /xmsgc) { push @sbcs, '\x30-\x39\x41-\x5A\x61-\x7A'; }
3552 2         6 elsif ($classmate =~ /\G \[:alpha:\] /xmsgc) { push @sbcs, '\x41-\x5A\x61-\x7A'; }
3553 2         6 elsif ($classmate =~ /\G \[:ascii:\] /xmsgc) { push @sbcs, '\x00-\x7F'; }
3554 2         5 elsif ($classmate =~ /\G \[:blank:\] /xmsgc) { push @sbcs, '\x09\x20'; }
3555 2         7 elsif ($classmate =~ /\G \[:cntrl:\] /xmsgc) { push @sbcs, '\x00-\x1F\x7F'; }
3556 2         6 elsif ($classmate =~ /\G \[:digit:\] /xmsgc) { push @sbcs, '\x30-\x39'; }
3557 2         7 elsif ($classmate =~ /\G \[:graph:\] /xmsgc) { push @sbcs, '\x21-\x7F'; }
3558 2         60 elsif ($classmate =~ /\G \[:lower:\] /xmsgc) { push @sbcs, 'abcdefghijklmnopqrstuvwxyz'; } # /i modifier requires 'a' to 'z' literally
3559 2         5 elsif ($classmate =~ /\G \[:print:\] /xmsgc) { push @sbcs, '\x20-\x7F'; }
3560 2         5 elsif ($classmate =~ /\G \[:punct:\] /xmsgc) { push @sbcs, '\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E'; }
3561 2         7 elsif ($classmate =~ /\G \[:space:\] /xmsgc) { push @sbcs, '\s\x0B'; } # "\s" and vertical tab ("\cK")
3562 2         5 elsif ($classmate =~ /\G \[:upper:\] /xmsgc) { push @sbcs, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; } # /i modifier requires 'A' to 'Z' literally
3563 2         7 elsif ($classmate =~ /\G \[:word:\] /xmsgc) { push @sbcs, '\x30-\x39\x41-\x5A\x5F\x61-\x7A'; }
3564 2         6 elsif ($classmate =~ /\G \[:xdigit:\] /xmsgc) { push @sbcs, '\x30-\x39\x41-\x46\x61-\x66'; }
3565              
3566             # [:^POSIX:]
3567 2         8 elsif ($classmate =~ /\G \[:\^alnum:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x61-\\x7A])${mb::x})"; }
3568 2         8 elsif ($classmate =~ /\G \[:\^alpha:\] /xmsgc) { push @xbcs, "(?:(?![\\x41-\\x5A\\x61-\\x7A])${mb::x})"; }
3569 2         8 elsif ($classmate =~ /\G \[:\^ascii:\] /xmsgc) { push @xbcs, "(?:(?![\\x00-\\x7F])${mb::x})"; }
3570 2         11 elsif ($classmate =~ /\G \[:\^blank:\] /xmsgc) { push @xbcs, "(?:(?![\\x09\\x20])${mb::x})"; }
3571 2         9 elsif ($classmate =~ /\G \[:\^cntrl:\] /xmsgc) { push @xbcs, "(?:(?![\\x00-\\x1F\\x7F])${mb::x})"; }
3572 2         9 elsif ($classmate =~ /\G \[:\^digit:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39])${mb::x})"; }
3573 2         11 elsif ($classmate =~ /\G \[:\^graph:\] /xmsgc) { push @xbcs, "(?:(?![\\x21-\\x7F])${mb::x})"; }
3574 2         8 elsif ($classmate =~ /\G \[:\^lower:\] /xmsgc) { push @xbcs, "(?:(?![abcdefghijklmnopqrstuvwxyz])${mb::x})"; } # /i modifier requires 'a' to 'z' literally
3575 2         11 elsif ($classmate =~ /\G \[:\^print:\] /xmsgc) { push @xbcs, "(?:(?![\\x20-\\x7F])${mb::x})"; }
3576 2         25 elsif ($classmate =~ /\G \[:\^punct:\] /xmsgc) { push @xbcs, "(?:(?![\\x21-\\x2F\\x3A-\\x3F\\x40\\x5B-\\x5F\\x60\\x7B-\\x7E])${mb::x})"; }
3577 2         12 elsif ($classmate =~ /\G \[:\^space:\] /xmsgc) { push @xbcs, "(?:(?![\\s\\x0B])${mb::x})"; } # "\s" and vertical tab ("\cK")
3578 2         9 elsif ($classmate =~ /\G \[:\^upper:\] /xmsgc) { push @xbcs, "(?:(?![ABCDEFGHIJKLMNOPQRSTUVWXYZ])${mb::x})"; } # /i modifier requires 'A' to 'Z' literally
3579 2         8 elsif ($classmate =~ /\G \[:\^word:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x5F\\x61-\\x7A])${mb::x})"; }
3580 2         9 elsif ($classmate =~ /\G \[:\^xdigit:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x46\\x61-\\x66])${mb::x})"; }
3581              
3582             # \o{...}
3583             elsif ($classmate =~ /\G \\o\{ (.*?) \} /xmsgc) {
3584 0         0 push @xbcs, '(?:' . escape_to_hex(mb::chr(oct $1), ']') . ')';
3585             }
3586              
3587             # \x{...}
3588             elsif ($classmate =~ /\G \\x\{ (.*?) \} /xmsgc) {
3589 0         0 push @xbcs, '(?:' . escape_to_hex(mb::chr(hex $1), ']') . ')';
3590             }
3591              
3592             # \any
3593             elsif ($classmate =~ /\G (\\) (${mb::x}) /xmsgc) {
3594 12 50       42 if (CORE::length($2) == 1) {
3595 12         37 push @sbcs, ($1 . $2);
3596             }
3597             else {
3598 0         0 push @xbcs, '(?:' . $1 . escape_to_hex($2, ']') . ')';
3599             }
3600             }
3601              
3602             # supported character ranges
3603             elsif ($classmate =~ /\G ((?:[\x20-\x7E]|\\[0-3][0-7][0-7]|\\x[0-9A-Fa-f][0-9A-Fa-f])-(?:[\x20-\x7E]|\\[0-3][0-7][0-7]|\\x[0-9A-Fa-f][0-9A-Fa-f])) /xmsgc) {
3604 24         64 push @sbcs, $1;
3605             }
3606              
3607             # other character ranges are no longer supported
3608             # range specification by '-' in codepoint class of regular expression supports US-ASCII only
3609             # this limitation makes it easier to change the script encoding
3610             elsif ($classmate =~ /\G (-) /xmsgc) {
3611 1 50       6 if ($^W) {
3612 0         0 cluck <
3613             [$parsed...] in regular expression
3614              
3615             range specification by '-' in codepoint class of regular expression supports US-ASCII only.
3616             this limitation makes it easier to change the script encoding.
3617             END
3618             }
3619 1         4 push @sbcs, '\\x2D';
3620             }
3621              
3622             # any
3623             elsif ($classmate =~ /\G (${mb::x}) /xmsgc) {
3624 471 100       1071 if (CORE::length($1) == 1) {
3625 127         303 push @sbcs, $1;
3626             }
3627             else {
3628 344         665 push @xbcs, '(?:' . escape_to_hex($1, ']') . ')';
3629             }
3630             }
3631              
3632             # something wrong happened
3633             else {
3634 0         0 die sprintf(<
3635 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3636             ------------------------------------------------------------------------------
3637             %s
3638             ------------------------------------------------------------------------------
3639             END
3640             }
3641             }
3642 912         22842 return $parsed;
3643             }
3644              
3645             #---------------------------------------------------------------------
3646             # parse qr'regexp' as q-like
3647             sub parse_re_as_q_endswith {
3648 936     939 0 2690 my($operator, $endswith) = @_;
3649 936         1583 my $parsed = $endswith;
3650 936         1108 while (1) {
3651 1932 100       11327 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          
3652 936         1630 $parsed .= $1;
3653 936         1468 last;
3654             }
3655              
3656             # get codepoint class
3657             elsif (/\G \[ /xmsgc) {
3658 562         897 my $classmate = '';
3659 562         666 while (1) {
3660 1758 100       6750 if (/\G \] /xmsgc) {
    100          
    100          
    50          
3661 562         872 last;
3662             }
3663             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
3664 28         59 $classmate .= $1;
3665             }
3666             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
3667 44         95 $classmate .= $1;
3668             }
3669             elsif (/\G (${mb::x}) /xmsgc) {
3670 1124         2232 $classmate .= $1;
3671             }
3672              
3673             # something wrong happened
3674             else {
3675 0         0 die sprintf(<
3676 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3677             ------------------------------------------------------------------------------
3678             %s
3679             ------------------------------------------------------------------------------
3680             END
3681             }
3682             }
3683              
3684             # parse codepoint class
3685 562 100       1186 if ($classmate =~ s{\A \^ }{}xms) {
3686 168         243 $parsed .= '(?:(?!';
3687 168         317 $parsed .= parse_re_codepoint_class($classmate);
3688 168         401 $parsed .= ")${mb::x})";
3689             }
3690             else {
3691 394         522 $parsed .= '(?:(?=';
3692 394         776 $parsed .= parse_re_codepoint_class($classmate);
3693 394         1045 $parsed .= ")${mb::x})";
3694             }
3695             }
3696              
3697             # /./ or \any
3698 2         10 elsif (/\G \. /xmsgc) { $parsed .= "(?:${mb::over_ascii}|.)"; } # after ${mb::over_ascii}, /s modifier wants "." (not [\x00-\xFF])
3699 2         19 elsif (/\G \\B /xmsgc) { $parsed .= "(?:(?
3700 12         47 elsif (/\G \\D /xmsgc) { $parsed .= "(?:(?![$mb::bare_d])${mb::x})"; }
3701 4         23 elsif (/\G \\H /xmsgc) { $parsed .= "(?:(?![$mb::bare_h])${mb::x})"; }
3702 2         20 elsif (/\G \\N /xmsgc) { $parsed .= "(?:(?!\\n)${mb::x})"; }
3703 2         11 elsif (/\G \\R /xmsgc) { $parsed .= "(?>\\r\\n|[$mb::bare_v])"; }
3704 7         38 elsif (/\G \\S /xmsgc) { $parsed .= "(?:(?![$mb::bare_s])${mb::x})"; }
3705 6         25 elsif (/\G \\V /xmsgc) { $parsed .= "(?:(?![$mb::bare_v])${mb::x})"; }
3706 65         224 elsif (/\G \\W /xmsgc) { $parsed .= "(?:(?![$mb::bare_w])${mb::x})"; }
3707 2         13 elsif (/\G \\b /xmsgc) { $parsed .= "(?:(?
3708 12         34 elsif (/\G \\d /xmsgc) { $parsed .= "[$mb::bare_d]"; }
3709 4         14 elsif (/\G \\h /xmsgc) { $parsed .= "[$mb::bare_h]"; }
3710 7         21 elsif (/\G \\s /xmsgc) { $parsed .= "[$mb::bare_s]"; }
3711 6         19 elsif (/\G \\v /xmsgc) { $parsed .= "[$mb::bare_v]"; }
3712 65         157 elsif (/\G \\w /xmsgc) { $parsed .= "[$mb::bare_w]"; }
3713              
3714             # \o{...}
3715             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3716 0         0 $parsed .= '(?:';
3717 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $endswith);
3718 0         0 $parsed .= ')';
3719             }
3720              
3721             # \x{...}
3722             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3723 0         0 $parsed .= '(?:';
3724 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $endswith);
3725 0         0 $parsed .= ')';
3726             }
3727              
3728             # \0... octal escape
3729             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
3730 0         0 $parsed .= $1;
3731             }
3732              
3733             # \100...\x377 octal escape
3734             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
3735 0         0 $parsed .= $1;
3736             }
3737              
3738             # \1...\99, ... n-th previously captured string (decimal)
3739             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
3740 0         0 $parsed .= $1;
3741 0 0       0 if ($operator eq 's') {
3742 0         0 $parsed .= ($2 + 1);
3743             }
3744             else {
3745 0         0 $parsed .= $2;
3746             }
3747             }
3748              
3749             # any
3750             elsif (/\G (${mb::x}) /xmsgc) {
3751 236 100       544 if (CORE::length($1) == 1) {
3752 91         179 $parsed .= $1;
3753             }
3754             else {
3755 145         193 $parsed .= '(?:';
3756 145         299 $parsed .= escape_to_hex($1, $endswith);
3757 145         268 $parsed .= ')';
3758             }
3759             }
3760              
3761             # something wrong happened
3762             else {
3763 0         0 die sprintf(<
3764 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3765             ------------------------------------------------------------------------------
3766             %s
3767             ------------------------------------------------------------------------------
3768             END
3769             }
3770             }
3771 936         1756 return $parsed;
3772             }
3773              
3774             #---------------------------------------------------------------------
3775             # parse qr{regexp} in balanced blackets
3776             sub parse_re_balanced {
3777 564     567 0 1542 my($operator, $open_bracket) = @_;
3778 564   50     2728 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3779 564         1268 my $parsed = $open_bracket;
3780 564         757 my $nest_bracket = 1;
3781 564         650 my $nest_escape = 0;
3782 564         621 while (1) {
3783 1133 50       7880 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3784 0         0 $parsed .= $1;
3785 0         0 $nest_bracket++;
3786             }
3787             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3788 564 50       1004 if (--$nest_bracket <= 0) {
3789 564         910 $parsed .= ('>)]}' x $nest_escape);
3790 564         793 $parsed .= $1;
3791 564         952 last;
3792             }
3793             else {
3794 0         0 $parsed .= $1;
3795             }
3796             }
3797              
3798             # \L\u --> \u\L
3799             elsif (/\G \\L \\u /xmsgc) {
3800 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3801 0         0 $parsed .= '@{[mb::lc(qq<';
3802 0         0 $nest_escape++;
3803 0         0 $nest_escape++;
3804             }
3805              
3806             # \U\l --> \l\U
3807             elsif (/\G \\U \\l /xmsgc) {
3808 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3809 0         0 $parsed .= '@{[mb::uc(qq<';
3810 0         0 $nest_escape++;
3811 0         0 $nest_escape++;
3812             }
3813              
3814             # \L
3815             elsif (/\G \\L /xmsgc) {
3816 0         0 $parsed .= '@{[mb::lc(qq<';
3817 0         0 $nest_escape++;
3818             }
3819              
3820             # \U
3821             elsif (/\G \\U /xmsgc) {
3822 0         0 $parsed .= '@{[mb::uc(qq<';
3823 0         0 $nest_escape++;
3824             }
3825              
3826             # \l
3827             elsif (/\G \\l /xmsgc) {
3828 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3829 0         0 $nest_escape++;
3830             }
3831              
3832             # \u
3833             elsif (/\G \\u /xmsgc) {
3834 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3835 0         0 $nest_escape++;
3836             }
3837              
3838             # \Q
3839             elsif (/\G \\Q /xmsgc) {
3840 0         0 $parsed .= '@{[quotemeta(qq<';
3841 0         0 $nest_escape++;
3842             }
3843              
3844             # \E
3845             elsif (/\G \\E /xmsgc) {
3846 0         0 $parsed .= ('>)]}' x $nest_escape);
3847 0         0 $nest_escape = 0;
3848             }
3849              
3850             else {
3851 569         2074 $parsed .= parse_re($operator, $open_bracket);
3852             }
3853             }
3854 564         1103 return $parsed;
3855             }
3856              
3857             #---------------------------------------------------------------------
3858             # parse qr/regexp/ that ends with a character
3859             sub parse_re_endswith {
3860 3142     3145 0 9025 my($operator, $endswith) = @_;
3861 3142         5110 my $parsed = $endswith;
3862 3142         4105 my $nest_escape = 0;
3863 3142         3731 while (1) {
3864 7436 100       39764 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3865 3142         5771 $parsed .= ('>)]}' x $nest_escape);
3866 3142         4873 $parsed .= $1;
3867 3142         5116 last;
3868             }
3869              
3870             # \L\u --> \u\L
3871             elsif (/\G \\L \\u /xmsgc) {
3872 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3873 0         0 $parsed .= '@{[mb::lc(qq<';
3874 0         0 $nest_escape++;
3875 0         0 $nest_escape++;
3876             }
3877              
3878             # \U\l --> \l\U
3879             elsif (/\G \\U \\l /xmsgc) {
3880 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3881 0         0 $parsed .= '@{[mb::uc(qq<';
3882 0         0 $nest_escape++;
3883 0         0 $nest_escape++;
3884             }
3885              
3886             # \L
3887             elsif (/\G \\L /xmsgc) {
3888 0         0 $parsed .= '@{[mb::lc(qq<';
3889 0         0 $nest_escape++;
3890             }
3891              
3892             # \U
3893             elsif (/\G \\U /xmsgc) {
3894 0         0 $parsed .= '@{[mb::uc(qq<';
3895 0         0 $nest_escape++;
3896             }
3897              
3898             # \l
3899             elsif (/\G \\l /xmsgc) {
3900 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3901 0         0 $nest_escape++;
3902             }
3903              
3904             # \u
3905             elsif (/\G \\u /xmsgc) {
3906 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3907 0         0 $nest_escape++;
3908             }
3909              
3910             # \Q
3911             elsif (/\G \\Q /xmsgc) {
3912 0         0 $parsed .= '@{[quotemeta(qq<';
3913 0         0 $nest_escape++;
3914             }
3915              
3916             # \E
3917             elsif (/\G \\E /xmsgc) {
3918 0         0 $parsed .= ('>)]}' x $nest_escape);
3919 0         0 $nest_escape = 0;
3920             }
3921              
3922             else {
3923 4294         8280 $parsed .= parse_re($operator, $endswith);
3924             }
3925             }
3926 3142         6371 return $parsed;
3927             }
3928              
3929             #---------------------------------------------------------------------
3930             # parse qr/regexp/ common routine
3931             sub parse_re {
3932 4863     4866 0 7750 my($operator, $closewith) = @_;
3933 4863         6184 my $parsed = '';
3934              
3935             # codepoint class
3936 4863 100       53145 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          
    50          
3937 1484         2187 my $classmate = '';
3938 1484         1893 while (1) {
3939 4398 100       18533 if (/\G \] /xmsgc) {
    100          
    100          
    100          
    50          
3940 1484         2268 last;
3941             }
3942             elsif (/\G (\\) /xmsgc) {
3943 510         1021 $classmate .= "\\$1";
3944             }
3945             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
3946 84         175 $classmate .= $1;
3947             }
3948             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
3949 100         212 $classmate .= $1;
3950             }
3951             elsif (/\G (${mb::x}) /xmsgc) {
3952 2220         4594 $classmate .= escape_qq($1, ']');
3953             }
3954              
3955             # something wrong happened
3956             else {
3957 0         0 die sprintf(<
3958 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3959             ------------------------------------------------------------------------------
3960             %s
3961             ------------------------------------------------------------------------------
3962             END
3963             }
3964             }
3965 1484         3198 $parsed .= "\@{[mb::_cc(qq[$classmate])]}";
3966             }
3967              
3968             # /./ or \any
3969 20         51 elsif (/\G \. /xmsgc) { $parsed .= '(?:@{[@mb::_dot]})'; }
3970 7         22 elsif (/\G \\B /xmsgc) { $parsed .= '(?:@{[@mb::_B]})'; }
3971 18         41 elsif (/\G \\D /xmsgc) { $parsed .= '(?:@{[@mb::_D]})'; }
3972 10         25 elsif (/\G \\H /xmsgc) { $parsed .= '(?:@{[@mb::_H]})'; }
3973 8         20 elsif (/\G \\N /xmsgc) { $parsed .= '(?:@{[@mb::_N]})'; }
3974 12         27 elsif (/\G \\R /xmsgc) { $parsed .= '(?:@{[@mb::_R]})'; }
3975 14         31 elsif (/\G \\S /xmsgc) { $parsed .= '(?:@{[@mb::_S]})'; }
3976 12         29 elsif (/\G \\V /xmsgc) { $parsed .= '(?:@{[@mb::_V]})'; }
3977 71         139 elsif (/\G \\W /xmsgc) { $parsed .= '(?:@{[@mb::_W]})'; }
3978 7         17 elsif (/\G \\b /xmsgc) { $parsed .= '(?:@{[@mb::_b]})'; }
3979 17         90 elsif (/\G \\d /xmsgc) { $parsed .= '(?:@{[@mb::_d]})'; }
3980 10         27 elsif (/\G \\h /xmsgc) { $parsed .= '(?:@{[@mb::_h]})'; }
3981 18         44 elsif (/\G \\s /xmsgc) { $parsed .= '(?:@{[@mb::_s]})'; }
3982 14         34 elsif (/\G \\v /xmsgc) { $parsed .= '(?:@{[@mb::_v]})'; }
3983 70         145 elsif (/\G \\w /xmsgc) { $parsed .= '(?:@{[@mb::_w]})'; }
3984              
3985             # \o{...}
3986             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3987 0         0 $parsed .= '(?:';
3988 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $closewith);
3989 0         0 $parsed .= ')';
3990             }
3991              
3992             # \x{...}
3993             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3994 0         0 $parsed .= '(?:';
3995 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $closewith);
3996 0         0 $parsed .= ')';
3997             }
3998              
3999             # \0... octal escape
4000             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
4001 0         0 $parsed .= $1;
4002             }
4003              
4004             # \100...\x377 octal escape
4005             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
4006 0         0 $parsed .= $1;
4007             }
4008              
4009             # \1...\99, ... n-th previously captured string (decimal)
4010             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
4011 24         39 $parsed .= $1;
4012 24 50       36 if ($operator eq 's') {
4013 0         0 $parsed .= ($2 + 1);
4014             }
4015             else {
4016 24         35 $parsed .= $2;
4017             }
4018             }
4019              
4020             # \any
4021             elsif (/\G (\\) (${mb::x}) /xmsgc) {
4022 5 50       17 if (CORE::length($2) == 1) {
4023 5         11 $parsed .= ($1 . $2);
4024             }
4025             else {
4026 0         0 $parsed .= ('(?:' . $1 . escape_qq($2, $closewith) . ')');
4027             }
4028             }
4029              
4030             # $` --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4031             # ${`} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4032             # $PREMATCH --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4033             # ${PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4034             # ${^PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4035             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
4036 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_PREMATCH())]}';
4037             }
4038              
4039             # $& --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4040             # ${&} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4041             # $MATCH --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4042             # ${MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4043             # ${^MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4044             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
4045 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_MATCH())]}';
4046             }
4047              
4048             # $1 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
4049             # $2 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
4050             # $3 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
4051             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
4052 24         51 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($1))]}";
4053             }
4054              
4055             # @{^CAPTURE} --> @{[mb::_clustered_codepoint(join $", mb::_CAPTURE())]}
4056             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
4057 0         0 $parsed .= '@{[mb::_clustered_codepoint(join $", mb::_CAPTURE())]}';
4058             }
4059              
4060             # ${^CAPTURE}[0] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
4061             # ${^CAPTURE}[1] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
4062             # ${^CAPTURE}[2] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
4063             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
4064 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
4065 0         0 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($n_th+1))]}";
4066             }
4067              
4068             # @- --> @{[join $", mb::_LAST_MATCH_START()]}
4069             # @LAST_MATCH_START --> @{[join $", mb::_LAST_MATCH_START()]}
4070             # @{LAST_MATCH_START} --> @{[join $", mb::_LAST_MATCH_START()]}
4071             # @{^LAST_MATCH_START} --> @{[join $", mb::_LAST_MATCH_START()]}
4072             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
4073 0         0 $parsed .= '@{[join $", mb::_LAST_MATCH_START()]}';
4074             }
4075              
4076             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
4077             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
4078             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
4079             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
4080             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
4081 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
4082 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
4083             }
4084              
4085             # @+ --> @{[join $", mb::_LAST_MATCH_END()]}
4086             # @LAST_MATCH_END --> @{[join $", mb::_LAST_MATCH_END()]}
4087             # @{LAST_MATCH_END} --> @{[join $", mb::_LAST_MATCH_END()]}
4088             # @{^LAST_MATCH_END} --> @{[join $", mb::_LAST_MATCH_END()]}
4089             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
4090 0         0 $parsed .= '@{[join $", mb::_LAST_MATCH_END()]}';
4091             }
4092              
4093             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
4094             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
4095             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
4096             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
4097             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
4098 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
4099 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
4100             }
4101              
4102             # any
4103             elsif (/\G (${mb::x}) /xmsgc) {
4104 3018 100       6436 if (CORE::length($1) == 1) {
4105 2457         3610 $parsed .= $1;
4106             }
4107             else {
4108 561         1169 $parsed .= ('(?:' . escape_qq($1, $closewith) . ')');
4109             }
4110             }
4111              
4112             # something wrong happened
4113             else {
4114 0         0 die sprintf(<
4115 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4116             ------------------------------------------------------------------------------
4117             %s
4118             ------------------------------------------------------------------------------
4119             END
4120             }
4121 4863         11075 return $parsed;
4122             }
4123              
4124             #---------------------------------------------------------------------
4125             # parse modifiers of qr///here
4126             sub parse_re_modifier {
4127 4642     4645 0 6358 my $modifier_i = '';
4128 4642         5715 my $modifier_not_cegir = '';
4129 4642         5796 my $modifier_cegr = '';
4130 4642         5458 while (1) {
4131 4832 50       18108 if (/\G [adlpu] /xmsgc) {
    100          
    100          
    100          
4132             # drop modifiers
4133             }
4134             elsif (/\G ([i]) /xmsgc) {
4135 76         146 $modifier_i .= $1;
4136             }
4137             elsif (/\G ([cegr]) /xmsgc) {
4138 35         79 $modifier_cegr .= $1;
4139             }
4140             elsif (/\G ([a-z]) /xmsgc) {
4141 79         127 $modifier_not_cegir .= $1;
4142             }
4143             else {
4144 4642         6041 last;
4145             }
4146             }
4147 4642         11033 return ($modifier_i, $modifier_not_cegir, $modifier_cegr);
4148             }
4149              
4150             #---------------------------------------------------------------------
4151             # parse modifiers of tr///here
4152             sub parse_tr_modifier {
4153 1250     1253 0 1737 my $modifier_not_r = '';
4154 1250         1555 my $modifier_r = '';
4155 1250         1440 while (1) {
4156 1314 50       3600 if (/\G ([r]) /xmsgc) {
    100          
4157 0         0 $modifier_r .= $1;
4158             }
4159             elsif (/\G ([a-z]) /xmsgc) {
4160 64         107 $modifier_not_r .= $1;
4161             }
4162             else {
4163 1250         1614 last;
4164             }
4165             }
4166 1250         2748 return ($modifier_not_r, $modifier_r);
4167             }
4168              
4169             #---------------------------------------------------------------------
4170             # makes code point class from string
4171             sub codepoint_tr {
4172 1230     1233 0 5039 my($searchlist) = $_[0] =~ /\A [\x00-\xFF] (.*) [\x00-\xFF] \z/xms;
4173 1230 100       2543 my $look_ahead = ($_[1] =~ /c/) ? '(?:(?!' : '(?:(?=';
4174 1230         1520 my $charclass = '';
4175 1230         1719 my @sbcs = ();
4176 1230         1512 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
4177 1230         1466 while (1) {
4178 2472 100       10680 if ($searchlist =~ /\G \z /xmsgc) {
    50          
    50          
4179 1230 50 100     9248 $charclass =
    100 66        
    100 33        
4180             ( @sbcs and @xbcs) ? $look_ahead . join('|', @xbcs, '['.join('',@sbcs).']') . ")${mb::x})" :
4181             (!@sbcs and @xbcs) ? $look_ahead . join('|', @xbcs ) . ")${mb::x})" :
4182             ( @sbcs and !@xbcs) ? $look_ahead . '['.join('',@sbcs).']' . ")${mb::x})" :
4183             die;
4184 1230         2153 last;
4185             }
4186              
4187             # range specification by '-' in tr/// is not supported
4188             # this limitation makes it easier to change the script encoding
4189             elsif ($searchlist =~ /\G (-) /xmsgc) {
4190 0 0       0 if ($^W) {
4191 0         0 cluck <
4192             "$searchlist" in tr///
4193              
4194             range specification by '-' in tr/// is not supported.
4195             this limitation makes it easier to change the script encoding.
4196             END
4197             }
4198 0         0 push @sbcs, '\\x2D';
4199             }
4200              
4201             # any
4202             elsif ($searchlist =~ /\G (${mb::x}) /xmsgc) {
4203 1242 100       2993 if (CORE::length($1) == 1) {
4204 1104         2590 push @sbcs, $1;
4205             }
4206             else {
4207 138         276 push @xbcs, '(?:' . escape_to_hex($1, ']') . ')';
4208             }
4209             }
4210              
4211             # something wrong happened
4212             else {
4213 0         0 die sprintf(<
4214 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4215             ------------------------------------------------------------------------------
4216             %s
4217             ------------------------------------------------------------------------------
4218             END
4219             }
4220             }
4221 1230         5990 return $charclass;
4222             }
4223              
4224             #---------------------------------------------------------------------
4225             # get quotee from quoted "quotee"
4226             sub quotee_of {
4227 1135 50   1138 0 2312 if (CORE::length($_[0]) >= 2) {
4228 1135         3137 return CORE::substr($_[0],1,-1);
4229             }
4230             else {
4231 0         0 die;
4232             }
4233             }
4234              
4235             #---------------------------------------------------------------------
4236             # escape q/string/ as q-like quote
4237             sub escape_q {
4238 13745     13748 0 25770 my($codepoint, $endswith) = @_;
4239 13745 50       91213 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
4240 0         0 return "$1\\$2";
4241             }
4242             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ($escapee_in_q__like) \z/xms) {
4243 102         379 return "$1\\$2";
4244             }
4245             else {
4246 13643         36929 return $codepoint;
4247             }
4248             }
4249              
4250             #---------------------------------------------------------------------
4251             # escape qq/string/ as qq-like quote
4252             sub escape_qq {
4253 10820     10823 0 19476 my($codepoint, $endswith) = @_;
4254              
4255             # m@`@ --> m`\x60`
4256             # qr@`@ --> qr`\x60`
4257             # s@`@``@ --> s`\x60`\x60\x60`
4258             # m:`: --> m`\x60`
4259             # qr:`: --> qr`\x60`
4260             # s:`:``: --> s`\x60`\x60\x60`
4261 10820 50       71593 if ($codepoint eq '`') {
    100          
    100          
4262 0         0 return '\\x60';
4263             }
4264             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
4265 38         139 return "$1\\$2";
4266             }
4267             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
4268 419         1724 return "$1\\$2";
4269             }
4270             else {
4271 10363         25673 return $codepoint;
4272             }
4273             }
4274              
4275             #---------------------------------------------------------------------
4276             # escape qq/string/ or qr/regexp/ to hex
4277             sub escape_to_hex {
4278 627     630 0 1266 my($codepoint, $endswith) = @_;
4279 627 100       3912 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
4280 30         165 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
4281             }
4282              
4283             # in qr'...', $escapee_in_qq_like is right, not $escapee_in_q__like
4284             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
4285 108         713 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
4286             }
4287             else {
4288 489         1809 return $codepoint;
4289             }
4290             }
4291              
4292             #---------------------------------------------------------------------
4293              
4294             1;
4295              
4296             __END__