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   1140354 use 5.00503; # Universal Consensus 1998 for primetools
  113         334  
14             # use 5.008001; # Lancaster Consensus 2013 for toolchains
15              
16             $VERSION = '0.63';
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   3183 BEGIN { pop @INC if $INC[-1] eq '.' } # CVE-2016-1238: Important unsafe module load path flaw
26 113     109   854 use strict;
  113         313  
  113         7416  
27 109 50 33 109   2481 BEGIN { if ($] < 5.006 && !defined(&warnings::import)) { $INC{'warnings.pm'} = 'stub'; eval 'package warnings; sub import {}' } } use warnings; local $^W=1;
  4     108   6  
  4         105  
  109         429  
  109         163  
  109         55640  
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   3295 my $self = shift @_;
79              
80             # confirm version
81 106 50 66     1270 if (defined($_[0]) and ($_[0] =~ /\A [0-9] /xms)) {
82 3 0       13 if ($_[0] ne $mb::VERSION) {
83 3         3 my($package, $filename, $line) = caller;
84 3         66 die "$filename requires @{[__PACKAGE__]} $_[0], however @{[__FILE__]} am only $mb::VERSION, stopped at $filename line $line.\n";
  3         12  
  3         3  
85             }
86 3         65 shift @_;
87             }
88              
89             # set system encoding
90 106         805 $system_encoding = detect_system_encoding();
91              
92             # set script encoding
93 106 100       308 if (defined $_[0]) {
94 13         88 my $encoding = $_[0];
95 13 50       71 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
96 13         38 mb::set_script_encoding($encoding);
97             }
98             else {
99 3         71 die "@{[__FILE__]} script_encoding '$encoding' not supported.\n";
  3         12  
100             }
101             }
102             else {
103 96         287 mb::set_script_encoding($system_encoding);
104             }
105              
106             # tie my %mb, __PACKAGE__; # makes: Parentheses missing around "my" list
107 108     108   719 no strict qw(refs);
  108         159  
  108         66059  
108 106         643 tie my %mb, 'mb';
109 106         460 *{caller().'::mb'} = { %mb };
  106         677  
110              
111             # $^X($EXECUTABLE_NAME) for execute MBCS Perl script
112 106         328 $mb::PERL = qq{$^X @{[__FILE__]}};
  106         435  
113 106         227 $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         439 ($mb::ORIG_PROGRAM_NAME = $0) =~ s/\.oo(\.[^.]+)\z/$1/;
117 106         156 $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         285 my $old_package = mb::get_old_package();
121 106         420 for my $subroutine (qw( chop chr do dosglob eval getc index index_byte length ord require reverse rindex rindex_byte substr tr )) {
122 1651         1414 *{$old_package . $subroutine} = \&{"mb::$subroutine"};
  1651         14408  
  1651         2770  
123             }
124             }
125              
126             #---------------------------------------------------------------------
127             # running as command
128             sub main {
129              
130             # usage
131 3 0   3 0 13 if (scalar(@ARGV) == 0) {
132 3         4 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         67 $system_encoding = detect_system_encoding();
155              
156             # set script encoding from command line
157 3         11 my $encoding = '';
158 3 0       5 if (($encoding) = $ARGV[0] =~ /\A -e ( .+ ) \z/xms) {
    0          
159 3 0       62 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
160 3         13 mb::set_script_encoding($encoding);
161 3         5 shift @ARGV;
162             }
163             else {
164 3         65 die "script_encoding '$encoding' not supported.\n";
165             }
166             }
167             elsif ($ARGV[0] =~ /\A -e \z/xms) {
168 3         12 $encoding = $ARGV[1];
169 3 0       29 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | rfc2279 | sjis | uhc | utf8 | wtf8 ) \z/xms) {
170 3         105 mb::set_script_encoding($encoding);
171 3         14 shift @ARGV;
172 3         3 shift @ARGV;
173             }
174             else {
175 3         90 die "script_encoding '$encoding' not supported.\n";
176             }
177             }
178             else {
179 3         14 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     67 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       12 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   682 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  108         177  
  108         5036  
  3         63  
  3         11  
  3         3  
  3         72  
196 108     108   2073 { no strict 'refs'; close($fh) }
  108         144  
  108         14744  
  3         13  
  3         4  
197              
198             # poor file locking
199 3     3   68 local $SIG{__DIE__} = sub { rmdir "$ARGV[0].lock"; };
  3         12  
200 3 0       4 if (mkdir "$ARGV[0].lock", 0755) {
201 3 0       66 my $fh = mb::_open_w($script_oo) or die "$0(@{[__LINE__]}): can't open file: $script_oo\n";
  3         11  
202 108     108   543 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  108         368  
  108         5609  
  3         80  
  3         11  
  3         4  
203 108     108   470 { no strict 'refs'; close($fh) }
  108         233  
  108         122646  
  3         4  
  3         95  
  3         14  
204 3         4 rmdir "$ARGV[0].lock";
205             }
206             else {
207 3         71 die "$0(@{[__LINE__]}): can't mkdir: $ARGV[0].lock\n";
  3         13  
208             }
209             }
210              
211             # run octet-oriented script
212 3         3 my $module_path = '';
213 3         66 my $module_name = '';
214 3         12 my $quote = '';
215 3 0       5 if ($OSNAME =~ /MSWin32/) {
216 3 0       63 if ($0 =~ m{ ([^\/\\]+)\.pm \z}xmsi) {
217 3         12 ($module_path, $module_name) = ($`, $1);
218 3   0     3 $module_path ||= '.';
219 3         64 $module_path =~ s{ [\/\\] \z}{}xms;
220             }
221             else {
222 3         12 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         5  
223             }
224 3         66 $quote = q{"};
225             }
226             else {
227 3 0       13 if ($0 =~ m{ ([^\/]+)\.pm \z}xmsi) {
228 3         3 ($module_path, $module_name) = ($`, $1);
229 3   0     66 $module_path ||= '.';
230 3         12 $module_path =~ s{ / \z}{}xms;
231             }
232             else {
233 3         5 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         64  
234             }
235 3         15 $quote = q{'};
236             }
237              
238             # @ARGV wildcard globbing
239 3 0       4 if ($OSNAME =~ /MSWin32/) {
240 3         78 my @argv = ();
241 3         16 for (@ARGV) {
242              
243             # has space
244 3 0       5 if (/\A (?:$x)*? [ ] /xms) {
    0          
245 3 0       98 if (my @glob = mb::dosglob(qq{"$_"})) {
246 3         16 push @argv, @glob;
247             }
248             else {
249 3         5 push @argv, $_;
250             }
251             }
252              
253             # has wildcard metachar
254             elsif (/\A (?:$x)*? [*?] /xms) {
255 3 0       84 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         115 push @argv, $_;
266             }
267             }
268 3         12 @ARGV = @argv;
269             }
270              
271             # run octet-oriented script
272 3         5 $| = 1;
273 3 0       69 system($^X, "-I$module_path", "-M$module_name=$mb::VERSION,$script_encoding", map { / / ? "$quote$_$quote" : $_ } $script_oo, @ARGV[1..$#ARGV]);
  3         12  
274 3         4 exit($? >> 8);
275             }
276              
277             #---------------------------------------------------------------------
278             # cluck() for MBCS encoding
279             sub cluck {
280 3     3 0 66 my $i = 0;
281 3         14 my @cluck = ();
282 3         3 while (my($package, $filename, $line, $subroutine) = caller($i)) {
283 3         69 push @cluck, "[$i] $filename($line) $subroutine\n";
284 3         14 $i++;
285             }
286 3         3 print STDERR "\n", @_, "\n";
287 3         67 print STDERR CORE::reverse @cluck;
288             }
289              
290             #---------------------------------------------------------------------
291             # confess() for MBCS encoding
292             sub confess {
293 3     3 0 12 my $i = 0;
294 3         4 my @confess = ();
295 3         63 while (my($package, $filename, $line, $subroutine) = caller($i)) {
296 3         11 push @confess, "[$i] $filename($line) $subroutine\n";
297 3         4 $i++;
298             }
299 3         61 print STDERR "\n", @_, "\n";
300 3         12 print STDERR CORE::reverse @confess;
301 3         4 die;
302             }
303              
304             #---------------------------------------------------------------------
305             # short cut of (stat(file))[9]
306             sub mtime {
307 3     3 0 112 my($file) = @_;
308 3         12 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 374 my $chop = '';
319 21 100       109 for (@_ ? @_ : $_) {
320 29 100       131 if (my @x = /\G$x/g) {
321 23         22 $chop = pop @x;
322 23         119 $_ = join '', @x;
323             }
324             }
325 21         34 return $chop;
326             }
327              
328             #---------------------------------------------------------------------
329             # chr() for MBCS encoding
330             sub mb::chr (;$) {
331 30 100   30 0 406 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         137 my @octet = ();
338 30         43 CORE::do {
339 34         79 unshift @octet, ($number % 0x100);
340 34         151 $number = int($number / 0x100);
341             } while ($number > 0);
342 30         115 return pack 'C*', @octet;
343             }
344              
345             #---------------------------------------------------------------------
346             # do FILE for MBCS encoding
347             sub mb::do ($) {
348 8     8 0 4993 my($file) = @_;
349 8         81 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  43         133  
350 8 50       107 if (-f $prefix_file) {
351              
352             # poor "make"
353 8         199 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
354 8 0 33     362 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       45 my $fh = mb::_open_r($prefix_file) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file\n";
  3         73  
360 108     108   763 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  108         174  
  108         5624  
  8         24  
  8         44  
  8         85  
  8         228  
361 108     108   465 { no strict 'refs'; close($fh) }
  108         149  
  108         11459  
  8         40  
  8         153  
362              
363             # poor file locking
364 8     3   96 local $SIG{__DIE__} = sub { rmdir "$prefix_file.lock"; };
  3         4  
365 8 50       1016 if (mkdir "$prefix_file.lock", 0755) {
366 8 50       38 my $fh = mb::_open_w($prefix_file_oo) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file_oo\n";
  3         6  
367 108     108   528 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  108         155  
  108         4903  
  8         23  
  8         15  
  8         119  
368 108     108   418 { no strict 'refs'; close($fh) }
  108         139  
  108         193411  
  8         80  
  8         29  
  8         312  
369 8         609 rmdir "$prefix_file.lock";
370             }
371             else {
372 3         26 confess "$0(@{[__LINE__]}): can't mkdir: $prefix_file.lock\n";
  3         10  
373             }
374             }
375 8         105 $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         485 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         4 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 670 my $expr = @_ ? $_[0] : $_;
394 11         26 my @glob = ();
395              
396             # works on not MSWin32
397 11 50       18 if ($OSNAME !~ /MSWin32/) {
398 11         1983 @glob = CORE::glob($expr);
399             }
400              
401             # works on MSWin32
402             else {
403              
404             # gets pattern
405 3         11 while ($expr =~ s{\A [\x20]* ( "(?:$x)+?" | (?:(?!["\x20])$x)+ ) }{}xms) {
406 3         5 my $pattern = $1;
407              
408             # avoids command injection
409 3 0       64 next if $pattern =~ /\G${mb::_anchor} \& /xms;
410 3 0       32 next if $pattern =~ /\G${mb::_anchor} \( /xms;
411 3 0       5 next if $pattern =~ /\G${mb::_anchor} \) /xms;
412 3 0       68 next if $pattern =~ /\G${mb::_anchor} \< /xms;
413 3 0       12 next if $pattern =~ /\G${mb::_anchor} \> /xms;
414 3 0       5 next if $pattern =~ /\G${mb::_anchor} \^ /xms;
415 3 0       74 next if $pattern =~ /\G${mb::_anchor} \| /xms;
416              
417             # makes globbing result
418 3         10 mb::tr($pattern, '/', "\x5C");
419 3 0       6 if (my($dir) = $pattern =~ m{\A ($x*) \\ }xms) {
420 3         63 push @glob, map { "$dir\\$_" } CORE::split /\n/, `DIR /B $pattern 2>NUL`;
  3         11  
421             }
422             else {
423 3         4 push @glob, CORE::split /\n/, `DIR /B $pattern 2>NUL`;
424             }
425             }
426             }
427              
428             # returns globbing result
429 11         112 my %glob = map { $_ => 1 } @glob;
  27         57  
430 11 50       34 return sort { (mb::uc($a) cmp mb::uc($b)) || ($a cmp $b) } keys %glob;
  26         131  
431             }
432              
433             #---------------------------------------------------------------------
434             # eval STRING for MBCS encoding
435             sub mb::eval (;$) {
436 15039 100   15039 0 38046852 local $_ = @_ ? $_[0] : $_;
437              
438             # run as Perl script in caller package
439 15039         60987 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 2406567 my $fh = @_ ? shift(@_) : \*STDIN;
450 40 50 33     171 confess 'Too many arguments for mb::getc' if @_ and not wantarray;
451 40         300 my $getc = CORE::getc $fh;
452 40 100       218 if ($script_encoding =~ /\A (?: sjis ) \z/xms) {
    50          
    50          
    50          
    50          
453 39 100       115 if ($getc =~ /\A [\x81-\x9F\xE0-\xFC] \z/xms) {
454 21         55 $getc .= CORE::getc $fh;
455             }
456             }
457             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
458 3 0       83 if ($getc =~ /\A [\xA1-\xFE] \z/xms) {
459 3         12 $getc .= CORE::getc $fh;
460             }
461             }
462             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
463 3 0       4 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
464 3         194 $getc .= CORE::getc $fh;
465             }
466             }
467             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
468 3 0       33 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
469 3         4 $getc .= CORE::getc $fh;
470 3 0       70 if ($getc =~ /\A [\x81-\xFE] [\x30-\x39] \z/xms) {
471 3         12 $getc .= CORE::getc $fh;
472 3         4 $getc .= CORE::getc $fh;
473             }
474             }
475             }
476             elsif ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
477 4 50       69 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         12 $getc .= CORE::getc $fh;
481             }
482             elsif ($getc =~ /\A [\xE0-\xEF] \z/xms) {
483 3         5 $getc .= CORE::getc $fh;
484 3         66 $getc .= CORE::getc $fh;
485             }
486             elsif ($getc =~ /\A [\xF0-\xF4] \z/xms) {
487 3         13 $getc .= CORE::getc $fh;
488 3         3 $getc .= CORE::getc $fh;
489 3         65 $getc .= CORE::getc $fh;
490             }
491             }
492 40 100       159 return wantarray ? ($getc,@_) : $getc;
493             }
494              
495             #---------------------------------------------------------------------
496             # index() for MBCS encoding
497             sub mb::index ($$;$) {
498 11     11 0 287 my $index = 0;
499 11 100       103 if (@_ == 3) {
500 7         83 $index = mb::index_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
501             }
502             else {
503 7         13 $index = mb::index_byte($_[0], $_[1]);
504             }
505 11 100       77 if ($index == -1) {
506 7         20 return -1;
507             }
508             else {
509 7         126 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 299 my($str,$substr,$position) = @_;
517 19   100     68 $position ||= 0;
518 19         16 my $pos = 0;
519 19         149 while ($pos < CORE::length($str)) {
520 181 100       216 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
521 15 100       18 if ($pos >= $position) {
522 11         87 return $pos;
523             }
524             }
525 173 50       496 if (CORE::substr($str,$pos) =~ /\A($x)/xms) {
526 173         227 $pos += CORE::length($1);
527             }
528             else {
529 3         67 $pos += 1;
530             }
531             }
532 11         24 return -1;
533             }
534              
535             #---------------------------------------------------------------------
536             # universal lc() for MBCS encoding
537             sub mb::lc (;$) {
538 14 100   14 1 1841 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       420 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         1205  
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 133 local $_ = @_ ? $_[0] : $_;
548 5 50       141 if (/\A($x)(.*)\z/s) {
549 5         17 return mb::lc($1) . $2;
550             }
551             else {
552 3         4 return '';
553             }
554             }
555              
556             #---------------------------------------------------------------------
557             # length() for MBCS encoding
558             sub mb::length (;$) {
559 19 100   19 0 296 local $_ = @_ ? $_[0] : $_;
560 19         202 return scalar(() = /\G$x/g);
561             }
562              
563             #---------------------------------------------------------------------
564             # ord() for MBCS encoding
565             sub mb::ord (;$) {
566 7 100   7 0 212 local $_ = @_ ? $_[0] : $_;
567 7         92 my $ord = 0;
568 7 50       72 if (/\A($x)/) {
569 7         16 for my $octet (unpack 'C*', $1) {
570 9         85 $ord = $ord * 0x100 + $octet;
571             }
572             }
573 7         19 return $ord;
574             }
575              
576             #---------------------------------------------------------------------
577             # require for MBCS encoding
578             sub mb::require (;$) {
579 8 50   8 0 1724 local $_ = @_ ? $_[0] : $_;
580              
581             # require perl version
582 8 50       84 if (/^[0-9]/) {
583 3 0       14 if ($] < $_) {
584 3         4 confess "Perl $_ required--this is only version $], stopped";
585             }
586             else {
587 3         66 undef $@;
588 3         13 return 1;
589             }
590             }
591              
592             # require expr
593             else {
594              
595             # find expr in @INC
596 8         8 my $file = $_;
597 8 50 33     111 if (($file =~ s{::}{/}g) or ($file !~ m{[\./\\]})) {
598 2         8 $file .= '.pm';
599             }
600 7 100       28 if (exists $INC{$file}) {
601 3         70 undef $@;
602 1 50       7 return 1 if $INC{$file};
603 0         0 confess "Compilation failed in require";
604             }
605 4         8 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  32         41  
606 4 50       61 if (-f $prefix_file) {
607              
608             # poor "make"
609 4         39 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
610 4 0 33     162 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       12 my $fh = mb::_open_r($prefix_file) or confess "$0(@{[__LINE__]}): can't open file: $prefix_file\n";
  0         0  
616 108     108   818 local $_ = CORE::do { local $/; no strict 'refs'; readline(*{$fh}) };
  108         165  
  108         5344  
  4         6  
  4         12  
  4         5  
  4         129  
617 108     108   428 { no strict 'refs'; close($fh) }
  108         511  
  108         14028  
  4         5  
  4         33  
618              
619             # poor file locking
620 4     3   34 local $SIG{__DIE__} = sub { rmdir "$prefix_file.lock"; };
  0         0  
621 4 50       444 if (mkdir "$prefix_file.lock", 0755) {
622 4 50       13 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   648 { no strict 'refs'; print {*{$fh}} mb::_insert_source_encoding_unimport(mb::parse()) }
  108         220  
  108         5095  
  4         7  
  4         2  
  4         25  
624 108     108   441 { no strict 'refs'; close($fh) }
  108         213  
  108         140274  
  4         4  
  4         8  
  4         150  
625 4         350 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         16 $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         6 local $@;
636 4         271 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       284 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         21 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 221 if (wantarray) {
666              
667             # returns a list value consisting of the elements of @_ in the opposite order
668 2         22 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       118 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 276 my $rindex = 0;
689 8 100       13 if (@_ == 3) {
690 4         80 $rindex = mb::rindex_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
691             }
692             else {
693 4         54 $rindex = mb::rindex_byte($_[0], $_[1]);
694             }
695 8 100       14 if ($rindex == -1) {
696 4         5 return -1;
697             }
698             else {
699 4         9 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 211 my($str,$substr,$position) = @_;
707 16   66     62 $position ||= CORE::length($str) - 1;
708 16         12 my $pos = 0;
709 16         15 my $rindex = -1;
710 16   100     39 while (($pos < CORE::length($str)) and ($pos <= $position)) {
711 230 100       265 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
712 20         17 $rindex = $pos;
713             }
714 230 50       660 if (CORE::substr($str,$pos) =~ /\A($x)/xms) {
715 230         414 $pos += CORE::length($1);
716             }
717             else {
718 0         0 $pos += 1;
719             }
720             }
721 16         26 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 11325877 $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     2696 }->{$script_encoding} || '[\x80-\xFF]';
754              
755             # supports qr/./ in MBCS script
756 194         19329 $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       1759 if ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
    50          
    0          
    0          
796 98         254 ${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     45276 }->{$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         2145 @{mb::_dot} = "(?>$over_ascii|.)"; # supports /s modifier by /./
837 194         668 @{mb::_B} = "(?:(?
838 194         786 @{mb::_D} = "(?:(?![0-9])$x)";
839 194         571 @{mb::_H} = "(?:(?![\\x09\\x20])$x)";
840 194         537 @{mb::_N} = "(?:(?!\\n)$x)";
841 194         423 @{mb::_R} = "(?>\\r\\n|[\\x0A\\x0B\\x0C\\x0D])";
842 194         596 @{mb::_S} = "(?:(?![\\t\\n\\f\\r\\x20])$x)";
843 194         570 @{mb::_V} = "(?:(?![\\x0A\\x0B\\x0C\\x0D])$x)";
844 194         542 @{mb::_W} = "(?:(?![A-Za-z0-9_])$x)";
845 194         1042 @{mb::_b} = "(?:(?
846 194         388 @{mb::_d} = "[0-9]";
847 194         350 @{mb::_h} = "[\\x09\\x20]";
848 194         333 @{mb::_s} = "[\\t\\n\\f\\r\\x20]";
849 194         335 @{mb::_v} = "[\\x0A\\x0B\\x0C\\x0D]";
850 194         490 @{mb::_w} = "[A-Za-z0-9_]";
851             }
852              
853             #---------------------------------------------------------------------
854             # get script encoding name
855             sub mb::get_script_encoding () {
856 680443     680446 0 2564380 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 3598789 )}->{mb::get_script_encoding()} || die;
874             }
875              
876             #---------------------------------------------------------------------
877             # substr() for MBCS encoding
878             BEGIN {
879 108 50 100 108 0 245633 CORE::eval sprintf <<'END', ($] >= 5.014) ? ':lvalue' : '';
  50 100   3   2982  
  50 100   53   169  
  2 100       7  
  48 50       88  
  16 100       30  
  16 50       26  
  16 100       40  
  24 100       107  
  24 100       69  
  24         84  
  24         186  
  8         23  
  8         46  
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 280675 my @x = $_[0] =~ /\G($x)/xmsg;
934 2512         9726 my @search = list_all_ASCII_by_hyphen($_[1] =~ /\G(\\-|$x)/xmsg);
935 2512         7811 my @replacement = list_all_ASCII_by_hyphen($_[2] =~ /\G(\\-|$x)/xmsg);
936 2512 100       6149 my %modifier = (defined $_[3]) ? (map { $_ => 1 } CORE::split //, $_[3]) : ();
  2735         6727  
937              
938 2512         3493 my %tr = ();
939 2512         3649 for (my $i=0; $i <= $#search; $i++) {
940              
941             # tr/AAA/123/ works as tr/A/1/
942 3334 100       4848 if (not exists $tr{$search[$i]}) {
943              
944             # tr/ABC/123/ makes %tr = ('A'=>'1','B'=>'2','C'=>'3',);
945 3274 100 66     7593 if (defined($replacement[$i]) and ($replacement[$i] ne '')) {
    100 66        
    100          
946 3069         6002 $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         170 $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         142 $tr{$search[$i]} = $replacement[-1];
957             }
958              
959             # tr/ABC// makes %tr = ('A'=>'A','B'=>'B','C'=>'C',);
960             else {
961 8         17 $tr{$search[$i]} = $search[$i];
962             }
963             }
964             }
965              
966 2512         2521 my $tr = 0;
967 2512         2514 my $replaced = '';
968              
969             # has /c modifier
970 2512 100       3206 if (exists $modifier{c}) {
971              
972             # has /s modifier
973 126 100       148 if (exists $modifier{s}) {
974 54         50 my $last_transliterated = undef;
975 54         80 while (defined(my $x = shift @x)) {
976              
977             # /c modifier works here
978 428 100       442 if (exists $tr{$x}) {
979 252         196 $replaced .= $x;
980 252         321 $last_transliterated = undef;
981             }
982             else {
983              
984             # /d modifier works here
985 176 100       195 if (exists $modifier{d}) {
    50          
986             }
987              
988             elsif (defined $replacement[-1]) {
989              
990             # /s modifier works here
991 52 100 66     79 if (defined($last_transliterated) and ($replacement[-1] eq $last_transliterated)) {
992             }
993              
994             # tr/// works here
995             else {
996 43         47 $replaced .= ($last_transliterated = $replacement[-1]);
997             }
998             }
999 176         238 $tr++;
1000             }
1001             }
1002             }
1003              
1004             # has no /s modifier
1005             else {
1006 72         126 while (defined(my $x = shift @x)) {
1007              
1008             # /c modifier works here
1009 314 100       322 if (exists $tr{$x}) {
1010 210         297 $replaced .= $x;
1011             }
1012             else {
1013              
1014             # /d modifier works here
1015 104 100       132 if (exists $modifier{d}) {
    50          
1016             }
1017              
1018             # tr/// works here
1019             elsif (defined $replacement[-1]) {
1020 70         79 $replaced .= $replacement[-1];
1021             }
1022 104         147 $tr++;
1023             }
1024             }
1025             }
1026             }
1027              
1028             # has no /c modifier
1029             else {
1030              
1031             # has /s modifier
1032 2386 100       2961 if (exists $modifier{s}) {
1033 85         79 my $last_transliterated = undef;
1034 85         131 while (defined(my $x = shift @x)) {
1035 593 100       603 if (exists $tr{$x}) {
1036              
1037             # /d modifier works here
1038 425 100 100     671 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         155 $replaced .= ($last_transliterated = $tr{$x});
1048             }
1049 425         563 $tr++;
1050             }
1051             else {
1052 168         121 $replaced .= $x;
1053 168         296 $last_transliterated = undef;
1054             }
1055             }
1056             }
1057              
1058             # has no /s modifier
1059             else {
1060 2301         3919 while (defined(my $x = shift @x)) {
1061 2731 100       3411 if (exists $tr{$x}) {
1062 2603         3150 $replaced .= $tr{$x};
1063 2603         4416 $tr++;
1064             }
1065             else {
1066 128         183 $replaced .= $x;
1067             }
1068             }
1069             }
1070             }
1071              
1072             # /r modifier works here
1073 2512 100       3132 if (exists $modifier{r}) {
1074 2344         11488 return $replaced;
1075             }
1076              
1077             # has no /r modifier
1078             else {
1079 168         167 $_[0] = $replaced;
1080 168         460 return $tr;
1081             }
1082             }
1083              
1084             #---------------------------------------------------------------------
1085             # universal uc() for MBCS encoding
1086             sub mb::uc (;$) {
1087 52 100   55 1 665 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 52 100       978 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;
  984         7139  
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 142 local $_ = @_ ? $_[0] : $_;
1097 2 50       64 if (/\A($x)(.*)\z/s) {
1098 2         7 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   713 if ($mb::last_s_passed) {
1113 29 50       43 if (defined $_[0]) {
1114              
1115             # $1 is used for multi-byte anchoring
1116 29         1244 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       108 if (defined $_[0]) {
1137 61         3031 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   28 if ($mb::last_s_passed) {
1163 5 50       11 if (scalar(@_) >= 1) {
1164 5         279 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       8 if (scalar(@_) >= 1) {
1172 5         167 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   29 if ($mb::last_s_passed) {
1187 9 50       13 if (scalar(@_) >= 1) {
1188 9         440 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       13 if (scalar(@_) >= 1) {
1196 9         299 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   543 if (defined $&) {
1208 61 100       85 if ($mb::last_s_passed) {
1209 8 50 33     59 if (defined($1) and (CORE::substr($&, 0, CORE::length($1)) eq $1)) {
1210 8         139 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     279 if (defined($1) and (CORE::substr($&, -CORE::length($1)) eq $1)) {
1218 53         910 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   132 if (defined $&) {
1234 15 100       24 if ($mb::last_s_passed) {
1235 8         104 return $1;
1236             }
1237             else {
1238 7 50 33     58 if (defined($1) and (CORE::substr($&,-CORE::length($1)) eq $1)) {
1239 7         95 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   443153 $mb::last_s_passed = 0;
1255 118477         23393673 return '';
1256             }
1257              
1258             #---------------------------------------------------------------------
1259             # flag on if last s/// was pass
1260             sub mb::_s_passed () {
1261 84     87   1149 $mb::last_s_passed = 1;
1262 84         8436 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   37 my($has_space) = @_;
1269 33         38 my $has_no_space = '';
1270              
1271             # parse into elements
1272 33         530 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         581 my($element, $classmate) = ($1, $2);
1284              
1285             # in codepoint class
1286 424 100       456 if (defined $classmate) {
1287 33         37 $has_no_space .= '[';
1288 33         273 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         717 my $element = $1;
1297 693 100       1543 if ($element !~ /\A[$bare_s]\z/) {
1298 559         1600 $has_no_space .= $element;
1299             }
1300             }
1301 33         156 $has_no_space .= ']';
1302             }
1303              
1304             # out of codepoint class
1305             else {
1306 391         1957 $has_no_space .= $element;
1307             }
1308             }
1309 33         55 return $has_no_space;
1310             }
1311              
1312             #---------------------------------------------------------------------
1313             # ignore case of m//i, qr//i, s///i
1314             sub mb::_ignorecase ($) {
1315 64     67   432 my($has_case) = @_;
1316 64         106 my $has_no_case = '';
1317              
1318             # parse into elements
1319 64         1555 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         893 my($element, $classmate) = ($1, $2);
1331              
1332             # in codepoint class
1333 512 100       570 if (defined $classmate) {
1334 60         48 $has_no_case .= '[';
1335 60         305 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         218 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     3151 )}->{$element} || $element;
1372             }
1373 60         284 $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     9218 )}->{$element} || $element;
1406             }
1407             }
1408 64         582 return qr{$has_no_case};
1409             }
1410              
1411             #---------------------------------------------------------------------
1412             # custom codepoint class in qq-like regular expression
1413             sub mb::_cc ($) {
1414 118269     118272   701373 my($classmate) = @_;
1415 118269 100       288348 if ($classmate =~ s{\A \^ }{}xms) {
1416 58974         114545 return '(?:(?!' . parse_re_codepoint_class($classmate) . ")$x)";
1417             }
1418             else {
1419 59295         106239 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   193 if (my @codepoint = $_[0] =~ /\G($x)/xmsgc) {
1427 10 100       22 if (CORE::length($codepoint[$#codepoint]) == 1) {
1428 5         124 return $_[0];
1429             }
1430             else {
1431 5         104 return join '', @codepoint[ 0 .. $#codepoint-1 ], "(?:$codepoint[$#codepoint])";
1432             }
1433             }
1434             else {
1435 12         194 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   847 { no strict 'refs'; open($fhn, ">> $_[0]") or return "" }
  108         240  
  108         11009  
  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   16 $mb::_fh_seq++;
1455 9         22 my $fhn = "mb::FH::H$mb::_fh_seq";
1456 108 50   108   522 { no strict 'refs'; open($fhn, "< $_[0]") or return "" }
  108         249  
  108         9892  
  9         14  
  9         355  
1457 9         45 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         28 my $fhn = "mb::FH::H$mb::_fh_seq";
1465 108 50   108   534 { no strict 'refs'; open($fhn, "> $_[0]") or return "" }
  108         274  
  108         2831311  
  9         14  
  9         1219  
1466 9         55 return $fhn;
1467             }
1468              
1469             #---------------------------------------------------------------------
1470             # split() for MBCS encoding
1471             sub mb::_split (;$$$) {
1472 336 100   339   7132 my $pattern = defined($_[0]) ? $_[0] : ' ';
1473 336 100       493 my $string = defined($_[1]) ? $_[1] : $_;
1474 336         387 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       553 if ($pattern eq ' ') {
1486 108         250 $pattern = qr/\s+/;
1487 108         308 $string =~ s{\A \s+ }{}xms;
1488             }
1489              
1490             # count '(' in pattern
1491 336         314 my @parsed = ();
1492 336         334 my $modifier = '';
1493 336 100 100     1924 if ((($modifier) = $pattern =~ /\A \(\?\^? (.+?) [\)\-\:] /xms) and ($modifier =~ /x/xms)) {
1494 34         1052 @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         3750 @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         591 scalar(grep { $_ eq '(' } @parsed); # other '(' are for pattern of split()
  2398         2640  
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       2301 my $substring_quantifier = ('' =~ / \A $pattern \z /xms) ? '+?' : '*?';
1525              
1526             # if $_[2] specified and positive
1527 336 100 100     622 if (defined($_[2]) and ($_[2] >= 1)) {
1528 21         23 my $limit = $_[2];
1529              
1530 21         1071 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     515 while ((--$limit > 0) and ($string =~ s<\A((?:$x)$substring_quantifier)$pattern><>)) {
1534 42         83 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1535 42         1314 push @split, CORE::eval('$'.$n_th);
1536             }
1537             }
1538             }
1539              
1540             # if $_[2] is omitted or zero or negative
1541             else {
1542 315     5   16257 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
  5     5   33  
  5         14  
  5         183  
  5         25  
  5         15  
  5         164  
1543              
1544             # gets substrings by repeat chopping by pattern
1545 315         7368 while ($string =~ s<\A((?:$x)$substring_quantifier)$pattern><>) {
1546 740         1369 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1547 792         23480 push @split, CORE::eval('$'.$n_th);
1548             }
1549             }
1550             }
1551              
1552             # get last substring
1553 336 100 100     634 if (CORE::length($string) > 0) {
    100          
1554 303         390 push @split, $string;
1555             }
1556             elsif (defined($_[2]) and ($_[2] >= 1)) {
1557 6 50       13 if (scalar(@split) < $_[2]) {
1558 6         12 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     658 if ((not defined $_[2]) or ($_[2] == 0)) {
1564 309   33     1027 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       476 if (wantarray) {
1573 203         1105 return @split;
1574             }
1575             else {
1576 133         516 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   16 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1590 2 50       6 if (@_ == 0) {
1591 0         0 return CORE::chdir;
1592             }
1593             else {
1594 2         47 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   50753 my @filetest = map { /(-[A-Za-z])/g } @{ shift(@_) };
  11217         52233  
  11209         24420  
1627 11209 0       22422 local $_ = @_ ? shift : (($filetest[-1] eq '-t') ? \*STDIN : $_);
    50          
1628 11209 50 33     19400 confess "Too many arguments for filetest @filetest" if @_ and not wantarray;
1629              
1630             # testee has "\x5C" octet at end
1631 11209 0 33     23235 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         11427 my $result;
1641 11209         15045 my $filetest = pop @filetest;
1642 11209 100       461267 if ($result = CORE::eval($filetest . ' $_')) { # '$_' at 1st time, and ...
1643             }
1644             else {
1645 2043 50       21834 return wantarray ? ($result, @_) : $result;
1646             }
1647 9166         35505 for my $filetest (CORE::reverse @filetest) {
1648 7 50       210 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       83184 return wantarray ? ($result, @_) : $result;
1655             }
1656              
1657             #---------------------------------------------------------------------
1658             # lstat() for MSWin32
1659             sub mb::_lstat (;$) {
1660 3 50   6   43 local $_ = @_ ? $_[0] : $_;
1661 3 50       7 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     6 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         37 return CORE::lstat $_;
1675             }
1676              
1677             #---------------------------------------------------------------------
1678             # opendir() for MSWin32
1679             sub mb::_opendir ($$) {
1680 7 100   10   50 if (not defined $_[0]) {
1681 3         4 $_[0] = \do { local *_ };
  3         11  
1682             }
1683              
1684             # works on MSWin32 only
1685 7 50 33     32 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
    0          
    0          
1686 7         198 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   219 local $_ = @_ ? $_[0] : $_;
1701              
1702             # testee has "\x5C" octet at end
1703 9 0 33     15 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         57 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   57195 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1720 10222 50       588817 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 1465 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       868 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     2428 )}->{$LANG} || 'utf8';
1861             }
1862             }
1863              
1864             my @here_document_delimiter = ();
1865              
1866             #---------------------------------------------------------------------
1867             # parse script
1868             sub parse {
1869 136739 100   136742 0 5731319 local $_ = @_ ? $_[0] : $_;
1870              
1871             # Yes, I studied study yesterday, once again.
1872 136739         179929 study $_; # acts between perl 5.005 to perl 5.014
1873              
1874 136739         192774 @here_document_delimiter = ();
1875              
1876             # transpile JPerl script to Perl script
1877 136739         199757 my $parsed_script = '';
1878 136739         460903 while (not /\G \z /xmsgc) {
1879 679105         983946 $parsed_script .= parse_expr();
1880             }
1881              
1882             # return octet-oriented Perl script
1883 136739         13209471 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   170 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         71 $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         130 return $script;
1917             }
1918              
1919             #---------------------------------------------------------------------
1920             # parse ambiguous characters
1921             sub parse_ambiguous_char {
1922 275604     275607 0 327443 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       583029 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         118 $parsed .= $1;
1954             }
1955              
1956 275604         429657 return $parsed;
1957             }
1958              
1959             #---------------------------------------------------------------------
1960             # parse expression in script
1961             sub parse_expr {
1962 680340     680343 0 763270 my $parsed = '';
1963 680340         981005 my $old_package = mb::get_old_package();
1964              
1965             # __END__ or __DATA__
1966 680340 100       12177372 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         6 $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         3 $parsed .= $1;
1973             }
1974              
1975             # "\r\n", "\r", "\n"
1976             elsif (/\G (?= $R ) /xmsgc) {
1977 8284         16183 while (my $here_document_delimiter = shift @here_document_delimiter) {
1978 23         22 my($delimiter, $quote_type) = @{$here_document_delimiter};
  23         33  
1979 23 100       35 if ($quote_type eq 'qq') {
    50          
1980 14         21 $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         17 $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         441964 $parsed .= $1;
2005             }
2006              
2007             # "\x3B" [;] SEMICOLON (U+003B)
2008             elsif (/\G ( ; ) /xmsgc) {
2009 5121         8511 $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         567 $parsed .= parse_expr_balanced($1);
2018 315         414 $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         5 my $v_string = $1;
2029 2         9 $parsed .= join('.', map { "mb::chr($_)" } ($v_string =~ /[0-9]+/g));
  8         13  
2030 2         3 $parsed .= parse_ambiguous_char();
2031             }
2032              
2033             # version string
2034             # v9786
2035             elsif (/\G v ( [0-9]+ ) \b (?! \s* => ) /xmsgc) {
2036 1         2 $parsed .= "mb::chr($1)";
2037 1         2 $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         1202 $parsed .= $1;
2083 840         1051 $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         8660 $parsed .= "mb::_filetest [qw( $1)], ";
2116 2828         3837 $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         27120 $parsed .= "mb::_filetest [qw( $1)]";
2124 8409 50       14025 if (my $ambiguous_char = parse_ambiguous_char()) {
2125 0         0 $parsed .= $ambiguous_char;
2126             }
2127             else {
2128 8409         12242 $parsed .= ', ';
2129             }
2130             }
2131              
2132             # yada-yada or triple-dot operator
2133             elsif (/\G ( \.\.\. ) /xmsgc) {
2134 1         2 $parsed .= $1;
2135             }
2136              
2137             # -> and any method
2138             elsif (/\G ( -> \s* [A-Za-z_][A-Za-z_0-9]* ) /xmsgc) {
2139 1         1 $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         217271 $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         3053 $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         28 $parsed .= 'mb::_PREMATCH()';
2173 20         28 $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         80 $parsed .= 'mb::_MATCH()';
2183 68         86 $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         120 $parsed .= "mb::_CAPTURE($1)";
2191 55         72 $parsed .= parse_ambiguous_char();
2192             }
2193              
2194             # @{^CAPTURE} --> mb::_CAPTURE()
2195             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
2196 3         3 $parsed .= 'mb::_CAPTURE()';
2197 3         19 $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         7 my $n_th = quotee_of(parse_expr_balanced($1));
2205 3         5 $parsed .= "mb::_CAPTURE($n_th+1)";
2206 3         15 $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         13 $parsed .= 'mb::_LAST_MATCH_START()';
2215 12         13 $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         40 my $n_th = quotee_of(parse_expr_balanced($1));
2224 22         29 $parsed .= "mb::_LAST_MATCH_START($n_th)";
2225 22         48 $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         15 $parsed .= 'mb::_LAST_MATCH_END()';
2234 12         13 $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         22 my $n_th = quotee_of(parse_expr_balanced($1));
2243 14         19 $parsed .= "mb::_LAST_MATCH_END($n_th)";
2244 14         18 $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         16 $parsed .= $1;
2253 11         13 $parsed .= parse_expr_balanced($2);
2254 11         13 $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         48 $parsed .= $1;
2267 30         38 $parsed .= parse_expr_balanced($2);
2268 30         32 $parsed .= parse_ambiguous_char();
2269             }
2270              
2271             # $#{}, ${}, @{}, %{}, &{}, *{}, defer {}, sub {}
2272             # "\x24" [$] DOLLAR SIGN (U+0024)
2273             elsif (/\G ((?: \$[#] | [\$\@%&*] | defer | sub ) \s* ) ( \{ ) /xmsgc) {
2274 10         14 $parsed .= $1;
2275 10         14 $parsed .= parse_expr_balanced($2);
2276 10         12 $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         6 $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         5 $parsed .= $1;
2291 3         4 $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         6 $parsed .= $1;
2297 3         4 $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         9903 $parsed .= $1;
2303 4964         7310 $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         189 $parsed .= $1;
2310 119         169 $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         14 $parsed .= $1;
2316 11         15 $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         17 $parsed .= $1;
2323 12         13 $parsed .= parse_ambiguous_char();
2324             }
2325              
2326             # comment
2327             # "\x23" [#] NUMBER SIGN (U+0023)
2328             elsif (/\G ( [#] [^\n]* ) /xmsgc) {
2329 17         31 $parsed .= $1;
2330             }
2331              
2332             # 2-quotes
2333              
2334             # '...'
2335             # "\x27" ['] APOSTROPHE (U+0027)
2336             elsif (m{\G ( ' ) }xmsgc) {
2337 5828         10512 $parsed .= parse_q__like_endswith($1);
2338 5828         10558 $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         330402 $parsed .= parse_qq_like_endswith($1);
2346 126173         239531 $parsed .= parse_ambiguous_char();
2347             }
2348              
2349             # /.../
2350             elsif (m{\G ( [/] ) }xmsgc) {
2351 118038         279003 my $regexp = parse_re_endswith('m',$1);
2352 118038         176958 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2353              
2354             # /xx modifier
2355 118038 100       272995 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2356 28         47 $regexp = mb::_ignore_space($regexp);
2357             }
2358              
2359             # /i modifier
2360 118038 100       169805 if ($modifier_i) {
2361 23         36 $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         171234 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2365             }
2366 118038         160678 $parsed .= parse_ambiguous_char();
2367             }
2368              
2369             # ?...?
2370             elsif (m{\G ( [?] ) }xmsgc) {
2371 1         3 my $regexp = parse_re_endswith('m',$1);
2372 1         3 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2373              
2374             # /xx modifier
2375 1 50       3 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2376 0         0 $regexp = mb::_ignore_space($regexp);
2377             }
2378              
2379             # /i modifier
2380 1 50       2 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         2 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2385             }
2386 1         12 $parsed .= parse_ambiguous_char();
2387             }
2388              
2389             # <<>> double-diamond operator
2390             elsif (/\G ( <<>> ) /xmsgc) {
2391 1         2 $parsed .= $1;
2392 1         3 $parsed .= parse_ambiguous_char();
2393             }
2394              
2395             # diamond operator
2396             # <${file}>
2397             # <$file>
2398             #
2399             elsif (/\G (<) ((?:(?!\s)$x)*?) (>) /xmsgc) {
2400 5         15 my($open_bracket, $quotee, $close_bracket) = ($1, $2, $3);
2401 5         6 $parsed .= $open_bracket;
2402 5         78 while ($quotee =~ /\G ($x) /xmsgc) {
2403 25         27 $parsed .= escape_qq($1, $close_bracket);
2404             }
2405 5         8 $parsed .= $close_bracket;
2406 5         6 $parsed .= parse_ambiguous_char();
2407             }
2408              
2409             # qw/.../, q/.../
2410             elsif (/\G ( qw | q ) \b /xmsgc) {
2411 160         286 $parsed .= $1;
2412 160 100       597 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
  2 100       4  
    100          
    100          
    100          
    50          
2413 2         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2414 34         71 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); }
2415 6         11 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); }
2416 48         64 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2417 68         78 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2418 68         131 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2419 4         13 $parsed .= $1;
2420             }
2421 68 100       206 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
  6 100       7  
    100          
    100          
    50          
2422 2         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2423 8         12 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); }
2424 2         3 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); }
2425 50         70 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         214 $parsed .= parse_ambiguous_char();
2430             }
2431              
2432             # qq/.../
2433             elsif (/\G ( qq ) \b /xmsgc) {
2434 69         109 $parsed .= $1;
2435 69 100       263 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  1 100       2  
    100          
    100          
    100          
    50          
2436 1         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); } # qq'...' works as "..."
2437 6         13 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2438 3         6 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2439 24         34 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2440 34         39 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2441 34         68 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2442 2         5 $parsed .= $1;
2443             }
2444 34 100       120 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         6 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2447 1         3 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2448 25         34 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         110 $parsed .= parse_ambiguous_char();
2453             }
2454              
2455             # qx/.../
2456             elsif (/\G ( qx ) \b /xmsgc) {
2457 67         112 $parsed .= $1;
2458 67 100       257 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  1 100       2  
    100          
    100          
    100          
    50          
2459 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2460 4         6 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2461 3         6 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2462 24         30 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2463 34         43 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2464 34         62 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2465 2         5 $parsed .= $1;
2466             }
2467 34 100       106 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); }
  3 100       5  
    100          
    100          
    50          
2468 1         3 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); }
2469 4         8 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); }
2470 1         3 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); }
2471 25         34 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         94 $parsed .= parse_ambiguous_char();
2476             }
2477              
2478             # m/.../, qr/.../
2479             elsif (/\G ( m | qr ) \b /xmsgc) {
2480 1655         3023 $parsed .= $1;
2481 1655         1950 my $regexp = '';
2482 1655 100       4820 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr#...#
  2 100       5  
    100          
    100          
    100          
    100          
    50          
2483 643         1117 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr'...'
2484 8         14 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr{...}
2485 360         593 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr/.../
2486 530         760 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # qr@...@
2487 44         74 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr?...?
2488 68         72 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # qr SPACE ...
  68         69  
2489 68         113 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2490 4         9 $parsed .= $1;
2491             }
2492 68 100       237 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE A...A
  6 100       8  
    100          
    100          
    100          
    50          
2493 2         3 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr SPACE '...'
2494 8         13 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr SPACE {...}
2495 2         2 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE /.../
2496 4         7 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # qr SPACE @...@
2497 46         65 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         2826 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2503              
2504             # /xx modifier
2505 1655 100       3490 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2506 2         4 $regexp = mb::_ignore_space($regexp);
2507             }
2508              
2509             # /i modifier
2510 1655 100       1973 if ($modifier_i) {
2511 37         67 $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         2237 $parsed .= sprintf('{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2515             }
2516 1655         2129 $parsed .= parse_ambiguous_char();
2517             }
2518              
2519             # 3-quotes
2520              
2521             # s/.../.../
2522             elsif (/\G ( s ) \b /xmsgc) {
2523 1712         3406 $parsed .= $1;
2524 1712         2021 my $regexp = '';
2525 1712         2166 my $comment = '';
2526 1712         3302 my @replacement = ();
2527 1712 100       5937 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         457 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s'...'...'
  286         461  
2529 240         371 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s{...}...
2530 240 50       870 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2531 4         9 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}'...'
2532 16         24 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{}{...}
2533 4         8 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}/.../
2534 96         158 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}?...?
2535 120         136 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s{} SPACE ...
2536 120         251 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2537 0         0 $comment .= $1;
2538             }
2539 120 50       452 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         11 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE '...'
2541 16         27 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{} SPACE {...}
2542 4         9 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE /.../
2543 96         130 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         691 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s/.../.../
  353         709  
2549 528         750 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('s',$1)) . '`');
2550 528         751 @replacement = parse_qq_like_endswith($1); } # s@...@...@
2551 22         57 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s?...?...?
  22         66  
2552 282         362 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # s SPACE ...
  282         316  
2553 282         664 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2554 12         26 $parsed .= $1;
2555             }
2556 282 100       846 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       35  
  12 100       37  
    100          
    100          
    50          
2557 1         5 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE '...'...'
  1         38  
2558 244         400 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s SPACE {...}...
2559 244 100       1024 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}#...#
  1 100       2  
    100          
    100          
    100          
    50          
2560 4         10 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}'...'
2561 17         28 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {}{...}
2562 4         11 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}/.../
2563 96         155 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}?...?
2564 122         146 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s SPACE {} SPACE ...
2565 122         238 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2566 8         19 $comment .= $1;
2567             }
2568 122 50       395 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         18 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE '...'
2570 18         65 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {} SPACE {...}
2571 4         13 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE /.../
2572 96         161 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         5 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE /.../.../
  1         5  
2578 2         7 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= ('`' . quotee_of(parse_re_endswith('s',$1)) . '`');
2579 2         8 @replacement = parse_qq_like_endswith($1); } # s SPACE @...@...@
2580 22         61 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE ?...?...?
  22         63  
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         2606 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2586 1712         2168 my $replacement = '';
2587 1712         2023 my $eval = '';
2588              
2589             # has /e modifier
2590 1712 100       4479 if (my $e = $modifier_cegr =~ tr/e//d) {
    100          
    100          
2591 9         14 $replacement = 'q'. $replacement[1]; # q-type quotee
2592 9         17 $eval = 'mb::eval ' x $e;
2593             }
2594              
2595             # s''q-quotee'
2596             elsif ($replacement[0] =~ /\A ' /xms) {
2597 300         293 $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         1667 $replacement = 'qq ' . $replacement[0]; # qq-type quotee
2608             }
2609              
2610             # /xx modifier
2611 1712 100       2542 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2612 1         2 $regexp = mb::_ignore_space($regexp);
2613             }
2614              
2615             # /i modifier
2616 1712 100       2122 if ($modifier_i) {
2617 18         30 $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         2644 $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         2399 $parsed .= parse_ambiguous_char();
2623             }
2624              
2625             # tr/.../.../, y/.../.../
2626             elsif (/\G (?: tr | y ) \b /xmsgc) {
2627 2153         3686 $parsed .= 's'; # not 'tr'
2628 2153         3068 my $search = '';
2629 2153         2662 my $comment = '';
2630 2153         2628 my $replacement = '';
2631 2153 100       9016 if (/\G ( [#] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr#...#...#
  4 100       11  
  4 100       7  
    100          
    100          
    50          
2632 4         13 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr'...'...'
  4         8  
2633 912         1877 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_tr_like_balanced($1); # tr{...}...
2634 912 50       3772 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2635 16         23 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}'...'
2636 64         79 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr{}{...}
2637 16         22 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}/.../
2638 360         469 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{}?...?
2639 456         591 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr{} SPACE ...
2640 456         1082 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2641 0         0 $comment .= $1;
2642             }
2643 456 50       1477 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         22 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE '...'
2645 64         77 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr{} SPACE {...}
2646 16         24 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr{} SPACE /.../
2647 360         481 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         145 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr/.../.../
  92         112  
2653 131         258 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr?...?...?
  131         214  
2654 1010         1994 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; # tr SPACE ...
2655 1010         2545 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2656 0         0 $parsed .= $1;
2657             }
2658 1010 50       2856 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         11 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE '...'...'
  4         7  
2660 912         1600 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_tr_like_balanced($1); # tr SPACE {...}...
2661 912 50       3678 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2662 16         23 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}'...'
2663 64         76 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr SPACE {}{...}
2664 16         28 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}/.../
2665 360         463 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {}?...?
2666 456         615 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr SPACE {} SPACE ...
2667 456         938 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2668 0         0 $comment .= $1;
2669             }
2670 456 50       1500 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         22 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE '...'
2672 64         77 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_tr_like_balanced($1); } # tr SPACE {} SPACE {...}
2673 16         21 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_tr_like_endswith($1); } # tr SPACE {} SPACE /.../
2674 360         450 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         10 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE /.../.../
  4         8  
2680 90         152 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_tr_like_endswith($1); $replacement .= parse_tr_like_endswith($1); } # tr SPACE ?...?...?
  90         120  
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         3746 my($modifier_not_r, $modifier_r) = parse_tr_modifier();
2687 2153 50       4009 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         46 $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       2596 if ($modifier_not_r =~ /c/) {
2738 16         21 $parsed .= sprintf(q<{(\\G${mb::_anchor})((?!%s)@{mb::_dot})}%s{$1.mb::tr($2,q%s,q%s,'%sr')}sge>, codepoint_tr($search), $comment, $search, $replacement, $modifier_not_r);
2739             }
2740             else {
2741 2109         2751 $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         2990 $parsed .= parse_ambiguous_char();
2754             }
2755              
2756             # indented here document
2757             elsif (/\G ( <<~ ) /xmsgc) {
2758 11         19 $parsed .= $1;
2759 11 100       42 if (/\G ( ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  1 100       2  
  1 100       5  
    100          
    50          
2760 1         2 elsif (/\G ( \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; }
  1         3  
2761 3         3 elsif (/\G ( [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; }
  3         7  
2762 3         4 elsif (/\G ( [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  3         8  
2763 3         5 elsif (/\G ( [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; }
  3         6  
2764 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2765 11         14 $parsed .= parse_ambiguous_char();
2766             }
2767              
2768             # here document
2769             elsif (/\G ( << ) /xmsgc) {
2770 12         20 $parsed .= $1;
2771 12 100       100 if (/\G ( ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  1 100       2  
  1 100       3  
    100          
    50          
2772 1         2 elsif (/\G ( \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; }
  1         3  
2773 4         7 elsif (/\G ( [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; }
  4         12  
2774 3         5 elsif (/\G ( [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  3         6  
2775 3         4 elsif (/\G ( [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; }
  3         5  
2776 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2777 12         16 $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         55 $parsed .= $1;
2783             }
2784              
2785             # while (<<>>)
2786             elsif (/\G ( while \s* \( \s* ) ( <<>> ) ( \s* \) ) /xmsgc) {
2787 2         3 $parsed .= $1;
2788 2         3 $parsed .= $2;
2789 2         4 $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         12 $parsed .= $1;
2798 8         27 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2799 8         9 my $close_bracket2 = $5;
2800 8         7 $parsed .= $open_bracket;
2801 8         65 while ($quotee =~ /\G ($x) /xmsgc) {
2802 50         52 $parsed .= escape_qq($1, $close_bracket);
2803             }
2804 8         9 $parsed .= $close_bracket;
2805 8         10 $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         44 $parsed .= $1;
2839              
2840             # outputs expr
2841 25         31 my $expr = parse_expr_balanced($2);
2842 25         26 $parsed .= $expr;
2843             }
2844              
2845             # mb::catch (expr) --> catch (expr)
2846             elsif (/\G mb:: ( catch \s* ) ( \( ) /xmsgc) {
2847 4         5 $parsed .= $1;
2848              
2849             # outputs expr
2850 4         6 my $expr = parse_expr_balanced($2);
2851 4         4 $parsed .= $expr;
2852             }
2853              
2854             # else
2855             elsif (/\G ( else ) \b /xmsgc) {
2856 1         2 $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         13 $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         8 $parsed .= $1;
2887 4         21 $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         937 $parsed .= "mb::_split";
2895              
2896             # parse \s and '('
2897 679         609 while (1) {
2898 1364 100       3055 if (/\G ( \s+ ) /xmsgc) {
    100          
    100          
2899 296         500 $parsed .= $1;
2900             }
2901             elsif (/\G ( \( ) /xmsgc) {
2902 389         612 $parsed .= $1;
2903             }
2904             elsif (/\G ( \# .* \n ) /xmgc) {
2905 16         22 $parsed .= $1;
2906 16         19 last;
2907             }
2908             else {
2909 663         746 last;
2910             }
2911             }
2912 679         701 my $regexp = '';
2913              
2914             # split /^/ --> mb::_split qr/^/m
2915             # split /.../ --> mb::_split qr/.../
2916 679 100       1743 if (m{\G ( [/] ) }xmsgc) {
    100          
2917 24         25 $parsed .= "qr";
2918 24         34 $regexp = parse_re_endswith('m',$1); # split /.../
2919 24         42 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       45 if ($modifier_not_cegir !~ /m/xms) {
2934 18         16 $modifier_not_cegir .= 'm';
2935             }
2936              
2937             # /xx modifier
2938 24 100       48 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2939 1         2 $regexp = mb::_ignore_space($regexp);
2940             }
2941              
2942             # /i modifier
2943 24 100       44 if ($modifier_i) {
2944 6         9 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2945             }
2946             else {
2947 18         25 $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         636 $parsed .= "qr";
2955              
2956 611 100       2464 if (/\G ( [#] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr#...#
  8 100       16  
    100          
    100          
    100          
    100          
    50          
2957 8         17 elsif (/\G ( ['] ) /xmsgc) { $regexp = parse_re_as_q_endswith('m',$1); } # split qr'...'
2958 32         56 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp = parse_re_balanced('m',$1); } # split qr{...}
2959 83         168 elsif (m{\G( [/] ) }xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr/.../
2960 16         29 elsif (/\G ( [:\@] ) /xmsgc) { $regexp = ('`' . quotee_of(parse_re_endswith('m',$1)) . '`'); } # split qr@...@
2961 184         301 elsif (/\G ( [\S] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr?...?
2962 280         357 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp = $1; # split qr SPACE ...
  280         339  
2963 280         579 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2964 32         58 $parsed .= $1;
2965             }
2966 280 100       1007 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE A...A
  24 100       41  
    100          
    100          
    100          
    50          
2967 8         20 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # split qr SPACE '...'
2968 32         58 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # split qr SPACE {...}
2969 8         17 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         303 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         887 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2977              
2978 611 100       997 if ($modifier_not_cegir !~ /m/xms) {
2979 607         590 $modifier_not_cegir .= 'm';
2980             }
2981              
2982             # /xx modifier
2983 611 100       1072 if (($modifier_not_cegir =~ tr/x//) >= 2) {
2984 1         4 $regexp = mb::_ignore_space($regexp);
2985             }
2986              
2987             # /i modifier
2988 611 100       728 if ($modifier_i) {
2989 16         23 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2990             }
2991             else {
2992 595         761 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2993             }
2994             }
2995              
2996 679         836 $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         47 $parsed .= "mb::$1";
3002 15         42 $parsed .= parse_ambiguous_char();
3003             }
3004              
3005             # CORE::require, mb::require, require
3006             elsif (/\G ( (?: CORE:: | mb:: )? require ) /xmsgc) {
3007 3         39 $parsed .= $1;
3008 3         6 $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     229 my $method = { 'mb::use'=>'import', 'mb::no'=>'unimport' }->{$1} || die;
3015 42         85 $parsed .= "BEGIN { mb::require";
3016 42         111 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3017 58         156 $parsed .= $1;
3018             }
3019 42 50       123 if (/\G ( [A-Za-z_][A-Za-z_0-9]* (?: ::[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
3020 42         63 my $module = $1;
3021 42         59 $parsed .= qq{'$module';};
3022 42         104 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3023 54         114 $parsed .= $1;
3024             }
3025 42 100       96 if (/\G ( [0-9]+ (?: \.[0-9]+)* ) /xmsgc) {
3026 26         34 my $version = $1;
3027 26         34 $parsed .= qq{$module->VERSION($version);};
3028 26         54 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
3029 46         94 $parsed .= $1;
3030             }
3031             }
3032 42         149 my $list = parse_expr_endswith(qr< [;\}] | \z >xms);
3033 42 100       1864 if ($list eq '') {
    100          
3034 12         21 $parsed .= qq{ $module->$method; };
3035             }
3036             elsif (scalar(CORE::eval("()=$list")) == 0) {
3037             }
3038             else {
3039 22         67 $parsed .= qq{ $module->$method($list); };
3040             }
3041             }
3042 42         107 $parsed .= "}";
3043             }
3044              
3045             # mb::getc() --> mb::getc()
3046             # vvvvvvvvvvvvvvvvvvvvvvvvvv
3047             # vvvvvvvvvvvv
3048             elsif (/\G ( mb::getc ) (?= (?: \s* \( )+ \s* \) ) /xmsgc) {
3049 1         2 $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         4 $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         4 $parsed .= $1;
3066 2         3 $parsed .= $2;
3067 2         2 $parsed .= '\\*';
3068             }
3069              
3070             # mb::getc --> mb::getc
3071             elsif (/\G ( mb::getc ) /xmsgc) {
3072 1         3 $parsed .= $1;
3073 1         2 $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         34 $parsed .= $1;
3090 23         26 $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         43 $parsed .= $1;
3102             }
3103              
3104             # mb::subroutines
3105             elsif (/\G ( mb:: (?: index_byte | rindex_byte ) ) \b /xmsgc) {
3106 2         4 $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         5370 $parsed .= $1;
3137 2884         3726 $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         4 $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         37 $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         21 $parsed .= "mb::_$1";
3166 10         12 $parsed .= $2;
3167 10         11 $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         21 $parsed .= "mb::_$1";
3176 4         10 $parsed .= $2;
3177 4         8 $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         89 $parsed .= "mb::_$1";
3184 32         63 $parsed .= parse_ambiguous_char();
3185             }
3186             elsif (/\G ( opendir ) \b /xmsgc) {
3187 4         13 $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         32 $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         24 $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         594 $parsed .= $1;
3311 287         413 $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         766 $parsed .= $1;
3320 396         474 $parsed .= parse_ambiguous_char();
3321             }
3322              
3323             # any US-ASCII
3324             # "\x3A" [:] COLON (U+003A)
3325             elsif (/\G ([\x00-\x7F]) /xmsgc) {
3326 8271         14587 $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         1810292 return $parsed;
3335             }
3336              
3337             #---------------------------------------------------------------------
3338             # parse expression in balanced blackets
3339             sub parse_expr_balanced {
3340 438     441 0 753 my($open_bracket) = @_;
3341 438   50     1495 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3342 438         723 my $parsed = $open_bracket;
3343 438         466 my $nest_bracket = 1;
3344 438         425 while (1) {
3345              
3346             # open bracket
3347 1687 100       8234 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
3348 22         28 $parsed .= $1;
3349 22         29 $nest_bracket++;
3350             }
3351              
3352             # close bracket
3353             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3354 460         587 $parsed .= $1;
3355 460         560 $parsed .= parse_ambiguous_char();
3356 460 100       805 if (--$nest_bracket <= 0) {
3357 438         502 last;
3358             }
3359             }
3360              
3361             # otherwise
3362             else {
3363 1205         3989 $parsed .= parse_expr();
3364             }
3365             }
3366 438         689 return $parsed;
3367             }
3368              
3369             #---------------------------------------------------------------------
3370             # parse expression that ends with a regexp
3371             sub parse_expr_endswith {
3372 42     45 0 68 my($endswith) = @_;
3373 42         75 my $parsed = '';
3374 42         46 while (1) {
3375 72 100       336 if (/\G (?= $endswith ) /xmsgc) {
3376 42         52 last;
3377             }
3378             else {
3379 30         222 $parsed .= parse_expr();
3380             }
3381             }
3382 42         69 return $parsed;
3383             }
3384              
3385             #---------------------------------------------------------------------
3386             # parse <<'HERE_DOCUMENT' as q-like
3387             sub parse_heredocument_as_q_endswith {
3388 9     12 0 10 my($endswith) = @_;
3389 9         9 my $parsed = '';
3390 9         10 while (1) {
3391 465 100       1502 if (/\G ( $R $endswith ) /xmsgc) {
    50          
3392 9         12 $parsed .= $1;
3393 9         10 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         24 return $parsed;
3410             }
3411              
3412             #---------------------------------------------------------------------
3413             # parse <<"HERE_DOCUMENT" as qq-like
3414             sub parse_heredocument_as_qq_endswith {
3415 14     17 0 15 my($endswith) = @_;
3416 14         13 my $parsed = '';
3417 14         11 my $nest_escape = 0;
3418 14         15 while (1) {
3419 14 50       105 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         18 $parsed .= ('>)]}' x $nest_escape);
3421 14         18 $parsed .= $1;
3422 14         15 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         31 return $parsed;
3580             }
3581              
3582             #---------------------------------------------------------------------
3583             # parse q{string} in balanced blackets
3584             sub parse_q__like_balanced {
3585 42     45 0 111 my($open_bracket) = @_;
3586 42   50     180 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3587 42         76 my $parsed = $open_bracket;
3588 42         53 my $nest_bracket = 1;
3589 42         71 while (1) {
3590 192 50       1178 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         64 $parsed .= $1;
3596 42 50       75 if (--$nest_bracket <= 0) {
3597 42         52 last;
3598             }
3599             }
3600             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3601 0         0 $parsed .= $1;
3602             }
3603             else {
3604 150         212 $parsed .= parse_q__like($close_bracket);
3605             }
3606             }
3607 42         70 return $parsed;
3608             }
3609              
3610             #---------------------------------------------------------------------
3611             # parse q/string/ that ends with a character
3612             sub parse_q__like_endswith {
3613 5948     5951 0 11698 my($endswith) = @_;
3614 5948         6662 my $parsed = $endswith;
3615 5948         6407 while (1) {
3616 14476 100       43674 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
3617 5948         7866 $parsed .= $1;
3618 5948         7079 last;
3619             }
3620             elsif (/\G (\\ \Q$endswith\E) /xmsgc) {
3621 0         0 $parsed .= $1;
3622             }
3623             else {
3624 8528         10939 $parsed .= parse_q__like($endswith);
3625             }
3626             }
3627 5948         8552 return $parsed;
3628             }
3629              
3630             #---------------------------------------------------------------------
3631             # parse q/string/ common routine
3632             sub parse_q__like {
3633 8678     8681 0 10038 my($closewith) = @_;
3634 8678 100       30205 if (/\G (\\\\) /xmsgc) {
    50          
3635 13         20 return $1;
3636             }
3637             elsif (/\G ($x) /xmsgc) {
3638 8665         13063 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 136 my($open_bracket) = @_;
3656 85   50     336 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3657 85         179 my $parsed_as_q = $open_bracket;
3658 85         92 my $parsed_as_qq = $open_bracket;
3659 85         75 my $nest_bracket = 1;
3660 85         85 my $nest_escape = 0;
3661 85         80 while (1) {
3662              
3663             # blackets
3664 317 50       4623 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       120 if (--$nest_bracket <= 0) {
3679 85         153 $parsed_as_q .= $1;
3680 85         106 $parsed_as_qq .= ('>)]}' x $nest_escape);
3681 85         107 $parsed_as_qq .= $1;
3682 85         114 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         296 my($as_qq, $as_q) = parse_qq_like($close_bracket);
3752 232         221 $parsed_as_q .= $as_q;
3753 232         241 $parsed_as_qq .= $as_qq;
3754             }
3755             }
3756              
3757             # return qq-like and q-like quotee
3758 85 100       102 if (wantarray) {
3759 67         170 return ($parsed_as_qq, $parsed_as_q);
3760             }
3761             else {
3762 18         31 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 346597 my($endswith) = @_;
3770 127934         170050 my $parsed_as_q = $endswith;
3771 127934         145776 my $parsed_as_qq = $endswith;
3772 127934         156241 my $nest_escape = 0;
3773 127934         149649 while (1) {
3774              
3775             # ends with
3776 688963 50       3527993 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         279453 $parsed_as_q .= $1;
3782 127934         211403 $parsed_as_qq .= ('>)]}' x $nest_escape);
3783 127934 50       298028 $parsed_as_qq .= "\n" if CORE::length($1) >= 2; # here document
3784 127934         166868 $parsed_as_qq .= $1;
3785 127934         187635 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         679611 my($as_qq, $as_q) = parse_qq_like($endswith);
3850 561029         556819 $parsed_as_q .= $as_q;
3851 561029         547189 $parsed_as_qq .= $as_qq;
3852             }
3853             }
3854              
3855             # return qq-like and q-like quotee
3856 127934 100       195463 if (wantarray) {
3857 1645         3094 return ($parsed_as_qq, $parsed_as_q);
3858             }
3859             else {
3860 126289         281479 return $parsed_as_qq;
3861             }
3862             }
3863              
3864             #---------------------------------------------------------------------
3865             # parse qq/string/ common routine
3866             sub parse_qq_like {
3867 561261     561264 0 621179 my($closewith) = @_;
3868 561261         522870 my $parsed_as_q = '';
3869 561261         500566 my $parsed_as_qq = '';
3870              
3871             # \o{...}
3872 561261 50       4022496 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         2 $parsed_as_q .= $1;
3880 1         4 $parsed_as_qq .= escape_to_hex(mb::chr(hex $2), $closewith);
3881             }
3882              
3883             # \any
3884             elsif (/\G ( (\\) ($x) ) /xmsgc) {
3885 226         367 $parsed_as_q .= $1;
3886 226         385 $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         3 $parsed_as_q .= $1;
3896 2         4 $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         3 $parsed_as_q .= $1;
3906 2         3 $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         35 $parsed_as_q .= $1;
3914 23         36 $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         758661 $parsed_as_q .= escape_q ($1, $closewith);
3976 561007         709242 $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       674974 if (wantarray) {
3991 561261         929130 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 7950 my @hyphened = @_;
4002 5024         5005 my @list_all = ();
4003 5024         8695 for (my $i=0; $i <= $#hyphened; ) {
4004 6357 100 100     11883 if (
      100        
4005             ($i+1 < $#hyphened) and
4006             ($hyphened[$i+1] eq '-') and
4007             1) {
4008 71 100       125 $hyphened[$i+0] = ($hyphened[$i+0] eq '\\-') ? '-' : $hyphened[$i+0];
4009 71 100       141 $hyphened[$i+2] = ($hyphened[$i+2] eq '\\-') ? '-' : $hyphened[$i+2];
4010 71 50       214 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         146 push @list_all, map { CORE::chr($_) } (CORE::ord($hyphened[$i+0]) .. CORE::ord($hyphened[$i+2]));
  225         348  
4022 71         111 $i += 3;
4023             }
4024             }
4025             else {
4026 6286 100       7668 if ($hyphened[$i] eq '\\-') {
4027 19         21 push @list_all, '-';
4028             }
4029             else {
4030 6267         7243 push @list_all, $hyphened[$i];
4031             }
4032 6286         8529 $i++;
4033             }
4034             }
4035 5024         8813 return @list_all;
4036             }
4037              
4038             #---------------------------------------------------------------------
4039             # parse tr{here}{here} in balanced blackets
4040             sub parse_tr_like_balanced {
4041 2080     2083 0 3695 my($open_bracket) = @_;
4042 2080   50     8899 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
4043 2080         4270 my @x = ();
4044 2080         2118 my $nest_bracket = 1;
4045 2080         1850 while (1) {
4046              
4047             # blackets
4048 4160 50       64675 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       3550 if (--$nest_bracket <= 0) {
4060 2080         2425 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         3709 push @x, parse_tr_like($close_bracket);
4072             }
4073             }
4074 2080         5192 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 3311 my($endswith) = @_;
4081 2226         2102 my $openwith = $endswith;
4082 2226         2162 my @x = ();
4083 2226         1884 while (1) {
4084 4752 50       16084 if (/\G (\\ \Q$endswith\E) /xmsgc) {
    100          
    100          
4085 0         0 push @x, $1;
4086             }
4087             elsif (/\G (\Q$endswith\E) /xmsgc) {
4088 2226         2316 last;
4089             }
4090              
4091             # \-
4092             elsif (/\G (\\ -) /xmsgc) {
4093 9         14 push @x, $1;
4094             }
4095              
4096             else {
4097 2517         3021 push @x, parse_tr_like($endswith);
4098             }
4099             }
4100 2226         4528 return join('', $openwith, @x, $endswith);
4101             }
4102              
4103             #---------------------------------------------------------------------
4104             # parse tr/here/here/ common routine
4105             sub parse_tr_like {
4106 4597     4600 0 5673 my($closewith) = @_;
4107              
4108 4597 100       22241 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         9 return escape_tr(mb::chr(oct $1), $closewith);
4126             }
4127              
4128             # \o{...}
4129             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
4130 4         9 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         7 return escape_tr(mb::chr(hex $1), $closewith);
4136             }
4137              
4138             # \x{...}
4139             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
4140 3         8 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     165 }->{$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     108 }->{$1} || $2;
4194             }
4195              
4196             # any
4197             elsif (/\G ($x) /xmsgc) {
4198 4554         6337 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 10697 my($a, $b) = @_;
4216 8434         21338 my @a = (undef, unpack 'C*', $a);
4217 8434         12415 my @b = (undef, unpack 'C*', $b);
4218              
4219 8434 100       16357 if (0) { }
    50          
4220 0         0 elsif (CORE::length($a) == 1) {
4221 2994 100       5638 if (0) { }
    50          
4222 0         0 elsif (CORE::length($b) == 1) {
4223             return (
4224 434 50 100     2593 (($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       17986 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       8085 if (0) { }
4243 0         0 elsif (CORE::length($b) == 2) {
4244 5440 100       24270 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       14735 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         16779 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 318 my($a, $b) = @_;
4264 252         688 my @a = (undef, unpack 'C*', $a);
4265 252         360 my @b = (undef, unpack 'C*', $b);
4266              
4267 252 100       421 if (0) { }
    50          
4268 0         0 elsif (CORE::length($a) == 1) {
4269 132 100       274 if (0) { }
    50          
4270 0         0 elsif (CORE::length($b) == 1) {
4271             return (
4272 36 50       173 $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       586 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       155 if (0) { }
4286 0         0 elsif (CORE::length($b) == 2) {
4287 120 100       602 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       339 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         338 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 329 my($a, $b) = @_;
4307 252         681 my @a = (undef, unpack 'C*', $a);
4308 252         432 my @b = (undef, unpack 'C*', $b);
4309              
4310 252 100       519 if (0) { }
    50          
4311 0         0 elsif (CORE::length($a) == 1) {
4312 132 100       250 if (0) { }
    50          
4313 0         0 elsif (CORE::length($b) == 1) {
4314             return (
4315 36 50       175 $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       648 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       167 if (0) { }
4329 0         0 elsif (CORE::length($b) == 2) {
4330 120 100       529 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       340 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         383 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 22653 my($a, $b) = @_;
4350 18252         48291 my @a = (undef, unpack 'C*', $a);
4351 18252         29256 my @b = (undef, unpack 'C*', $b);
4352              
4353 18252 100       37641 if (0) { }
    100          
    50          
4354 0         0 elsif (CORE::length($a) == 1) {
4355 2652 100       5221 if (0) { }
    100          
    50          
4356 0         0 elsif (CORE::length($b) == 1) {
4357             return (
4358 156 50       715 $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       4951 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       13663 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       14868 if (0) { }
    50          
4382 0         0 elsif (CORE::length($b) == 2) {
4383 1872 100       8594 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       5185 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         5858 return qq{(?=$lower_limit)(?=$upper_limit)};
4392             }
4393             elsif (CORE::length($b) == 4) {
4394             return (
4395 6656 100       60075 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       11101 if (0) { }
4406 0         0 elsif (CORE::length($b) == 4) {
4407 7072 100       43450 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       31906 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         22360 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 119683 my($a, $b) = @_;
4431 90108         248273 my @a = (undef, unpack 'C*', $a);
4432 90108         139295 my @b = (undef, unpack 'C*', $b);
4433              
4434 90108 100       269809 if (0) { }
    100          
    100          
    50          
4435 0         0 elsif (CORE::length($a) == 1) {
4436 9732 100       24200 if (0) { }
    100          
    100          
    50          
4437 0         0 elsif (CORE::length($b) == 1) {
4438             return (
4439 420 50       1968 $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       5006 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       25914 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       42798 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       29314 if (0) { }
    100          
    50          
4473 0         0 elsif (CORE::length($b) == 2) {
4474 868 100       3997 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       2571 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         2786 return qq{(?=$lower_limit)(?=$upper_limit)};
4483             }
4484             elsif (CORE::length($b) == 3) {
4485             return (
4486 6448 100       53756 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       50833 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       47006 if (0) { }
    50          
4507 0         0 elsif (CORE::length($b) == 3) {
4508 19428 100       105751 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       72690 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         62839 return qq{(?=$lower_limit)(?=$upper_limit)};
4519             }
4520             elsif (CORE::length($b) == 4) {
4521             return (
4522 7936 100       91166 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       67483 if (0) { }
4534 0         0 elsif (CORE::length($b) == 4) {
4535 40320 100       265792 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       192030 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         139697 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 150907 my($codepoint_class) = @_;
4559 118269         143307 my @sbcs = ();
4560 118269         122644 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
4561              
4562             # get members from class
4563 118269         118370 my @classmate = ();
4564 118269         271863 while ($codepoint_class !~ /\G \z /xmsgc) {
4565 353317 50       1955499 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         285 push @classmate, $1;
4574             }
4575             elsif ($codepoint_class =~ /\G((?>\\$x))/xmsgc) {
4576 562         1734 push @classmate, $1;
4577             }
4578             elsif ($codepoint_class =~ /\G($x)/xmsgc) {
4579 352655         801683 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         261384 for (my $i=0; $i <= $#classmate; $i++) {
4588 118721         167360 my $classmate = $classmate[$i];
4589              
4590             # hyphen of [A-Z] or [^A-Z]
4591 118721 100 100     411197 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         122262 my $a = $classmate[$i];
4593 117298         130093 my $b = $classmate[$i+2];
4594 117298 100       471950 if (0) { }
    100          
    100          
    100          
    50          
4595 0         0 elsif ($script_encoding =~ /\A (?: sjis ) \z/xms) {
4596 8434         14626 push @xbcs, list_all_by_hyphen_sjis_like ($a, $b);
4597             }
4598             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
4599 252         473 push @xbcs, list_all_by_hyphen_eucjp_like ($a, $b);
4600             }
4601             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
4602 252         494 push @xbcs, list_all_by_hyphen_big5_like ($a, $b);
4603             }
4604             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
4605 18252         29858 push @xbcs, list_all_by_hyphen_gb18030_like($a, $b);
4606             }
4607             elsif ($script_encoding =~ /\A (?: rfc2279 | utf8 | wtf8 ) \z/xms) {
4608 90108         160216 push @xbcs, list_all_by_hyphen_utf8_like ($a, $b);
4609             }
4610             else {
4611 0         0 push @sbcs, "$a-$b";
4612             }
4613 117298         277768 $i += 2;
4614             }
4615              
4616             # classic perl codepoint class shortcuts
4617 34         117 elsif ($classmate eq '\\D') { push @xbcs, "(?:(?![$bare_d])$x)"; }
4618 10         38 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         67 elsif ($classmate eq '\\S') { push @xbcs, "(?:(?![$bare_s])$x)"; }
4622 16         57 elsif ($classmate eq '\\V') { push @xbcs, "(?:(?![$bare_v])$x)"; }
4623 193         685 elsif ($classmate eq '\\W') { push @xbcs, "(?:(?![$bare_w])$x)"; }
4624 6         24 elsif ($classmate eq '\\b') { push @sbcs, $bare_backspace; }
4625 34         89 elsif ($classmate eq '\\d') { push @sbcs, $bare_d; }
4626 10         22 elsif ($classmate eq '\\h') { push @sbcs, $bare_h; }
4627 19         45 elsif ($classmate eq '\\s') { push @sbcs, $bare_s; }
4628 16         41 elsif ($classmate eq '\\v') { push @sbcs, $bare_v; }
4629 193         432 elsif ($classmate eq '\\w') { push @sbcs, $bare_w; }
4630              
4631             # [:POSIX:]
4632 19         36 elsif ($classmate eq '[:alnum:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x61-\x7A'; }
4633 3         8 elsif ($classmate eq '[:alpha:]' ) { push @sbcs, '\x41-\x5A\x61-\x7A'; }
4634 3         13 elsif ($classmate eq '[:ascii:]' ) { push @sbcs, '\x00-\x7F'; }
4635 3         11 elsif ($classmate eq '[:blank:]' ) { push @sbcs, '\x09\x20'; }
4636 3         7 elsif ($classmate eq '[:cntrl:]' ) { push @sbcs, '\x00-\x1F\x7F'; }
4637 3         8 elsif ($classmate eq '[:digit:]' ) { push @sbcs, '\x30-\x39'; }
4638 3         9 elsif ($classmate eq '[:graph:]' ) { push @sbcs, '\x21-\x7F'; }
4639 3         8 elsif ($classmate eq '[:lower:]' ) { push @sbcs, 'abcdefghijklmnopqrstuvwxyz'; } # /i modifier requires 'a' to 'z' literally
4640 3         8 elsif ($classmate eq '[:print:]' ) { push @sbcs, '\x20-\x7F'; }
4641 3         7 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         7 elsif ($classmate eq '[:upper:]' ) { push @sbcs, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; } # /i modifier requires 'A' to 'Z' literally
4644 3         8 elsif ($classmate eq '[:word:]' ) { push @sbcs, '\x30-\x39\x41-\x5A\x5F\x61-\x7A'; }
4645 3         10 elsif ($classmate eq '[:xdigit:]') { push @sbcs, '\x30-\x39\x41-\x46\x61-\x66'; }
4646              
4647             # [:^POSIX:]
4648 3         12 elsif ($classmate eq '[:^alnum:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x61-\\x7A])$x)"; }
4649 3         34 elsif ($classmate eq '[:^alpha:]' ) { push @xbcs, "(?:(?![\\x41-\\x5A\\x61-\\x7A])$x)"; }
4650 3         12 elsif ($classmate eq '[:^ascii:]' ) { push @xbcs, "(?:(?![\\x00-\\x7F])$x)"; }
4651 3         14 elsif ($classmate eq '[:^blank:]' ) { push @xbcs, "(?:(?![\\x09\\x20])$x)"; }
4652 3         16 elsif ($classmate eq '[:^cntrl:]' ) { push @xbcs, "(?:(?![\\x00-\\x1F\\x7F])$x)"; }
4653 3         18 elsif ($classmate eq '[:^digit:]' ) { push @xbcs, "(?:(?![\\x30-\\x39])$x)"; }
4654 3         13 elsif ($classmate eq '[:^graph:]' ) { push @xbcs, "(?:(?![\\x21-\\x7F])$x)"; }
4655 3         11 elsif ($classmate eq '[:^lower:]' ) { push @xbcs, "(?:(?![abcdefghijklmnopqrstuvwxyz])$x)"; } # /i modifier requires 'a' to 'z' literally
4656 3         12 elsif ($classmate eq '[:^print:]' ) { push @xbcs, "(?:(?![\\x20-\\x7F])$x)"; }
4657 3         17 elsif ($classmate eq '[:^punct:]' ) { push @xbcs, "(?:(?![\\x21-\\x2F\\x3A-\\x3F\\x40\\x5B-\\x5F\\x60\\x7B-\\x7E])$x)"; }
4658 3         11 elsif ($classmate eq '[:^space:]' ) { push @xbcs, "(?:(?![\\s\\x0B])$x)"; } # "\s" and vertical tab ("\cK")
4659 3         11 elsif ($classmate eq '[:^upper:]' ) { push @xbcs, "(?:(?![ABCDEFGHIJKLMNOPQRSTUVWXYZ])$x)"; } # /i modifier requires 'A' to 'Z' literally
4660 3         12 elsif ($classmate eq '[:^word:]' ) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x5F\\x61-\\x7A])$x)"; }
4661 3         16 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       26 if (CORE::length($2) == 1) {
4666 12         35 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       1046 if (CORE::length($1) == 1) {
4676 417         821 push @sbcs, $1;
4677             }
4678             else {
4679 344         534 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     463381 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         22075928 return $parsed;
4701             }
4702              
4703             #---------------------------------------------------------------------
4704             # parse qr'regexp' as q-like
4705             sub parse_re_as_q_endswith {
4706 948     951 0 1880 my($operator, $endswith) = @_;
4707 948         1160 my $parsed = $endswith;
4708 948         974 while (1) {
4709 1956 100       9486 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         1263 $parsed .= $1;
4711 948         984 last;
4712             }
4713              
4714             # get codepoint class
4715             elsif (/\G \[ /xmsgc) {
4716 566         643 my $classmate = '';
4717 566         480 while (1) {
4718 1766 100       5245 if (/\G \] /xmsgc) {
    100          
    100          
    50          
4719 566         640 last;
4720             }
4721             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
4722 28         33 $classmate .= $1;
4723             }
4724             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
4725 44         55 $classmate .= $1;
4726             }
4727             elsif (/\G ($x) /xmsgc) {
4728 1128         1330 $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         802 $parsed .= mb::_cc($classmate);
4744             }
4745              
4746             # /./ or \any
4747 2         4 elsif (/\G \. /xmsgc) { $parsed .= "(?:$over_ascii|.)"; } # after $over_ascii, /s modifier wants "." (not [\x00-\xFF])
4748 2         7 elsif (/\G \\B /xmsgc) { $parsed .= "(?:(?
4749 12         30 elsif (/\G \\D /xmsgc) { $parsed .= "(?:(?![$bare_d])$x)"; }
4750 4         12 elsif (/\G \\H /xmsgc) { $parsed .= "(?:(?![$bare_h])$x)"; }
4751 2         6 elsif (/\G \\N /xmsgc) { $parsed .= "(?:(?!\\n)$x)"; }
4752 2         5 elsif (/\G \\R /xmsgc) { $parsed .= "(?>\\r\\n|[$bare_v])"; }
4753 7         19 elsif (/\G \\S /xmsgc) { $parsed .= "(?:(?![$bare_s])$x)"; }
4754 6         20 elsif (/\G \\V /xmsgc) { $parsed .= "(?:(?![$bare_v])$x)"; }
4755 65         256 elsif (/\G \\W /xmsgc) { $parsed .= "(?:(?![$bare_w])$x)"; }
4756 2         5 elsif (/\G \\b /xmsgc) { $parsed .= "(?:(?
4757 12         16 elsif (/\G \\d /xmsgc) { $parsed .= "[$bare_d]"; }
4758 4         8 elsif (/\G \\h /xmsgc) { $parsed .= "[$bare_h]"; }
4759 7         8 elsif (/\G \\s /xmsgc) { $parsed .= "[$bare_s]"; }
4760 6         9 elsif (/\G \\v /xmsgc) { $parsed .= "[$bare_v]"; }
4761 65         118 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       398 if (CORE::length($1) == 1) {
4801 99         141 $parsed .= $1;
4802             }
4803             else {
4804 145         136 $parsed .= '(?:';
4805 145         229 $parsed .= escape_to_hex($1, $endswith);
4806 145         181 $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         1370 return $parsed;
4821             }
4822              
4823             #---------------------------------------------------------------------
4824             # parse qr{regexp} in balanced blackets
4825             sub parse_re_balanced {
4826 564     567 0 1201 my($operator, $open_bracket) = @_;
4827 564   50     2163 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
4828 564         932 my $parsed = $open_bracket;
4829 564         577 my $nest_bracket = 1;
4830 564         532 my $nest_escape = 0;
4831 564         524 while (1) {
4832 1133 50       6735 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       814 if (--$nest_bracket <= 0) {
4838 564         653 $parsed .= ('>)]}' x $nest_escape);
4839 564         612 $parsed .= $1;
4840 564         642 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         921 $parsed .= parse_re($operator, $open_bracket);
4901             }
4902             }
4903 564         838 return $parsed;
4904             }
4905              
4906             #---------------------------------------------------------------------
4907             # parse qr/regexp/ that ends with a character
4908             sub parse_re_endswith {
4909 120529     120531 0 332510 my($operator, $endswith) = @_;
4910 120529         162513 my $parsed = $endswith;
4911 120529         133023 my $nest_escape = 0;
4912 120529         133410 while (1) {
4913 242344 100       996074 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
4914 120529         154768 $parsed .= ('>)]}' x $nest_escape);
4915 120529         170060 $parsed .= $1;
4916 120529         116751 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         217739 $parsed .= parse_re($operator, $endswith);
4973             }
4974             }
4975 120529         174652 return $parsed;
4976             }
4977              
4978             #---------------------------------------------------------------------
4979             # parse qr/regexp/ common routine
4980             sub parse_re {
4981 122384     122384 0 157499 my($operator, $closewith) = @_;
4982 122384         127143 my $parsed = '';
4983              
4984             # codepoint class
4985 122384 100       256371 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         135493 my $classmate = '';
4987 118837         103324 while (1) {
4988 532652 100       1964026 if (/\G \] /xmsgc) {
    100          
    100          
    100          
    50          
4989 118837         133387 last;
4990             }
4991             elsif (/\G (\\) /xmsgc) {
4992 510         852 $classmate .= "\\$1";
4993             }
4994             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
4995 98         141 $classmate .= $1;
4996             }
4997             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
4998 114         157 $classmate .= $1;
4999             }
5000             elsif (/\G ($x) /xmsgc) {
5001 413093         500135 $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         195754 $parsed .= "(?:\@{[mb::_cc(qq[$classmate])]})";
5021             }
5022              
5023             # /./ or \any
5024 20         30 elsif (/\G \. /xmsgc) { $parsed .= '(?:@{[@mb::_dot]})'; }
5025 7         13 elsif (/\G \\B /xmsgc) { $parsed .= '(?:@{[@mb::_B]})'; }
5026 18         27 elsif (/\G \\D /xmsgc) { $parsed .= '(?:@{[@mb::_D]})'; }
5027 10         28 elsif (/\G \\H /xmsgc) { $parsed .= '(?:@{[@mb::_H]})'; }
5028 8         13 elsif (/\G \\N /xmsgc) { $parsed .= '(?:@{[@mb::_N]})'; }
5029 12         15 elsif (/\G \\R /xmsgc) { $parsed .= '(?:@{[@mb::_R]})'; }
5030 14         24 elsif (/\G \\S /xmsgc) { $parsed .= '(?:@{[@mb::_S]})'; }
5031 12         22 elsif (/\G \\V /xmsgc) { $parsed .= '(?:@{[@mb::_V]})'; }
5032 71         128 elsif (/\G \\W /xmsgc) { $parsed .= '(?:@{[@mb::_W]})'; }
5033 7         10 elsif (/\G \\b /xmsgc) { $parsed .= '(?:@{[@mb::_b]})'; }
5034 17         24 elsif (/\G \\d /xmsgc) { $parsed .= '(?:@{[@mb::_d]})'; }
5035 10         14 elsif (/\G \\h /xmsgc) { $parsed .= '(?:@{[@mb::_h]})'; }
5036 18         29 elsif (/\G \\s /xmsgc) { $parsed .= '(?:@{[@mb::_s]})'; }
5037 14         21 elsif (/\G \\v /xmsgc) { $parsed .= '(?:@{[@mb::_v]})'; }
5038 70         95 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         31 $parsed .= $1;
5067 24 50       38 if ($operator eq 's') {
5068 0         0 $parsed .= ($2 + 1);
5069             }
5070             else {
5071 24         31 $parsed .= $2;
5072             }
5073             }
5074              
5075             # \any
5076             elsif (/\G (\\) ($x) /xmsgc) {
5077 5 50       24 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         44 $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       6618 if (CORE::length($1) == 1) {
5155 2625         3139 $parsed .= $1;
5156             }
5157             else {
5158 561         819 $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         213156 return $parsed;
5172             }
5173              
5174             #---------------------------------------------------------------------
5175             # parse modifiers of qr///here
5176             sub parse_re_modifier {
5177 122041     122041 0 143641 my $modifier_i = '';
5178 122041         121146 my $modifier_not_cegir = '';
5179 122041         114784 my $modifier_cegr = '';
5180 122041         105917 while (1) {
5181 122341 50       261714 if (/\G [adlpu] /xmsgc) {
    100          
    100          
    100          
5182             # drop modifiers
5183             }
5184             elsif (/\G ([i]) /xmsgc) {
5185 100         143 $modifier_i .= $1;
5186             }
5187             elsif (/\G ([cegr]) /xmsgc) {
5188 35         51 $modifier_cegr .= $1;
5189             }
5190             elsif (/\G ([a-z]) /xmsgc) {
5191 165         199 $modifier_not_cegir .= $1;
5192             }
5193             else {
5194 122041         107999 last;
5195             }
5196             }
5197 122041         241643 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 2078 my $modifier_not_r = '';
5204 2153         2080 my $modifier_r = '';
5205 2153         1912 while (1) {
5206 2241 50       4508 if (/\G ([r]) /xmsgc) {
    100          
5207 0         0 $modifier_r .= $1;
5208             }
5209             elsif (/\G ([a-z]) /xmsgc) {
5210 88         123 $modifier_not_r .= $1;
5211             }
5212             else {
5213 2153         2031 last;
5214             }
5215             }
5216 2153         4096 return ($modifier_not_r, $modifier_r);
5217             }
5218              
5219             #---------------------------------------------------------------------
5220             # makes codepoint class from string
5221             sub codepoint_tr {
5222 2125     2125 0 3347 my $searchlist = quotee_of($_[0]);
5223              
5224 2125         2157 my @sbcs = ();
5225 2125         2015 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
5226 2125         3985 while ($searchlist !~ /\G \z /xmsgc) {
5227              
5228             # \-
5229 3249 100       14132 if ($searchlist =~ /\G (\\-) /xmsgc) {
    100          
    100          
    50          
5230 9         15 push @sbcs, $1;
5231             }
5232              
5233             # -
5234             elsif ($searchlist =~ /\G (-) /xmsgc) {
5235 27         48 push @sbcs, $1;
5236             }
5237              
5238             # any qq escapee
5239             elsif ($searchlist =~ /\G ([$escapee_in_qq_like]) /xmsgc) {
5240 1036         2769 push @sbcs, "\\$1";
5241             }
5242              
5243             # any
5244             elsif ($searchlist =~ /\G ($x) /xmsgc) {
5245 2177 100       3514 if (CORE::length($1) == 1) {
5246 1146         3010 push @sbcs, $1;
5247             }
5248             else {
5249 1031         1285 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     15171 ( @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 5000 if (CORE::length($_[0]) >= 2) {
5276 3260         5769 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 817695 my($codepoint, $endswith) = @_;
5287 569672 50       1673193 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         7127 return "$1\\$2";
5292             }
5293             else {
5294 567680         818245 return $codepoint;
5295             }
5296             }
5297              
5298             #---------------------------------------------------------------------
5299             # escape qq/string/ as qq-like quote
5300             sub escape_qq {
5301 975993     975993 0 1261099 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       8315143 if ($codepoint eq '`') {
    100          
    100          
5310 0         0 return '\\x60';
5311             }
5312             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
5313 1032         2844 return "$1\\$2";
5314             }
5315             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
5316 18843         64596 return "$1\\$2";
5317             }
5318             else {
5319 956118         1462199 return $codepoint;
5320             }
5321             }
5322              
5323             #---------------------------------------------------------------------
5324             # escape tr/here/here/ as tr-like quote
5325             sub escape_tr {
5326 4572     4572 0 6681 my($codepoint, $endswith) = @_;
5327 4572 50       78558 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         7177 return "$1\\$2";
5335             }
5336             else {
5337 2584         6125 return $codepoint;
5338             }
5339             }
5340              
5341             #---------------------------------------------------------------------
5342             # escape qq/string/ or qr/regexp/ to hex
5343             sub escape_to_hex {
5344 490     490 0 687 my($codepoint, $endswith) = @_;
5345 490 100       2753 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
5346 28         92 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         417 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
5352             }
5353             else {
5354 380         961 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   363 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__