File Coverage

lib/mb.pm
Criterion Covered Total %
statement 1519 1967 77.2
branch 1266 1692 74.8
condition 97 190 51.0
subroutine 118 127 92.9
pod 2 65 3.0
total 3002 4041 74.2


line stmt bran cond sub pod time code
1             package mb;
2             '有朋自遠方来不亦楽乎'=~/^\xE6\x9C\x89/ or die "Perl script '@{[__FILE__]}' must be UTF-8 encoding.\n";
3             # You are welcome! MOJIBAKE-san, you are our friend forever!!
4             ######################################################################
5             #
6             # mb - Can easy script in Big5, Big5-HKSCS, GBK, Sjis(also CP932), UHC, UTF-8, ...
7             #
8             # https://metacpan.org/release/mb
9             #
10             # Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2026 INABA Hitoshi in a CPAN
11             ######################################################################
12              
13 113     113   1423387 use 5.00503; # Universal Consensus 1998 for primetools
  113         456  
14             # use 5.008001; # Lancaster Consensus 2013 for toolchains
15              
16             $VERSION = '0.62';
17             $VERSION = $VERSION;
18              
19             # internal use
20             $mb::last_s_passed = 0; # last s/// status (1 if s/// passed)
21              
22             # filehandle sequence counter for _open_a/_open_r/_open_w
23             $mb::_fh_seq = 0;
24              
25 113 100   113   4075 BEGIN { pop @INC if $INC[-1] eq '.' } # CVE-2016-1238: Important unsafe module load path flaw
26 113     109   1189 use strict;
  113         408  
  113         9327  
27 109 50 33 109   3384 BEGIN { if ($] < 5.006 && !defined(&warnings::import)) { $INC{'warnings.pm'} = 'stub'; eval 'package warnings; sub import {}' } } use warnings; local $^W=1;
  4     108   5  
  4         115  
  109         1015  
  109         206  
  109         76251  
28              
29             # set OSNAME
30             my $OSNAME = $^O;
31              
32             # encoding name of operating system
33             my $system_encoding = undef;
34              
35             # encoding name of MBCS script
36             my $script_encoding = undef;
37              
38             # over US-ASCII
39             my $over_ascii = undef;
40              
41             # supports qr/./ in MBCS script
42             my $x = undef;
43              
44             # supports [\b] \d \h \s \v \w in MBCS script
45             my $bare_backspace = '\x08';
46             my $bare_d = '0123456789';
47             my $bare_h = '\x09\x20';
48             my $bare_s = '\t\n\f\r\x20';
49             my $bare_v = '\x0A\x0B\x0C\x0D';
50             my $bare_w = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';
51              
52             # as many escapes as possible to avoid perl's feature
53             my $escapee_in_qq_like = join('', map {"\\$_"} grep( ! /[A-Za-z0-9_]/, map { CORE::chr } 0x21..0x7E));
54              
55             # as less escapes as possible to avoid over-escaping
56             my $escapee_in_q__like = '\\' . "\x5C";
57              
58             # generic linebreak
59             my $R = '(?>\\r\\n|\\r|\\n)';
60              
61             # check running perl interpreter
62             if ($^X =~ /jperl/i) {
63             die "script '@{[__FILE__]}' can run on only perl, not JPerl\n";
64             }
65              
66             # this file is used as command on command line
67             if ($0 eq __FILE__) {
68             main();
69             }
70              
71             ######################################################################
72             # main program
73             ######################################################################
74              
75             #---------------------------------------------------------------------
76             # running as module, runtime routines
77             sub import {
78 106     106   3410 my $self = shift @_;
79              
80             # confirm version
81 106 50 66     9081 if (defined($_[0]) and ($_[0] =~ /\A [0-9] /xms)) {
82 3 0       19 if ($_[0] ne $mb::VERSION) {
83 3         6 my($package, $filename, $line) = caller;
84 3         159 die "$filename requires @{[__PACKAGE__]} $_[0], however @{[__FILE__]} am only $mb::VERSION, stopped at $filename line $line.\n";
  3         18  
  3         7  
85             }
86 3         102 shift @_;
87             }
88              
89             # set system encoding
90 106         673 $system_encoding = detect_system_encoding();
91              
92             # set script encoding
93 106 100       364 if (defined $_[0]) {
94 13         112 my $encoding = $_[0];
95 13 50       97 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
96 13         44 mb::set_script_encoding($encoding);
97             }
98             else {
99 3         96 die "@{[__FILE__]} script_encoding '$encoding' not supported.\n";
  3         16  
100             }
101             }
102             else {
103 96         366 mb::set_script_encoding($system_encoding);
104             }
105              
106             # tie my %mb, __PACKAGE__; # makes: Parentheses missing around "my" list
107 108     108   941 no strict qw(refs);
  108         218  
  108         89359  
108 106         751 tie my %mb, 'mb';
109 106         547 *{caller().'::mb'} = { %mb };
  106         834  
110              
111             # $^X($EXECUTABLE_NAME) for execute MBCS Perl script
112 106         484 $mb::PERL = qq{$^X @{[__FILE__]}};
  106         506  
113 106         268 $mb::PERL = $mb::PERL; # to avoid: Name "mb::PERL" used only once: possible typo at ...
114              
115             # original $0($PROGRAM_NAME) before transpile
116 106         539 ($mb::ORIG_PROGRAM_NAME = $0) =~ s/\.oo(\.[^.]+)\z/$1/;
117 106         223 $mb::ORIG_PROGRAM_NAME = $mb::ORIG_PROGRAM_NAME; # to avoid: Name "mb::ORIG_PROGRAM_NAME" used only once: possible typo at ...
118              
119             # Sjis software compatible subroutines
120 106         407 my $old_package = mb::get_old_package();
121 106         493 for my $subroutine (qw( chop chr do dosglob eval getc index index_byte length ord require reverse rindex rindex_byte substr tr )) {
122 1651         2163 *{$old_package . $subroutine} = \&{"mb::$subroutine"};
  1651         20662  
  1651         3908  
123             }
124             }
125              
126             #---------------------------------------------------------------------
127             # running as command
128             sub main {
129              
130             # usage
131 3 0   3 0 17 if (scalar(@ARGV) == 0) {
132 3         5 die <
133             usage:
134              
135             perl mb.pm script_by_mbcs.pl (auto detect)
136             perl mb.pm -e big5 script_by_big5.pl
137             perl mb.pm -e big5hkscs script_by_big5hkscs.pl
138             perl mb.pm -e eucjp script_by_eucjp.pl
139             perl mb.pm -e gb18030 script_by_gb18030.pl
140             perl mb.pm -e gbk script_by_gbk.pl
141             perl mb.pm -e rfc2279 script_by_rfc2279.pl
142             perl mb.pm -e sjis script_by_sjis.pl
143             perl mb.pm -e sjis script_by_cp932.pl
144             perl mb.pm -e uhc script_by_uhc.pl
145             perl mb.pm -e utf8 script_by_utf8.pl
146             perl mb.pm -e wtf8 script_by_wtf8.pl
147              
148             perl mb.pm script.pl ??-DOS-like *wildcard* available
149              
150             END
151             }
152              
153             # set system encoding
154 3         91 $system_encoding = detect_system_encoding();
155              
156             # set script encoding from command line
157 3         17 my $encoding = '';
158 3 0       6 if (($encoding) = $ARGV[0] =~ /\A -e ( .+ ) \z/xms) {
    0          
159 3 0       84 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
160 3         16 mb::set_script_encoding($encoding);
161 3         4 shift @ARGV;
162             }
163             else {
164 3         86 die "script_encoding '$encoding' not supported.\n";
165             }
166             }
167             elsif ($ARGV[0] =~ /\A -e \z/xms) {
168 3         18 $encoding = $ARGV[1];
169 3 0       43 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
170 3         96 mb::set_script_encoding($encoding);
171 3         15 shift @ARGV;
172 3         6 shift @ARGV;
173             }
174             else {
175 3         84 die "script_encoding '$encoding' not supported.\n";
176             }
177             }
178             else {
179 3         18 mb::set_script_encoding($system_encoding);
180             }
181              
182             # poor "make"
183 3         4 (my $script_oo = $ARGV[0]) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
184 3 0 0     90 if (
      0        
185             (not -e $script_oo) or
186             (mtime($script_oo) <= mtime($ARGV[0])) or
187             (mtime($script_oo) <= mtime(__FILE__))
188             ) {
189              
190             # read application script
191 3 0       16 my $fh = mb::_open_r($ARGV[0]) or die "$0(@{[__LINE__]}): can't open file: $ARGV[0]\n";
  3         5  
192              
193             # sysread(...) has hidden binmode($fh) that's not portable
194             # local $_; sysread($fh, $_, -s $ARGV[0]);
195 108     108   919 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  108         227  
  108         6545  
  3         86  
  3         18  
  3         4  
  3         105  
196 108     108   590 { no strict 'refs'; close($fh) }
  108         204  
  108         18957  
  3         19  
  3         5  
197              
198             # poor file locking
199 3     3   90 local $SIG{__DIE__} = sub { rmdir "$ARGV[0].lock"; };
  3         20  
200 3 0       5 if (mkdir "$ARGV[0].lock", 0755) {
201 3 0       112 my $fh = mb::_open_w($script_oo) or die "$0(@{[__LINE__]}): can't open file: $script_oo\n";
  3         17  
202 108     108   742 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  108         505  
  108         19013  
  3         96  
  3         16  
  3         5  
203 108     108   687 { no strict 'refs'; close($fh) }
  108         208  
  108         178768  
  3         5  
  3         166  
  3         18  
204 3         6 rmdir "$ARGV[0].lock";
205             }
206             else {
207 3         91 die "$0(@{[__LINE__]}): can't mkdir: $ARGV[0].lock\n";
  3         16  
208             }
209             }
210              
211             # run octet-oriented script
212 3         6 my $module_path = '';
213 3         133 my $module_name = '';
214 3         16 my $quote = '';
215 3 0       6 if ($OSNAME =~ /MSWin32/) {
216 3 0       100 if ($0 =~ m{ ([^\/\\]+)\.pm \z}xmsi) {
217 3         16 ($module_path, $module_name) = ($`, $1);
218 3   0     5 $module_path ||= '.';
219 3         105 $module_path =~ s{ [\/\\] \z}{}xms;
220             }
221             else {
222 3         15 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         5  
223             }
224 3         84 $quote = q{"};
225             }
226             else {
227 3 0       16 if ($0 =~ m{ ([^\/]+)\.pm \z}xmsi) {
228 3         6 ($module_path, $module_name) = ($`, $1);
229 3   0     82 $module_path ||= '.';
230 3         16 $module_path =~ s{ / \z}{}xms;
231             }
232             else {
233 3         23 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         114  
234             }
235 3         17 $quote = q{'};
236             }
237              
238             # @ARGV wildcard globbing
239 3 0       6 if ($OSNAME =~ /MSWin32/) {
240 3         84 my @argv = ();
241 3         16 for (@ARGV) {
242              
243             # has space
244 3 0       7 if (/\A (?:$x)*? [ ] /xms) {
    0          
245 3 0       104 if (my @glob = mb::dosglob(qq{"$_"})) {
246 3         15 push @argv, @glob;
247             }
248             else {
249 3         7 push @argv, $_;
250             }
251             }
252              
253             # has wildcard metachar
254             elsif (/\A (?:$x)*? [*?] /xms) {
255 3 0       86 if (my @glob = mb::dosglob($_)) {
256 3         16 push @argv, @glob;
257             }
258             else {
259 3         5 push @argv, $_;
260             }
261             }
262              
263             # no wildcard globbing
264             else {
265 3         81 push @argv, $_;
266             }
267             }
268 3         17 @ARGV = @argv;
269             }
270              
271             # run octet-oriented script
272 3         7 $| = 1;
273 3 0       115 system($^X, "-I$module_path", "-M$module_name=$mb::VERSION,$script_encoding", map { / / ? "$quote$_$quote" : $_ } $script_oo, @ARGV[1..$#ARGV]);
  3         17  
274 3         5 exit($? >> 8);
275             }
276              
277             #---------------------------------------------------------------------
278             # cluck() for MBCS encoding
279             sub cluck {
280 3     3 0 86 my $i = 0;
281 3         18 my @cluck = ();
282 3         6 while (my($package, $filename, $line, $subroutine) = caller($i)) {
283 3         88 push @cluck, "[$i] $filename($line) $subroutine\n";
284 3         16 $i++;
285             }
286 3         6 print STDERR "\n", @_, "\n";
287 3         84 print STDERR CORE::reverse @cluck;
288             }
289              
290             #---------------------------------------------------------------------
291             # confess() for MBCS encoding
292             sub confess {
293 3     3 0 15 my $i = 0;
294 3         6 my @confess = ();
295 3         120 while (my($package, $filename, $line, $subroutine) = caller($i)) {
296 3         20 push @confess, "[$i] $filename($line) $subroutine\n";
297 3         6 $i++;
298             }
299 3         91 print STDERR "\n", @_, "\n";
300 3         16 print STDERR CORE::reverse @confess;
301 3         5 die;
302             }
303              
304             #---------------------------------------------------------------------
305             # short cut of (stat(file))[9]
306             sub mtime {
307 3     3 0 110 my($file) = @_;
308 3         18 return ((stat $file)[9]);
309             }
310              
311             ######################################################################
312             # subroutines for MBCS application programmers
313             ######################################################################
314              
315             #---------------------------------------------------------------------
316             # chop() for MBCS encoding
317             sub mb::chop (@) {
318 21     21 0 742 my $chop = '';
319 21 100       167 for (@_ ? @_ : $_) {
320 29 100       262 if (my @x = /\G$x/g) {
321 23         41 $chop = pop @x;
322 23         148 $_ = join '', @x;
323             }
324             }
325 21         56 return $chop;
326             }
327              
328             #---------------------------------------------------------------------
329             # chr() for MBCS encoding
330             sub mb::chr (;$) {
331 30 100   30 0 514 my $number = @_ ? $_[0] : $_;
332              
333             # Negative values give the Unicode replacement character (chr(0xfffd)),
334             # except under the bytes pragma, where the low eight bits of the value
335             # (truncated to an integer) are used.
336              
337 30         144 my @octet = ();
338 30         44 CORE::do {
339 34         96 unshift @octet, ($number % 0x100);
340 34         217 $number = int($number / 0x100);
341             } while ($number > 0);
342 30         155 return pack 'C*', @octet;
343             }
344              
345             #---------------------------------------------------------------------
346             # do FILE for MBCS encoding
347             sub mb::do ($) {
348 8     8 0 1766 my($file) = @_;
349 8         99 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  43         97  
350 8 50       139 if (-f $prefix_file) {
351              
352             # poor "make"
353 8         154 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
354 8 0 33     287 if (
      33        
355             (not -e $prefix_file_oo) or
356             (mtime($prefix_file_oo) <= mtime($prefix_file)) or
357             (mtime($prefix_file_oo) <= mtime(__FILE__))
358             ) {
359 8 50       46 my $fh = mb::_open_r($prefix_file) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file\n";
  3         93  
360 108     108   1004 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  108         230  
  108         7936  
  8         25  
  8         88  
  8         98  
  8         204  
361 108     108   682 { no strict 'refs'; close($fh) }
  108         175  
  108         15477  
  8         17  
  8         151  
362              
363             # poor file locking
364 8     3   99 local $SIG{__DIE__} = sub { rmdir "$prefix_file.lock"; };
  3         7  
365 8 50       812 if (mkdir "$prefix_file.lock", 0755) {
366 8 50       40 my $fh = mb::_open_w($prefix_file_oo) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file_oo\n";
  3         5  
367 108     108   741 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  108         205  
  108         6930  
  8         22  
  8         10  
  8         132  
368 108     108   594 { no strict 'refs'; close($fh) }
  108         222  
  108         261205  
  8         95  
  8         25  
  8         250  
369 8         500 rmdir "$prefix_file.lock";
370             }
371             else {
372 3         17 confess "$0(@{[__LINE__]}): can't mkdir: $prefix_file.lock\n";
  3         6  
373             }
374             }
375 8         117 $INC{$file} = $prefix_file_oo;
376              
377             # run as Perl script
378             # must use CORE::do to use , because CORE::eval cannot do it
379             # moreover "goto &CORE::do" doesn't work
380 8         297 return CORE::eval sprintf(<<'END', (caller)[0,2,1]);
381             package %s;
382             #line %s "%s"
383             CORE::do "$prefix_file_oo";
384             END
385             }
386             }
387 3         6 confess "Can't find $file in \@INC";
388             }
389              
390             #---------------------------------------------------------------------
391             # DOS-like glob() for MBCS encoding
392             sub mb::dosglob (;$) {
393 11 50   11 0 1234 my $expr = @_ ? $_[0] : $_;
394 11         33 my @glob = ();
395              
396             # works on not MSWin32
397 11 50       49 if ($OSNAME !~ /MSWin32/) {
398 11         3459 @glob = CORE::glob($expr);
399             }
400              
401             # works on MSWin32
402             else {
403              
404             # gets pattern
405 3         17 while ($expr =~ s{\A [\x20]* ( "(?:$x)+?" | (?:(?!["\x20])$x)+ ) }{}xms) {
406 3         5 my $pattern = $1;
407              
408             # avoids command injection
409 3 0       87 next if $pattern =~ /\G${mb::_anchor} \& /xms;
410 3 0       33 next if $pattern =~ /\G${mb::_anchor} \( /xms;
411 3 0       6 next if $pattern =~ /\G${mb::_anchor} \) /xms;
412 3 0       101 next if $pattern =~ /\G${mb::_anchor} \< /xms;
413 3 0       20 next if $pattern =~ /\G${mb::_anchor} \> /xms;
414 3 0       6 next if $pattern =~ /\G${mb::_anchor} \^ /xms;
415 3 0       110 next if $pattern =~ /\G${mb::_anchor} \| /xms;
416              
417             # makes globbing result
418 3         19 mb::tr($pattern, '/', "\x5C");
419 3 0       5 if (my($dir) = $pattern =~ m{\A ($x*) \\ }xms) {
420 3         93 push @glob, map { "$dir\\$_" } CORE::split /\n/, `DIR /B $pattern 2>NUL`;
  3         20  
421             }
422             else {
423 3         6 push @glob, CORE::split /\n/, `DIR /B $pattern 2>NUL`;
424             }
425             }
426             }
427              
428             # returns globbing result
429 11         157 my %glob = map { $_ => 1 } @glob;
  27         110  
430 11 50       47 return sort { (mb::uc($a) cmp mb::uc($b)) || ($a cmp $b) } keys %glob;
  23         178  
431             }
432              
433             #---------------------------------------------------------------------
434             # eval STRING for MBCS encoding
435             sub mb::eval (;$) {
436 15039 100   15039 0 60727635 local $_ = @_ ? $_[0] : $_;
437              
438             # run as Perl script in caller package
439 15039         82008 return CORE::eval sprintf(<<'END', (caller)[0,2,1], mb::parse());
440             package %s;
441             #line %s "%s"
442             %s
443             END
444             }
445              
446             #---------------------------------------------------------------------
447             # getc() for MBCS encoding
448             sub mb::getc (;*) {
449 40 100   40 0 3456826 my $fh = @_ ? shift(@_) : \*STDIN;
450 40 50 33     122 confess 'Too many arguments for mb::getc' if @_ and not wantarray;
451 40         326 my $getc = CORE::getc $fh;
452 40 100       274 if ($script_encoding =~ /\A (?: sjis ) \z/xms) {
    50          
    50          
    50          
    50          
453 39 100       185 if ($getc =~ /\A [\x81-\x9F\xE0-\xFC] \z/xms) {
454 21         70 $getc .= CORE::getc $fh;
455             }
456             }
457             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
458 3 0       132 if ($getc =~ /\A [\xA1-\xFE] \z/xms) {
459 3         17 $getc .= CORE::getc $fh;
460             }
461             }
462             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
463 3 0       6 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
464 3         116 $getc .= CORE::getc $fh;
465             }
466             }
467             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
468 3 0       18 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
469 3         6 $getc .= CORE::getc $fh;
470 3 0       87 if ($getc =~ /\A [\x81-\xFE] [\x30-\x39] \z/xms) {
471 3         17 $getc .= CORE::getc $fh;
472 3         6 $getc .= CORE::getc $fh;
473             }
474             }
475             }
476             elsif ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
477 4 50       93 if ($getc =~ /\A [\x00-\x7F\x80-\xC1\xF5-\xFF] \z/xms) {
    0          
    0          
    0          
478             }
479             elsif ($getc =~ /\A [\xC2-\xDF] \z/xms) {
480 3         18 $getc .= CORE::getc $fh;
481             }
482             elsif ($getc =~ /\A [\xE0-\xEF] \z/xms) {
483 3         5 $getc .= CORE::getc $fh;
484 3         88 $getc .= CORE::getc $fh;
485             }
486             elsif ($getc =~ /\A [\xF0-\xF4] \z/xms) {
487 3         15 $getc .= CORE::getc $fh;
488 3         6 $getc .= CORE::getc $fh;
489 3         107 $getc .= CORE::getc $fh;
490             }
491             }
492 40 100       190 return wantarray ? ($getc,@_) : $getc;
493             }
494              
495             #---------------------------------------------------------------------
496             # index() for MBCS encoding
497             sub mb::index ($$;$) {
498 11     11 0 517 my $index = 0;
499 11 100       153 if (@_ == 3) {
500 7         152 $index = mb::index_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
501             }
502             else {
503 7         18 $index = mb::index_byte($_[0], $_[1]);
504             }
505 11 100       121 if ($index == -1) {
506 7         232 return -1;
507             }
508             else {
509 7         40 return mb::length(CORE::substr $_[0], 0, $index);
510             }
511             }
512              
513             #---------------------------------------------------------------------
514             # JPerl like index() for MBCS encoding
515             sub mb::index_byte ($$;$) {
516 19     19 0 371 my($str,$substr,$position) = @_;
517 19   100     74 $position ||= 0;
518 19         43 my $pos = 0;
519 19         120 while ($pos < CORE::length($str)) {
520 181 100       330 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
521 15 100       29 if ($pos >= $position) {
522 11         124 return $pos;
523             }
524             }
525 173 50       715 if (CORE::substr($str,$pos) =~ /\A($x)/xms) {
526 173         311 $pos += CORE::length($1);
527             }
528             else {
529 3         88 $pos += 1;
530             }
531             }
532 11         33 return -1;
533             }
534              
535             #---------------------------------------------------------------------
536             # universal lc() for MBCS encoding
537             sub mb::lc (;$) {
538 14 100   14 1 1758 local $_ = @_ ? $_[0] : $_;
539             # 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
540 14 100       499 return join '', map { {qw( A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z )}->{$_}||$_ } /\G$x/g;
  122         1198  
541             # 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
542             }
543              
544             #---------------------------------------------------------------------
545             # universal lcfirst() for MBCS encoding
546             sub mb::lcfirst (;$) {
547 5 100   5 0 111 local $_ = @_ ? $_[0] : $_;
548 5 50       144 if (/\A($x)(.*)\z/s) {
549 5         21 return mb::lc($1) . $2;
550             }
551             else {
552 3         7 return '';
553             }
554             }
555              
556             #---------------------------------------------------------------------
557             # length() for MBCS encoding
558             sub mb::length (;$) {
559 19 100   19 0 385 local $_ = @_ ? $_[0] : $_;
560 19         360 return scalar(() = /\G$x/g);
561             }
562              
563             #---------------------------------------------------------------------
564             # ord() for MBCS encoding
565             sub mb::ord (;$) {
566 7 100   7 0 293 local $_ = @_ ? $_[0] : $_;
567 7         149 my $ord = 0;
568 7 50       125 if (/\A($x)/) {
569 7         23 for my $octet (unpack 'C*', $1) {
570 9         95 $ord = $ord * 0x100 + $octet;
571             }
572             }
573 7         29 return $ord;
574             }
575              
576             #---------------------------------------------------------------------
577             # require for MBCS encoding
578             sub mb::require (;$) {
579 8 50   8 0 1854 local $_ = @_ ? $_[0] : $_;
580              
581             # require perl version
582 8 50       110 if (/^[0-9]/) {
583 3 0       17 if ($] < $_) {
584 3         5 confess "Perl $_ required--this is only version $], stopped";
585             }
586             else {
587 3         88 undef $@;
588 3         17 return 1;
589             }
590             }
591              
592             # require expr
593             else {
594              
595             # find expr in @INC
596 8         12 my $file = $_;
597 8 50 33     162 if (($file =~ s{::}{/}g) or ($file !~ m{[\./\\]})) {
598 2         14 $file .= '.pm';
599             }
600 7 100       19 if (exists $INC{$file}) {
601 3         71 undef $@;
602 1 50       9 return 1 if $INC{$file};
603 0         0 confess "Compilation failed in require";
604             }
605 4         10 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  32         47  
606 4 50       64 if (-f $prefix_file) {
607              
608             # poor "make"
609 4         46 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
610 4 0 33     135 if (
      33        
611             (not -e $prefix_file_oo) or
612             (mtime($prefix_file_oo) <= mtime($prefix_file)) or
613             (mtime($prefix_file_oo) <= mtime(__FILE__))
614             ) {
615 4 50       15 my $fh = mb::_open_r($prefix_file) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file\n";
  0         0  
616 108     108   936 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  108         186  
  108         6749  
  4         5  
  4         15  
  4         6  
  4         137  
617 108     108   616 { no strict 'refs'; close($fh) }
  108         662  
  108         18585  
  4         8  
  4         33  
618              
619             # poor file locking
620 4     3   64 local $SIG{__DIE__} = sub { rmdir "$prefix_file.lock"; };
  0         0  
621 4 50       2010 if (mkdir "$prefix_file.lock", 0755) {
622 4 50       17 my $fh = mb::_open_w($prefix_file_oo) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file_oo\n";
  0         0  
623 108     108   928 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  108         246  
  108         6960  
  4         4  
  4         4  
  4         25  
624 108     108   629 { no strict 'refs'; close($fh) }
  108         238  
  108         185918  
  4         6  
  4         10  
  4         223  
625 4         375 rmdir "$prefix_file.lock";
626             }
627             else {
628 0         0 confess "$0(@{[__LINE__]}): can't mkdir: $prefix_file.lock\n";
  0         0  
629             }
630             }
631 4         20 $INC{$_} = $prefix_file_oo;
632              
633             # run as Perl script
634             # must use CORE::do to use , because CORE::eval cannot do it.
635 4         4 local $@;
636 4         317 my $result = CORE::eval sprintf(<<'END', (caller)[0,2,1]);
637             package %s;
638             #line %s "%s"
639             CORE::do "$prefix_file_oo";
640             END
641              
642             # return result
643 4 50       324 if ($@) {
    50          
644 0         0 $INC{$_} = undef;
645 0         0 confess $@;
646             }
647             elsif (not $result) {
648 0         0 delete $INC{$_};
649 0         0 confess "$_ did not return true value";
650             }
651             else {
652 4         25 return $result;
653             }
654             }
655             }
656 0         0 confess "Can't find $_ in \@INC";
657             }
658             }
659              
660             #---------------------------------------------------------------------
661             # reverse() for MBCS encoding
662             sub mb::reverse (@) {
663              
664             # in list context,
665 10 100   13 0 454 if (wantarray) {
666              
667             # returns a list value consisting of the elements of @_ in the opposite order
668 2         10 return CORE::reverse @_;
669             }
670              
671             # in scalar context,
672             else {
673              
674             # returns a string value with all characters in the opposite order of
675 8 100       276 return (join '',
676             CORE::reverse(
677             @_ ?
678             join('',@_) =~ /\G$x/g : # concatenates the elements of @_
679             /\G$x/g # $_ when without arguments
680             )
681             );
682             }
683             }
684              
685             #---------------------------------------------------------------------
686             # rindex() for MBCS encoding
687             sub mb::rindex ($$;$) {
688 8     11 0 383 my $rindex = 0;
689 8 100       23 if (@_ == 3) {
690 4         127 $rindex = mb::rindex_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
691             }
692             else {
693 4         50 $rindex = mb::rindex_byte($_[0], $_[1]);
694             }
695 8 100       18 if ($rindex == -1) {
696 4         14 return -1;
697             }
698             else {
699 4         16 return mb::length(CORE::substr $_[0], 0, $rindex);
700             }
701             }
702              
703             #---------------------------------------------------------------------
704             # JPerl like rindex() for MBCS encoding
705             sub mb::rindex_byte ($$;$) {
706 16     19 0 392 my($str,$substr,$position) = @_;
707 16   66     96 $position ||= CORE::length($str) - 1;
708 16         28 my $pos = 0;
709 16         23 my $rindex = -1;
710 16   100     66 while (($pos < CORE::length($str)) and ($pos <= $position)) {
711 230 100       484 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
712 20         32 $rindex = $pos;
713             }
714 230 50       1156 if (CORE::substr($str,$pos) =~ /\A($x)/xms) {
715 230         850 $pos += CORE::length($1);
716             }
717             else {
718 0         0 $pos += 1;
719             }
720             }
721 16         58 return $rindex;
722             }
723              
724             #---------------------------------------------------------------------
725             # set OSNAME
726             sub mb::set_OSNAME ($) {
727 0     3 0 0 $OSNAME = $_[0];
728             }
729              
730             #---------------------------------------------------------------------
731             # get OSNAME
732             sub mb::get_OSNAME () {
733 0     3 0 0 return $OSNAME;
734             }
735              
736             #---------------------------------------------------------------------
737             # set script encoding name and more
738             sub mb::set_script_encoding ($) {
739 194     197 0 16734903 $script_encoding = $_[0];
740              
741             # over US-ASCII
742             $over_ascii = {
743             'sjis' => '(?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|[\x80-\xFF])', # shift_jis ANSI/OEM Japanese; Japanese (Shift-JIS)
744             'gbk' => '(?>[\x81-\xFE][\x00-\xFF])', # gb2312 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
745             'uhc' => '(?>[\x81-\xFE][\x00-\xFF])', # ks_c_5601-1987 ANSI/OEM Korean (Unified Hangul Code)
746             'big5' => '(?>[\x81-\xFE][\x00-\xFF])', # big5 ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
747             'big5hkscs' => '(?>[\x81-\xFE][\x00-\xFF])', # HKSCS support on top of traditional Chinese Windows
748             'eucjp' => '(?>[\xA1-\xFE][\x00-\xFF])', # EUC-JP Japanese (JIS 0208-1990 and 0121-1990)
749             '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)
750             'rfc2279' => '(?>[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF])', # utf-8 Unicode (UTF-8) RFC2279
751             '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
752             'wtf8' => '(?>[\xE1-\xEF][\x80-\xBF][\x80-\xBF]|[\xC2-\xDF][\x80-\xBF]|[\xE0-\xE0][\xA0-\xBF][\x80-\xBF]|[\xF0-\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]|[\xF4-\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF])', # optimized WTF-8 for ja_JP
753 194   50     3583 }->{$script_encoding} || '[\x80-\xFF]';
754              
755             # supports qr/./ in MBCS script
756 194         29529 $x = qr/(?>$over_ascii|[\x00-\x7F])/;
757              
758             # regexp of multi-byte anchoring
759              
760             # Quantifiers
761             # {n,m} --- Match at least n but not more than m times
762             #
763             # n and m are limited to non-negative integral values less than a
764             # preset limit defined when perl is built. This is usually 32766 on
765             # the most common platforms.
766             #
767             # The following code is an attempt to solve the above limitations
768             # in a multi-byte anchoring.
769             #
770             # avoid "Segmentation fault" and "Error: Parse exception"
771             #
772             # perl5101delta
773             # http://perldoc.perl.org/perl5101delta.html
774             # In 5.10.0, the * quantifier in patterns was sometimes treated as {0,32767}
775             # [RT #60034, #60464]. For example, this match would fail:
776             # ("ab" x 32768) =~ /^(ab)*$/
777             #
778             # SEE ALSO
779             #
780             # Complex regular subexpression recursion limit
781             # http://www.perlmonks.org/?node_id=810857
782             #
783             # regexp iteration limits
784             # http://www.nntp.perl.org/group/perl.perl5.porters/2009/02/msg144065.html
785             #
786             # latest Perl won't match certain regexes more than 32768 characters long
787             # http://stackoverflow.com/questions/26226630/latest-perl-wont-match-certain-regexes-more-than-32768-characters-long
788             #
789             # Break through the limitations of regular expressions of Perl
790             # http://d.hatena.ne.jp/gfx/20110212/1297512479
791             #
792             # REG_INF has been raised from 65,536 to 2,147,483,647
793             # https://perldoc.perl.org/perl5380delta#REG_INF-has-been-raised-from-65,536-to-2,147,483,647
794              
795 194 100       2451 if ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
    50          
    0          
    0          
796 98         445 ${mb::_anchor} = qr{.*?}xms;
797             }
798             elsif ($] >= 5.038000) {
799             ${mb::_anchor} = {
800             'sjis' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
801             'eucjp' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
802             'gbk' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
803             'uhc' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
804             'big5' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
805             'big5hkscs' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
806             'gb18030' => qr{(?(?=.{0,2147483646}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
807 96   50     77011 }->{$script_encoding} || die;
808             }
809             elsif ($] >= 5.030000) {
810             ${mb::_anchor} = {
811             'sjis' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
812             'eucjp' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
813             'gbk' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
814             'uhc' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
815             'big5' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
816             'big5hkscs' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
817             'gb18030' => qr{(?(?=.{0,65534}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
818 0   0     0 }->{$script_encoding} || die;
819             }
820             elsif ($] >= 5.010001) {
821             ${mb::_anchor} = {
822             'sjis' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
823             'eucjp' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
824             'gbk' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
825             'uhc' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
826             'big5' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
827             'big5hkscs' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
828             'gb18030' => qr{(?(?=.{0,32766}\z)(?:$x)*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
829 0   0     0 }->{$script_encoding} || die;
830             }
831             else {
832 0         0 ${mb::_anchor} = qr{(?:$x)*?}xms;
833             }
834              
835             # codepoint class shortcuts in qq-like regular expression
836 194         2941 @{mb::_dot} = "(?>$over_ascii|.)"; # supports /s modifier by /./
837 194         909 @{mb::_B} = "(?:(?
838 194         1099 @{mb::_D} = "(?:(?![0-9])$x)";
839 194         777 @{mb::_H} = "(?:(?![\\x09\\x20])$x)";
840 194         850 @{mb::_N} = "(?:(?!\\n)$x)";
841 194         583 @{mb::_R} = "(?>\\r\\n|[\\x0A\\x0B\\x0C\\x0D])";
842 194         836 @{mb::_S} = "(?:(?![\\t\\n\\f\\r\\x20])$x)";
843 194         760 @{mb::_V} = "(?:(?![\\x0A\\x0B\\x0C\\x0D])$x)";
844 194         774 @{mb::_W} = "(?:(?![A-Za-z0-9_])$x)";
845 194         1548 @{mb::_b} = "(?:(?
846 194         732 @{mb::_d} = "[0-9]";
847 194         513 @{mb::_h} = "[\\x09\\x20]";
848 194         497 @{mb::_s} = "[\\t\\n\\f\\r\\x20]";
849 194         507 @{mb::_v} = "[\\x0A\\x0B\\x0C\\x0D]";
850 194         716 @{mb::_w} = "[A-Za-z0-9_]";
851             }
852              
853             #---------------------------------------------------------------------
854             # get script encoding name
855             sub mb::get_script_encoding () {
856 680443     680446 0 3336447 return $script_encoding;
857             }
858              
859             #---------------------------------------------------------------------
860             # get old package name
861             sub mb::get_old_package () {
862             return {qw(
863             sjis Sjis::
864             gbk GBK::
865             uhc UHC::
866             big5 Big5::
867             big5hkscs Big5HKSCS::
868             eucjp EUCJP::
869             gb18030 GB18030::
870             rfc2279 RFC2279::
871             utf8 UTF2::
872             wtf8 WTF8::
873 680443   50 680446 0 4891573 )}->{mb::get_script_encoding()} || die;
874             }
875              
876             #---------------------------------------------------------------------
877             # substr() for MBCS encoding
878             BEGIN {
879 108 50 100 108 0 358427 CORE::eval sprintf <<'END', ($] >= 5.014) ? ':lvalue' : '';
  50 100   3   3207  
  50 100   53   202  
  2 100       7  
  48 50       101  
  16 100       30  
  16 50       43  
  16 100       30  
  24 100       123  
  24 100       94  
  24         107  
  24         229  
  8         27  
  8         75  
880             # VV------------------------AAAAAAA
881             sub mb::substr ($$;$$) %s {
882             my @x = $_[0] =~ /\G$x/g;
883              
884             # If the substring is beyond either end of the string, substr() returns the undefined
885             # value and produces a warning. When used as an lvalue, specifying a substring that
886             # is entirely outside the string raises an exception.
887             # http://perldoc.perl.org/functions/substr.html
888              
889             # A return with no argument returns the scalar value undef in scalar context,
890             # an empty list () in list context, and (naturally) nothing at all in void
891             # context.
892              
893             if (($_[1] < (-1 * scalar(@x))) or (+1 * scalar(@x) < $_[1])) {
894             return;
895             }
896              
897             # substr($string,$offset,$length,$replacement)
898             if (@_ == 4) {
899             my $substr = join '', splice @x, $_[1], $_[2], $_[3];
900             $_[0] = join '', @x;
901             $substr; # "return $substr" doesn't work, don't write "return"
902             }
903              
904             # substr($string,$offset,$length)
905             elsif (@_ == 3) {
906             local $SIG{__WARN__} = sub {}; # avoid: Use of uninitialized value in join or string at here
907             my $octet_offset =
908             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
909             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
910             0;
911             my $octet_length =
912             ($_[2] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[2]+1 .. $#x]) :
913             ($_[2] > 0) ? CORE::length(join '', @x[$_[1] .. $_[1]+$_[2]-1]) :
914             0;
915             CORE::substr($_[0], $octet_offset, $octet_length);
916             }
917              
918             # substr($string,$offset)
919             else {
920             my $octet_offset =
921             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
922             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
923             0;
924             CORE::substr($_[0], $octet_offset);
925             }
926             }
927             END
928             }
929              
930             #---------------------------------------------------------------------
931             # tr/// and y/// for MBCS encoding
932             sub mb::tr ($$$;$) {
933 2512     2515 0 419434 my @x = $_[0] =~ /\G($x)/xmsg;
934 2512         15426 my @search = list_all_ASCII_by_hyphen($_[1] =~ /\G(\\-|$x)/xmsg);
935 2512         15499 my @replacement = list_all_ASCII_by_hyphen($_[2] =~ /\G(\\-|$x)/xmsg);
936 2512 100       8566 my %modifier = (defined $_[3]) ? (map { $_ => 1 } CORE::split //, $_[3]) : ();
  2735         9414  
937              
938 2512         4526 my %tr = ();
939 2512         5581 for (my $i=0; $i <= $#search; $i++) {
940              
941             # tr/AAA/123/ works as tr/A/1/
942 3334 100       7278 if (not exists $tr{$search[$i]}) {
943              
944             # tr/ABC/123/ makes %tr = ('A'=>'1','B'=>'2','C'=>'3',);
945 3274 100 66     11716 if (defined($replacement[$i]) and ($replacement[$i] ne '')) {
    100 66        
    100          
946 3069         9057 $tr{$search[$i]} = $replacement[$i];
947             }
948              
949             # tr/ABC/12/d makes %tr = ('A'=>'1','B'=>'2','C'=>'',);
950             elsif (exists $modifier{d}) {
951 108         319 $tr{$search[$i]} = '';
952             }
953              
954             # tr/ABC/12/ makes %tr = ('A'=>'1','B'=>'2','C'=>'2',);
955             elsif (defined($replacement[-1]) and ($replacement[-1] ne '')) {
956 89         295 $tr{$search[$i]} = $replacement[-1];
957             }
958              
959             # tr/ABC// makes %tr = ('A'=>'A','B'=>'B','C'=>'C',);
960             else {
961 8         29 $tr{$search[$i]} = $search[$i];
962             }
963             }
964             }
965              
966 2512         3825 my $tr = 0;
967 2512         3607 my $replaced = '';
968              
969             # has /c modifier
970 2512 100       4622 if (exists $modifier{c}) {
971              
972             # has /s modifier
973 126 100       240 if (exists $modifier{s}) {
974 54         92 my $last_transliterated = undef;
975 54         152 while (defined(my $x = shift @x)) {
976              
977             # /c modifier works here
978 428 100       760 if (exists $tr{$x}) {
979 252         389 $replaced .= $x;
980 252         570 $last_transliterated = undef;
981             }
982             else {
983              
984             # /d modifier works here
985 176 100       383 if (exists $modifier{d}) {
    50          
986             }
987              
988             elsif (defined $replacement[-1]) {
989              
990             # /s modifier works here
991 52 100 66     137 if (defined($last_transliterated) and ($replacement[-1] eq $last_transliterated)) {
992             }
993              
994             # tr/// works here
995             else {
996 43         80 $replaced .= ($last_transliterated = $replacement[-1]);
997             }
998             }
999 176         459 $tr++;
1000             }
1001             }
1002             }
1003              
1004             # has no /s modifier
1005             else {
1006 72         211 while (defined(my $x = shift @x)) {
1007              
1008             # /c modifier works here
1009 314 100       539 if (exists $tr{$x}) {
1010 210         544 $replaced .= $x;
1011             }
1012             else {
1013              
1014             # /d modifier works here
1015 104 100       231 if (exists $modifier{d}) {
    50          
1016             }
1017              
1018             # tr/// works here
1019             elsif (defined $replacement[-1]) {
1020 70         108 $replaced .= $replacement[-1];
1021             }
1022 104         309 $tr++;
1023             }
1024             }
1025             }
1026             }
1027              
1028             # has no /c modifier
1029             else {
1030              
1031             # has /s modifier
1032 2386 100       4261 if (exists $modifier{s}) {
1033 85         144 my $last_transliterated = undef;
1034 85         239 while (defined(my $x = shift @x)) {
1035 593 100       1113 if (exists $tr{$x}) {
1036              
1037             # /d modifier works here
1038 425 100 100     1350 if ($tr{$x} eq '') {
    100          
1039             }
1040              
1041             # /s modifier works here
1042             elsif (defined($last_transliterated) and ($tr{$x} eq $last_transliterated)) {
1043             }
1044              
1045             # tr/// works here
1046             else {
1047 159         311 $replaced .= ($last_transliterated = $tr{$x});
1048             }
1049 425         948 $tr++;
1050             }
1051             else {
1052 168         255 $replaced .= $x;
1053 168         444 $last_transliterated = undef;
1054             }
1055             }
1056             }
1057              
1058             # has no /s modifier
1059             else {
1060 2301         6039 while (defined(my $x = shift @x)) {
1061 2731 100       5217 if (exists $tr{$x}) {
1062 2603         4381 $replaced .= $tr{$x};
1063 2603         6636 $tr++;
1064             }
1065             else {
1066 128         303 $replaced .= $x;
1067             }
1068             }
1069             }
1070             }
1071              
1072             # /r modifier works here
1073 2512 100       5977 if (exists $modifier{r}) {
1074 2344         16816 return $replaced;
1075             }
1076              
1077             # has no /r modifier
1078             else {
1079 168         322 $_[0] = $replaced;
1080 168         1054 return $tr;
1081             }
1082             }
1083              
1084             #---------------------------------------------------------------------
1085             # universal uc() for MBCS encoding
1086             sub mb::uc (;$) {
1087 46 100   49 1 563 local $_ = @_ ? $_[0] : $_;
1088             # 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
1089 46 100       1254 return join '', map { {qw( a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z )}->{$_}||$_ } /\G$x/g;
  870         10403  
1090             # 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
1091             }
1092              
1093             #---------------------------------------------------------------------
1094             # universal ucfirst() for MBCS encoding
1095             sub mb::ucfirst (;$) {
1096 2 100   5 0 110 local $_ = @_ ? $_[0] : $_;
1097 2 50       80 if (/\A($x)(.*)\z/s) {
1098 2         8 return mb::uc($1) . $2;
1099             }
1100             else {
1101 0         0 return '';
1102             }
1103             }
1104              
1105             ######################################################################
1106             # runtime routines on all operating systems (used automatically)
1107             ######################################################################
1108              
1109             #---------------------------------------------------------------------
1110             # implement of special variable $1,$2,$3,...
1111             sub mb::_CAPTURE (;$) {
1112 90 100   93   1101 if ($mb::last_s_passed) {
1113 29 50       138 if (defined $_[0]) {
1114              
1115             # $1 is used for multi-byte anchoring
1116 29         1900 return CORE::eval('$' . ($_[0] + 1));
1117             }
1118             else {
1119 0         0 my @capture = ();
1120 0 0       0 if ($] >= 5.006) {
1121              
1122             # $1 is used for multi-byte anchoring in s///
1123 0         0 push @capture, map { CORE::eval('$'.$_) } 2 .. CORE::eval('$#-');
  0         0  
1124             }
1125             else {
1126              
1127             # @{^CAPTURE} doesn't work enough in perl 5.005
1128 0         0 for (my $n_th=2; defined(CORE::eval('$'.$n_th)); $n_th++) {
1129 0         0 push @capture, CORE::eval('$'.$n_th);
1130             }
1131             }
1132 0         0 return @capture;
1133             }
1134             }
1135             else {
1136 61 50       150 if (defined $_[0]) {
1137 61         4585 return CORE::eval('$' . $_[0]);
1138             }
1139             else {
1140 0         0 my @capture = ();
1141 0 0       0 if ($] >= 5.006) {
1142 0         0 push @capture, map { CORE::eval('$'.$_) } 1 .. CORE::eval('$#-');
  0         0  
1143             }
1144             else {
1145              
1146             # @{^CAPTURE} doesn't work enough in perl 5.005
1147 0         0 for (my $n_th=1; defined(CORE::eval('$'.$n_th)); $n_th++) {
1148 0         0 push @capture, CORE::eval('$'.$n_th);
1149             }
1150             }
1151 0         0 return @capture;
1152             }
1153             }
1154             }
1155              
1156             #---------------------------------------------------------------------
1157             # implement of special variable @+
1158             sub mb::_LAST_MATCH_END (@) {
1159              
1160             # perl 5.005 does not support @+, so it need CORE::eval
1161              
1162 10 100   13   60 if ($mb::last_s_passed) {
1163 5 50       20 if (scalar(@_) >= 1) {
1164 5         336 return CORE::eval q{ ($+[0], @+[2..$#-])[ @_ ] };
1165             }
1166             else {
1167 0         0 return CORE::eval q{ ($+[0], @+[2..$#-]) };
1168             }
1169             }
1170             else {
1171 5 50       12 if (scalar(@_) >= 1) {
1172 5         317 return CORE::eval q{ @+[ @_ ] };
1173             }
1174             else {
1175 0         0 return CORE::eval q{ @+ };
1176             }
1177             }
1178             }
1179              
1180             #---------------------------------------------------------------------
1181             # implement of special variable @-
1182             sub mb::_LAST_MATCH_START (@) {
1183              
1184             # perl 5.005 does not support @-, so it need CORE::eval
1185              
1186 18 100   21   49 if ($mb::last_s_passed) {
1187 9 50       23 if (scalar(@_) >= 1) {
1188 9         611 return CORE::eval q{ ($-[2], @-[2..$#-])[ @_ ] };
1189             }
1190             else {
1191 0         0 return CORE::eval q{ ($-[2], @-[2..$#-]) };
1192             }
1193             }
1194             else {
1195 9 50       22 if (scalar(@_) >= 1) {
1196 9         617 return CORE::eval q{ @-[ @_ ] };
1197             }
1198             else {
1199 0         0 return CORE::eval q{ @- };
1200             }
1201             }
1202             }
1203              
1204             #---------------------------------------------------------------------
1205             # implement of special variable $&
1206             sub mb::_MATCH () {
1207 61 50   64   886 if (defined $&) {
1208 61 100       167 if ($mb::last_s_passed) {
1209 8 50 33     92 if (defined($1) and (CORE::substr($&, 0, CORE::length($1)) eq $1)) {
1210 8         162 return CORE::substr($&, CORE::length($1));
1211             }
1212             else {
1213 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1214             }
1215             }
1216             else {
1217 53 50 33     413 if (defined($1) and (CORE::substr($&, -CORE::length($1)) eq $1)) {
1218 53         1249 return $1;
1219             }
1220             else {
1221 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1222             }
1223             }
1224             }
1225             else {
1226 0         0 return '';
1227             }
1228             }
1229              
1230             #---------------------------------------------------------------------
1231             # implement of special variable $`
1232             sub mb::_PREMATCH () {
1233 15 50   18   258 if (defined $&) {
1234 15 100       69 if ($mb::last_s_passed) {
1235 8         167 return $1;
1236             }
1237             else {
1238 7 50 33     62 if (defined($1) and (CORE::substr($&,-CORE::length($1)) eq $1)) {
1239 7         147 return CORE::substr($&, 0, -CORE::length($1));
1240             }
1241             else {
1242 0         0 confess 'Use of "$`", $PREMATCH, and ${^PREMATCH} need to /( capture all )/ in regexp';
1243             }
1244             }
1245             }
1246             else {
1247 0         0 return '';
1248             }
1249             }
1250              
1251             #---------------------------------------------------------------------
1252             # flag off if last m// was pass
1253             sub mb::_m_passed () {
1254 118477     118480   692823 $mb::last_s_passed = 0;
1255 118477         36577853 return '';
1256             }
1257              
1258             #---------------------------------------------------------------------
1259             # flag on if last s/// was pass
1260             sub mb::_s_passed () {
1261 84     87   1838 $mb::last_s_passed = 1;
1262 84         13354 return '';
1263             }
1264              
1265             #---------------------------------------------------------------------
1266             # ignore space of m/[here]/xx, qr/[here]/xx, s/[here]//xx
1267             sub mb::_ignore_space ($) {
1268 33     36   56 my($has_space) = @_;
1269 33         53 my $has_no_space = '';
1270              
1271             # parse into elements
1272 33         673 while ($has_space =~ /\G (
1273             \(\? \^? [a-z]* [:\)] | # cloister (?^x) (?^x: ...
1274             \(\? \^? [a-z]*-[a-z]+ [:\)] | # cloister (?^x-y) (?^x-y: ...
1275             \[ ((?: \\@{mb::_dot} | @{mb::_dot} )+?) \] |
1276             \\x\{ [0-9A-Fa-f]{2} \} |
1277             \\o\{ [0-7]{3} \} |
1278             \\x [0-9A-Fa-f]{2} |
1279             \\ [0-7]{3} |
1280             \\@{mb::_dot} |
1281             @{mb::_dot}
1282             ) /xmsgc) {
1283 424         1128 my($element, $classmate) = ($1, $2);
1284              
1285             # in codepoint class
1286 424 100       829 if (defined $classmate) {
1287 33         58 $has_no_space .= '[';
1288 33         395 while ($classmate =~ /\G (
1289             \\x\{ [0-9A-Fa-f]{2} \} |
1290             \\o\{ [0-7]{3} \} |
1291             \\x [0-9A-Fa-f]{2} |
1292             \\ [0-7]{3} |
1293             \\@{mb::_dot} |
1294             @{mb::_dot}
1295             ) /xmsgc) {
1296 693         1307 my $element = $1;
1297 693 100       2927 if ($element !~ /\A[$bare_s]\z/) {
1298 559         2950 $has_no_space .= $element;
1299             }
1300             }
1301 33         284 $has_no_space .= ']';
1302             }
1303              
1304             # out of codepoint class
1305             else {
1306 391         3347 $has_no_space .= $element;
1307             }
1308             }
1309 33         107 return $has_no_space;
1310             }
1311              
1312             #---------------------------------------------------------------------
1313             # ignore case of m//i, qr//i, s///i
1314             sub mb::_ignorecase ($) {
1315 64     67   598 my($has_case) = @_;
1316 64         132 my $has_no_case = '';
1317              
1318             # parse into elements
1319 64         4249 while ($has_case =~ /\G (
1320             \(\? \^? [a-z]* [:\)] | # cloister (?^x) (?^x: ...
1321             \(\? \^? [a-z]*-[a-z]+ [:\)] | # cloister (?^x-y) (?^x-y: ...
1322             \[ ((?: \\@{mb::_dot} | @{mb::_dot} )+?) \] |
1323             \\x\{ [0-9A-Fa-f]{2} \} |
1324             \\o\{ [0-7]{3} \} |
1325             \\x [0-9A-Fa-f]{2} |
1326             \\ [0-7]{3} |
1327             \\@{mb::_dot} |
1328             @{mb::_dot}
1329             ) /xmsgc) {
1330 512         1416 my($element, $classmate) = ($1, $2);
1331              
1332             # in codepoint class
1333 512 100       908 if (defined $classmate) {
1334 60         90 $has_no_case .= '[';
1335 60         547 while ($classmate =~ /\G (
1336             \\x\{ [0-9A-Fa-f]{2} \} |
1337             \\o\{ [0-7]{3} \} |
1338             \\x [0-9A-Fa-f]{2} |
1339             \\ [0-7]{3} |
1340             \\@{mb::_dot} |
1341             @{mb::_dot}
1342             ) /xmsgc) {
1343 192         396 my $element = $1;
1344             $has_no_case .= {qw(
1345             A Aa a Aa
1346             B Bb b Bb
1347             C Cc c Cc
1348             D Dd d Dd
1349             E Ee e Ee
1350             F Ff f Ff
1351             G Gg g Gg
1352             H Hh h Hh
1353             I Ii i Ii
1354             J Jj j Jj
1355             K Kk k Kk
1356             L Ll l Ll
1357             M Mm m Mm
1358             N Nn n Nn
1359             O Oo o Oo
1360             P Pp p Pp
1361             Q Qq q Qq
1362             R Rr r Rr
1363             S Ss s Ss
1364             T Tt t Tt
1365             U Uu u Uu
1366             V Vv v Vv
1367             W Ww w Ww
1368             X Xx x Xx
1369             Y Yy y Yy
1370             Z Zz z Zz
1371 192   66     6142 )}->{$element} || $element;
1372             }
1373 60         591 $has_no_case .= ']';
1374             }
1375              
1376             # out of codepoint class
1377             else {
1378             $has_no_case .= {qw(
1379             A [Aa] a [Aa]
1380             B [Bb] b [Bb]
1381             C [Cc] c [Cc]
1382             D [Dd] d [Dd]
1383             E [Ee] e [Ee]
1384             F [Ff] f [Ff]
1385             G [Gg] g [Gg]
1386             H [Hh] h [Hh]
1387             I [Ii] i [Ii]
1388             J [Jj] j [Jj]
1389             K [Kk] k [Kk]
1390             L [Ll] l [Ll]
1391             M [Mm] m [Mm]
1392             N [Nn] n [Nn]
1393             O [Oo] o [Oo]
1394             P [Pp] p [Pp]
1395             Q [Qq] q [Qq]
1396             R [Rr] r [Rr]
1397             S [Ss] s [Ss]
1398             T [Tt] t [Tt]
1399             U [Uu] u [Uu]
1400             V [Vv] v [Vv]
1401             W [Ww] w [Ww]
1402             X [Xx] x [Xx]
1403             Y [Yy] y [Yy]
1404             Z [Zz] z [Zz]
1405 452   66     15425 )}->{$element} || $element;
1406             }
1407             }
1408 64         958 return qr{$has_no_case};
1409             }
1410              
1411             #---------------------------------------------------------------------
1412             # custom codepoint class in qq-like regular expression
1413             sub mb::_cc ($) {
1414 118269     118272   1091321 my($classmate) = @_;
1415 118269 100       437022 if ($classmate =~ s{\A \^ }{}xms) {
1416 58974         167262 return '(?:(?!' . parse_re_codepoint_class($classmate) . ")$x)";
1417             }
1418             else {
1419 59295         173298 return '(?:(?=' . parse_re_codepoint_class($classmate) . ")$x)";
1420             }
1421             }
1422              
1423             #---------------------------------------------------------------------
1424             # makes clustered codepoint from string
1425             sub mb::_clustered_codepoint ($) {
1426 22 100   25   336 if (my @codepoint = $_[0] =~ /\G($x)/xmsgc) {
1427 10 100       32 if (CORE::length($codepoint[$#codepoint]) == 1) {
1428 5         135 return $_[0];
1429             }
1430             else {
1431 5         122 return join '', @codepoint[ 0 .. $#codepoint-1 ], "(?:$codepoint[$#codepoint])";
1432             }
1433             }
1434             else {
1435 12         259 return '';
1436             }
1437             }
1438              
1439             #---------------------------------------------------------------------
1440             # open for append -- returns glob-name string on success, "" on failure.
1441             # Works on Perl 5.005_03 and all later versions.
1442             # Always uses a unique numbered package glob (mb::FH::H) so that
1443             # concurrent callers each get their own IO slot.
1444             sub mb::_open_a ($) {
1445 0     3   0 $mb::_fh_seq++;
1446 0         0 my $fhn = "mb::FH::H$mb::_fh_seq";
1447 108 0   108   1087 { no strict 'refs'; open($fhn, ">> $_[0]") or return "" }
  108         316  
  108         14558  
  0         0  
  0         0  
1448 0         0 return $fhn;
1449             }
1450              
1451             #---------------------------------------------------------------------
1452             # open for read -- returns glob-name string on success, "" on failure.
1453             sub mb::_open_r ($) {
1454 9     12   15 $mb::_fh_seq++;
1455 9         24 my $fhn = "mb::FH::H$mb::_fh_seq";
1456 108 50   108   698 { no strict 'refs'; open($fhn, $_[0]) or return "" }
  108         320  
  108         12288  
  9         10  
  9         356  
1457 9         59 return $fhn;
1458             }
1459              
1460             #---------------------------------------------------------------------
1461             # open for write -- returns glob-name string on success, "" on failure.
1462             sub mb::_open_w ($) {
1463 9     12   18 $mb::_fh_seq++;
1464 9         27 my $fhn = "mb::FH::H$mb::_fh_seq";
1465 108 50   108   689 { no strict 'refs'; open($fhn, "> $_[0]") or return "" }
  108         342  
  108         4116963  
  9         10  
  9         922  
1466 9         50 return $fhn;
1467             }
1468              
1469             #---------------------------------------------------------------------
1470             # split() for MBCS encoding
1471             sub mb::_split (;$$$) {
1472 336 100   339   13444 my $pattern = defined($_[0]) ? $_[0] : ' ';
1473 336 100       702 my $string = defined($_[1]) ? $_[1] : $_;
1474 336         570 my @split = ();
1475              
1476             # split's first argument is more consistently interpreted
1477             #
1478             # After some changes earlier in v5.17, split's behavior has been simplified:
1479             # if the PATTERN argument evaluates to a string containing one space, it is
1480             # treated the way that a literal string containing one space once was.
1481             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#split's_first_argument_is_more_consistently_interpreted
1482             # if $pattern is also omitted or is the literal space, " ", the function splits
1483             # on whitespace, /\s+/, after skipping any leading whitespace
1484              
1485 336 100       768 if ($pattern eq ' ') {
1486 108         393 $pattern = qr/\s+/;
1487 108         373 $string =~ s{\A \s+ }{}xms;
1488             }
1489              
1490             # count '(' in pattern
1491 336         489 my @parsed = ();
1492 336         429 my $modifier = '';
1493 336 100 100     2636 if ((($modifier) = $pattern =~ /\A \(\?\^? (.+?) [\)\-\:] /xms) and ($modifier =~ /x/xms)) {
1494 34         1466 @parsed = $pattern =~ m{ \G (
1495             \\ $x |
1496             \# .*? $ | # comment on /x modifier
1497             \(\?\# (?:$x)*? \) |
1498             \[ (?:$x)+? \] |
1499             \(\? |
1500             \(\+ |
1501             \(\* |
1502             $x |
1503             [\x00-\xFF]
1504             ) }xgc;
1505             }
1506             else {
1507 302         5128 @parsed = $pattern =~ m{ \G (
1508             \\ $x |
1509             \(\?\# (?:$x)*? \) |
1510             \[ (?:$x)+? \] |
1511             \(\? |
1512             \(\+ |
1513             \(\* |
1514             $x |
1515             [\x00-\xFF]
1516             ) }xgc;
1517             }
1518             my $last_match_no =
1519             1 + # first '(' is for substring
1520 336         823 scalar(grep { $_ eq '(' } @parsed); # other '(' are for pattern of split()
  2398         3720  
1521              
1522             # Repeated Patterns Matching a Zero-length Substring
1523             # https://perldoc.perl.org/perlre.html#Repeated-Patterns-Matching-a-Zero-length-Substring
1524 336 100       3544 my $substring_quantifier = ('' =~ / \A $pattern \z /xms) ? '+?' : '*?';
1525              
1526             # if $_[2] specified and positive
1527 336 100 100     855 if (defined($_[2]) and ($_[2] >= 1)) {
1528 21         31 my $limit = $_[2];
1529              
1530 21         1398 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
1531              
1532             # gets substrings by repeat chopping by pattern
1533 21   100     708 while ((--$limit > 0) and ($string =~ s<\A((?:$x)$substring_quantifier)$pattern><>)) {
1534 42         137 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1535 42         1833 push @split, CORE::eval('$'.$n_th);
1536             }
1537             }
1538             }
1539              
1540             # if $_[2] is omitted or zero or negative
1541             else {
1542 315     5   44518 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
  5     5   48  
  5         17  
  5         270  
  5         34  
  5         9  
  5         203  
1543              
1544             # gets substrings by repeat chopping by pattern
1545 315         9976 while ($string =~ s<\A((?:$x)$substring_quantifier)$pattern><>) {
1546 740         1889 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1547 792         34495 push @split, CORE::eval('$'.$n_th);
1548             }
1549             }
1550             }
1551              
1552             # get last substring
1553 336 100 100     943 if (CORE::length($string) > 0) {
    100          
1554 303         586 push @split, $string;
1555             }
1556             elsif (defined($_[2]) and ($_[2] >= 1)) {
1557 6 50       18 if (scalar(@split) < $_[2]) {
1558 6         15 push @split, ('') x ($_[2] - scalar(@split));
1559             }
1560             }
1561              
1562             # if $_[2] is omitted or zero, trailing null fields are stripped from the result
1563 336 100 100     877 if ((not defined $_[2]) or ($_[2] == 0)) {
1564 309   33     1411 while ((scalar(@split) >= 1) and ($split[-1] eq '')) {
1565 0         0 pop @split;
1566             }
1567             }
1568              
1569             # old days, split had write its result to @_ on scalar context,
1570             # but this usage is no longer supported
1571              
1572 336 100       597 if (wantarray) {
1573 203         1408 return @split;
1574             }
1575             else {
1576 133         706 return scalar @split;
1577             }
1578             }
1579              
1580             ######################################################################
1581             # runtime routines for MSWin32 (used automatically)
1582             ######################################################################
1583              
1584             #---------------------------------------------------------------------
1585             # chdir() for MSWin32
1586             sub mb::_chdir (;$) {
1587              
1588             # not on MSWin32 or UTF-8
1589 2 50 33 5   23 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1590 2 50       7 if (@_ == 0) {
1591 0         0 return CORE::chdir;
1592             }
1593             else {
1594 2         1365 return CORE::chdir $_[0];
1595             }
1596             }
1597              
1598             # on MSWin32
1599 0 0 0     0 if (@_ == 0) {
    0 0        
    0          
1600 0         0 return CORE::chdir;
1601             }
1602             elsif (($script_encoding =~ /\A (?: sjis ) \z/xms) and ($_[0] =~ /\A $x* [\x81-\x9F\xE0-\xFC][\x5C] \z/xms)) {
1603 0 0       0 if (defined wantarray) {
1604 0         0 return 0;
1605             }
1606             else {
1607 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1608             }
1609             }
1610             elsif (($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and ($_[0] =~ /\A $x* [\x81-\xFE][\x5C] \z/xms)) {
1611 0 0       0 if (defined wantarray) {
1612 0         0 return 0;
1613             }
1614             else {
1615 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1616             }
1617             }
1618             else {
1619 0         0 return CORE::chdir $_[0];
1620             }
1621             }
1622              
1623             #---------------------------------------------------------------------
1624             # stackable filetest -X -Y -Z for MSWin32
1625             sub mb::_filetest {
1626 11209     11212   76198 my @filetest = map { /(-[A-Za-z])/g } @{ shift(@_) };
  11217         75317  
  11209         31768  
1627 11209 0       30606 local $_ = @_ ? shift : (($filetest[-1] eq '-t') ? \*STDIN : $_);
    50          
1628 11209 50 33     28545 confess "Too many arguments for filetest @filetest" if @_ and not wantarray;
1629              
1630             # testee has "\x5C" octet at end
1631 11209 0 33     26572 if (
      33        
1632             ($OSNAME =~ /MSWin32/) and
1633             ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and
1634             /[\x5C]\z/
1635             ) {
1636 0         0 $_ = qq{$_.};
1637             }
1638              
1639             # supports stackable filetest
1640 11209         16946 my $result;
1641 11209         22326 my $filetest = pop @filetest;
1642 11209 100       668200 if ($result = CORE::eval($filetest . ' $_')) { # '$_' at 1st time, and ...
1643             }
1644             else {
1645 2043 50       30542 return wantarray ? ($result, @_) : $result;
1646             }
1647 9166         51246 for my $filetest (CORE::reverse @filetest) {
1648 7 50       297 if ($result = CORE::eval($filetest . ' _')) { # '_' at 2nd time or later
1649             }
1650             else {
1651 0 0       0 return wantarray ? ($result, @_) : $result;
1652             }
1653             }
1654 9166 50       121807 return wantarray ? ($result, @_) : $result;
1655             }
1656              
1657             #---------------------------------------------------------------------
1658             # lstat() for MSWin32
1659             sub mb::_lstat (;$) {
1660 3 50   6   71 local $_ = @_ ? $_[0] : $_;
1661 3 50       11 if ($_ eq '_') {
1662 0         0 confess qq{lstat doesn't support '_'\n};
1663             }
1664              
1665             # testee has "\x5C" octet at end
1666 3 0 33     11 if (
      33        
1667             ($OSNAME =~ /MSWin32/) and
1668             ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and
1669             /[\x5C]\z/
1670             ) {
1671 0         0 $_ = qq{$_.};
1672             }
1673              
1674 3         55 return CORE::lstat $_;
1675             }
1676              
1677             #---------------------------------------------------------------------
1678             # opendir() for MSWin32
1679             sub mb::_opendir ($$) {
1680 7 100   10   58 if (not defined $_[0]) {
1681 3         3 $_[0] = \do { local *_ };
  3         12  
1682             }
1683              
1684             # works on MSWin32 only
1685 7 50 33     38 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
    0          
    0          
1686 7         262 return CORE::opendir $_[0], $_[1];
1687             }
1688             elsif (-d $_[1]) {
1689 0         0 return CORE::opendir $_[0], $_[1];
1690             }
1691             elsif (-d qq{$_[1].}) {
1692 0         0 return CORE::opendir $_[0], qq{$_[1].};
1693             }
1694 0         0 return undef;
1695             }
1696              
1697             #---------------------------------------------------------------------
1698             # stat() for MSWin32
1699             sub mb::_stat (;$) {
1700 9 50   12   256 local $_ = @_ ? $_[0] : $_;
1701              
1702             # testee has "\x5C" octet at end
1703 9 0 33     19 if (
      33        
1704             ($OSNAME =~ /MSWin32/) and
1705             ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and
1706             /[\x5C]\z/
1707             ) {
1708 0         0 $_ = qq{$_.};
1709             }
1710              
1711 9         69 return CORE::stat $_;
1712             }
1713              
1714             #---------------------------------------------------------------------
1715             # unlink() for MSWin32
1716             sub mb::_unlink (@) {
1717              
1718             # works on MSWin32 only
1719 10222 50 33 10225   81341 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1720 10222 50       906442 return CORE::unlink(@_ ? @_ : $_);
1721             }
1722              
1723 0         0 my $unlink = 0;
1724 0 0       0 for (@_ ? @_ : $_) {
1725 0 0       0 if (CORE::unlink) {
    0          
1726 0         0 $unlink++;
1727             }
1728             elsif (CORE::unlink qq{$_.}) {
1729 0         0 $unlink++;
1730             }
1731             }
1732 0         0 return $unlink;
1733             }
1734              
1735             ######################################################################
1736             # source code filter
1737             ######################################################################
1738              
1739             #---------------------------------------------------------------------
1740             # detect system encoding any of big5, big5hkscs, eucjp, gb18030, gbk, rfc2279, sjis, uhc, utf8, wtf8
1741             sub detect_system_encoding {
1742              
1743             # running on Microsoft Windows
1744 103 50   106 0 1537 if ($OSNAME =~ /MSWin32/) {
    50          
    50          
    50          
1745 0 0       0 if (my($codepage) = qx{chcp} =~ m/[^0123456789](932|936|949|950|951|20932|54936)\Z/) {
1746             return {qw(
1747             932 sjis
1748             936 gbk
1749             949 uhc
1750             950 big5
1751             951 big5hkscs
1752             20932 eucjp
1753             54936 gb18030
1754 0         0 )}->{$codepage};
1755             }
1756             else {
1757 0         0 return 'utf8';
1758             }
1759             }
1760              
1761             # running on Oracle Solaris
1762             elsif ($OSNAME =~ /solaris/) {
1763             my $LANG =
1764             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1765             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1766 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1767             '';
1768             return {qw(
1769             ja_JP.PCK sjis
1770             ja eucjp
1771             japanese eucjp
1772             ja_JP.eucJP eucjp
1773             zh gbk
1774             zh.GBK gbk
1775             zh_CN.GBK gbk
1776             zh_CN.EUC gbk
1777             zh_CN.GB18030 gb18030
1778             ko uhc
1779             ko_KR.EUC uhc
1780             zh_TW.BIG5 big5
1781             zh_HK.BIG5HK big5hkscs
1782 0   0     0 )}->{$LANG} || 'utf8';
1783             }
1784              
1785             # running on HP HP-UX
1786             elsif ($OSNAME =~ /hpux/) {
1787             my $LANG =
1788             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1789             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1790 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1791             '';
1792             return {qw(
1793             japanese sjis
1794             ja_JP.SJIS sjis
1795             japanese.euc eucjp
1796             ja_JP.eucJP eucjp
1797             zh_CN.hp15CN gbk
1798             zh_CN.gb18030 gb18030
1799             ko_KR.eucKR uhc
1800             zh_TW.big5 big5
1801             zh_HK.big5 big5hkscs
1802             zh_HK.hkbig5 big5hkscs
1803 0   0     0 )}->{$LANG} || 'utf8';
1804             }
1805              
1806             # running on IBM AIX
1807             elsif ($OSNAME =~ /aix/) {
1808             my $LANG =
1809             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1810             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1811 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1812             '';
1813             return {qw(
1814             Ja_JP sjis
1815             Ja_JP.IBM-943 sjis
1816             ja_JP eucjp
1817             ja_JP.IBM-eucJP eucjp
1818             zh_CN gbk
1819             zh_CN.IBM-eucCN gbk
1820             Zh_CN gb18030
1821             Zh_CN.GB18030 gb18030
1822             ko_KR uhc
1823             ko_KR.IBM-eucKR uhc
1824             Zh_TW big5
1825             Zh_TW.big-5 big5
1826             Zh_HK big5hkscs
1827             Zh_HK.BIG5-HKSCS big5hkscs
1828 0   0     0 )}->{$LANG} || 'utf8';
1829             }
1830              
1831             # running on Other Systems
1832             else {
1833             my $LANG =
1834             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1835             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1836 103 50       1094 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    50          
1837             '';
1838             return {qw(
1839             japanese sjis
1840             ja_JP.SJIS sjis
1841             ja_JP.mscode sjis
1842             ja eucjp
1843             japan eucjp
1844             japanese.euc eucjp
1845             Japanese-EUC eucjp
1846             ja_JP eucjp
1847             ja_JP.ujis eucjp
1848             ja_JP.eucJP eucjp
1849             ja_JP.AJEC eucjp
1850             ja_JP.EUC eucjp
1851             Jp_JP eucjp
1852             zh_CN.EUC gbk
1853             zh_CN.GB2312 gbk
1854             zh_CN.hp15CN gbk
1855             zh_CN.gb18030 gb18030
1856             ko_KR.eucKR uhc
1857             zh_TW.Big5 big5
1858             zh_TW.big5 big5
1859             zh_HK.big5 big5hkscs
1860 103   50     3099 )}->{$LANG} || 'utf8';
1861             }
1862             }
1863              
1864             my @here_document_delimiter = ();
1865              
1866             #---------------------------------------------------------------------
1867             # parse script
1868             sub parse {
1869 136739 100   136742 0 13866993 local $_ = @_ ? $_[0] : $_;
1870              
1871             # Yes, I studied study yesterday, once again.
1872 136739         254816 study $_; # acts between perl 5.005 to perl 5.014
1873              
1874 136739         262654 @here_document_delimiter = ();
1875              
1876             # transpile JPerl script to Perl script
1877 136739         250293 my $parsed_script = '';
1878 136739         624517 while (not /\G \z /xmsgc) {
1879 679105         1241498 $parsed_script .= parse_expr();
1880             }
1881              
1882             # return octet-oriented Perl script
1883 136739         18184070 return $parsed_script;
1884             }
1885              
1886             #---------------------------------------------------------------------
1887             # Perl 5.42 introduces source::encoding and automatically enables
1888             # ASCII-only checking for "use v5.41" and later.
1889             #
1890             # mb transpiles scripts to mostly US-ASCII, but it intentionally keeps
1891             # comments and POD as-is. Those may contain multibyte characters.
1892             #
1893             # source::encoding is only activated when "use v5.41" or later appears
1894             # in the script. We append "no source::encoding;" on the same line as
1895             # the "use VERSION" statement (replacing any trailing semicolon first)
1896             # to avoid introducing extra lines that would shift line numbers in
1897             # error messages.
1898             sub _insert_source_encoding_unimport {
1899 18     21   205 my($script) = @_;
1900              
1901             # append "no source::encoding;" on the same line as "use v5.41" or later,
1902             # before any trailing comment, to avoid line number shifts in error messages.
1903             # matches: use v5.41; use v5.42; use 5.041; use 5.042; etc.
1904 18         107 $script =~ s{
1905             ( \buse \s+
1906             (?: v5\. (?:4[1-9]|[5-9]\d|\d{3,}) # use v5.41 and later
1907             | 5\.0(?:4[1-9]|[5-9]\d|\d{3,}) # use 5.041 and later
1908             )
1909             [^\n#;]* # rest of statement (no # or ;)
1910             )
1911             ;? # consume trailing semicolon
1912             ( [^\n]* ) # trailing comment (if any)
1913             ( (?:\r\n|\r|\n) ) # line ending
1914             }{$1; no source::encoding;$2$3}xmsg;
1915              
1916 18         139 return $script;
1917             }
1918              
1919             #---------------------------------------------------------------------
1920             # parse ambiguous characters
1921             sub parse_ambiguous_char {
1922 275604     275607 0 436599 my $parsed = '';
1923              
1924             # Ambiguous characters
1925             # --------------------------------------------------------
1926             # Character Operator Term
1927             # --------------------------------------------------------
1928             # % modulo %hash
1929             # & &, && &subroutine
1930             # ' package 'string'
1931             # * multiplication *typeglob
1932             # + addition unary plus
1933             # - subtraction unary minus
1934             # . concatenation .3333
1935             # / division /pattern/
1936             # < less than <>, ,
1937             # << left shift <>
1938             # ? ?: ?pattern?
1939             # --------------------------------------------------------
1940              
1941             # any term then operator
1942 275604 100       789089 if (m{\G ( \s* (?:
1943              
1944             # 12345 | 12345 | 12345 | 12345 | 12345 | 12345 |
1945             %= | % | # "\x25" [%] PERCENT SIGN (U+0025)
1946             &&= | && | &\.= | &\. | &= | & | # "\x26" [&] AMPERSAND (U+0026)
1947             \*\*= | \*\* | \*= | \* | # "\x2A" [*] ASTERISK (U+002A)
1948             \.\.\.| \.\. | \.= | \. | # "\x2E" [.] FULL STOP (U+002E)
1949             \/\/= | \/\/ | \/= | \/ | # "\x2F" [/] SOLIDUS (U+002F)
1950             <=> | << | <= | < | # "\x3C" [<] LESS-THAN SIGN (U+003C)
1951             \? # "\x3F" [?] QUESTION MARK (U+003F)
1952             )) }xmsgc) {
1953 99         189 $parsed .= $1;
1954             }
1955              
1956 275604         573034 return $parsed;
1957             }
1958              
1959             #---------------------------------------------------------------------
1960             # parse expression in script
1961             sub parse_expr {
1962 680340     680343 0 936497 my $parsed = '';
1963 680340         1259695 my $old_package = mb::get_old_package();
1964              
1965             # __END__ or __DATA__
1966 680340 100       16578574 if (/\G ^ ( (?: __END__ | __DATA__ ) $R .* ) \z/xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    50          
    100          
    100          
    100          
    50          
    0          
1967 2         10 $parsed .= $1;
1968             }
1969              
1970             # =pod ... =cut
1971             elsif (/\G ^ ( = [A-Za-z_][A-Za-z_0-9]* [\x00-\xFF]*? $R =cut \b [^\n]* $R ) /xmsgc) {
1972 1         6 $parsed .= $1;
1973             }
1974              
1975             # "\r\n", "\r", "\n"
1976             elsif (/\G (?= $R ) /xmsgc) {
1977 8284         25336 while (my $here_document_delimiter = shift @here_document_delimiter) {
1978 23         51 my($delimiter, $quote_type) = @{$here_document_delimiter};
  23         61  
1979 23 100       66 if ($quote_type eq 'qq') {
    50          
1980 14         33 $parsed .= parse_heredocument_as_qq_endswith($delimiter);
1981             }
1982             elsif ($quote_type eq 'q') {
1983              
1984             # perlop > Quote-Like Operators > < Single Quotes
1985             #
1986             # Single quotes indicate the text is to be treated literally
1987             # with no interpolation of its content. This is similar to
1988             # single quoted strings except that backslashes have no special
1989             # meaning, with \\ being treated as two backslashes and not
1990             # one as they would in every other quoting construct.
1991             # https://perldoc.perl.org/perlop.html#Quote-Like-Operators
1992              
1993 9         22 $parsed .= parse_heredocument_as_q_endswith($delimiter);
1994             }
1995             else {
1996 0         0 die "$0(@{[__LINE__]}): $ARGV[0] here document delimiter '$delimiter' not found.\n";
  0         0  
1997             }
1998             }
1999             }
2000              
2001             # "\t"
2002             # "\x20" [ ] SPACE (U+0020)
2003             elsif (/\G ( [\t ]+ ) /xmsgc) {
2004 256597         603593 $parsed .= $1;
2005             }
2006              
2007             # "\x3B" [;] SEMICOLON (U+003B)
2008             elsif (/\G ( ; ) /xmsgc) {
2009 5121         12622 $parsed .= $1;
2010             }
2011              
2012             # balanced brackets
2013             # "\x28" [(] LEFT PARENTHESIS (U+0028)
2014             # "\x7B" [{] LEFT CURLY BRACKET (U+007B)
2015             # "\x5B" [[] LEFT SQUARE BRACKET (U+005B)
2016             elsif (/\G ( [(\{\[] ) /xmsgc) {
2017 315         873 $parsed .= parse_expr_balanced($1);
2018 315         607 $parsed .= parse_ambiguous_char();
2019             }
2020              
2021             # version string
2022             # v102.111.111
2023             # 102.111.111
2024             elsif (/\G (
2025             v [0-9]+ (?: \.[0-9]+ ){1,} \b |
2026             [0-9]+ (?: \.[0-9]+ ){2,} \b
2027             ) /xmsgc) {
2028 2         7 my $v_string = $1;
2029 2         20 $parsed .= join('.', map { "mb::chr($_)" } ($v_string =~ /[0-9]+/g));
  8         26  
2030 2         40 $parsed .= parse_ambiguous_char();
2031             }
2032              
2033             # version string
2034             # v9786
2035             elsif (/\G v ( [0-9]+ ) \b (?! \s* => ) /xmsgc) {
2036 1         6 $parsed .= "mb::chr($1)";
2037 1         4 $parsed .= parse_ambiguous_char();
2038             }
2039              
2040             # numbers
2041             # "\x2E" [.] [0-9]
2042             # "\x30" [0] DIGIT ZERO (U+0030)
2043             # "\x31" [1] DIGIT ONE (U+0031)
2044             # "\x32" [2] DIGIT TWO (U+0032)
2045             # "\x33" [3] DIGIT THREE (U+0033)
2046             # "\x34" [4] DIGIT FOUR (U+0034)
2047             # "\x35" [5] DIGIT FIVE (U+0035)
2048             # "\x36" [6] DIGIT SIX (U+0036)
2049             # "\x37" [7] DIGIT SEVEN (U+0037)
2050             # "\x38" [8] DIGIT EIGHT (U+0038)
2051             # "\x39" [9] DIGIT NINE (U+0039)
2052             elsif (m{\G (
2053              
2054             # since Perl v5.22 adds hexadecimal floating point literals
2055             # https://perldoc.perl.org/perl5220delta#Floating-point-parsing-has-been-improved
2056             # https://perldoc.perl.org/5.32.0/perldata#Scalar-value-constructors
2057              
2058             # https://qiita.com/mod_poppo/items/3fa4cdc35f9bfb352ad5
2059             # https://qiita.com/mod_poppo/items/3fa4cdc35f9bfb352ad5#perl
2060             #
2061             # $ perl -l -e 'print(0x1.23); print(0x1.23p0)'
2062             # makes ==> 123
2063             # makes ==> 1.13671875
2064              
2065             0[Xx] [0-9A-Fa-f_]+ \. [0-9A-Fa-f_]* [Pp] [+-]? [0-9_]+ |
2066             0[Xx] \. [0-9A-Fa-f_]+ [Pp] [+-]? [0-9_]+ |
2067             0[Xx] [0-9A-Fa-f_]+ |
2068              
2069             # since perl v5.33.5 Core Enhancements New octal syntax 0oddddd
2070              
2071             0[Oo] [0-7_]+ |
2072             0 [0-7_]* |
2073              
2074             0[Bb] [01_]+ |
2075              
2076             [1-9] [0-9_]* \. [0-9_]* [Ee] [+-]? [0-9_]+ |
2077             [1-9] [0-9_]* |
2078             \. [0-9_]+ [Ee] [+-]? [0-9_]+ |
2079             \. [0-9_]+
2080              
2081             ) }xmsgc) {
2082 840         2134 $parsed .= $1;
2083 840         1625 $parsed .= parse_ambiguous_char();
2084             }
2085              
2086             # file test operators on MSWin32
2087             # "\x2D" [-] HYPHEN-MINUS (U+002D)
2088              
2089             # -X -Y -Z 'file' --> mb::_filetest [qw( -X -Y -Z )], 'file'
2090             # -X -Y -Z "file" --> mb::_filetest [qw( -X -Y -Z )], "file"
2091             # -X -Y -Z `file` --> mb::_filetest [qw( -X -Y -Z )], `file`
2092             # -X -Y -Z $file --> mb::_filetest [qw( -X -Y -Z )], $file
2093             # ..., and filetest any word except file handle or directory handle
2094             # -X -Y -Z m// --> mb::_filetest [qw( -X -Y -Z )], m//
2095             # -X -Y -Z q// --> mb::_filetest [qw( -X -Y -Z )], q//
2096             # -X -Y -Z qq// --> mb::_filetest [qw( -X -Y -Z )], qq//
2097             # -X -Y -Z qr// --> mb::_filetest [qw( -X -Y -Z )], qr//
2098             # -X -Y -Z qw// --> mb::_filetest [qw( -X -Y -Z )], qw//
2099             # -X -Y -Z qx// --> mb::_filetest [qw( -X -Y -Z )], qx//
2100             # -X -Y -Z s/// --> mb::_filetest [qw( -X -Y -Z )], s///
2101             # -X -Y -Z tr/// --> mb::_filetest [qw( -X -Y -Z )], tr///
2102             # -X -Y -Z y/// --> mb::_filetest [qw( -X -Y -Z )], y///
2103             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2104             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2105             elsif (/\G ( (?: -[ABCMORSTWXbcdefgkloprstuwxz] \s* )+ \b ) (?= (?: \( \s* )* (?: ' | " | ` | \$ | (?: (?: m | q | qq | qr | qw | qx | s | tr | y ) \b )) ) /xmsgc) {
2106 0         0 $parsed .= "mb::_filetest [qw( $1 )], ";
2107             }
2108              
2109             # filetest file handle or directory handle
2110             # -X -Y -Z _ --> mb::_filetest [qw( -X -Y -Z )], \*_
2111             # -X -Y -Z FILE --> mb::_filetest [qw( -X -Y -Z )], \*FILE
2112             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2113             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvv
2114             elsif (/\G ( (?: -[ABCMORSTWXbcdefgkloprstuwxz] \s* )+ \b ) (?= [A-Za-z_][A-Za-z0-9_]* ) /xmsgc) {
2115 2828         13275 $parsed .= "mb::_filetest [qw( $1)], ";
2116 2828         5750 $parsed .= '\\*';
2117             }
2118              
2119             # -X -Y -Z ... --> mb::_filetest [qw( -X -Y -Z )], ...
2120             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2121             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
2122             elsif (/\G ( (?: -[ABCMORSTWXbcdefgkloprstuwxz] \s* )+ \b ) /xmsgc) {
2123 8409         37083 $parsed .= "mb::_filetest [qw( $1)]";
2124 8409 50       20106 if (my $ambiguous_char = parse_ambiguous_char()) {
2125 0         0 $parsed .= $ambiguous_char;
2126             }
2127             else {
2128 8409         17603 $parsed .= ', ';
2129             }
2130             }
2131              
2132             # yada-yada or triple-dot operator
2133             elsif (/\G ( \.\.\. ) /xmsgc) {
2134 1         4 $parsed .= $1;
2135             }
2136              
2137             # -> and any method
2138             elsif (/\G ( -> \s* [A-Za-z_][A-Za-z_0-9]* ) /xmsgc) {
2139 1         4 $parsed .= $1;
2140             }
2141              
2142             # symbolic operators
2143             elsif (/\G (
2144              
2145             # 12345 | 12345 | 12345 | 12345 | 12345 | 12345 |
2146             != | !~ | ! | # "\x21" [!] EXCLAMATION MARK (U+0021)
2147             \+\+ | \+= | \+ | # "\x2B" [+] PLUS SIGN (U+002B)
2148             , | # "\x2C" [,] COMMA (U+002C)
2149             -- | -= | -> | - | # "\x2D" [-] HYPHEN-MINUS (U+002D)
2150             == | => | =~ | = | # "\x3D" [=] EQUALS SIGN (U+003D)
2151             >> | >= | > | # "\x3E" [>] GREATER-THAN SIGN (U+003E)
2152             \\ | # "\x5C" [\] REVERSE SOLIDUS (U+005C)
2153             \^\^= | \^\^ | \^\.= | \^\. | \^= | \^ | # "\x5E" [^] CIRCUMFLEX ACCENT (U+005E)
2154             \|\|= | \|\| | \|\.= | \|\. | \|= | \| | # "\x7C" [|] VERTICAL LINE (U+007C)
2155             ~~ | ~\. | ~= | ~ # "\x7E" [~] TILDE (U+007E)
2156              
2157             ) /xmsgc) {
2158 121435         374790 $parsed .= $1;
2159             }
2160              
2161             # named operators
2162             elsif (/\G ( (?: and | cmp | eq | ge | gt | isa | le | lt | ne | not | or | x | x= | xor ) \b ) /xmsgc) {
2163 2428         4912 $parsed .= $1;
2164             }
2165              
2166             # $` --> mb::_PREMATCH()
2167             # ${`} --> mb::_PREMATCH()
2168             # $PREMATCH --> mb::_PREMATCH()
2169             # ${PREMATCH} --> mb::_PREMATCH()
2170             # ${^PREMATCH} --> mb::_PREMATCH()
2171             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
2172 20         46 $parsed .= 'mb::_PREMATCH()';
2173 20         111 $parsed .= parse_ambiguous_char();
2174             }
2175              
2176             # $& --> mb::_MATCH()
2177             # ${&} --> mb::_MATCH()
2178             # $MATCH --> mb::_MATCH()
2179             # ${MATCH} --> mb::_MATCH()
2180             # ${^MATCH} --> mb::_MATCH()
2181             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
2182 68         124 $parsed .= 'mb::_MATCH()';
2183 68         129 $parsed .= parse_ambiguous_char();
2184             }
2185              
2186             # $1 --> mb::_CAPTURE(1)
2187             # $2 --> mb::_CAPTURE(2)
2188             # $3 --> mb::_CAPTURE(3)
2189             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
2190 55         210 $parsed .= "mb::_CAPTURE($1)";
2191 55         134 $parsed .= parse_ambiguous_char();
2192             }
2193              
2194             # @{^CAPTURE} --> mb::_CAPTURE()
2195             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
2196 3         8 $parsed .= 'mb::_CAPTURE()';
2197 3         7 $parsed .= parse_ambiguous_char();
2198             }
2199              
2200             # ${^CAPTURE}[0] --> mb::_CAPTURE(1)
2201             # ${^CAPTURE}[1] --> mb::_CAPTURE(2)
2202             # ${^CAPTURE}[2] --> mb::_CAPTURE(3)
2203             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
2204 3         10 my $n_th = quotee_of(parse_expr_balanced($1));
2205 3         8 $parsed .= "mb::_CAPTURE($n_th+1)";
2206 3         7 $parsed .= parse_ambiguous_char();
2207             }
2208              
2209             # @- --> mb::_LAST_MATCH_START()
2210             # @LAST_MATCH_START --> mb::_LAST_MATCH_START()
2211             # @{LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2212             # @{^LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2213             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
2214 12         31 $parsed .= 'mb::_LAST_MATCH_START()';
2215 12         24 $parsed .= parse_ambiguous_char();
2216             }
2217              
2218             # $-[1] --> mb::_LAST_MATCH_START(1)
2219             # $LAST_MATCH_START[1] --> mb::_LAST_MATCH_START(1)
2220             # ${LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2221             # ${^LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2222             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
2223 22         69 my $n_th = quotee_of(parse_expr_balanced($1));
2224 22         64 $parsed .= "mb::_LAST_MATCH_START($n_th)";
2225 22         41 $parsed .= parse_ambiguous_char();
2226             }
2227              
2228             # @+ --> mb::_LAST_MATCH_END()
2229             # @LAST_MATCH_END --> mb::_LAST_MATCH_END()
2230             # @{LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2231             # @{^LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2232             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
2233 12         31 $parsed .= 'mb::_LAST_MATCH_END()';
2234 12         25 $parsed .= parse_ambiguous_char();
2235             }
2236              
2237             # $+[1] --> mb::_LAST_MATCH_END(1)
2238             # $LAST_MATCH_END[1] --> mb::_LAST_MATCH_END(1)
2239             # ${LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2240             # ${^LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2241             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
2242 14         48 my $n_th = quotee_of(parse_expr_balanced($1));
2243 14         41 $parsed .= "mb::_LAST_MATCH_END($n_th)";
2244 14         62 $parsed .= parse_ambiguous_char();
2245             }
2246              
2247             # CORE::do { block } --> CORE::do { block }
2248             # CORE::eval { block } --> CORE::eval { block }
2249             # CORE::try { block } --> CORE::try { block }
2250             # CORE::finally { block } --> CORE::finally { block }
2251             elsif (/\G ( CORE:: (?: do | eval | try | finally ) \s* ) ( \{ ) /xmsgc) {
2252 11         35 $parsed .= $1;
2253 11         28 $parsed .= parse_expr_balanced($2);
2254 11         24 $parsed .= parse_ambiguous_char();
2255             }
2256              
2257             # mb::do { block } --> do { block }
2258             # mb::eval { block } --> eval { block }
2259             # mb::try { block } --> try { block }
2260             # mb::finally { block } --> finally { block }
2261             # do { block } --> do { block }
2262             # eval { block } --> eval { block }
2263             # try { block } --> try { block }
2264             # finally { block } --> finally { block }
2265             elsif (/\G (?: mb:: | $old_package )? ( (?: do | eval | try | finally ) \s* ) ( \{ ) /xmsgc) {
2266 30         100 $parsed .= $1;
2267 30         70 $parsed .= parse_expr_balanced($2);
2268 30         65 $parsed .= parse_ambiguous_char();
2269             }
2270              
2271             # $#{}, ${}, @{}, %{}, &{}, *{}, defer {}, sub {}
2272             # "\x24" [$] DOLLAR SIGN (U+0024)
2273             elsif (/\G ((?: \$[#] | [\$\@%&*] | defer | sub ) \s* ) ( \{ ) /xmsgc) {
2274 10         38 $parsed .= $1;
2275 10         26 $parsed .= parse_expr_balanced($2);
2276 10         22 $parsed .= parse_ambiguous_char();
2277             }
2278              
2279             # mb::do --> mb::do
2280             # CORE::do --> CORE::do
2281             # do --> do
2282             elsif (/\G ( (?: mb:: | CORE:: )? do ) \b /xmsgc) {
2283 3         10 $parsed .= $1;
2284             }
2285              
2286             # mb::eval --> mb::eval
2287             # CORE::eval --> CORE::eval
2288             # eval --> eval
2289             elsif (/\G ( (?: mb:: | CORE:: )? eval ) \b /xmsgc) {
2290 3         11 $parsed .= $1;
2291 3         8 $parsed .= parse_ambiguous_char();
2292             }
2293              
2294             # last index of array
2295             elsif (/\G ( [\$] [#] (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2296 3         13 $parsed .= $1;
2297 3         7 $parsed .= parse_ambiguous_char();
2298             }
2299              
2300             # scalar variable
2301             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) {
2302 4964         13802 $parsed .= $1;
2303 4964         8799 $parsed .= parse_ambiguous_char();
2304             }
2305              
2306             # array variable
2307             # "\x40" [@] COMMERCIAL AT (U+0040)
2308             elsif (/\G ( [\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [_] ) ) /xmsgc) {
2309 119         323 $parsed .= $1;
2310 119         232 $parsed .= parse_ambiguous_char();
2311             }
2312              
2313             # hash variable
2314             elsif (/\G ( [\%\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [!+\-] ) ) /xmsgc) {
2315 11         41 $parsed .= $1;
2316 11         25 $parsed .= parse_ambiguous_char();
2317             }
2318              
2319             # user subroutine call
2320             # type glob
2321             elsif (/\G ( [&*] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2322 12         44 $parsed .= $1;
2323 12         23 $parsed .= parse_ambiguous_char();
2324             }
2325              
2326             # comment
2327             # "\x23" [#] NUMBER SIGN (U+0023)
2328             elsif (/\G ( [#] [^\n]* ) /xmsgc) {
2329 17         44 $parsed .= $1;
2330             }
2331              
2332             # 2-quotes
2333              
2334             # '...'
2335             # "\x27" ['] APOSTROPHE (U+0027)
2336             elsif (m{\G ( ' ) }xmsgc) {
2337 5828         14536 $parsed .= parse_q__like_endswith($1);
2338 5828         13176 $parsed .= parse_ambiguous_char();
2339             }
2340              
2341             # "...", `...`
2342             # "\x22" ["] QUOTATION MARK (U+0022)
2343             # "\x60" [`] GRAVE ACCENT (U+0060)
2344             elsif (m{\G ( ["`] ) }xmsgc) {
2345 126173         400950 $parsed .= parse_qq_like_endswith($1);
2346 126173         339988 $parsed .= parse_ambiguous_char();
2347             }
2348              
2349             # /.../
2350             elsif (m{\G ( [/] ) }xmsgc) {
2351 118038         365619 my $regexp = parse_re_endswith('m',$1);
2352 118038         330017 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2353              
2354             # /xx modifier
2355 118038 100       382938 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2356 28         77 $regexp = mb::_ignore_space($regexp);
2357             }
2358              
2359             # /i modifier
2360 118038 100       218946 if ($modifier_i) {
2361 23         60 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2362             }
2363             else {
2364 118015         247990 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2365             }
2366 118038         245236 $parsed .= parse_ambiguous_char();
2367             }
2368              
2369             # ?...?
2370             elsif (m{\G ( [?] ) }xmsgc) {
2371 1         4 my $regexp = parse_re_endswith('m',$1);
2372 1         5 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2373              
2374             # /xx modifier
2375 1 50       5 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2376 0         0 $regexp = mb::_ignore_space($regexp);
2377             }
2378              
2379             # /i modifier
2380 1 50       4 if ($modifier_i) {
2381 0         0 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2382             }
2383             else {
2384 1         4 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2385             }
2386 1         3 $parsed .= parse_ambiguous_char();
2387             }
2388              
2389             # <<>> double-diamond operator
2390             elsif (/\G ( <<>> ) /xmsgc) {
2391 1         5 $parsed .= $1;
2392 1         4 $parsed .= parse_ambiguous_char();
2393             }
2394              
2395             # diamond operator
2396             # <${file}>
2397             # <$file>
2398             #
2399             elsif (/\G (<) ((?:(?!\s)$x)*?) (>) /xmsgc) {
2400 5         650 my($open_bracket, $quotee, $close_bracket) = ($1, $2, $3);
2401 5         8 $parsed .= $open_bracket;
2402 5         129 while ($quotee =~ /\G ($x) /xmsgc) {
2403 25         54 $parsed .= escape_qq($1, $close_bracket);
2404             }
2405 5         12 $parsed .= $close_bracket;
2406 5         13 $parsed .= parse_ambiguous_char();
2407             }
2408              
2409             # qw/.../, q/.../
2410             elsif (/\G ( qw | q ) \b /xmsgc) {
2411 160         546 $parsed .= $1;
2412 160 100       964 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
  2 100       7  
    100          
    100          
    100          
    50          
2413 2         7 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2414 34         94 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); }
2415 6         17 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); }
2416 48         135 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2417 68         122 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2418 68         221 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2419 4         9 $parsed .= $1;
2420             }
2421 68 100       367 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
  6 100       16  
    100          
    100          
    50          
2422 2         8 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2423 8         26 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); }
2424 2         5 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); }
2425 50         123 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2426 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2427             }
2428 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2429 160         418 $parsed .= parse_ambiguous_char();
2430             }
2431              
2432             # qq/.../
2433             elsif (/\G ( qq ) \b /xmsgc) {
2434 69         184 $parsed .= $1;
2435 69 100       332 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  1 100       3  
    100          
    100          
    100          
    50          
2436 1         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); } # qq'...' works as "..."
2437 6         18 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2438 3         8 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2439 24         53 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2440 34         47 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2441 34         80 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2442 2         6 $parsed .= $1;
2443             }
2444 34 100       151 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  3 100       5  
    100          
    100          
    50          
2445 1         2 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); } # qq'...' works as "..."
2446 4         7 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2447 1         3 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2448 25         44 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2449 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2450             }
2451 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2452 69         154 $parsed .= parse_ambiguous_char();
2453             }
2454              
2455             # qx/.../
2456             elsif (/\G ( qx ) \b /xmsgc) {
2457 67         140 $parsed .= $1;
2458 67 100       798 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  1 100       3  
    100          
    100          
    100          
    50          
2459 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2460 4         9 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2461 3         10 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2462 24         38 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2463 34         45 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2464 34         81 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2465 2         4 $parsed .= $1;
2466             }
2467 34 100       118 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  3 100       4  
    100          
    100          
    50          
2468 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2469 4         8 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2470 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2471 25         39 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2472 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2473             }
2474 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2475 67         131 $parsed .= parse_ambiguous_char();
2476             }
2477              
2478             # m/.../, qr/.../
2479             elsif (/\G ( m | qr ) \b /xmsgc) {
2480 1655         4870 $parsed .= $1;
2481 1655         2652 my $regexp = '';
2482 1655 100       7161 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr#...#
  2 100       6  
    100          
    100          
    100          
    100          
    50          
2483 643         1326 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr'...'
2484 8         23 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr{...}
2485 360         981 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr/.../
2486 530         1419 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # qr@...@
2487 44         98 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr?...?
2488 68         109 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # qr SPACE ...
  68         97  
2489 68         186 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2490 4         9 $parsed .= $1;
2491             }
2492 68 100       306 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE A...A
  6 100       14  
    100          
    100          
    100          
    50          
2493 2         23 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr SPACE '...'
2494 8         19 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr SPACE {...}
2495 2         5 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE /.../
2496 4         11 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # qr SPACE @...@
2497 46         89 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE ?...?
2498 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2499             }
2500 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2501              
2502 1655         3766 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2503              
2504             # /xx modifier
2505 1655 100       5058 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2506 2         6 $regexp = mb::_ignore_space($regexp);
2507             }
2508              
2509             # /i modifier
2510 1655 100       2975 if ($modifier_i) {
2511 37         99 $parsed .= sprintf('{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2512             }
2513             else {
2514 1618         3413 $parsed .= sprintf('{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2515             }
2516 1655         3120 $parsed .= parse_ambiguous_char();
2517             }
2518              
2519             # 3-quotes
2520              
2521             # s/.../.../
2522             elsif (/\G ( s ) \b /xmsgc) {
2523 1712         4795 $parsed .= $1;
2524 1712         2778 my $regexp = '';
2525 1712         2352 my $comment = '';
2526 1712         2467 my @replacement = ();
2527 1712 100       7668 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s#...#...#
  1 100       4  
  1 100       4  
    100          
    100          
    100          
    50          
2528 286         807 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s'...'...'
  286         890  
2529 240         467 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s{...}...
2530 240 50       1150 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2531 4         12 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}'...'
2532 16         28 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{}{...}
2533 4         10 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}/.../
2534 96         1481 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}?...?
2535 120         166 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s{} SPACE ...
2536 120         296 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2537 0         0 $comment .= $1;
2538             }
2539 120 50       496 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2540 4         13 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE '...'
2541 16         30 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{} SPACE {...}
2542 4         14 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE /.../
2543 96         185 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE ?...?
2544 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2545             }
2546 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2547             }
2548 353         914 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s/.../.../
  353         954  
2549 528         1241 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('s',$1)) . '`');
2550 528         1178 @replacement = parse_qq_like_endswith($1); } # s@...@...@
2551 22         116 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s?...?...?
  22         64  
2552 282         464 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # s SPACE ...
  282         363  
2553 282         784 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2554 12         24 $parsed .= $1;
2555             }
2556 282 100       1069 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE A...A...A
  12 100       30  
  12 100       34  
    100          
    100          
    50          
2557 1         27 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE '...'...'
  1         4  
2558 244         522 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s SPACE {...}...
2559 244 100       1297 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}#...#
  1 100       2  
    100          
    100          
    100          
    50          
2560 4         12 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}'...'
2561 17         24 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {}{...}
2562 4         12 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}/.../
2563 96         187 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}?...?
2564 122         214 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s SPACE {} SPACE ...
2565 122         339 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2566 8         18 $comment .= $1;
2567             }
2568 122 50       524 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          
2569 4         20 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE '...'
2570 18         31 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {} SPACE {...}
2571 4         14 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE /.../
2572 96         207 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE ?...?
2573 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2574             }
2575 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2576             }
2577 1         4 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE /.../.../
  1         5  
2578 2         8 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('s',$1)) . '`');
2579 2         8 @replacement = parse_qq_like_endswith($1); } # s SPACE @...@...@
2580 22         57 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE ?...?...?
  22         77  
2581 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2582             }
2583 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2584              
2585 1712         3726 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2586 1712         3171 my $replacement = '';
2587 1712         2307 my $eval = '';
2588              
2589             # has /e modifier
2590 1712 100       6146 if (my $e = $modifier_cegr =~ tr/e//d) {
    100          
    100          
2591 9         19 $replacement = 'q'. $replacement[1]; # q-type quotee
2592 9         26 $eval = 'mb::eval ' x $e;
2593             }
2594              
2595             # s''q-quotee'
2596             elsif ($replacement[0] =~ /\A ' /xms) {
2597 300         592 $replacement = $replacement[1]; # q-type quotee
2598             }
2599              
2600             # s##qq-quotee#
2601             elsif ($replacement[0] =~ /\A [#] /xms) {
2602 2         3 $replacement = 'qq' . $replacement[0]; # qq-type quotee
2603             }
2604              
2605             # s//qq-quotee/
2606             else {
2607 1401         2021 $replacement = 'qq ' . $replacement[0]; # qq-type quotee
2608             }
2609              
2610             # /xx modifier
2611 1712 100       3623 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2612 1         4 $regexp = mb::_ignore_space($regexp);
2613             }
2614              
2615             # /i modifier
2616 1712 100       2852 if ($modifier_i) {
2617 18         49 $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);
2618             }
2619             else {
2620 1694         3862 $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);
2621             }
2622 1712         3118 $parsed .= parse_ambiguous_char();
2623             }
2624              
2625             # tr/.../.../, y/.../.../
2626             elsif (/\G (?: tr | y ) \b /xmsgc) {
2627 2153         4541 $parsed .= 's'; # not 'tr'
2628 2153         3311 my $search = '';
2629 2153         2816 my $comment = '';
2630 2153         2864 my $replacement = '';
2631 2153 100       11941 if (/\G ( [#] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr#...#...#
  4 100       15  
  4 100       9  
    100          
    100          
    50          
2632 4         11 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr'...'...'
  4         10  
2633 912         2172 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_tr_like_balanced($1); # tr{...}...
2634 912 50       6320 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2635 16         36 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}'...'
2636 64         147 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr{}{...}
2637 16         38 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}/.../
2638 360         700 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}?...?
2639 456         1076 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr{} SPACE ...
2640 456         1481 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2641 0         0 $comment .= $1;
2642             }
2643 456 50       2545 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2644 16         32 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE '...'
2645 64         141 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr{} SPACE {...}
2646 16         35 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE /.../
2647 360         698 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE ?...?
2648 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2649             }
2650 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2651             }
2652 92         160 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr/.../.../
  92         144  
2653 131         350 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr?...?...?
  131         265  
2654 1010         2241 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; # tr SPACE ...
2655 1010         3491 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2656 0         0 $parsed .= $1;
2657             }
2658 1010 50       4058 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE A...A...A
  0 100       0  
  0 100       0  
    100          
    50          
2659 4         14 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE '...'...'
  4         12  
2660 912         2281 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_tr_like_balanced($1); # tr SPACE {...}...
2661 912 50       6320 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2662 16         36 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}'...'
2663 64         125 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr SPACE {}{...}
2664 16         35 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}/.../
2665 360         699 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}?...?
2666 456         1033 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr SPACE {} SPACE ...
2667 456         1431 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2668 0         0 $comment .= $1;
2669             }
2670 456 50       2555 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2671 16         35 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE '...'
2672 64         125 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr SPACE {} SPACE {...}
2673 16         35 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE /.../
2674 360         718 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE ?...?
2675 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2676             }
2677 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2678             }
2679 4         12 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE /.../.../
  4         12  
2680 90         253 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE ?...?...?
  90         218  
2681 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2682             }
2683 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2684              
2685             # modifier
2686 2153         4750 my($modifier_not_r, $modifier_r) = parse_tr_modifier();
2687 2153 50       5329 if ($modifier_r) {
    100          
2688 0         0 $parsed .= sprintf(q<{[\x00-\xFF]*}%s{mb::tr($&,q%s,q%s,'%sr')}ser>, $comment, $search, $replacement, $modifier_not_r);
2689             }
2690             elsif ($modifier_not_r =~ /s/) {
2691              
2692             # this implementation cannot return right count of codepoints replaced.
2693             # if you want right count, you can call mb::tr() yourself.
2694 28         106 $parsed .= sprintf(q<{[\x00-\xFF]+}%s{mb::tr($&,q%s,q%s,'%sr')}se>, $comment, $search, $replacement, $modifier_not_r);
2695             }
2696             else {
2697              
2698             # $parsed .= sprintf(q<{@{mb::_dot}}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $comment, $search, $replacement, $modifier_not_r);
2699             #------------------------------------------------------------------------------------------------------------------------------------------------
2700             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (9,111222DE1)
2701             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (9,111222DE1)
2702             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (9,11122DE1)
2703             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (9,11122DE1)
2704             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (9,AAABBC22A)
2705             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (9,AAABBC22A)
2706             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (9,AAABBCA)
2707             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (9,AAABBCA)
2708              
2709             # $parsed .= sprintf(q<{[\x00-\xFF]*}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $comment, $search, $replacement, $modifier_not_r);
2710             #------------------------------------------------------------------------------------------------------------------------------------------------
2711             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (2,111222DE1)
2712             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (2,12DE1)
2713             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (2,11122DE1)
2714             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (2,12DE1)
2715             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (2,AAABBC22A)
2716             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (2,AAABBC2A)
2717             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (2,AAABBCA)
2718             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (2,AAABBCA)
2719              
2720             # if ($modifier_not_r =~ /c/) {
2721             # $parsed .= sprintf(q<{@{[mb::_cc(q[^%s])]}}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $search, $comment, $search, $replacement, $modifier_not_r);
2722             # }
2723             # else {
2724             # $parsed .= sprintf(q<{@{[mb::_cc(q[%s])]}}%s{mb::tr($&,q%s,q%s,'%sr')}msge>, $search, $comment, $search, $replacement, $modifier_not_r);
2725             # }
2726             #------------------------------------------------------------------------------------------------------------------------------------------------
2727             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (7,111222DE1)
2728             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (7,111222DE1)
2729             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (7,11122DE1)
2730             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (7,11122DE1)
2731             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (2,AAABBC22A)
2732             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (2,AAABBC22A)
2733             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (2,AAABBCA)
2734             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (2,AAABBCA)
2735              
2736             # better idea of mine
2737 2125 100       3273 if ($modifier_not_r =~ /c/) {
2738 16         40 $parsed .= sprintf(q<{(\\G${mb::_anchor})((?!%s)@{mb::_dot})}%s{$1.mb::tr($2,q%s,q%s,'%sr')}sge>, codepoint_tr($search), $comment, $search, $replacement, $modifier_not_r);
2739             }
2740             else {
2741 2109         4295 $parsed .= sprintf(q<{(\\G${mb::_anchor})((?=%s)@{mb::_dot})}%s{$1.mb::tr($2,q%s,q%s,'%sr')}sge>, codepoint_tr($search), $comment, $search, $replacement, $modifier_not_r);
2742             }
2743             #------------------------------------------------------------------------------------------------------------------------------------------------
2744             # do { $_='AAABBCDEA'; $r=tr/ABC/12/; ($r,$_) } => (7,111222DE1)
2745             # do { $_='AAABBCDEA'; $r=tr/ABC/12/s; ($r,$_) } => (1,12DE1)
2746             # do { $_='AAABBCDEA'; $r=tr/ABC/12/d; ($r,$_) } => (7,11122DE1)
2747             # do { $_='AAABBCDEA'; $r=tr/ABC/12/ds; ($r,$_) } => (1,12DE1)
2748             # do { $_='AAABBCDEA'; $r=tr/ABC/12/c; ($r,$_) } => (2,AAABBC22A)
2749             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cs; ($r,$_) } => (1,AAABBC2A)
2750             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cd; ($r,$_) } => (2,AAABBCA)
2751             # do { $_='AAABBCDEA'; $r=tr/ABC/12/cds; ($r,$_) } => (1,AAABBCA)
2752             }
2753 2153         4753 $parsed .= parse_ambiguous_char();
2754             }
2755              
2756             # indented here document
2757             elsif (/\G ( <<~ ) /xmsgc) {
2758 11         35 $parsed .= $1;
2759 11 100       102 if (/\G ( ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  1 100       2  
  1 100       8  
    100          
    50          
2760 1         4 elsif (/\G ( \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; }
  1         6  
2761 3         7 elsif (/\G ( [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; }
  3         17  
2762 3         8 elsif (/\G ( [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  3         14  
2763 3         7 elsif (/\G ( [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  3         16  
2764 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2765 11         25 $parsed .= parse_ambiguous_char();
2766             }
2767              
2768             # here document
2769             elsif (/\G ( << ) /xmsgc) {
2770 12         45 $parsed .= $1;
2771 12 100       94 if (/\G ( ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  1 100       3  
  1 100       6  
    100          
    50          
2772 1         74 elsif (/\G ( \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; }
  1         7  
2773 4         10 elsif (/\G ( [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; }
  4         20  
2774 3         7 elsif (/\G ( [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  3         15  
2775 3         7 elsif (/\G ( [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  3         13  
2776 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2777 12         32 $parsed .= parse_ambiguous_char();
2778             }
2779              
2780             # sub subroutine();
2781             elsif (/\G ( sub \s+ [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* \s* ) /xmsgc) {
2782 18         63 $parsed .= $1;
2783             }
2784              
2785             # while (<<>>)
2786             elsif (/\G ( while \s* \( \s* ) ( <<>> ) ( \s* \) ) /xmsgc) {
2787 2         8 $parsed .= $1;
2788 2         5 $parsed .= $2;
2789 2         7 $parsed .= $3;
2790             }
2791              
2792             # while (<${file}>)
2793             # while (<$file>)
2794             # while ()
2795             # while ()
2796             elsif (/\G ( while \s* \( \s* ) (<) ((?:(?!\s)$x)*?) (>) ( \s* \) ) /xmsgc) {
2797 8         27 $parsed .= $1;
2798 8         57 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2799 8         15 my $close_bracket2 = $5;
2800 8         15 $parsed .= $open_bracket;
2801 8         127 while ($quotee =~ /\G ($x) /xmsgc) {
2802 50         96 $parsed .= escape_qq($1, $close_bracket);
2803             }
2804 8         15 $parsed .= $close_bracket;
2805 8         17 $parsed .= $close_bracket2;
2806             }
2807              
2808             # while <<>>
2809             elsif (/\G ( while \s* ) ( <<>> ) /xmsgc) {
2810 0         0 $parsed .= $1;
2811 0         0 $parsed .= $2;
2812             }
2813              
2814             # while <${file}>
2815             # while <$file>
2816             # while
2817             # while
2818             elsif (/\G ( while \s* ) (<) ((?:(?!\s)$x)*?) (>) /xmsgc) {
2819 0         0 $parsed .= $1;
2820 0         0 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2821 0         0 $parsed .= $open_bracket;
2822 0         0 while ($quotee =~ /\G ($x) /xmsgc) {
2823 0         0 $parsed .= escape_qq($1, $close_bracket);
2824             }
2825 0         0 $parsed .= $close_bracket;
2826             }
2827              
2828             # if (expr)
2829             # elsif (expr)
2830             # unless (expr)
2831             # while (expr)
2832             # until (expr)
2833             # given (expr)
2834             # when (expr)
2835             # CORE::catch (expr)
2836             # catch (expr)
2837             elsif (/\G ( (?: if | elsif | unless | while | until | given | when | (?: CORE:: )? catch ) \s* ) ( \( ) /xmsgc) {
2838 25         87 $parsed .= $1;
2839              
2840             # outputs expr
2841 25         57 my $expr = parse_expr_balanced($2);
2842 25         47 $parsed .= $expr;
2843             }
2844              
2845             # mb::catch (expr) --> catch (expr)
2846             elsif (/\G mb:: ( catch \s* ) ( \( ) /xmsgc) {
2847 4         15 $parsed .= $1;
2848              
2849             # outputs expr
2850 4         11 my $expr = parse_expr_balanced($2);
2851 4         8 $parsed .= $expr;
2852             }
2853              
2854             # else
2855             elsif (/\G ( else ) \b /xmsgc) {
2856 1         5 $parsed .= $1;
2857             }
2858              
2859             # ... if expr;
2860             # ... unless expr;
2861             # ... while expr;
2862             # ... until expr;
2863             elsif (/\G ( if | unless | while | until ) \b /xmsgc) {
2864 8         21 $parsed .= $1;
2865             }
2866              
2867             # foreach my $var (expr) --> foreach my $var (expr)
2868             # for my $var (expr) --> for my $var (expr)
2869             elsif (/\G ( (?: foreach | for ) \s+ my \s* [\$] [A-Za-z_][A-Za-z_0-9]* ) ( \( ) /xmsgc) {
2870 0         0 $parsed .= $1;
2871 0         0 $parsed .= parse_expr_balanced($2);
2872             }
2873              
2874             # foreach $var (expr) --> foreach $var (expr)
2875             # for $var (expr) --> for $var (expr)
2876             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) {
2877 0         0 $parsed .= $1;
2878 0         0 $parsed .= parse_expr_balanced($2);
2879             }
2880              
2881             # foreach (expr1; expr2; expr3) --> foreach (expr1; expr2; expr3)
2882             # foreach (expr) --> foreach (expr)
2883             # for (expr1; expr2; expr3) --> for (expr1; expr2; expr3)
2884             # for (expr) --> for (expr)
2885             elsif (/\G ( (?: foreach | for ) \s* ) ( \( ) /xmsgc) {
2886 4         17 $parsed .= $1;
2887 4         11 $parsed .= parse_expr_balanced($2);
2888             }
2889              
2890             # CORE::split --> mb::_split
2891             # mb::split --> mb::_split
2892             # split --> mb::_split
2893             elsif (/\G (?: CORE:: | mb:: | $old_package )? ( split ) \b /xmsgc) {
2894 679         1216 $parsed .= "mb::_split";
2895              
2896             # parse \s and '('
2897 679         792 while (1) {
2898 1364 100       3406 if (/\G ( \s+ ) /xmsgc) {
    100          
    100          
2899 296         653 $parsed .= $1;
2900             }
2901             elsif (/\G ( \( ) /xmsgc) {
2902 389         736 $parsed .= $1;
2903             }
2904             elsif (/\G ( \# .* \n ) /xmgc) {
2905 16         23 $parsed .= $1;
2906 16         17 last;
2907             }
2908             else {
2909 663         914 last;
2910             }
2911             }
2912 679         893 my $regexp = '';
2913              
2914             # split /^/ --> mb::_split qr/^/m
2915             # split /.../ --> mb::_split qr/.../
2916 679 100       1995 if (m{\G ( [/] ) }xmsgc) {
    100          
2917 24         38 $parsed .= "qr";
2918 24         67 $regexp = parse_re_endswith('m',$1); # split /.../
2919 24         83 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2920              
2921             # P.794 29.2.161. split
2922             # in Chapter 29: Functions
2923             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2924              
2925             # P.951 split
2926             # in Chapter 27: Functions
2927             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2928              
2929             # said "The //m modifier is assumed when you split on the pattern /^/",
2930             # but perl5.008 is not so. Therefore, this software adds //m.
2931             # (and so on)
2932              
2933 24 100       110 if ($modifier_not_cegir !~ /m/xms) {
2934 18         31 $modifier_not_cegir .= 'm';
2935             }
2936              
2937             # /xx modifier
2938 24 100       74 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2939 1         3 $regexp = mb::_ignore_space($regexp);
2940             }
2941              
2942             # /i modifier
2943 24 100       58 if ($modifier_i) {
2944 6         18 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2945             }
2946             else {
2947 18         49 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2948             }
2949             }
2950              
2951             # split m/^/ --> mb::_split qr/^/m
2952             # split m/.../ --> mb::_split qr/.../
2953             elsif (/\G ( m | qr ) \b /xmsgc) {
2954 611         714 $parsed .= "qr";
2955              
2956 611 100       2558 if (/\G ( [#] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr#...#
  8 100       19  
    100          
    100          
    100          
    100          
    50          
2957 8         23 elsif (/\G ( ['] ) /xmsgc) { $regexp = parse_re_as_q_endswith('m',$1); } # split qr'...'
2958 32         62 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp = parse_re_balanced('m',$1); } # split qr{...}
2959 83         193 elsif (m{\G( [/] ) }xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr/.../
2960 16         32 elsif (/\G ( [:\@] ) /xmsgc) { $regexp = ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # split qr@...@
2961 184         345 elsif (/\G ( [\S] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr?...?
2962 280         462 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp = $1; # split qr SPACE ...
  280         350  
2963 280         587 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2964 32         61 $parsed .= $1;
2965             }
2966 280 100       1109 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE A...A
  24 100       45  
    100          
    100          
    100          
    50          
2967 8         27 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # split qr SPACE '...'
2968 32         77 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # split qr SPACE {...}
2969 8         15 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE /.../
2970 16         30 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # split qr SPACE @...@
2971 192         315 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE ?...?
2972 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2973             }
2974 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2975              
2976 611         1021 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2977              
2978 611 100       1296 if ($modifier_not_cegir !~ /m/xms) {
2979 607         749 $modifier_not_cegir .= 'm';
2980             }
2981              
2982             # /xx modifier
2983 611 100       1251 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2984 1         3 $regexp = mb::_ignore_space($regexp);
2985             }
2986              
2987             # /i modifier
2988 611 100       888 if ($modifier_i) {
2989 16         31 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2990             }
2991             else {
2992 595         922 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2993             }
2994             }
2995              
2996 679         1122 $parsed .= parse_ambiguous_char();
2997             }
2998              
2999             # provides bare Perl and JPerl compatible functions
3000             elsif (/\G ( (?: lc | lcfirst | uc | ucfirst ) ) \b /xmsgc) {
3001 15         62 $parsed .= "mb::$1";
3002 15         36 $parsed .= parse_ambiguous_char();
3003             }
3004              
3005             # CORE::require, mb::require, require
3006             elsif (/\G ( (?: CORE:: | mb:: )? require ) /xmsgc) {
3007 3         10 $parsed .= $1;
3008 3         7 $parsed .= parse_ambiguous_char();
3009             }
3010              
3011             # mb::use --> BEGIN { mb::require ... }
3012             # mb::no --> BEGIN { mb::require ... }
3013             elsif (/\G ( mb::use | mb::no ) \b /xmsgc) {
3014 42   50     449 my $method = { 'mb::use'=>'import', 'mb::no'=>'unimport' }->{$1} || die;
3015 42         158 $parsed .= "BEGIN { mb::require";
3016 42         173 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3017 58         217 $parsed .= $1;
3018             }
3019 42 50       163 if (/\G ( [A-Za-z_][A-Za-z_0-9]* (?: ::[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
3020 42         112 my $module = $1;
3021 42         102 $parsed .= qq{'$module';};
3022 42         136 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3023 54         176 $parsed .= $1;
3024             }
3025 42 100       117 if (/\G ( [0-9]+ (?: \.[0-9]+)* ) /xmsgc) {
3026 26         44 my $version = $1;
3027 26         77 $parsed .= qq{$module->VERSION($version);};
3028 26         127 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3029 46         130 $parsed .= $1;
3030             }
3031             }
3032 42         206 my $list = parse_expr_endswith(qr< [;\}] | \z >xms);
3033 42 100       2666 if ($list eq '') {
    100          
3034 12         58 $parsed .= qq{ $module->$method; };
3035             }
3036             elsif (scalar(CORE::eval("()=$list")) == 0) {
3037             }
3038             else {
3039 22         85 $parsed .= qq{ $module->$method($list); };
3040             }
3041             }
3042 42         140 $parsed .= "}";
3043             }
3044              
3045             # mb::getc() --> mb::getc()
3046             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3047             # vvvvvvvvvvvv
3048             elsif (/\G ( mb::getc ) (?= (?: \s* \( )+ \s* \) ) /xmsgc) {
3049 1         4 $parsed .= $1;
3050             }
3051              
3052             # mb::getc($fh) --> mb::getc($fh)
3053             # mb::getc $fh --> mb::getc $fh
3054             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3055             # vvvvvvvvvvvv
3056             elsif (/\G ( mb::getc ) (?= (?: \s* \( )* \s* \$ ) /xmsgc) {
3057 2         7 $parsed .= $1;
3058             }
3059              
3060             # mb::getc(FILE) --> mb::getc(\*FILE)
3061             # mb::getc FILE --> mb::getc \*FILE
3062             # vvvvvvvvvvvvvvvvvvvvv
3063             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3064             elsif (/\G ( mb::getc ) \b ( (?: \s* \( )* \s* ) (?= [A-Za-z_][A-Za-z0-9_]* \b ) /xmsgc) {
3065 2         5 $parsed .= $1;
3066 2         3 $parsed .= $2;
3067 2         3 $parsed .= '\\*';
3068             }
3069              
3070             # mb::getc --> mb::getc
3071             elsif (/\G ( mb::getc ) /xmsgc) {
3072 1         2 $parsed .= $1;
3073 1         3 $parsed .= parse_ambiguous_char();
3074             }
3075              
3076             # CORE::functions that allow zero parameters
3077             # mb::functions that allow zero parameters
3078             elsif (/\G ( (?: CORE:: | mb:: )? (?:
3079             chop |
3080             chr |
3081             getc |
3082             lc |
3083             lcfirst |
3084             length |
3085             ord |
3086             uc |
3087             ucfirst
3088             ) ) \b /xmsgc) {
3089 23         71 $parsed .= $1;
3090 23         47 $parsed .= parse_ambiguous_char();
3091             }
3092              
3093             # CORE::functions that must parameters
3094             # mb::functions that must parameters
3095             elsif (/\G ( (?: CORE:: | mb:: )? (?:
3096             index |
3097             reverse |
3098             rindex |
3099             substr
3100             ) ) \b /xmsgc) {
3101 26         142 $parsed .= $1;
3102             }
3103              
3104             # mb::subroutines
3105             elsif (/\G ( mb:: (?: index_byte | rindex_byte ) ) \b /xmsgc) {
3106 2         9 $parsed .= $1;
3107             }
3108              
3109             # CORE::functions that allow zero parameters
3110             # functions that allow zero parameters
3111             elsif (/\G ( (?: CORE:: )? (?:
3112             _ |
3113             abs |
3114             chomp |
3115             cos |
3116             exp |
3117             fc |
3118             hex |
3119             int |
3120             __LINE__ |
3121             log |
3122             oct |
3123             pop |
3124             pos |
3125             quotemeta |
3126             rand |
3127             rmdir |
3128             shift |
3129             sin |
3130             sqrt |
3131             tell |
3132             time |
3133             umask |
3134             wantarray
3135             ) ) \b /xmsgc) {
3136 2884         10800 $parsed .= $1;
3137 2884         6896 $parsed .= parse_ambiguous_char();
3138             }
3139              
3140             # lstat(), stat() on MSWin32
3141              
3142             # lstat() --> mb::_lstat()
3143             # stat() --> mb::_stat()
3144             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3145             # vvvvvvvvvvvv
3146             elsif (/\G ( lstat | stat ) (?= (?: \s* \( )+ \s* \) ) /xmsgc) {
3147 2         5 $parsed .= "mb::_$1";
3148             }
3149              
3150             # lstat(...) --> mb::_lstat(...)
3151             # stat(...) --> mb::_stat(...)
3152             # vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3153             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3154             elsif (/\G ( lstat | stat ) (?= (?: \s* \( )* \b (?: ' | " | ` | m | q | qq | qr | qw | qx | s | tr | y | \$ ) \b ) /xmsgc) {
3155 18         70 $parsed .= "mb::_$1";
3156             }
3157              
3158             # lstat(FILE) --> mb::_lstat(\*FILE)
3159             # lstat FILE --> mb::_lstat \*FILE
3160             # stat(FILE) --> mb::_stat(\*FILE)
3161             # stat FILE --> mb::_stat \*FILE
3162             # vvvvvvvvvvvvvvvvvvvvv
3163             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3164             elsif (/\G ( lstat | stat ) \b ( (?: \s* \( )* \s* ) (?= [A-Za-z_][A-Za-z0-9_]* \b ) /xmsgc) {
3165 10         29 $parsed .= "mb::_$1";
3166 10         20 $parsed .= $2;
3167 10         14 $parsed .= '\\*';
3168             }
3169              
3170             # opendir(DIR, ...) --> mb::_opendir(\*DIR, ...)
3171             # opendir DIR, ... --> mb::_opendir \*DIR, ...
3172             # vvvvvvvvvvvvvvvvvvvvv
3173             # vvvvvvvvvvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3174             elsif (/\G ( opendir ) \b ( (?: \s* \( )* \s* ) (?= [A-Za-z_][A-Za-z0-9_]* \s* , ) /xmsgc) {
3175 4         23 $parsed .= "mb::_$1";
3176 4         10 $parsed .= $2;
3177 4         7 $parsed .= '\\*';
3178             }
3179              
3180             # function --> mb::subroutine on MSWin32
3181             # implements run on any systems by transpiling once
3182             elsif (/\G ( chdir | lstat | stat | unlink ) \b /xmsgc) {
3183 32         137 $parsed .= "mb::_$1";
3184 32         75 $parsed .= parse_ambiguous_char();
3185             }
3186             elsif (/\G ( opendir ) \b /xmsgc) {
3187 4         17 $parsed .= "mb::_$1";
3188             }
3189              
3190             # Carp::carp <
3191             # Carp::cluck <
3192             # Carp::confess <
3193             # Carp::croak <
3194             # carp <
3195             # cluck <
3196             # confess <
3197             # croak <
3198             # die <
3199             # print <
3200             # printf <
3201             # say <
3202             # warn <
3203             elsif (/\G (
3204             Carp::carp |
3205             Carp::cluck |
3206             Carp::confess |
3207             Carp::croak |
3208             carp |
3209             cluck |
3210             confess |
3211             croak |
3212             die |
3213             print |
3214             printf |
3215             say |
3216             warn
3217             ) (?= (?: \s+ | [#] .* )* << ) /xgc) {
3218 0         0 $parsed .= $1;
3219             # without $parsed .= parse_ambiguous_char();
3220             }
3221              
3222             # printf FILEHANDLE <
3223             # print FILEHANDLE <
3224             # say FILEHANDLE <
3225             elsif (/\G (
3226             (?: printf | print | say )
3227             (?: \s+ | [#] .* )*
3228             (?! [a-z]+ ) # lowercase is considered to be function
3229             (?: \b [A-Za-z_][A-Za-z_0-9]*(?: :: [A-Za-z_][A-Za-z_0-9]*)* |
3230             \$ [A-Za-z_][A-Za-z_0-9]*(?: :: [A-Za-z_][A-Za-z_0-9]*)*
3231             )
3232             ) /xgc) {
3233 12         39 $parsed .= $1;
3234             # without $parsed .= parse_ambiguous_char();
3235             }
3236              
3237             # printf {FILEHANDLE} <
3238             # print {FILEHANDLE} <
3239             # say {FILEHANDLE} <
3240             elsif (/\G (
3241             (?: printf | print | say )
3242             (?: \s+ | [#] .* )*
3243             ) (\{)
3244             /xgc) {
3245 0         0 $parsed .= $1;
3246 0         0 $parsed .= parse_expr_balanced($2);
3247             # without $parsed .= parse_ambiguous_char();
3248             }
3249              
3250             # return
3251             elsif (/\G ( return ) /xmsgc) {
3252 12         52 $parsed .= $1;
3253             }
3254              
3255             # any word
3256             # "\x5F" [_] LOW LINE (U+005F)
3257             # "\x41" [A] LATIN CAPITAL LETTER A (U+0041)
3258             # "\x42" [B] LATIN CAPITAL LETTER B (U+0042)
3259             # "\x43" [C] LATIN CAPITAL LETTER C (U+0043)
3260             # "\x44" [D] LATIN CAPITAL LETTER D (U+0044)
3261             # "\x45" [E] LATIN CAPITAL LETTER E (U+0045)
3262             # "\x46" [F] LATIN CAPITAL LETTER F (U+0046)
3263             # "\x47" [G] LATIN CAPITAL LETTER G (U+0047)
3264             # "\x48" [H] LATIN CAPITAL LETTER H (U+0048)
3265             # "\x49" [I] LATIN CAPITAL LETTER I (U+0049)
3266             # "\x4A" [J] LATIN CAPITAL LETTER J (U+004A)
3267             # "\x4B" [K] LATIN CAPITAL LETTER K (U+004B)
3268             # "\x4C" [L] LATIN CAPITAL LETTER L (U+004C)
3269             # "\x4D" [M] LATIN CAPITAL LETTER M (U+004D)
3270             # "\x4E" [N] LATIN CAPITAL LETTER N (U+004E)
3271             # "\x4F" [O] LATIN CAPITAL LETTER O (U+004F)
3272             # "\x50" [P] LATIN CAPITAL LETTER P (U+0050)
3273             # "\x51" [Q] LATIN CAPITAL LETTER Q (U+0051)
3274             # "\x52" [R] LATIN CAPITAL LETTER R (U+0052)
3275             # "\x53" [S] LATIN CAPITAL LETTER S (U+0053)
3276             # "\x54" [T] LATIN CAPITAL LETTER T (U+0054)
3277             # "\x55" [U] LATIN CAPITAL LETTER U (U+0055)
3278             # "\x56" [V] LATIN CAPITAL LETTER V (U+0056)
3279             # "\x57" [W] LATIN CAPITAL LETTER W (U+0057)
3280             # "\x58" [X] LATIN CAPITAL LETTER X (U+0058)
3281             # "\x59" [Y] LATIN CAPITAL LETTER Y (U+0059)
3282             # "\x5A" [Z] LATIN CAPITAL LETTER Z (U+005A)
3283             # "\x61" [a] LATIN SMALL LETTER A (U+0061)
3284             # "\x62" [b] LATIN SMALL LETTER B (U+0062)
3285             # "\x63" [c] LATIN SMALL LETTER C (U+0063)
3286             # "\x64" [d] LATIN SMALL LETTER D (U+0064)
3287             # "\x65" [e] LATIN SMALL LETTER E (U+0065)
3288             # "\x66" [f] LATIN SMALL LETTER F (U+0066)
3289             # "\x67" [g] LATIN SMALL LETTER G (U+0067)
3290             # "\x68" [h] LATIN SMALL LETTER H (U+0068)
3291             # "\x69" [i] LATIN SMALL LETTER I (U+0069)
3292             # "\x6A" [j] LATIN SMALL LETTER J (U+006A)
3293             # "\x6B" [k] LATIN SMALL LETTER K (U+006B)
3294             # "\x6C" [l] LATIN SMALL LETTER L (U+006C)
3295             # "\x6D" [m] LATIN SMALL LETTER M (U+006D)
3296             # "\x6E" [n] LATIN SMALL LETTER N (U+006E)
3297             # "\x6F" [o] LATIN SMALL LETTER O (U+006F)
3298             # "\x70" [p] LATIN SMALL LETTER P (U+0070)
3299             # "\x71" [q] LATIN SMALL LETTER Q (U+0071)
3300             # "\x72" [r] LATIN SMALL LETTER R (U+0072)
3301             # "\x73" [s] LATIN SMALL LETTER S (U+0073)
3302             # "\x74" [t] LATIN SMALL LETTER T (U+0074)
3303             # "\x75" [u] LATIN SMALL LETTER U (U+0075)
3304             # "\x76" [v] LATIN SMALL LETTER V (U+0076)
3305             # "\x77" [w] LATIN SMALL LETTER W (U+0077)
3306             # "\x78" [x] LATIN SMALL LETTER X (U+0078)
3307             # "\x79" [y] LATIN SMALL LETTER Y (U+0079)
3308             # "\x7A" [z] LATIN SMALL LETTER Z (U+007A)
3309             elsif (/\G ( [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
3310 287         1014 $parsed .= $1;
3311 287         624 $parsed .= parse_ambiguous_char();
3312             }
3313              
3314             # any right parenthesis
3315             # "\x29" [)] RIGHT PARENTHESIS (U+0029)
3316             # "\x7D" [}] RIGHT CURLY BRACKET (U+007D)
3317             # "\x5D" []] RIGHT SQUARE BRACKET (U+005D)
3318             elsif (/\G ([\)\}\]]) /xmsgc) {
3319 396         908 $parsed .= $1;
3320 396         555 $parsed .= parse_ambiguous_char();
3321             }
3322              
3323             # any US-ASCII
3324             # "\x3A" [:] COLON (U+003A)
3325             elsif (/\G ([\x00-\x7F]) /xmsgc) {
3326 8271         26361 $parsed .= $1;
3327             }
3328              
3329             # otherwise
3330             elsif (/\G ($x) /xmsgc) {
3331 0         0 die "$0(@{[__LINE__]}): can't parse not US-ASCII '$1'.\n";
  0         0  
3332             }
3333              
3334 680340         2503605 return $parsed;
3335             }
3336              
3337             #---------------------------------------------------------------------
3338             # parse expression in balanced blackets
3339             sub parse_expr_balanced {
3340 438     441 0 1331 my($open_bracket) = @_;
3341 438   50     2703 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3342 438         1141 my $parsed = $open_bracket;
3343 438         750 my $nest_bracket = 1;
3344 438         645 while (1) {
3345              
3346             # open bracket
3347 1687 100       14362 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
3348 22         50 $parsed .= $1;
3349 22         35 $nest_bracket++;
3350             }
3351              
3352             # close bracket
3353             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3354 460         1009 $parsed .= $1;
3355 460         1180 $parsed .= parse_ambiguous_char();
3356 460 100       1295 if (--$nest_bracket <= 0) {
3357 438         884 last;
3358             }
3359             }
3360              
3361             # otherwise
3362             else {
3363 1205         5040 $parsed .= parse_expr();
3364             }
3365             }
3366 438         1166 return $parsed;
3367             }
3368              
3369             #---------------------------------------------------------------------
3370             # parse expression that ends with a regexp
3371             sub parse_expr_endswith {
3372 42     45 0 79 my($endswith) = @_;
3373 42         84 my $parsed = '';
3374 42         54 while (1) {
3375 72 100       641 if (/\G (?= $endswith ) /xmsgc) {
3376 42         69 last;
3377             }
3378             else {
3379 30         387 $parsed .= parse_expr();
3380             }
3381             }
3382 42         117 return $parsed;
3383             }
3384              
3385             #---------------------------------------------------------------------
3386             # parse <<'HERE_DOCUMENT' as q-like
3387             sub parse_heredocument_as_q_endswith {
3388 9     12 0 19 my($endswith) = @_;
3389 9         17 my $parsed = '';
3390 9         12 while (1) {
3391 465 100       1573 if (/\G ( $R $endswith ) /xmsgc) {
    50          
3392 9         23 $parsed .= $1;
3393 9         18 last;
3394             }
3395             elsif (/\G ($x) /xmsgc) {
3396 456         432 $parsed .= $1;
3397             }
3398              
3399             # something wrong happened
3400             else {
3401 0         0 die sprintf(<
3402 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3403             ------------------------------------------------------------------------------
3404             %s
3405             ------------------------------------------------------------------------------
3406             END
3407             }
3408             }
3409 9         49 return $parsed;
3410             }
3411              
3412             #---------------------------------------------------------------------
3413             # parse <<"HERE_DOCUMENT" as qq-like
3414             sub parse_heredocument_as_qq_endswith {
3415 14     17 0 29 my($endswith) = @_;
3416 14         22 my $parsed = '';
3417 14         22 my $nest_escape = 0;
3418 14         20 while (1) {
3419 14 50       241 if (/\G ( $R $endswith ) /xmsgc) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3420 14         34 $parsed .= ('>)]}' x $nest_escape);
3421 14         34 $parsed .= $1;
3422 14         30 last;
3423             }
3424              
3425             # \L\u --> \u\L
3426             elsif (/\G \\L \\u /xmsgc) {
3427 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3428 0         0 $parsed .= '@{[mb::lc(qq<';
3429 0         0 $nest_escape++;
3430 0         0 $nest_escape++;
3431             }
3432              
3433             # \U\l --> \l\U
3434             elsif (/\G \\U \\l /xmsgc) {
3435 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3436 0         0 $parsed .= '@{[mb::uc(qq<';
3437 0         0 $nest_escape++;
3438 0         0 $nest_escape++;
3439             }
3440              
3441             # \L
3442             elsif (/\G \\L /xmsgc) {
3443 0         0 $parsed .= '@{[mb::lc(qq<';
3444 0         0 $nest_escape++;
3445             }
3446              
3447             # \U
3448             elsif (/\G \\U /xmsgc) {
3449 0         0 $parsed .= '@{[mb::uc(qq<';
3450 0         0 $nest_escape++;
3451             }
3452              
3453             # \l
3454             elsif (/\G \\l /xmsgc) {
3455 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3456 0         0 $nest_escape++;
3457             }
3458              
3459             # \u
3460             elsif (/\G \\u /xmsgc) {
3461 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3462 0         0 $nest_escape++;
3463             }
3464              
3465             # \Q
3466             elsif (/\G \\Q /xmsgc) {
3467 0         0 $parsed .= '@{[quotemeta(qq<';
3468 0         0 $nest_escape++;
3469             }
3470              
3471             # \E
3472             elsif (/\G \\E /xmsgc) {
3473 0         0 $parsed .= ('>)]}' x $nest_escape);
3474 0         0 $nest_escape = 0;
3475             }
3476              
3477             # \o{...}
3478             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3479 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), '\\');
3480             }
3481              
3482             # \x{...}
3483             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3484 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), '\\');
3485             }
3486              
3487             # \any
3488             elsif (/\G (\\) ($x) /xmsgc) {
3489 0         0 $parsed .= ($1 . escape_qq($2, '\\'));
3490             }
3491              
3492             # $` --> @{[mb::_PREMATCH()]}
3493             # ${`} --> @{[mb::_PREMATCH()]}
3494             # $PREMATCH --> @{[mb::_PREMATCH()]}
3495             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3496             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3497             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3498 0         0 $parsed .= '@{[mb::_PREMATCH()]}';
3499             }
3500              
3501             # $& --> @{[mb::_MATCH()]}
3502             # ${&} --> @{[mb::_MATCH()]}
3503             # $MATCH --> @{[mb::_MATCH()]}
3504             # ${MATCH} --> @{[mb::_MATCH()]}
3505             # ${^MATCH} --> @{[mb::_MATCH()]}
3506             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3507 0         0 $parsed .= '@{[mb::_MATCH()]}';
3508             }
3509              
3510             # $1 --> @{[mb::_CAPTURE(1)]}
3511             # $2 --> @{[mb::_CAPTURE(2)]}
3512             # $3 --> @{[mb::_CAPTURE(3)]}
3513             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
3514 0         0 $parsed .= "\@{[mb::_CAPTURE($1)]}";
3515             }
3516              
3517             # @{^CAPTURE} --> @{[mb::_CAPTURE()]}
3518             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
3519 0         0 $parsed .= '@{[mb::_CAPTURE()]}';
3520             }
3521              
3522             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3523             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3524             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3525             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
3526 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3527 0         0 $parsed .= "\@{[mb::_CAPTURE($n_th+1)]}";
3528             }
3529              
3530             # @- --> @{[mb::_LAST_MATCH_START()]}
3531             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3532             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3533             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3534             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3535 0         0 $parsed .= '@{[mb::_LAST_MATCH_START()]}';
3536             }
3537              
3538             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3539             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3540             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3541             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3542             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3543 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3544 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3545             }
3546              
3547             # @+ --> @{[mb::_LAST_MATCH_END()]}
3548             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3549             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3550             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3551             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3552 0         0 $parsed .= '@{[mb::_LAST_MATCH_END()]}';
3553             }
3554              
3555             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3556             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3557             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3558             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3559             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3560 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3561 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3562             }
3563              
3564             # any
3565             elsif (/\G ($x) /xmsgc) {
3566 0         0 $parsed .= escape_qq($1, '\\');
3567             }
3568              
3569             # something wrong happened
3570             else {
3571 0         0 die sprintf(<
3572 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3573             ------------------------------------------------------------------------------
3574             %s
3575             ------------------------------------------------------------------------------
3576             END
3577             }
3578             }
3579 14         71 return $parsed;
3580             }
3581              
3582             #---------------------------------------------------------------------
3583             # parse q{string} in balanced blackets
3584             sub parse_q__like_balanced {
3585 42     45 0 100 my($open_bracket) = @_;
3586 42   50     313 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3587 42         120 my $parsed = $open_bracket;
3588 42         64 my $nest_bracket = 1;
3589 42         60 while (1) {
3590 192 50       5771 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
3591 0         0 $parsed .= $1;
3592 0         0 $nest_bracket++;
3593             }
3594             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3595 42         103 $parsed .= $1;
3596 42 50       167 if (--$nest_bracket <= 0) {
3597 42         79 last;
3598             }
3599             }
3600             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3601 0         0 $parsed .= $1;
3602             }
3603             else {
3604 150         395 $parsed .= parse_q__like($close_bracket);
3605             }
3606             }
3607 42         114 return $parsed;
3608             }
3609              
3610             #---------------------------------------------------------------------
3611             # parse q/string/ that ends with a character
3612             sub parse_q__like_endswith {
3613 5948     5951 0 15784 my($endswith) = @_;
3614 5948         8595 my $parsed = $endswith;
3615 5948         7829 while (1) {
3616 14476 100       65640 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
3617 5948         10775 $parsed .= $1;
3618 5948         9749 last;
3619             }
3620             elsif (/\G (\\ \Q$endswith\E) /xmsgc) {
3621 0         0 $parsed .= $1;
3622             }
3623             else {
3624 8528         15837 $parsed .= parse_q__like($endswith);
3625             }
3626             }
3627 5948         11416 return $parsed;
3628             }
3629              
3630             #---------------------------------------------------------------------
3631             # parse q/string/ common routine
3632             sub parse_q__like {
3633 8678     8681 0 14327 my($closewith) = @_;
3634 8678 100       43302 if (/\G (\\\\) /xmsgc) {
    50          
3635 13         28 return $1;
3636             }
3637             elsif (/\G ($x) /xmsgc) {
3638 8665         19420 return escape_q($1, $closewith);
3639             }
3640              
3641             # something wrong happened
3642             else {
3643 0         0 die sprintf(<
3644 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3645             ------------------------------------------------------------------------------
3646             %s
3647             ------------------------------------------------------------------------------
3648             END
3649             }
3650             }
3651              
3652             #---------------------------------------------------------------------
3653             # parse qq{string} in balanced blackets
3654             sub parse_qq_like_balanced {
3655 85     88 0 423 my($open_bracket) = @_;
3656 85   50     326 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3657 85         190 my $parsed_as_q = $open_bracket;
3658 85         108 my $parsed_as_qq = $open_bracket;
3659 85         81 my $nest_bracket = 1;
3660 85         83 my $nest_escape = 0;
3661 85         109 while (1) {
3662              
3663             # blackets
3664 317 50       4151 if (/\G (\\ \Q$open_bracket\E) /xmsgc) {
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3665 0         0 $parsed_as_q .= $1;
3666 0         0 $parsed_as_qq .= $1;
3667             }
3668             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3669 0         0 $parsed_as_q .= $1;
3670 0         0 $parsed_as_qq .= $1;
3671             }
3672             elsif (/\G (\Q$open_bracket\E) /xmsgc) {
3673 0         0 $parsed_as_q .= $1;
3674 0         0 $parsed_as_qq .= $1;
3675 0         0 $nest_bracket++;
3676             }
3677             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3678 85 50       146 if (--$nest_bracket <= 0) {
3679 85         146 $parsed_as_q .= $1;
3680 85         141 $parsed_as_qq .= ('>)]}' x $nest_escape);
3681 85         121 $parsed_as_qq .= $1;
3682 85         104 last;
3683             }
3684             else {
3685 0         0 $parsed_as_q .= $1;
3686 0         0 $parsed_as_qq .= $1;
3687             }
3688             }
3689              
3690             # \L\u --> \u\L
3691             elsif (/\G (\\L \\u) /xmsgc) {
3692 0         0 $parsed_as_q .= $1;
3693 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3694 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3695 0         0 $nest_escape++;
3696 0         0 $nest_escape++;
3697             }
3698              
3699             # \U\l --> \l\U
3700             elsif (/\G (\\U \\l) /xmsgc) {
3701 0         0 $parsed_as_q .= $1;
3702 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3703 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3704 0         0 $nest_escape++;
3705 0         0 $nest_escape++;
3706             }
3707              
3708             # \L
3709             elsif (/\G (\\L) /xmsgc) {
3710 0         0 $parsed_as_q .= $1;
3711 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3712 0         0 $nest_escape++;
3713             }
3714              
3715             # \U
3716             elsif (/\G (\\U) /xmsgc) {
3717 0         0 $parsed_as_q .= $1;
3718 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3719 0         0 $nest_escape++;
3720             }
3721              
3722             # \l
3723             elsif (/\G (\\l) /xmsgc) {
3724 0         0 $parsed_as_q .= $1;
3725 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3726 0         0 $nest_escape++;
3727             }
3728              
3729             # \u
3730             elsif (/\G (\\u) /xmsgc) {
3731 0         0 $parsed_as_q .= $1;
3732 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3733 0         0 $nest_escape++;
3734             }
3735              
3736             # \Q
3737             elsif (/\G (\\Q) /xmsgc) {
3738 0         0 $parsed_as_q .= $1;
3739 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
3740 0         0 $nest_escape++;
3741             }
3742              
3743             # \E
3744             elsif (/\G (\\E) /xmsgc) {
3745 0         0 $parsed_as_q .= $1;
3746 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
3747 0         0 $nest_escape = 0;
3748             }
3749              
3750             else {
3751 232         316 my($as_qq, $as_q) = parse_qq_like($close_bracket);
3752 232         261 $parsed_as_q .= $as_q;
3753 232         312 $parsed_as_qq .= $as_qq;
3754             }
3755             }
3756              
3757             # return qq-like and q-like quotee
3758 85 100       140 if (wantarray) {
3759 67         158 return ($parsed_as_qq, $parsed_as_q);
3760             }
3761             else {
3762 18         40 return $parsed_as_qq;
3763             }
3764             }
3765              
3766             #---------------------------------------------------------------------
3767             # parse qq/string/ that ends with a character
3768             sub parse_qq_like_endswith {
3769 127934     127937 0 453962 my($endswith) = @_;
3770 127934         214424 my $parsed_as_q = $endswith;
3771 127934         178105 my $parsed_as_qq = $endswith;
3772 127934         199596 my $nest_escape = 0;
3773 127934         173330 while (1) {
3774              
3775             # ends with
3776 688963 50       5201030 if (/\G (\\ \Q$endswith\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3777 0         0 $parsed_as_q .= $1;
3778 0         0 $parsed_as_qq .= $1;
3779             }
3780             elsif (/\G (\Q$endswith\E) /xmsgc) {
3781 127934         353678 $parsed_as_q .= $1;
3782 127934         276498 $parsed_as_qq .= ('>)]}' x $nest_escape);
3783 127934 50       388070 $parsed_as_qq .= "\n" if CORE::length($1) >= 2; # here document
3784 127934         204669 $parsed_as_qq .= $1;
3785 127934         235929 last;
3786             }
3787              
3788             # \L\u --> \u\L
3789             elsif (/\G (\\L \\u) /xmsgc) {
3790 0         0 $parsed_as_q .= $1;
3791 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3792 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3793 0         0 $nest_escape++;
3794 0         0 $nest_escape++;
3795             }
3796              
3797             # \U\l --> \l\U
3798             elsif (/\G (\\U \\l) /xmsgc) {
3799 0         0 $parsed_as_q .= $1;
3800 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3801 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3802 0         0 $nest_escape++;
3803 0         0 $nest_escape++;
3804             }
3805              
3806             # \L
3807             elsif (/\G (\\L) /xmsgc) {
3808 0         0 $parsed_as_q .= $1;
3809 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3810 0         0 $nest_escape++;
3811             }
3812              
3813             # \U
3814             elsif (/\G (\\U) /xmsgc) {
3815 0         0 $parsed_as_q .= $1;
3816 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3817 0         0 $nest_escape++;
3818             }
3819              
3820             # \l
3821             elsif (/\G (\\l) /xmsgc) {
3822 0         0 $parsed_as_q .= $1;
3823 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3824 0         0 $nest_escape++;
3825             }
3826              
3827             # \u
3828             elsif (/\G (\\u) /xmsgc) {
3829 0         0 $parsed_as_q .= $1;
3830 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3831 0         0 $nest_escape++;
3832             }
3833              
3834             # \Q
3835             elsif (/\G (\\Q) /xmsgc) {
3836 0         0 $parsed_as_q .= $1;
3837 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
3838 0         0 $nest_escape++;
3839             }
3840              
3841             # \E
3842             elsif (/\G (\\E) /xmsgc) {
3843 0         0 $parsed_as_q .= $1;
3844 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
3845 0         0 $nest_escape = 0;
3846             }
3847              
3848             else {
3849 561029         990970 my($as_qq, $as_q) = parse_qq_like($endswith);
3850 561029         809882 $parsed_as_q .= $as_q;
3851 561029         817620 $parsed_as_qq .= $as_qq;
3852             }
3853             }
3854              
3855             # return qq-like and q-like quotee
3856 127934 100       254524 if (wantarray) {
3857 1645         4569 return ($parsed_as_qq, $parsed_as_q);
3858             }
3859             else {
3860 126289         366133 return $parsed_as_qq;
3861             }
3862             }
3863              
3864             #---------------------------------------------------------------------
3865             # parse qq/string/ common routine
3866             sub parse_qq_like {
3867 561261     561264 0 890514 my($closewith) = @_;
3868 561261         729705 my $parsed_as_q = '';
3869 561261         703707 my $parsed_as_qq = '';
3870              
3871             # \o{...}
3872 561261 50       6176071 if (/\G ( \\o\{ (.*?) \} ) /xmsgc) {
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3873 0         0 $parsed_as_q .= $1;
3874 0         0 $parsed_as_qq .= escape_to_hex(mb::chr(oct $2), $closewith);
3875             }
3876              
3877             # \x{...}
3878             elsif (/\G ( \\x\{ (.*?) \} ) /xmsgc) {
3879 1         3 $parsed_as_q .= $1;
3880 1         5 $parsed_as_qq .= escape_to_hex(mb::chr(hex $2), $closewith);
3881             }
3882              
3883             # \any
3884             elsif (/\G ( (\\) ($x) ) /xmsgc) {
3885 226         532 $parsed_as_q .= $1;
3886 226         586 $parsed_as_qq .= ($2 . escape_qq($3, $closewith));
3887             }
3888              
3889             # $` --> @{[mb::_PREMATCH()]}
3890             # ${`} --> @{[mb::_PREMATCH()]}
3891             # $PREMATCH --> @{[mb::_PREMATCH()]}
3892             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3893             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3894             elsif (/\G ( \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3895 2         6 $parsed_as_q .= $1;
3896 2         5 $parsed_as_qq .= '@{[mb::_PREMATCH()]}';
3897             }
3898              
3899             # $& --> @{[mb::_MATCH()]}
3900             # ${&} --> @{[mb::_MATCH()]}
3901             # $MATCH --> @{[mb::_MATCH()]}
3902             # ${MATCH} --> @{[mb::_MATCH()]}
3903             # ${^MATCH} --> @{[mb::_MATCH()]}
3904             elsif (/\G ( \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3905 2         5 $parsed_as_q .= $1;
3906 2         6 $parsed_as_qq .= '@{[mb::_MATCH()]}';
3907             }
3908              
3909             # $1 --> @{[mb::_CAPTURE(1)]}
3910             # $2 --> @{[mb::_CAPTURE(2)]}
3911             # $3 --> @{[mb::_CAPTURE(3)]}
3912             elsif (/\G ( \$ ([1-9][0-9]*) ) /xmsgc) {
3913 23         61 $parsed_as_q .= $1;
3914 23         82 $parsed_as_qq .= "\@{[mb::_CAPTURE($2)]}";
3915             }
3916              
3917             # @{^CAPTURE} --> @{[mb::_CAPTURE()]}
3918             elsif (/\G ( \@\{\^CAPTURE\} ) /xmsgc) {
3919 0         0 $parsed_as_q .= $1;
3920 0         0 $parsed_as_qq .= '@{[mb::_CAPTURE()]}';
3921             }
3922              
3923             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3924             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3925             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3926             elsif (/\G (\$\{\^CAPTURE\}) \s* (\[) /xmsgc) {
3927 0         0 my $indexing = parse_expr_balanced($2);
3928 0         0 $parsed_as_q .= ($1 . $indexing);
3929 0         0 my $n_th = quotee_of($indexing);
3930 0         0 $parsed_as_qq .= "\@{[mb::_CAPTURE($n_th)]}";
3931             }
3932              
3933             # @- --> @{[mb::_LAST_MATCH_START()]}
3934             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3935             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3936             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3937             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3938 0         0 $parsed_as_q .= $&;
3939 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_START()]}';
3940             }
3941              
3942             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3943             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3944             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3945             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3946             elsif (/\G ( \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3947 0         0 my $indexing = parse_expr_balanced($2);
3948 0         0 $parsed_as_q .= ($1 . $indexing);
3949 0         0 my $n_th = quotee_of($indexing);
3950 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3951             }
3952              
3953             # @+ --> @{[mb::_LAST_MATCH_END()]}
3954             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3955             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3956             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3957             elsif (/\G ( \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3958 0         0 $parsed_as_q .= $1;
3959 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_END()]}';
3960             }
3961              
3962             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3963             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3964             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3965             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3966             elsif (/\G ( \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3967 0         0 my $indexing = parse_expr_balanced($2);
3968 0         0 $parsed_as_q .= ($1 . $indexing);
3969 0         0 my $n_th = quotee_of($indexing);
3970 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3971             }
3972              
3973             # any
3974             elsif (/\G ($x) /xmsgc) {
3975 561007         1119597 $parsed_as_q .= escape_q ($1, $closewith);
3976 561007         1017514 $parsed_as_qq .= escape_qq($1, $closewith);
3977             }
3978              
3979             # something wrong happened
3980             else {
3981 0         0 die sprintf(<
3982 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3983             ------------------------------------------------------------------------------
3984             %s
3985             ------------------------------------------------------------------------------
3986             END
3987             }
3988              
3989             # return qq-like and q-like quotee
3990 561261 50       984004 if (wantarray) {
3991 561261         1362395 return ($parsed_as_qq, $parsed_as_q);
3992             }
3993             else {
3994 0         0 return $parsed_as_qq;
3995             }
3996             }
3997              
3998             #---------------------------------------------------------------------
3999             # tr/A-C/1-3/ for US-ASCII codepoint
4000             sub list_all_ASCII_by_hyphen {
4001 5024     5027 0 11306 my @hyphened = @_;
4002 5024         6754 my @list_all = ();
4003 5024         12211 for (my $i=0; $i <= $#hyphened; ) {
4004 6357 100 100     17297 if (
      100        
4005             ($i+1 < $#hyphened) and
4006             ($hyphened[$i+1] eq '-') and
4007             1) {
4008 71 100       133 $hyphened[$i+0] = ($hyphened[$i+0] eq '\\-') ? '-' : $hyphened[$i+0];
4009 71 100       121 $hyphened[$i+2] = ($hyphened[$i+2] eq '\\-') ? '-' : $hyphened[$i+2];
4010 71 50       293 if (0) { }
    50          
    50          
4011 0         0 elsif ($hyphened[$i+0] !~ m/\A [\x00-\x7F] \z/xms) {
4012 0         0 confess sprintf(qq{@{[__FILE__]}: "$hyphened[$i+0]-$hyphened[$i+2]" in tr/// is not US-ASCII});
  0         0  
4013             }
4014             elsif ($hyphened[$i+2] !~ m/\A [\x00-\x7F] \z/xms) {
4015 0         0 confess sprintf(qq{@{[__FILE__]}: "$hyphened[$i+0]-$hyphened[$i+2]" in tr/// is not US-ASCII});
  0         0  
4016             }
4017             elsif ($hyphened[$i+0] gt $hyphened[$i+2]) {
4018 0         0 confess sprintf(qq{@{[__FILE__]}: "$hyphened[$i+0]-$hyphened[$i+2]" in tr/// is not "$hyphened[$i+0]" le "$hyphened[$i+2]"});
  0         0  
4019             }
4020             else {
4021 71         147 push @list_all, map { CORE::chr($_) } (CORE::ord($hyphened[$i+0]) .. CORE::ord($hyphened[$i+2]));
  225         425  
4022 71         163 $i += 3;
4023             }
4024             }
4025             else {
4026 6286 100       11913 if ($hyphened[$i] eq '\\-') {
4027 19         31 push @list_all, '-';
4028             }
4029             else {
4030 6267         10967 push @list_all, $hyphened[$i];
4031             }
4032 6286         12019 $i++;
4033             }
4034             }
4035 5024         13264 return @list_all;
4036             }
4037              
4038             #---------------------------------------------------------------------
4039             # parse tr{here}{here} in balanced blackets
4040             sub parse_tr_like_balanced {
4041 2080     2083 0 5089 my($open_bracket) = @_;
4042 2080   50     11510 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
4043 2080         5417 my @x = ();
4044 2080         2842 my $nest_bracket = 1;
4045 2080         3585 while (1) {
4046              
4047             # blackets
4048 4160 50       94729 if (/\G (\\ \Q$open_bracket\E) /xmsgc) {
    50          
    50          
    100          
    50          
4049 0         0 push @x, $1;
4050             }
4051             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
4052 0         0 push @x, $1;
4053             }
4054             elsif (/\G (\Q$open_bracket\E) /xmsgc) {
4055 0         0 push @x, $1;
4056 0         0 $nest_bracket++;
4057             }
4058             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
4059 2080 50       5290 if (--$nest_bracket <= 0) {
4060 2080         3569 last;
4061             }
4062 0         0 push @x, $1;
4063             }
4064              
4065             # \-
4066             elsif (/\G (\\ -) /xmsgc) {
4067 0         0 push @x, $1;
4068             }
4069              
4070             else {
4071 2080         5555 push @x, parse_tr_like($close_bracket);
4072             }
4073             }
4074 2080         7505 return join('', $open_bracket, @x, $close_bracket);
4075             }
4076              
4077             #---------------------------------------------------------------------
4078             # parse tr/here/here/ that ends with a character
4079             sub parse_tr_like_endswith {
4080 2226     2229 0 4720 my($endswith) = @_;
4081 2226         2965 my $openwith = $endswith;
4082 2226         3098 my @x = ();
4083 2226         2675 while (1) {
4084 4752 50       23702 if (/\G (\\ \Q$endswith\E) /xmsgc) {
    100          
    100          
4085 0         0 push @x, $1;
4086             }
4087             elsif (/\G (\Q$endswith\E) /xmsgc) {
4088 2226         3162 last;
4089             }
4090              
4091             # \-
4092             elsif (/\G (\\ -) /xmsgc) {
4093 9         21 push @x, $1;
4094             }
4095              
4096             else {
4097 2517         4515 push @x, parse_tr_like($endswith);
4098             }
4099             }
4100 2226         6895 return join('', $openwith, @x, $endswith);
4101             }
4102              
4103             #---------------------------------------------------------------------
4104             # parse tr/here/here/ common routine
4105             sub parse_tr_like {
4106 4597     4600 0 7657 my($closewith) = @_;
4107              
4108 4597 100       34604 if (0) {
    100          
    100          
    100          
    100          
    100          
    100          
    50          
4109             }
4110              
4111             # https://perldoc.perl.org/perlop#Interpolation
4112             # tr///, y///
4113             # No variable interpolation occurs.
4114             # String modifying combinations for case and quoting such as \Q, \U, and \E are not recognized.
4115             # The other escape sequences such as \200 and \t and backslashed characters such as \\ and \- are converted to appropriate literals.
4116             # The character "-" is treated specially and therefore \- is treated as a literal "-".
4117              
4118             # \ddd
4119 0         0 elsif (/\G \\ ( [0-3][0-7][0-7] | [0-7][0-7] | [0-7] ) /xmsgc) {
4120 4         13 return escape_tr(mb::chr(oct $1), $closewith);
4121             }
4122              
4123             # \oddd
4124             elsif (/\G \\o ( [0-3][0-7][0-7] | [0-7][0-7] | [0-7] ) /xmsgc) {
4125 4         11 return escape_tr(mb::chr(oct $1), $closewith);
4126             }
4127              
4128             # \o{...}
4129             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
4130 4         11 return escape_tr(mb::chr(oct $1), $closewith);
4131             }
4132              
4133             # \xhh
4134             elsif (/\G \\x ( [0-9A-Fa-f][0-9A-Fa-f] | [0-9A-Fa-f] ) /xmsgc) {
4135 3         9 return escape_tr(mb::chr(hex $1), $closewith);
4136             }
4137              
4138             # \x{...}
4139             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
4140 3         9 return escape_tr(mb::chr(hex $1), $closewith);
4141             }
4142              
4143             # \cX
4144             elsif (/\G ( \\c [\@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]^_?] ) /xmsgc) {
4145             return {
4146             '\\c@' => "\c@",
4147             '\\cA' => "\cA",
4148             '\\cB' => "\cB",
4149             '\\cC' => "\cC",
4150             '\\cD' => "\cD",
4151             '\\cE' => "\cE",
4152             '\\cF' => "\cF",
4153             '\\cG' => "\cG",
4154             '\\cH' => "\cH",
4155             '\\cI' => "\cI",
4156             '\\cJ' => "\cJ",
4157             '\\cK' => "\cK",
4158             '\\cL' => "\cL",
4159             '\\cM' => "\cM",
4160             '\\cN' => "\cN",
4161             '\\cO' => "\cO",
4162             '\\cP' => "\cP",
4163             '\\cQ' => "\cQ",
4164             '\\cR' => "\cR",
4165             '\\cS' => "\cS",
4166             '\\cT' => "\cT",
4167             '\\cU' => "\cU",
4168             '\\cV' => "\cV",
4169             '\\cW' => "\cW",
4170             '\\cX' => "\cX",
4171             '\\cY' => "\cY",
4172             '\\cZ' => "\cZ",
4173             '\\c[' => "\c[",
4174             '\\c\\' => CORE::chr(0x1C),
4175             '\\c]' => "\c]",
4176             '\\c^' => "\c^",
4177             '\\c_' => "\c_",
4178             '\\c?' => CORE::chr(0x7F),
4179 9   50     181 }->{$1} || die;
4180             }
4181              
4182             # \\ \a \b \e \f \n \r \t \E \l \L \u \U \Q
4183             elsif (/\G ( \\ ([\\abefnrtElLuUQ]) ) /xmsgc) {
4184             return {
4185             "\x5C\x5C" => "\x5C\x5C",
4186             '\a' => "\a",
4187             '\b' => "\b",
4188             '\e' => "\e",
4189             '\f' => "\f",
4190             '\n' => "\n",
4191             '\r' => "\r",
4192             '\t' => "\t",
4193 16   66     142 }->{$1} || $2;
4194             }
4195              
4196             # any
4197             elsif (/\G ($x) /xmsgc) {
4198 4554         8775 return escape_tr($1, $closewith);
4199             }
4200              
4201             # something wrong happened
4202             else {
4203 0         0 die sprintf(<
4204 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4205             ------------------------------------------------------------------------------
4206             %s
4207             ------------------------------------------------------------------------------
4208             END
4209             }
4210             }
4211              
4212             #---------------------------------------------------------------------
4213             # qr/ [A-Z] / for Shift_JIS-like encoding
4214             sub list_all_by_hyphen_sjis_like {
4215 8434     8437 0 16028 my($a, $b) = @_;
4216 8434         32204 my @a = (undef, unpack 'C*', $a);
4217 8434         17128 my @b = (undef, unpack 'C*', $b);
4218              
4219 8434 100       24254 if (0) { }
    50          
4220 0         0 elsif (CORE::length($a) == 1) {
4221 2994 100       8270 if (0) { }
    50          
4222 0         0 elsif (CORE::length($b) == 1) {
4223             return (
4224 434 50 100     4070 (($a[1] <= 0x80) and (0xA0 <= $b[1])) ?
    100          
4225             sprintf(join('', qw( [\x%02x-\x80\xA0-\x%02x] )), $a[1],
4226             $b[1]) :
4227             $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4228             $b[1]) : (),
4229             );
4230             }
4231             elsif (CORE::length($b) == 2) {
4232             return (
4233 2560 100       30280 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
    50          
    50          
    100          
4234             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4235             $a[1] <= 0x80 ? sprintf(join('', qw( [\x%02x-\x80\xA0-\xDF] )), $a[1]) :
4236             $a[1] < 0xA0 ? () :
4237             $a[1] <= 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] )), $a[1]) : (),
4238             );
4239             }
4240             }
4241             elsif (CORE::length($a) == 2) {
4242 5440 50       11500 if (0) { }
4243 0         0 elsif (CORE::length($b) == 2) {
4244 5440 100       32007 my $lower_limit = join('|',
4245             $a[1] < 0xFC ? sprintf(join('', qw( [\x%02x-\xFC] [\x00-\xFF ] )), $a[1]+1 ) : (),
4246             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4247             );
4248 5440 100       20125 my $upper_limit = join('|',
4249             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4250             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4251             );
4252 5440         21796 return qq{(?=$lower_limit)(?=$upper_limit)};
4253             }
4254             }
4255              
4256             # over range of codepoint
4257 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4258             }
4259              
4260             #---------------------------------------------------------------------
4261             # qr/ [A-Z] / for EUC-JP-like encoding
4262             sub list_all_by_hyphen_eucjp_like {
4263 252     255 0 568 my($a, $b) = @_;
4264 252         1049 my @a = (undef, unpack 'C*', $a);
4265 252         596 my @b = (undef, unpack 'C*', $b);
4266              
4267 252 100       721 if (0) { }
    50          
4268 0         0 elsif (CORE::length($a) == 1) {
4269 132 100       381 if (0) { }
    50          
4270 0         0 elsif (CORE::length($b) == 1) {
4271             return (
4272 36 50       251 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4273             $b[1]) : (),
4274             );
4275             }
4276             elsif (CORE::length($b) == 2) {
4277             return (
4278 96 100       945 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4279             0xA1 < $b[1] ? sprintf(join('', qw( [\xA1-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4280             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4281             );
4282             }
4283             }
4284             elsif (CORE::length($a) == 2) {
4285 120 50       246 if (0) { }
4286 0         0 elsif (CORE::length($b) == 2) {
4287 120 100       4158 my $lower_limit = join('|',
4288             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\x00-\xFF ] )), $a[1]+1 ) : (),
4289             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4290             );
4291 120 100       514 my $upper_limit = join('|',
4292             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4293             0xA1 < $b[1] ? sprintf(join('', qw( [\xA1-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4294             );
4295 120         531 return qq{(?=$lower_limit)(?=$upper_limit)};
4296             }
4297             }
4298              
4299             # over range of codepoint
4300 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4301             }
4302              
4303             #---------------------------------------------------------------------
4304             # qr/ [A-Z] / for Big5-like encoding
4305             sub list_all_by_hyphen_big5_like {
4306 252     255 0 523 my($a, $b) = @_;
4307 252         1066 my @a = (undef, unpack 'C*', $a);
4308 252         7239 my @b = (undef, unpack 'C*', $b);
4309              
4310 252 100       746 if (0) { }
    50          
4311 0         0 elsif (CORE::length($a) == 1) {
4312 132 100       338 if (0) { }
    50          
4313 0         0 elsif (CORE::length($b) == 1) {
4314             return (
4315 36 50       362 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4316             $b[1]) : (),
4317             );
4318             }
4319             elsif (CORE::length($b) == 2) {
4320             return (
4321 96 100       937 sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4322             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4323             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4324             );
4325             }
4326             }
4327             elsif (CORE::length($a) == 2) {
4328 120 50       294 if (0) { }
4329 0         0 elsif (CORE::length($b) == 2) {
4330 120 100       874 my $lower_limit = join('|',
4331             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\x00-\xFF ] )), $a[1]+1 ) : (),
4332             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4333             );
4334 120 100       539 my $upper_limit = join('|',
4335             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4336             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x00-\xFF ] )), $b[1]-1 ) : (),
4337             );
4338 120         611 return qq{(?=$lower_limit)(?=$upper_limit)};
4339             }
4340             }
4341              
4342             # over range of codepoint
4343 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4344             }
4345              
4346             #---------------------------------------------------------------------
4347             # qr/ [A-Z] / for GB18030-like encoding
4348             sub list_all_by_hyphen_gb18030_like {
4349 18252     18255 0 33891 my($a, $b) = @_;
4350 18252         74766 my @a = (undef, unpack 'C*', $a);
4351 18252         45687 my @b = (undef, unpack 'C*', $b);
4352              
4353 18252 100       58680 if (0) { }
    100          
    50          
4354 0         0 elsif (CORE::length($a) == 1) {
4355 2652 100       8766 if (0) { }
    100          
    50          
4356 0         0 elsif (CORE::length($b) == 1) {
4357             return (
4358 156 50       1277 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4359             $b[1]) : (),
4360             );
4361             }
4362             elsif (CORE::length($b) == 2) {
4363             return (
4364 832 100       10036 sprintf(join('', qw( \x%02x [\x00-\x2F\x3A-\x%02x] )), $b[1], $b[2]),
4365             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [^\x30-\x39 ] )), $b[1]-1 ) : (),
4366             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4367             );
4368             }
4369             elsif (CORE::length($b) == 4) {
4370             return (
4371 1664 100       35935 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x30-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
4372             0x81 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x81-\x%02x] [\x30-\x39 ] )), $b[1], $b[2], $b[3]-1 ) : (),
4373             0x30 < $b[2] ? sprintf(join('', qw( \x%02x [\x30-\x%02x] [\x81-\xFE ] [\x30-\x39 ] )), $b[1], $b[2]-1 ) : (),
4374             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $b[1]-1 ) : (),
4375             sprintf(join('', qw( [\x81-\xFE ] [^\x30-\x39 ] )), ),
4376             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4377             );
4378             }
4379             }
4380             elsif (CORE::length($a) == 2) {
4381 8528 100       22916 if (0) { }
    50          
4382 0         0 elsif (CORE::length($b) == 2) {
4383 1872 100       10939 my $lower_limit = join('|',
4384             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [^\x30-\x39 ] )), $a[1]+1 ) : (),
4385             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2]),
4386             );
4387 1872 100       7423 my $upper_limit = join('|',
4388             sprintf(join('', qw( \x%02x [\x00-\x%02x] )), $b[1], $b[2]),
4389             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [^\x30-\x39 ] )), $b[1]-1 ) : (),
4390             );
4391 1872         7912 return qq{(?=$lower_limit)(?=$upper_limit)};
4392             }
4393             elsif (CORE::length($b) == 4) {
4394             return (
4395 6656 100       89480 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x30-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
    100          
4396             0x81 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x81-\x%02x] [\x30-\x39 ] )), $b[1], $b[2], $b[3]-1 ) : (),
4397             0x30 < $b[2] ? sprintf(join('', qw( \x%02x [\x30-\x%02x] [\x81-\xFE ] [\x30-\x39 ] )), $b[1], $b[2]-1 ) : (),
4398             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $b[1]-1 ) : (),
4399             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [^\x30-\x39 ] )), $a[1]+1 ) : (),
4400             sprintf(join('', qw( \x%02x [\x%02x-\xFF] )), $a[1], $a[2] ),
4401             );
4402             }
4403             }
4404             elsif (CORE::length($a) == 4) {
4405 7072 50       15396 if (0) { }
4406 0         0 elsif (CORE::length($b) == 4) {
4407 7072 100       65765 my $lower_limit = join('|',
    100          
    100          
4408             $a[1] < 0xFE ? sprintf(join('', qw( [\x%02x-\xFE] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $a[1]+1 ) : (),
4409             $a[2] < 0x39 ? sprintf(join('', qw( \x%02x [\x%02x-\x39] [\x81-\xFE ] [\x30-\x39 ] )), $a[1], $a[2]+1 ) : (),
4410             $a[3] < 0xFE ? sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xFE] [\x30-\x39 ] )), $a[1], $a[2], $a[3]+1 ) : (),
4411             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x%02x-\x39] )), $a[1], $a[2], $a[3], $a[4]),
4412             );
4413 7072 100       48728 my $upper_limit = join('|',
    100          
    100          
4414             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x30-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
4415             0x81 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x81-\x%02x] [\x30-\x39 ] )), $b[1], $b[2], $b[3]-1 ) : (),
4416             0x30 < $b[2] ? sprintf(join('', qw( \x%02x [\x30-\x%02x] [\x81-\xFE ] [\x30-\x39 ] )), $b[1], $b[2]-1 ) : (),
4417             0x81 < $b[1] ? sprintf(join('', qw( [\x81-\x%02x] [\x30-\x39 ] [\x81-\xFE ] [\x30-\x39 ] )), $b[1]-1 ) : (),
4418             );
4419 7072         34433 return qq{(?=$lower_limit)(?=$upper_limit)};
4420             }
4421             }
4422              
4423             # over range of codepoint
4424 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4425             }
4426              
4427             #---------------------------------------------------------------------
4428             # qr/ [A-Z] / for UTF-8-like encoding
4429             sub list_all_by_hyphen_utf8_like {
4430 90108     90111 0 168704 my($a, $b) = @_;
4431 90108         341656 my @a = (undef, unpack 'C*', $a);
4432 90108         199406 my @b = (undef, unpack 'C*', $b);
4433              
4434 90108 100       354983 if (0) { }
    100          
    100          
    50          
4435 0         0 elsif (CORE::length($a) == 1) {
4436 9732 100       33943 if (0) { }
    100          
    100          
    50          
4437 0         0 elsif (CORE::length($b) == 1) {
4438             return (
4439 420 50       2641 $a[1]<=$b[1] ? sprintf(join('', qw( [\x%02x-\x%02x] )), $a[1],
4440             $b[1]) : (),
4441             );
4442             }
4443             elsif (CORE::length($b) == 2) {
4444             return (
4445 816 100       6953 sprintf(join('', qw( \x%02x [\x80-\x%02x] )), $b[1], $b[2]),
4446             0xC2 < $b[1] ? sprintf(join('', qw( [\xC2-\x%02x] [\x80-\xBF ] )), $b[1]-1 ) : (),
4447             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4448             );
4449             }
4450             elsif (CORE::length($b) == 3) {
4451             return (
4452 3376 100       44586 sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3]),
    100          
4453             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4454             0xE0 < $b[1] ? sprintf(join('', qw( [\xE0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4455             sprintf(join('', qw( [\xC2-\xDF ] [\x80-\xBF ] )), ),
4456             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4457             );
4458             }
4459             elsif (CORE::length($b) == 4) {
4460             return (
4461 5120 100       59944 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
4462             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
4463             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4464             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4465             sprintf(join('', qw( [\xE0-\xEF ] [\x80-\xBF ] [\x80-\xBF ] )), ),
4466             sprintf(join('', qw( [\xC2-\xDF ] [\x80-\xBF ] )), ),
4467             sprintf(join('', qw( [\x%02x-\x7F] )), $a[1] ),
4468             );
4469             }
4470             }
4471             elsif (CORE::length($a) == 2) {
4472 12692 100       49402 if (0) { }
    100          
    50          
4473 0         0 elsif (CORE::length($b) == 2) {
4474 868 100       5262 my $lower_limit = join('|',
4475             $a[1] < 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] [\x80-\xBF ] )), $a[1]+1 ) : (),
4476             sprintf(join('', qw( \x%02x [\x%02x-\xBF] )), $a[1], $a[2]),
4477             );
4478 868 100       3423 my $upper_limit = join('|',
4479             sprintf(join('', qw( \x%02x [\x80-\x%02x] )), $b[1], $b[2]),
4480             0xC2 < $b[1] ? sprintf(join('', qw( [\xC2-\x%02x] [\x80-\xBF ] )), $b[1]-1 ) : (),
4481             );
4482 868         3515 return qq{(?=$lower_limit)(?=$upper_limit)};
4483             }
4484             elsif (CORE::length($b) == 3) {
4485             return (
4486 6448 100       81930 sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3] ),
    100          
    100          
4487             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4488             0xE0 < $b[1] ? sprintf(join('', qw( [\xE0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4489             $a[1] < 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] [\x80-\xBF ] )), $a[1]+1 ) : (),
4490             sprintf(join('', qw( \x%02x [\x%02x-\xBF] )), $a[1], $a[2] ),
4491             );
4492             }
4493             elsif (CORE::length($b) == 4) {
4494             return (
4495 5376 100       84915 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
    100          
4496             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
4497             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4498             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4499             sprintf(join('', qw( [\xE0-\xEF ] [\x80-\xBF ] [\x80-\xBF ] )), ),
4500             $a[1] < 0xDF ? sprintf(join('', qw( [\x%02x-\xDF] [\x80-\xBF ] )), $a[1]+1 ) : (),
4501             sprintf(join('', qw( \x%02x [\x%02x-\xBF] )), $a[1], $a[2] ),
4502             );
4503             }
4504             }
4505             elsif (CORE::length($a) == 3) {
4506 27364 100       62264 if (0) { }
    50          
4507 0         0 elsif (CORE::length($b) == 3) {
4508 19428 100       145775 my $lower_limit = join('|',
    100          
4509             $a[1] < 0xEF ? sprintf(join('', qw( [\x%02x-\xEF] [\x80-\xBF ] [\x80-\xBF ] )), $a[1]+1 ) : (),
4510             $a[2] < 0xBF ? sprintf(join('', qw( \x%02x [\x%02x-\xBF] [\x80-\xBF ] )), $a[1], $a[2]+1 ) : (),
4511             sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xBF] )), $a[1], $a[2], $a[3]),
4512             );
4513 19428 100       126525 my $upper_limit = join('|',
    100          
4514             sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3]),
4515             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4516             0xE0 < $b[1] ? sprintf(join('', qw( [\xE0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4517             );
4518 19428         84789 return qq{(?=$lower_limit)(?=$upper_limit)};
4519             }
4520             elsif (CORE::length($b) == 4) {
4521             return (
4522 7936 100       131778 sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
    100          
    100          
    100          
    100          
4523             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
4524             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4525             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4526             $a[1] < 0xEF ? sprintf(join('', qw( [\x%02x-\xEF] [\x80-\xBF ] [\x80-\xBF ] )), $a[1]+1 ) : (),
4527             $a[2] < 0xBF ? sprintf(join('', qw( \x%02x [\x%02x-\xBF] [\x80-\xBF ] )), $a[1], $a[2]+1 ) : (),
4528             sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xBF] )), $a[1], $a[2], $a[3] ),
4529             );
4530             }
4531             }
4532             elsif (CORE::length($a) == 4) {
4533 40320 50       89565 if (0) { }
4534 0         0 elsif (CORE::length($b) == 4) {
4535 40320 100       381450 my $lower_limit = join('|',
    100          
    100          
4536             $a[1] < 0xF4 ? sprintf(join('', qw( [\x%02x-\xF4] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $a[1]+1 ) : (),
4537             $a[2] < 0xBF ? sprintf(join('', qw( \x%02x [\x%02x-\xBF] [\x80-\xBF ] [\x80-\xBF ] )), $a[1], $a[2]+1 ) : (),
4538             $a[3] < 0xBF ? sprintf(join('', qw( \x%02x \x%02x [\x%02x-\xBF] [\x80-\xBF ] )), $a[1], $a[2], $a[3]+1 ) : (),
4539             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x%02x-\xBF] )), $a[1], $a[2], $a[3], $a[4]),
4540             );
4541 40320 100       277515 my $upper_limit = join('|',
    100          
    100          
4542             sprintf(join('', qw( \x%02x \x%02x \x%02x [\x80-\x%02x] )), $b[1], $b[2], $b[3], $b[4]),
4543             0x80 < $b[3] ? sprintf(join('', qw( \x%02x \x%02x [\x80-\x%02x] [\x80-\xBF ] )), $b[1], $b[2], $b[3]-1 ) : (),
4544             0x80 < $b[2] ? sprintf(join('', qw( \x%02x [\x80-\x%02x] [\x80-\xBF ] [\x80-\xBF ] )), $b[1], $b[2]-1 ) : (),
4545             0xF0 < $b[1] ? sprintf(join('', qw( [\xF0-\x%02x] [\x80-\xBF ] [\x80-\xBF ] [\x80-\xBF ] )), $b[1]-1 ) : (),
4546             );
4547 40320         196328 return qq{(?=$lower_limit)(?=$upper_limit)};
4548             }
4549             }
4550              
4551             # over range of codepoint
4552 0         0 confess sprintf(qq{@{[__FILE__]}: codepoint class [$_[0]-$_[1]] is not 1 to 4 octets (%d-%d)}, CORE::length($a), CORE::length($b));
  0         0  
4553             }
4554              
4555             #---------------------------------------------------------------------
4556             # parse codepoint class
4557             sub parse_re_codepoint_class {
4558 118269     118272 0 230615 my($codepoint_class) = @_;
4559 118269         195794 my @sbcs = ();
4560 118269         158118 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
4561              
4562             # get members from class
4563 118269         190590 my @classmate = ();
4564 118269         428780 while ($codepoint_class !~ /\G \z /xmsgc) {
4565 353317 50       3148060 if (0) { }
    50          
    100          
    100          
    50          
4566 0         0 elsif ($codepoint_class =~ /\G\\o\{([01234567]+)\}/xmsgc) {
4567 0         0 push @classmate, mb::chr(oct $1);
4568             }
4569             elsif ($codepoint_class =~ /\G\\x\{([0123456789ABCDEFabcdef]+)\}/xmsgc) {
4570 0         0 push @classmate, mb::chr(hex $1);
4571             }
4572             elsif ($codepoint_class =~ /\G(\[:.+?:\])/xmsgc) {
4573 100         417 push @classmate, $1;
4574             }
4575             elsif ($codepoint_class =~ /\G((?>\\$x))/xmsgc) {
4576 562         2608 push @classmate, $1;
4577             }
4578             elsif ($codepoint_class =~ /\G($x)/xmsgc) {
4579 352655         1208367 push @classmate, $1;
4580             }
4581             else {
4582 0         0 confess qq{@{[__FILE__]}: codepoint_class=($codepoint_class), classmate=(@classmate)};
  0         0  
4583             }
4584             }
4585              
4586             # get regular expression for MBCS codepoint class
4587 118269         340936 for (my $i=0; $i <= $#classmate; $i++) {
4588 118721         230613 my $classmate = $classmate[$i];
4589              
4590             # hyphen of [A-Z] or [^A-Z]
4591 118721 100 100     597475 if (($i < $#classmate) and ($classmate[$i+1] eq '-')) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
4592 117298         170146 my $a = $classmate[$i];
4593 117298         194410 my $b = $classmate[$i+2];
4594 117298 100       654900 if (0) { }
    100          
    100          
    100          
    50          
4595 0         0 elsif ($script_encoding =~ /\A (?: sjis ) \z/xms) {
4596 8434         24765 push @xbcs, list_all_by_hyphen_sjis_like ($a, $b);
4597             }
4598             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
4599 252         711 push @xbcs, list_all_by_hyphen_eucjp_like ($a, $b);
4600             }
4601             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
4602 252         770 push @xbcs, list_all_by_hyphen_big5_like ($a, $b);
4603             }
4604             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
4605 18252         41843 push @xbcs, list_all_by_hyphen_gb18030_like($a, $b);
4606             }
4607             elsif ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
4608 90108         215038 push @xbcs, list_all_by_hyphen_utf8_like ($a, $b);
4609             }
4610             else {
4611 0         0 push @sbcs, "$a-$b";
4612             }
4613 117298         405659 $i += 2;
4614             }
4615              
4616             # classic perl codepoint class shortcuts
4617 34         165 elsif ($classmate eq '\\D') { push @xbcs, "(?:(?![$bare_d])$x)"; }
4618 10         55 elsif ($classmate eq '\\H') { push @xbcs, "(?:(?![$bare_h])$x)"; }
4619             # elsif ($classmate eq '\\N') { push @xbcs, "(?:(?!\\n)$x)"; } # \N in a codepoint class must be a named character: \N{...} in regex
4620             # elsif ($classmate eq '\\R') { push @xbcs, "(?>\\r\\n|[$bare_v])"; } # Unrecognized escape \R in codepoint class passed through in regex
4621 19         90 elsif ($classmate eq '\\S') { push @xbcs, "(?:(?![$bare_s])$x)"; }
4622 16         78 elsif ($classmate eq '\\V') { push @xbcs, "(?:(?![$bare_v])$x)"; }
4623 193         865 elsif ($classmate eq '\\W') { push @xbcs, "(?:(?![$bare_w])$x)"; }
4624 6         20 elsif ($classmate eq '\\b') { push @sbcs, $bare_backspace; }
4625 34         115 elsif ($classmate eq '\\d') { push @sbcs, $bare_d; }
4626 10         42 elsif ($classmate eq '\\h') { push @sbcs, $bare_h; }
4627 19         67 elsif ($classmate eq '\\s') { push @sbcs, $bare_s; }
4628 16         53 elsif ($classmate eq '\\v') { push @sbcs, $bare_v; }
4629 193         701 elsif ($classmate eq '\\w') { push @sbcs, $bare_w; }
4630              
4631             # [:POSIX:]
4632 19         53 elsif ($classmate eq '[:alnum:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x61-\x7A'; }
4633 3         10 elsif ($classmate eq '[:alpha:]' ) { push @sbcs, '\x41-\x5A\x61-\x7A'; }
4634 3         13 elsif ($classmate eq '[:ascii:]' ) { push @sbcs, '\x00-\x7F'; }
4635 3         30 elsif ($classmate eq '[:blank:]' ) { push @sbcs, '\x09\x20'; }
4636 3         13 elsif ($classmate eq '[:cntrl:]' ) { push @sbcs, '\x00-\x1F\x7F'; }
4637 3         16 elsif ($classmate eq '[:digit:]' ) { push @sbcs, '\x30-\x39'; }
4638 3         16 elsif ($classmate eq '[:graph:]' ) { push @sbcs, '\x21-\x7F'; }
4639 3         14 elsif ($classmate eq '[:lower:]' ) { push @sbcs, 'abcdefghijklmnopqrstuvwxyz'; } # /i modifier requires 'a' to 'z' literally
4640 3         9 elsif ($classmate eq '[:print:]' ) { push @sbcs, '\x20-\x7F'; }
4641 3         13 elsif ($classmate eq '[:punct:]' ) { push @sbcs, '\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E'; }
4642 3         9 elsif ($classmate eq '[:space:]' ) { push @sbcs, '\s\x0B'; } # "\s" and vertical tab ("\cK")
4643 3         14 elsif ($classmate eq '[:upper:]' ) { push @sbcs, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; } # /i modifier requires 'A' to 'Z' literally
4644 3         11 elsif ($classmate eq '[:word:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x5F\x61-\x7A'; }
4645 3         14 elsif ($classmate eq '[:xdigit:]') { push @sbcs, '\x30-\x39\x41-\x46\x61-\x66'; }
4646              
4647             # [:^POSIX:]
4648 3         21 elsif ($classmate eq '[:^alnum:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x61-\\x7A])$x)"; }
4649 3         24 elsif ($classmate eq '[:^alpha:]' ) { push @xbcs, "(?:(?![\\x41-\\x5A\\x61-\\x7A])$x)"; }
4650 3         18 elsif ($classmate eq '[:^ascii:]' ) { push @xbcs, "(?:(?![\\x00-\\x7F])$x)"; }
4651 3         20 elsif ($classmate eq '[:^blank:]' ) { push @xbcs, "(?:(?![\\x09\\x20])$x)"; }
4652 3         17 elsif ($classmate eq '[:^cntrl:]' ) { push @xbcs, "(?:(?![\\x00-\\x1F\\x7F])$x)"; }
4653 3         20 elsif ($classmate eq '[:^digit:]' ) { push @xbcs, "(?:(?![\\x30-\\x39])$x)"; }
4654 3         6094 elsif ($classmate eq '[:^graph:]' ) { push @xbcs, "(?:(?![\\x21-\\x7F])$x)"; }
4655 3         15 elsif ($classmate eq '[:^lower:]' ) { push @xbcs, "(?:(?![abcdefghijklmnopqrstuvwxyz])$x)"; } # /i modifier requires 'a' to 'z' literally
4656 3         16 elsif ($classmate eq '[:^print:]' ) { push @xbcs, "(?:(?![\\x20-\\x7F])$x)"; }
4657 3         20 elsif ($classmate eq '[:^punct:]' ) { push @xbcs, "(?:(?![\\x21-\\x2F\\x3A-\\x3F\\x40\\x5B-\\x5F\\x60\\x7B-\\x7E])$x)"; }
4658 3         15 elsif ($classmate eq '[:^space:]' ) { push @xbcs, "(?:(?![\\s\\x0B])$x)"; } # "\s" and vertical tab ("\cK")
4659 3         25 elsif ($classmate eq '[:^upper:]' ) { push @xbcs, "(?:(?![ABCDEFGHIJKLMNOPQRSTUVWXYZ])$x)"; } # /i modifier requires 'A' to 'Z' literally
4660 3         16 elsif ($classmate eq '[:^word:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x5F\\x61-\\x7A])$x)"; }
4661 3         20 elsif ($classmate eq '[:^xdigit:]') { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x46\\x61-\\x66])$x)"; }
4662              
4663             # \any
4664             elsif ($classmate =~ /\G (\\) ($x) /xmsgc) {
4665 12 50       37 if (CORE::length($2) == 1) {
4666 12         56 push @sbcs, ($1 . $2);
4667             }
4668             else {
4669 0         0 push @xbcs, '(?:' . $1 . escape_to_hex($2, ']') . ')';
4670             }
4671             }
4672              
4673             # any
4674             elsif ($classmate =~ /\G ($x) /xmsgc) {
4675 761 100       1694 if (CORE::length($1) == 1) {
4676 417         1331 push @sbcs, $1;
4677             }
4678             else {
4679 344         724 push @xbcs, '(?:' . escape_to_hex($1, ']') . ')';
4680             }
4681             }
4682              
4683             # something wrong happened
4684             else {
4685 0         0 die sprintf(<
4686 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4687             ------------------------------------------------------------------------------
4688             %s
4689             ------------------------------------------------------------------------------
4690             END
4691             }
4692             }
4693              
4694             # return codepoint class
4695 118269 50 100     665020 my $parsed =
    100 66        
    100 33        
4696             ( @sbcs and @xbcs) ? join('|', @xbcs, '['.join('',@sbcs).']') :
4697             (!@sbcs and @xbcs) ? join('|', @xbcs ) :
4698             ( @sbcs and !@xbcs) ? '['.join('',@sbcs).']' :
4699             die;
4700 118269         33752281 return $parsed;
4701             }
4702              
4703             #---------------------------------------------------------------------
4704             # parse qr'regexp' as q-like
4705             sub parse_re_as_q_endswith {
4706 948     951 0 2894 my($operator, $endswith) = @_;
4707 948         1604 my $parsed = $endswith;
4708 948         1249 while (1) {
4709 1956 100       14361 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          
4710 948         1807 $parsed .= $1;
4711 948         1453 last;
4712             }
4713              
4714             # get codepoint class
4715             elsif (/\G \[ /xmsgc) {
4716 566         909 my $classmate = '';
4717 566         689 while (1) {
4718 1766 100       7576 if (/\G \] /xmsgc) {
    100          
    100          
    50          
4719 566         901 last;
4720             }
4721             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
4722 28         58 $classmate .= $1;
4723             }
4724             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
4725 44         96 $classmate .= $1;
4726             }
4727             elsif (/\G ($x) /xmsgc) {
4728 1128         1942 $classmate .= $1;
4729             }
4730              
4731             # something wrong happened
4732             else {
4733 0         0 die sprintf(<
4734 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4735             ------------------------------------------------------------------------------
4736             %s
4737             ------------------------------------------------------------------------------
4738             END
4739             }
4740             }
4741              
4742             # parse codepoint class
4743 566         1139 $parsed .= mb::_cc($classmate);
4744             }
4745              
4746             # /./ or \any
4747 2         6 elsif (/\G \. /xmsgc) { $parsed .= "(?:$over_ascii|.)"; } # after $over_ascii, /s modifier wants "." (not [\x00-\xFF])
4748 2         9 elsif (/\G \\B /xmsgc) { $parsed .= "(?:(?
4749 12         47 elsif (/\G \\D /xmsgc) { $parsed .= "(?:(?![$bare_d])$x)"; }
4750 4         42 elsif (/\G \\H /xmsgc) { $parsed .= "(?:(?![$bare_h])$x)"; }
4751 2         8 elsif (/\G \\N /xmsgc) { $parsed .= "(?:(?!\\n)$x)"; }
4752 2         6 elsif (/\G \\R /xmsgc) { $parsed .= "(?>\\r\\n|[$bare_v])"; }
4753 7         30 elsif (/\G \\S /xmsgc) { $parsed .= "(?:(?![$bare_s])$x)"; }
4754 6         24 elsif (/\G \\V /xmsgc) { $parsed .= "(?:(?![$bare_v])$x)"; }
4755 65         260 elsif (/\G \\W /xmsgc) { $parsed .= "(?:(?![$bare_w])$x)"; }
4756 2         6 elsif (/\G \\b /xmsgc) { $parsed .= "(?:(?
4757 12         23 elsif (/\G \\d /xmsgc) { $parsed .= "[$bare_d]"; }
4758 4         11 elsif (/\G \\h /xmsgc) { $parsed .= "[$bare_h]"; }
4759 7         17 elsif (/\G \\s /xmsgc) { $parsed .= "[$bare_s]"; }
4760 6         19 elsif (/\G \\v /xmsgc) { $parsed .= "[$bare_v]"; }
4761 65         162 elsif (/\G \\w /xmsgc) { $parsed .= "[$bare_w]"; }
4762              
4763             # \o{...}
4764             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
4765 0         0 $parsed .= '(?:';
4766 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $endswith);
4767 0         0 $parsed .= ')';
4768             }
4769              
4770             # \x{...}
4771             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
4772 0         0 $parsed .= '(?:';
4773 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $endswith);
4774 0         0 $parsed .= ')';
4775             }
4776              
4777             # \0... octal escape
4778             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
4779 0         0 $parsed .= $1;
4780             }
4781              
4782             # \100...\x377 octal escape
4783             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
4784 0         0 $parsed .= $1;
4785             }
4786              
4787             # \1...\99, ... n-th previously captured string (decimal)
4788             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
4789 0         0 $parsed .= $1;
4790 0 0       0 if ($operator eq 's') {
4791 0         0 $parsed .= ($2 + 1);
4792             }
4793             else {
4794 0         0 $parsed .= $2;
4795             }
4796             }
4797              
4798             # any
4799             elsif (/\G ($x) /xmsgc) {
4800 244 100       559 if (CORE::length($1) == 1) {
4801 99         212 $parsed .= $1;
4802             }
4803             else {
4804 145         195 $parsed .= '(?:';
4805 145         315 $parsed .= escape_to_hex($1, $endswith);
4806 145         234 $parsed .= ')';
4807             }
4808             }
4809              
4810             # something wrong happened
4811             else {
4812 0         0 die sprintf(<
4813 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4814             ------------------------------------------------------------------------------
4815             %s
4816             ------------------------------------------------------------------------------
4817             END
4818             }
4819             }
4820 948         2081 return $parsed;
4821             }
4822              
4823             #---------------------------------------------------------------------
4824             # parse qr{regexp} in balanced blackets
4825             sub parse_re_balanced {
4826 564     567 0 1440 my($operator, $open_bracket) = @_;
4827 564   50     2780 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
4828 564         1189 my $parsed = $open_bracket;
4829 564         662 my $nest_bracket = 1;
4830 564         590 my $nest_escape = 0;
4831 564         601 while (1) {
4832 1133 50       9851 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
4833 0         0 $parsed .= $1;
4834 0         0 $nest_bracket++;
4835             }
4836             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
4837 564 50       958 if (--$nest_bracket <= 0) {
4838 564         875 $parsed .= ('>)]}' x $nest_escape);
4839 564         810 $parsed .= $1;
4840 564         830 last;
4841             }
4842             else {
4843 0         0 $parsed .= $1;
4844             }
4845             }
4846              
4847             # \L\u --> \u\L
4848             elsif (/\G \\L \\u /xmsgc) {
4849 0         0 $parsed .= '@{[mb::ucfirst(qq<';
4850 0         0 $parsed .= '@{[mb::lc(qq<';
4851 0         0 $nest_escape++;
4852 0         0 $nest_escape++;
4853             }
4854              
4855             # \U\l --> \l\U
4856             elsif (/\G \\U \\l /xmsgc) {
4857 0         0 $parsed .= '@{[mb::lcfirst(qq<';
4858 0         0 $parsed .= '@{[mb::uc(qq<';
4859 0         0 $nest_escape++;
4860 0         0 $nest_escape++;
4861             }
4862              
4863             # \L
4864             elsif (/\G \\L /xmsgc) {
4865 0         0 $parsed .= '@{[mb::lc(qq<';
4866 0         0 $nest_escape++;
4867             }
4868              
4869             # \U
4870             elsif (/\G \\U /xmsgc) {
4871 0         0 $parsed .= '@{[mb::uc(qq<';
4872 0         0 $nest_escape++;
4873             }
4874              
4875             # \l
4876             elsif (/\G \\l /xmsgc) {
4877 0         0 $parsed .= '@{[mb::lcfirst(qq<';
4878 0         0 $nest_escape++;
4879             }
4880              
4881             # \u
4882             elsif (/\G \\u /xmsgc) {
4883 0         0 $parsed .= '@{[mb::ucfirst(qq<';
4884 0         0 $nest_escape++;
4885             }
4886              
4887             # \Q
4888             elsif (/\G \\Q /xmsgc) {
4889 0         0 $parsed .= '@{[quotemeta(qq<';
4890 0         0 $nest_escape++;
4891             }
4892              
4893             # \E
4894             elsif (/\G \\E /xmsgc) {
4895 0         0 $parsed .= ('>)]}' x $nest_escape);
4896 0         0 $nest_escape = 0;
4897             }
4898              
4899             else {
4900 569         1170 $parsed .= parse_re($operator, $open_bracket);
4901             }
4902             }
4903 564         1049 return $parsed;
4904             }
4905              
4906             #---------------------------------------------------------------------
4907             # parse qr/regexp/ that ends with a character
4908             sub parse_re_endswith {
4909 120529     120531 0 414626 my($operator, $endswith) = @_;
4910 120529         221209 my $parsed = $endswith;
4911 120529         199518 my $nest_escape = 0;
4912 120529         166785 while (1) {
4913 242344 100       1548602 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
4914 120529         221568 $parsed .= ('>)]}' x $nest_escape);
4915 120529         243058 $parsed .= $1;
4916 120529         174857 last;
4917             }
4918              
4919             # \L\u --> \u\L
4920             elsif (/\G \\L \\u /xmsgc) {
4921 0         0 $parsed .= '@{[mb::ucfirst(qq<';
4922 0         0 $parsed .= '@{[mb::lc(qq<';
4923 0         0 $nest_escape++;
4924 0         0 $nest_escape++;
4925             }
4926              
4927             # \U\l --> \l\U
4928             elsif (/\G \\U \\l /xmsgc) {
4929 0         0 $parsed .= '@{[mb::lcfirst(qq<';
4930 0         0 $parsed .= '@{[mb::uc(qq<';
4931 0         0 $nest_escape++;
4932 0         0 $nest_escape++;
4933             }
4934              
4935             # \L
4936             elsif (/\G \\L /xmsgc) {
4937 0         0 $parsed .= '@{[mb::lc(qq<';
4938 0         0 $nest_escape++;
4939             }
4940              
4941             # \U
4942             elsif (/\G \\U /xmsgc) {
4943 0         0 $parsed .= '@{[mb::uc(qq<';
4944 0         0 $nest_escape++;
4945             }
4946              
4947             # \l
4948             elsif (/\G \\l /xmsgc) {
4949 0         0 $parsed .= '@{[mb::lcfirst(qq<';
4950 0         0 $nest_escape++;
4951             }
4952              
4953             # \u
4954             elsif (/\G \\u /xmsgc) {
4955 0         0 $parsed .= '@{[mb::ucfirst(qq<';
4956 0         0 $nest_escape++;
4957             }
4958              
4959             # \Q
4960             elsif (/\G \\Q /xmsgc) {
4961 0         0 $parsed .= '@{[quotemeta(qq<';
4962 0         0 $nest_escape++;
4963             }
4964              
4965             # \E
4966             elsif (/\G \\E /xmsgc) {
4967 0         0 $parsed .= ('>)]}' x $nest_escape);
4968 0         0 $nest_escape = 0;
4969             }
4970              
4971             else {
4972 121815         291589 $parsed .= parse_re($operator, $endswith);
4973             }
4974             }
4975 120529         271057 return $parsed;
4976             }
4977              
4978             #---------------------------------------------------------------------
4979             # parse qr/regexp/ common routine
4980             sub parse_re {
4981 122384     122384 0 222312 my($operator, $closewith) = @_;
4982 122384         181320 my $parsed = '';
4983              
4984             # codepoint class
4985 122384 100       377363 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          
4986 118837         194088 my $classmate = '';
4987 118837         162338 while (1) {
4988 532652 100       3074046 if (/\G \] /xmsgc) {
    100          
    100          
    100          
    50          
4989 118837         187893 last;
4990             }
4991             elsif (/\G (\\) /xmsgc) {
4992 510         1169 $classmate .= "\\$1";
4993             }
4994             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
4995 98         220 $classmate .= $1;
4996             }
4997             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
4998 114         285 $classmate .= $1;
4999             }
5000             elsif (/\G ($x) /xmsgc) {
5001 413093         786385 $classmate .= escape_qq($1, ']');
5002             }
5003              
5004             # something wrong happened
5005             else {
5006 0         0 die sprintf(<
5007 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5008             ------------------------------------------------------------------------------
5009             %s
5010             ------------------------------------------------------------------------------
5011             END
5012             }
5013             }
5014              
5015             # quote by (?: ... ) to avoid syntax error: Can't coerce array into hash at ...
5016             #
5017             # [ABC]{3} --> @{[mb::_cc(qq[ABC])]}{3} # makes: Can't coerce array into hash at ...
5018             # [ABC]{3} --> (?:@{[mb::_cc(qq[ABC])]}){3} # ok
5019              
5020 118837         271108 $parsed .= "(?:\@{[mb::_cc(qq[$classmate])]})";
5021             }
5022              
5023             # /./ or \any
5024 20         49 elsif (/\G \. /xmsgc) { $parsed .= '(?:@{[@mb::_dot]})'; }
5025 7         21 elsif (/\G \\B /xmsgc) { $parsed .= '(?:@{[@mb::_B]})'; }
5026 18         39 elsif (/\G \\D /xmsgc) { $parsed .= '(?:@{[@mb::_D]})'; }
5027 10         23 elsif (/\G \\H /xmsgc) { $parsed .= '(?:@{[@mb::_H]})'; }
5028 8         26 elsif (/\G \\N /xmsgc) { $parsed .= '(?:@{[@mb::_N]})'; }
5029 12         29 elsif (/\G \\R /xmsgc) { $parsed .= '(?:@{[@mb::_R]})'; }
5030 14         29 elsif (/\G \\S /xmsgc) { $parsed .= '(?:@{[@mb::_S]})'; }
5031 12         31 elsif (/\G \\V /xmsgc) { $parsed .= '(?:@{[@mb::_V]})'; }
5032 71         105 elsif (/\G \\W /xmsgc) { $parsed .= '(?:@{[@mb::_W]})'; }
5033 7         18 elsif (/\G \\b /xmsgc) { $parsed .= '(?:@{[@mb::_b]})'; }
5034 17         28 elsif (/\G \\d /xmsgc) { $parsed .= '(?:@{[@mb::_d]})'; }
5035 10         25 elsif (/\G \\h /xmsgc) { $parsed .= '(?:@{[@mb::_h]})'; }
5036 18         44 elsif (/\G \\s /xmsgc) { $parsed .= '(?:@{[@mb::_s]})'; }
5037 14         30 elsif (/\G \\v /xmsgc) { $parsed .= '(?:@{[@mb::_v]})'; }
5038 70         102 elsif (/\G \\w /xmsgc) { $parsed .= '(?:@{[@mb::_w]})'; }
5039              
5040             # \o{...}
5041             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
5042 0         0 $parsed .= '(?:';
5043 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $closewith);
5044 0         0 $parsed .= ')';
5045             }
5046              
5047             # \x{...}
5048             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
5049 0         0 $parsed .= '(?:';
5050 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $closewith);
5051 0         0 $parsed .= ')';
5052             }
5053              
5054             # \0... octal escape
5055             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
5056 0         0 $parsed .= $1;
5057             }
5058              
5059             # \100...\x377 octal escape
5060             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
5061 0         0 $parsed .= $1;
5062             }
5063              
5064             # \1...\99, ... n-th previously captured string (decimal)
5065             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
5066 24         50 $parsed .= $1;
5067 24 50       51 if ($operator eq 's') {
5068 0         0 $parsed .= ($2 + 1);
5069             }
5070             else {
5071 24         44 $parsed .= $2;
5072             }
5073             }
5074              
5075             # \any
5076             elsif (/\G (\\) ($x) /xmsgc) {
5077 5 50       15 if (CORE::length($2) == 1) {
5078 5         10 $parsed .= ($1 . $2);
5079             }
5080             else {
5081 0         0 $parsed .= ('(?:' . $1 . escape_qq($2, $closewith) . ')');
5082             }
5083             }
5084              
5085             # $` --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5086             # ${`} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5087             # $PREMATCH --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5088             # ${PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5089             # ${^PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
5090             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
5091 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_PREMATCH())]}';
5092             }
5093              
5094             # $& --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5095             # ${&} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5096             # $MATCH --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5097             # ${MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5098             # ${^MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
5099             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
5100 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_MATCH())]}';
5101             }
5102              
5103             # $1 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
5104             # $2 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
5105             # $3 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
5106             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
5107 24         74 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($1))]}";
5108             }
5109              
5110             # ${^CAPTURE}[0] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
5111             # ${^CAPTURE}[1] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
5112             # ${^CAPTURE}[2] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
5113             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
5114 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
5115 0         0 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($n_th+1))]}";
5116             }
5117              
5118             # @- --> @{[mb::_LAST_MATCH_START()]}
5119             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
5120             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
5121             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
5122             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
5123 0         0 $parsed .= '@{[mb::_LAST_MATCH_START()]}';
5124             }
5125              
5126             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
5127             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
5128             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
5129             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
5130             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
5131 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
5132 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
5133             }
5134              
5135             # @+ --> @{[mb::_LAST_MATCH_END()]}
5136             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
5137             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
5138             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
5139             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
5140 0         0 $parsed .= '@{[mb::_LAST_MATCH_END()]}';
5141             }
5142              
5143             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
5144             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
5145             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
5146             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
5147             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
5148 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
5149 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
5150             }
5151              
5152             # any
5153             elsif (/\G ($x) /xmsgc) {
5154 3186 100       7238 if (CORE::length($1) == 1) {
5155 2625         4790 $parsed .= $1;
5156             }
5157             else {
5158 561         1190 $parsed .= ('(?:' . escape_qq($1, $closewith) . ')');
5159             }
5160             }
5161              
5162             # something wrong happened
5163             else {
5164 0         0 die sprintf(<
5165 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5166             ------------------------------------------------------------------------------
5167             %s
5168             ------------------------------------------------------------------------------
5169             END
5170             }
5171 122384         324518 return $parsed;
5172             }
5173              
5174             #---------------------------------------------------------------------
5175             # parse modifiers of qr///here
5176             sub parse_re_modifier {
5177 122041     122041 0 200572 my $modifier_i = '';
5178 122041         163119 my $modifier_not_cegir = '';
5179 122041         183978 my $modifier_cegr = '';
5180 122041         148572 while (1) {
5181 122341 50       431384 if (/\G [adlpu] /xmsgc) {
    100          
    100          
    100          
5182             # drop modifiers
5183             }
5184             elsif (/\G ([i]) /xmsgc) {
5185 100         205 $modifier_i .= $1;
5186             }
5187             elsif (/\G ([cegr]) /xmsgc) {
5188 35         83 $modifier_cegr .= $1;
5189             }
5190             elsif (/\G ([a-z]) /xmsgc) {
5191 165         314 $modifier_not_cegir .= $1;
5192             }
5193             else {
5194 122041         157536 last;
5195             }
5196             }
5197 122041         380923 return ($modifier_i, $modifier_not_cegir, $modifier_cegr);
5198             }
5199              
5200             #---------------------------------------------------------------------
5201             # parse modifiers of tr///here
5202             sub parse_tr_modifier {
5203 2153     2153 0 3104 my $modifier_not_r = '';
5204 2153         2954 my $modifier_r = '';
5205 2153         2615 while (1) {
5206 2241 50       6483 if (/\G ([r]) /xmsgc) {
    100          
5207 0         0 $modifier_r .= $1;
5208             }
5209             elsif (/\G ([a-z]) /xmsgc) {
5210 88         155 $modifier_not_r .= $1;
5211             }
5212             else {
5213 2153         2891 last;
5214             }
5215             }
5216 2153         5789 return ($modifier_not_r, $modifier_r);
5217             }
5218              
5219             #---------------------------------------------------------------------
5220             # makes codepoint class from string
5221             sub codepoint_tr {
5222 2125     2125 0 4698 my $searchlist = quotee_of($_[0]);
5223              
5224 2125         3411 my @sbcs = ();
5225 2125         2953 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
5226 2125         5764 while ($searchlist !~ /\G \z /xmsgc) {
5227              
5228             # \-
5229 3249 100       22486 if ($searchlist =~ /\G (\\-) /xmsgc) {
    100          
    100          
    50          
5230 9         24 push @sbcs, $1;
5231             }
5232              
5233             # -
5234             elsif ($searchlist =~ /\G (-) /xmsgc) {
5235 27         89 push @sbcs, $1;
5236             }
5237              
5238             # any qq escapee
5239             elsif ($searchlist =~ /\G ([$escapee_in_qq_like]) /xmsgc) {
5240 1036         4150 push @sbcs, "\\$1";
5241             }
5242              
5243             # any
5244             elsif ($searchlist =~ /\G ($x) /xmsgc) {
5245 2177 100       4941 if (CORE::length($1) == 1) {
5246 1146         3760 push @sbcs, $1;
5247             }
5248             else {
5249 1031         2163 push @xbcs, escape_qq($1, '\\');
5250             }
5251             }
5252              
5253             # something wrong happened
5254             else {
5255 0         0 die sprintf(<
5256 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
5257             ------------------------------------------------------------------------------
5258             %s
5259             ------------------------------------------------------------------------------
5260             END
5261             }
5262             }
5263              
5264             # return codepoint class
5265             return
5266 2125 50 100     20185 ( @sbcs and @xbcs) ? join('|', @xbcs, '['.join('',@sbcs).']') :
    100 66        
    100 33        
5267             (!@sbcs and @xbcs) ? join('|', @xbcs ) :
5268             ( @sbcs and !@xbcs) ? '['.join('',@sbcs).']' :
5269             die;
5270             }
5271              
5272             #---------------------------------------------------------------------
5273             # get quotee from quoted "quotee"
5274             sub quotee_of {
5275 3260 50   3260 0 6608 if (CORE::length($_[0]) >= 2) {
5276 3260         10754 return CORE::substr($_[0],1,-1);
5277             }
5278             else {
5279 0         0 die;
5280             }
5281             }
5282              
5283             #---------------------------------------------------------------------
5284             # escape q/string/ as q-like quote
5285             sub escape_q {
5286 569672     569672 0 1130920 my($codepoint, $endswith) = @_;
5287 569672 50       2450177 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
5288 0         0 return "$1\\$2";
5289             }
5290             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ($escapee_in_q__like) \z/xms) {
5291 1992         9458 return "$1\\$2";
5292             }
5293             else {
5294 567680         1192200 return $codepoint;
5295             }
5296             }
5297              
5298             #---------------------------------------------------------------------
5299             # escape qq/string/ as qq-like quote
5300             sub escape_qq {
5301 975993     975993 0 1844916 my($codepoint, $endswith) = @_;
5302              
5303             # m@`@ --> m`\x60`
5304             # qr@`@ --> qr`\x60`
5305             # s@`@``@ --> s`\x60`\x60\x60`
5306             # m:`: --> m`\x60`
5307             # qr:`: --> qr`\x60`
5308             # s:`:``: --> s`\x60`\x60\x60`
5309 975993 50       11664709 if ($codepoint eq '`') {
    100          
    100          
5310 0         0 return '\\x60';
5311             }
5312             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
5313 1032         5000 return "$1\\$2";
5314             }
5315             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
5316 18843         102979 return "$1\\$2";
5317             }
5318             else {
5319 956118         2185147 return $codepoint;
5320             }
5321             }
5322              
5323             #---------------------------------------------------------------------
5324             # escape tr/here/here/ as tr-like quote
5325             sub escape_tr {
5326 4572     4572 0 9815 my($codepoint, $endswith) = @_;
5327 4572 50       122028 if ($codepoint =~ /\A (\Q$endswith\E) \z/xms) {
    50          
    100          
5328 0         0 return "\\$1";
5329             }
5330             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
5331 0         0 return "$1\\$2";
5332             }
5333             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ($escapee_in_q__like) \z/xms) {
5334 1988         13325 return "$1\\$2";
5335             }
5336             else {
5337 2584         11957 return $codepoint;
5338             }
5339             }
5340              
5341             #---------------------------------------------------------------------
5342             # escape qq/string/ or qr/regexp/ to hex
5343             sub escape_to_hex {
5344 490     490 0 1018 my($codepoint, $endswith) = @_;
5345 490 100       4042 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
5346 28         143 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
5347             }
5348              
5349             # in qr'...', $escapee_in_qq_like is right, not $escapee_in_q__like
5350             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
5351 82         588 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
5352             }
5353             else {
5354 380         1640 return $codepoint;
5355             }
5356             }
5357              
5358             #---------------------------------------------------------------------
5359             # compatible routines for %mb of UTF8::R2 module
5360             #
5361             # tie my %mb, 'mb';
5362             # $result = $_ =~ $mb{qr/$utf8regex/imsxo}
5363             # $result = $_ =~ m<\G$mb{qr/$utf8regex/imsxo}>gc
5364             # $result = $_ =~ s<$mb{qr/before/imsxo}>egr
5365              
5366 103     103   491 sub TIEHASH { bless { }, $_[0] }
5367 0     0   0 sub FETCH { $_[1] }
5368       0     sub STORE { }
5369       103     sub FIRSTKEY { }
5370       0     sub NEXTKEY { }
5371       0     sub EXISTS { }
5372       0     sub DELETE { }
5373       0     sub CLEAR { }
5374       0     sub UNTIE { }
5375       0     sub DESTROY { }
5376       0     sub SCALAR { }
5377              
5378             #---------------------------------------------------------------------
5379              
5380             1;
5381              
5382             __END__