File Coverage

lib/mb.pm
Criterion Covered Total %
statement 1311 1726 75.9
branch 1090 1616 67.4
condition 97 220 44.0
subroutine 107 107 100.0
pod 6 48 12.5
total 2611 3717 70.2


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