File Coverage

blib/lib/Ecyrillic.pm
Criterion Covered Total %
statement 83 3085 2.6
branch 4 2674 0.1
condition 1 373 0.2
subroutine 36 125 28.8
pod 7 74 9.4
total 131 6331 2.0


line stmt bran cond sub pod time code
1             package Ecyrillic;
2             ######################################################################
3             #
4             # Ecyrillic - Run-time routines for Cyrillic.pm
5             #
6             # http://search.cpan.org/dist/Char-Cyrillic/
7             #
8             # Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 INABA Hitoshi
9             ######################################################################
10              
11 200     200   5235 use 5.00503; # Galapagos Consensus 1998 for primetools
  200         668  
  200         13469  
12             # use 5.008001; # Lancaster Consensus 2013 for toolchains
13              
14             # 12.3. Delaying use Until Runtime
15             # in Chapter 12. Packages, Libraries, and Modules
16             # of ISBN 0-596-00313-7 Perl Cookbook, 2nd Edition.
17             # (and so on)
18              
19             # Version numbers should be boring
20             # http://www.dagolden.com/index.php/369/version-numbers-should-be-boring/
21             # For the impatient, the disinterested or those who just want to follow
22             # a recipe, my advice for all modules is this:
23             # our $VERSION = "0.001"; # or "0.001_001" for a dev release
24             # $VERSION = eval $VERSION;
25              
26 200     200   17399 BEGIN { CORE::eval q{ use vars qw($VERSION) } }
  200     200   1263  
  200         1188  
  200         48199  
27             $VERSION = '1.05';
28             $VERSION = CORE::eval $VERSION;
29              
30             BEGIN {
31 200 50   200   1647 if ($^X =~ / jperl /oxmsi) {
32 0         0 die __FILE__, ": needs perl(not jperl) 5.00503 or later. (\$^X==$^X)\n";
33             }
34 200         336 if (CORE::ord('A') == 193) {
35             die __FILE__, ": is not US-ASCII script (may be EBCDIC or EBCDIK script).\n";
36             }
37 200         33702 if (CORE::ord('A') != 0x41) {
38             die __FILE__, ": is not US-ASCII script (must be US-ASCII script).\n";
39             }
40             }
41              
42             BEGIN {
43              
44             # instead of utf8.pm
45 200     200   15622 CORE::eval q{
  200     200   1479  
  200     77   436  
  200         36549  
  77         15940  
  65         13520  
  60         11533  
  75         14409  
  58         10926  
  65         13419  
46             no warnings qw(redefine);
47             *utf8::upgrade = sub { CORE::length $_[0] };
48             *utf8::downgrade = sub { 1 };
49             *utf8::encode = sub { };
50             *utf8::decode = sub { 1 };
51             *utf8::is_utf8 = sub { };
52             *utf8::valid = sub { 1 };
53             };
54 200 50       151258 if ($@) {
55 0         0 *utf8::upgrade = sub { CORE::length $_[0] };
  0         0  
56 0         0 *utf8::downgrade = sub { 1 };
  0         0  
57 0         0 *utf8::encode = sub { };
  0         0  
58 0         0 *utf8::decode = sub { 1 };
  0         0  
59 0         0 *utf8::is_utf8 = sub { };
  0         0  
60 0         0 *utf8::valid = sub { 1 };
  0         0  
61             }
62             }
63              
64             # instead of Symbol.pm
65             BEGIN {
66 200     200   567 my $genpkg = "Symbol::";
67 200         10800 my $genseq = 0;
68              
69             sub gensym () {
70 0     0 0 0 my $name = "GEN" . $genseq++;
71              
72             # here, no strict qw(refs); if strict.pm exists
73              
74 0         0 my $ref = \*{$genpkg . $name};
  0         0  
75 0         0 delete $$genpkg{$name};
76 0         0 return $ref;
77             }
78              
79             sub qualify ($;$) {
80 0     0 0 0 my ($name) = @_;
81 0 0 0     0 if (!ref($name) && (Ecyrillic::index($name, '::') == -1) && (Ecyrillic::index($name, "'") == -1)) {
      0        
82 0         0 my $pkg;
83 0         0 my %global = map {$_ => 1} qw(ARGV ARGVOUT ENV INC SIG STDERR STDIN STDOUT DATA);
  0         0  
84              
85             # Global names: special character, "^xyz", or other.
86 0 0 0     0 if ($name =~ /^(([^a-z])|(\^[a-z_]+))\z/i || $global{$name}) {
87             # RGS 2001-11-05 : translate leading ^X to control-char
88 0         0 $name =~ s/^\^([a-z_])/'qq(\c'.$1.')'/eei;
  0         0  
89 0         0 $pkg = "main";
90             }
91             else {
92 0 0       0 $pkg = (@_ > 1) ? $_[1] : caller;
93             }
94 0         0 $name = $pkg . "::" . $name;
95             }
96 0         0 return $name;
97             }
98              
99             sub qualify_to_ref ($;$) {
100              
101             # here, no strict qw(refs); if strict.pm exists
102              
103 0 0   0 0 0 return \*{ qualify $_[0], @_ > 1 ? $_[1] : caller };
  0         0  
104             }
105             }
106              
107             # Column: local $@
108             # in Chapter 9. Osaete okitai Perl no kiso
109             # of ISBN 10: 4798119172 | ISBN 13: 978-4798119175 MODAN Perl NYUMON
110             # (and so on)
111              
112             # use strict; if strict.pm exists
113             BEGIN {
114 200 50   200   645 if (CORE::eval { local $@; CORE::require strict }) {
  200         447  
  200         2493  
115 200         30069 strict::->import;
116             }
117             }
118              
119             # P.714 29.2.39. flock
120             # in Chapter 29: Functions
121             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
122              
123             # P.863 flock
124             # in Chapter 27: Functions
125             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
126              
127             sub LOCK_SH() {1}
128             sub LOCK_EX() {2}
129             sub LOCK_UN() {8}
130             sub LOCK_NB() {4}
131              
132             # instead of Carp.pm
133             sub carp;
134             sub croak;
135             sub cluck;
136             sub confess;
137              
138             # 6.18. Matching Multiple-Byte Characters
139             # in Chapter 6. Pattern Matching
140             # of ISBN 978-1-56592-243-3 Perl Perl Cookbook.
141             # (and so on)
142              
143             # regexp of character
144 200     200   16611 BEGIN { CORE::eval q{ use vars qw($your_char) } } $your_char = q{[\x00-\xFF]};
  200     200   1259  
  200         351  
  200         16143  
145 200     200   16833 BEGIN { CORE::eval q{ use vars qw($qq_char ) } } $qq_char = qr/\\c[\x40-\x5F]|\\?(?:$your_char)/oxms;
  200     200   1133  
  200         301  
  200         14200  
146 200     200   15267 BEGIN { CORE::eval q{ use vars qw($q_char ) } } $q_char = qr/$your_char/oxms;
  200     200   1182  
  200         353  
  200         17327  
147              
148             #
149             # Cyrillic character range per length
150             #
151             my %range_tr = ();
152              
153             #
154             # alias of encoding name
155             #
156 200     200   17070 BEGIN { CORE::eval q{ use vars qw($encoding_alias) } }
  200     200   1346  
  200         419  
  200         536642  
157              
158             #
159             # Cyrillic case conversion
160             #
161             my %lc = ();
162             @lc{qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)} =
163             qw(a b c d e f g h i j k l m n o p q r s t u v w x y z);
164             my %uc = ();
165             @uc{qw(a b c d e f g h i j k l m n o p q r s t u v w x y z)} =
166             qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
167             my %fc = ();
168             @fc{qw(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)} =
169             qw(a b c d e f g h i j k l m n o p q r s t u v w x y z);
170              
171             if (0) {
172             }
173              
174             elsif (__PACKAGE__ =~ / \b Ecyrillic \z/oxms) {
175             %range_tr = (
176             1 => [ [0x00..0xFF],
177             ],
178             );
179             $encoding_alias = qr/ \b (?: iso[-_ ]?8859-5 | iec[- ]?8859-5 | cyrillic ) \b /oxmsi;
180              
181             %lc = (%lc,
182             "\xA1" => "\xF1", # CYRILLIC LETTER IO
183             "\xA2" => "\xF2", # CYRILLIC LETTER DJE
184             "\xA3" => "\xF3", # CYRILLIC LETTER GJE
185             "\xA4" => "\xF4", # CYRILLIC LETTER UKRAINIAN IE
186             "\xA5" => "\xF5", # CYRILLIC LETTER DZE
187             "\xA6" => "\xF6", # CYRILLIC LETTER BYELORUSSIAN-UKRAINIAN I
188             "\xA7" => "\xF7", # CYRILLIC LETTER YI
189             "\xA8" => "\xF8", # CYRILLIC LETTER JE
190             "\xA9" => "\xF9", # CYRILLIC LETTER LJE
191             "\xAA" => "\xFA", # CYRILLIC LETTER NJE
192             "\xAB" => "\xFB", # CYRILLIC LETTER TSHE
193             "\xAC" => "\xFC", # CYRILLIC LETTER KJE
194             "\xAE" => "\xFE", # CYRILLIC LETTER SHORT U
195             "\xAF" => "\xFF", # CYRILLIC LETTER DZHE
196             "\xB0" => "\xD0", # CYRILLIC LETTER A
197             "\xB1" => "\xD1", # CYRILLIC LETTER BE
198             "\xB2" => "\xD2", # CYRILLIC LETTER VE
199             "\xB3" => "\xD3", # CYRILLIC LETTER GHE
200             "\xB4" => "\xD4", # CYRILLIC LETTER DE
201             "\xB5" => "\xD5", # CYRILLIC LETTER IE
202             "\xB6" => "\xD6", # CYRILLIC LETTER ZHE
203             "\xB7" => "\xD7", # CYRILLIC LETTER ZE
204             "\xB8" => "\xD8", # CYRILLIC LETTER I
205             "\xB9" => "\xD9", # CYRILLIC LETTER SHORT I
206             "\xBA" => "\xDA", # CYRILLIC LETTER KA
207             "\xBB" => "\xDB", # CYRILLIC LETTER EL
208             "\xBC" => "\xDC", # CYRILLIC LETTER EM
209             "\xBD" => "\xDD", # CYRILLIC LETTER EN
210             "\xBE" => "\xDE", # CYRILLIC LETTER O
211             "\xBF" => "\xDF", # CYRILLIC LETTER PE
212             "\xC0" => "\xE0", # CYRILLIC LETTER ER
213             "\xC1" => "\xE1", # CYRILLIC LETTER ES
214             "\xC2" => "\xE2", # CYRILLIC LETTER TE
215             "\xC3" => "\xE3", # CYRILLIC LETTER U
216             "\xC4" => "\xE4", # CYRILLIC LETTER EF
217             "\xC5" => "\xE5", # CYRILLIC LETTER HA
218             "\xC6" => "\xE6", # CYRILLIC LETTER TSE
219             "\xC7" => "\xE7", # CYRILLIC LETTER CHE
220             "\xC8" => "\xE8", # CYRILLIC LETTER SHA
221             "\xC9" => "\xE9", # CYRILLIC LETTER SHCHA
222             "\xCA" => "\xEA", # CYRILLIC LETTER HARD SIGN
223             "\xCB" => "\xEB", # CYRILLIC LETTER YERU
224             "\xCC" => "\xEC", # CYRILLIC LETTER SOFT SIGN
225             "\xCD" => "\xED", # CYRILLIC LETTER E
226             "\xCE" => "\xEE", # CYRILLIC LETTER YU
227             "\xCF" => "\xEF", # CYRILLIC LETTER YA
228             );
229              
230             %uc = (%uc,
231             "\xD0" => "\xB0", # CYRILLIC LETTER A
232             "\xD1" => "\xB1", # CYRILLIC LETTER BE
233             "\xD2" => "\xB2", # CYRILLIC LETTER VE
234             "\xD3" => "\xB3", # CYRILLIC LETTER GHE
235             "\xD4" => "\xB4", # CYRILLIC LETTER DE
236             "\xD5" => "\xB5", # CYRILLIC LETTER IE
237             "\xD6" => "\xB6", # CYRILLIC LETTER ZHE
238             "\xD7" => "\xB7", # CYRILLIC LETTER ZE
239             "\xD8" => "\xB8", # CYRILLIC LETTER I
240             "\xD9" => "\xB9", # CYRILLIC LETTER SHORT I
241             "\xDA" => "\xBA", # CYRILLIC LETTER KA
242             "\xDB" => "\xBB", # CYRILLIC LETTER EL
243             "\xDC" => "\xBC", # CYRILLIC LETTER EM
244             "\xDD" => "\xBD", # CYRILLIC LETTER EN
245             "\xDE" => "\xBE", # CYRILLIC LETTER O
246             "\xDF" => "\xBF", # CYRILLIC LETTER PE
247             "\xE0" => "\xC0", # CYRILLIC LETTER ER
248             "\xE1" => "\xC1", # CYRILLIC LETTER ES
249             "\xE2" => "\xC2", # CYRILLIC LETTER TE
250             "\xE3" => "\xC3", # CYRILLIC LETTER U
251             "\xE4" => "\xC4", # CYRILLIC LETTER EF
252             "\xE5" => "\xC5", # CYRILLIC LETTER HA
253             "\xE6" => "\xC6", # CYRILLIC LETTER TSE
254             "\xE7" => "\xC7", # CYRILLIC LETTER CHE
255             "\xE8" => "\xC8", # CYRILLIC LETTER SHA
256             "\xE9" => "\xC9", # CYRILLIC LETTER SHCHA
257             "\xEA" => "\xCA", # CYRILLIC LETTER HARD SIGN
258             "\xEB" => "\xCB", # CYRILLIC LETTER YERU
259             "\xEC" => "\xCC", # CYRILLIC LETTER SOFT SIGN
260             "\xED" => "\xCD", # CYRILLIC LETTER E
261             "\xEE" => "\xCE", # CYRILLIC LETTER YU
262             "\xEF" => "\xCF", # CYRILLIC LETTER YA
263             "\xF1" => "\xA1", # CYRILLIC LETTER IO
264             "\xF2" => "\xA2", # CYRILLIC LETTER DJE
265             "\xF3" => "\xA3", # CYRILLIC LETTER GJE
266             "\xF4" => "\xA4", # CYRILLIC LETTER UKRAINIAN IE
267             "\xF5" => "\xA5", # CYRILLIC LETTER DZE
268             "\xF6" => "\xA6", # CYRILLIC LETTER BYELORUSSIAN-UKRAINIAN I
269             "\xF7" => "\xA7", # CYRILLIC LETTER YI
270             "\xF8" => "\xA8", # CYRILLIC LETTER JE
271             "\xF9" => "\xA9", # CYRILLIC LETTER LJE
272             "\xFA" => "\xAA", # CYRILLIC LETTER NJE
273             "\xFB" => "\xAB", # CYRILLIC LETTER TSHE
274             "\xFC" => "\xAC", # CYRILLIC LETTER KJE
275             "\xFE" => "\xAE", # CYRILLIC LETTER SHORT U
276             "\xFF" => "\xAF", # CYRILLIC LETTER DZHE
277             );
278              
279             %fc = (%fc,
280             "\xA1" => "\xF1", # CYRILLIC CAPITAL LETTER IO --> CYRILLIC SMALL LETTER IO
281             "\xA2" => "\xF2", # CYRILLIC CAPITAL LETTER DJE --> CYRILLIC SMALL LETTER DJE
282             "\xA3" => "\xF3", # CYRILLIC CAPITAL LETTER GJE --> CYRILLIC SMALL LETTER GJE
283             "\xA4" => "\xF4", # CYRILLIC CAPITAL LETTER UKRAINIAN IE --> CYRILLIC SMALL LETTER UKRAINIAN IE
284             "\xA5" => "\xF5", # CYRILLIC CAPITAL LETTER DZE --> CYRILLIC SMALL LETTER DZE
285             "\xA6" => "\xF6", # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I --> CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
286             "\xA7" => "\xF7", # CYRILLIC CAPITAL LETTER YI --> CYRILLIC SMALL LETTER YI
287             "\xA8" => "\xF8", # CYRILLIC CAPITAL LETTER JE --> CYRILLIC SMALL LETTER JE
288             "\xA9" => "\xF9", # CYRILLIC CAPITAL LETTER LJE --> CYRILLIC SMALL LETTER LJE
289             "\xAA" => "\xFA", # CYRILLIC CAPITAL LETTER NJE --> CYRILLIC SMALL LETTER NJE
290             "\xAB" => "\xFB", # CYRILLIC CAPITAL LETTER TSHE --> CYRILLIC SMALL LETTER TSHE
291             "\xAC" => "\xFC", # CYRILLIC CAPITAL LETTER KJE --> CYRILLIC SMALL LETTER KJE
292             "\xAE" => "\xFE", # CYRILLIC CAPITAL LETTER SHORT U --> CYRILLIC SMALL LETTER SHORT U
293             "\xAF" => "\xFF", # CYRILLIC CAPITAL LETTER DZHE --> CYRILLIC SMALL LETTER DZHE
294             "\xB0" => "\xD0", # CYRILLIC CAPITAL LETTER A --> CYRILLIC SMALL LETTER A
295             "\xB1" => "\xD1", # CYRILLIC CAPITAL LETTER BE --> CYRILLIC SMALL LETTER BE
296             "\xB2" => "\xD2", # CYRILLIC CAPITAL LETTER VE --> CYRILLIC SMALL LETTER VE
297             "\xB3" => "\xD3", # CYRILLIC CAPITAL LETTER GHE --> CYRILLIC SMALL LETTER GHE
298             "\xB4" => "\xD4", # CYRILLIC CAPITAL LETTER DE --> CYRILLIC SMALL LETTER DE
299             "\xB5" => "\xD5", # CYRILLIC CAPITAL LETTER IE --> CYRILLIC SMALL LETTER IE
300             "\xB6" => "\xD6", # CYRILLIC CAPITAL LETTER ZHE --> CYRILLIC SMALL LETTER ZHE
301             "\xB7" => "\xD7", # CYRILLIC CAPITAL LETTER ZE --> CYRILLIC SMALL LETTER ZE
302             "\xB8" => "\xD8", # CYRILLIC CAPITAL LETTER I --> CYRILLIC SMALL LETTER I
303             "\xB9" => "\xD9", # CYRILLIC CAPITAL LETTER SHORT I --> CYRILLIC SMALL LETTER SHORT I
304             "\xBA" => "\xDA", # CYRILLIC CAPITAL LETTER KA --> CYRILLIC SMALL LETTER KA
305             "\xBB" => "\xDB", # CYRILLIC CAPITAL LETTER EL --> CYRILLIC SMALL LETTER EL
306             "\xBC" => "\xDC", # CYRILLIC CAPITAL LETTER EM --> CYRILLIC SMALL LETTER EM
307             "\xBD" => "\xDD", # CYRILLIC CAPITAL LETTER EN --> CYRILLIC SMALL LETTER EN
308             "\xBE" => "\xDE", # CYRILLIC CAPITAL LETTER O --> CYRILLIC SMALL LETTER O
309             "\xBF" => "\xDF", # CYRILLIC CAPITAL LETTER PE --> CYRILLIC SMALL LETTER PE
310             "\xC0" => "\xE0", # CYRILLIC CAPITAL LETTER ER --> CYRILLIC SMALL LETTER ER
311             "\xC1" => "\xE1", # CYRILLIC CAPITAL LETTER ES --> CYRILLIC SMALL LETTER ES
312             "\xC2" => "\xE2", # CYRILLIC CAPITAL LETTER TE --> CYRILLIC SMALL LETTER TE
313             "\xC3" => "\xE3", # CYRILLIC CAPITAL LETTER U --> CYRILLIC SMALL LETTER U
314             "\xC4" => "\xE4", # CYRILLIC CAPITAL LETTER EF --> CYRILLIC SMALL LETTER EF
315             "\xC5" => "\xE5", # CYRILLIC CAPITAL LETTER HA --> CYRILLIC SMALL LETTER HA
316             "\xC6" => "\xE6", # CYRILLIC CAPITAL LETTER TSE --> CYRILLIC SMALL LETTER TSE
317             "\xC7" => "\xE7", # CYRILLIC CAPITAL LETTER CHE --> CYRILLIC SMALL LETTER CHE
318             "\xC8" => "\xE8", # CYRILLIC CAPITAL LETTER SHA --> CYRILLIC SMALL LETTER SHA
319             "\xC9" => "\xE9", # CYRILLIC CAPITAL LETTER SHCHA --> CYRILLIC SMALL LETTER SHCHA
320             "\xCA" => "\xEA", # CYRILLIC CAPITAL LETTER HARD SIGN --> CYRILLIC SMALL LETTER HARD SIGN
321             "\xCB" => "\xEB", # CYRILLIC CAPITAL LETTER YERU --> CYRILLIC SMALL LETTER YERU
322             "\xCC" => "\xEC", # CYRILLIC CAPITAL LETTER SOFT SIGN --> CYRILLIC SMALL LETTER SOFT SIGN
323             "\xCD" => "\xED", # CYRILLIC CAPITAL LETTER E --> CYRILLIC SMALL LETTER E
324             "\xCE" => "\xEE", # CYRILLIC CAPITAL LETTER YU --> CYRILLIC SMALL LETTER YU
325             "\xCF" => "\xEF", # CYRILLIC CAPITAL LETTER YA --> CYRILLIC SMALL LETTER YA
326             );
327             }
328              
329             else {
330             croak "Don't know my package name '@{[__PACKAGE__]}'";
331             }
332              
333             #
334             # @ARGV wildcard globbing
335             #
336             sub import {
337              
338 0 0   0   0 if ($^O =~ /\A (?: MSWin32 | NetWare | symbian | dos ) \z/oxms) {
339 0         0 my @argv = ();
340 0         0 for (@ARGV) {
341              
342             # has space
343 0 0       0 if (/\A (?:$q_char)*? [ ] /oxms) {
    0          
344 0 0       0 if (my @glob = Ecyrillic::glob(qq{"$_"})) {
345 0         0 push @argv, @glob;
346             }
347             else {
348 0         0 push @argv, $_;
349             }
350             }
351              
352             # has wildcard metachar
353             elsif (/\A (?:$q_char)*? [*?] /oxms) {
354 0 0       0 if (my @glob = Ecyrillic::glob($_)) {
355 0         0 push @argv, @glob;
356             }
357             else {
358 0         0 push @argv, $_;
359             }
360             }
361              
362             # no wildcard globbing
363             else {
364 0         0 push @argv, $_;
365             }
366             }
367 0         0 @ARGV = @argv;
368             }
369              
370 0         0 *Char::ord = \&Cyrillic::ord;
371 0         0 *Char::ord_ = \&Cyrillic::ord_;
372 0         0 *Char::reverse = \&Cyrillic::reverse;
373 0         0 *Char::getc = \&Cyrillic::getc;
374 0         0 *Char::length = \&Cyrillic::length;
375 0         0 *Char::substr = \&Cyrillic::substr;
376 0         0 *Char::index = \&Cyrillic::index;
377 0         0 *Char::rindex = \&Cyrillic::rindex;
378 0         0 *Char::eval = \&Cyrillic::eval;
379 0         0 *Char::escape = \&Cyrillic::escape;
380 0         0 *Char::escape_token = \&Cyrillic::escape_token;
381 0         0 *Char::escape_script = \&Cyrillic::escape_script;
382             }
383              
384             # P.230 Care with Prototypes
385             # in Chapter 6: Subroutines
386             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
387             #
388             # If you aren't careful, you can get yourself into trouble with prototypes.
389             # But if you are careful, you can do a lot of neat things with them. This is
390             # all very powerful, of course, and should only be used in moderation to make
391             # the world a better place.
392              
393             # P.332 Care with Prototypes
394             # in Chapter 7: Subroutines
395             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
396             #
397             # If you aren't careful, you can get yourself into trouble with prototypes.
398             # But if you are careful, you can do a lot of neat things with them. This is
399             # all very powerful, of course, and should only be used in moderation to make
400             # the world a better place.
401              
402             #
403             # Prototypes of subroutines
404             #
405 0     0   0 sub unimport {}
406             sub Ecyrillic::split(;$$$);
407             sub Ecyrillic::tr($$$$;$);
408             sub Ecyrillic::chop(@);
409             sub Ecyrillic::index($$;$);
410             sub Ecyrillic::rindex($$;$);
411             sub Ecyrillic::lcfirst(@);
412             sub Ecyrillic::lcfirst_();
413             sub Ecyrillic::lc(@);
414             sub Ecyrillic::lc_();
415             sub Ecyrillic::ucfirst(@);
416             sub Ecyrillic::ucfirst_();
417             sub Ecyrillic::uc(@);
418             sub Ecyrillic::uc_();
419             sub Ecyrillic::fc(@);
420             sub Ecyrillic::fc_();
421             sub Ecyrillic::ignorecase;
422             sub Ecyrillic::classic_character_class;
423             sub Ecyrillic::capture;
424             sub Ecyrillic::chr(;$);
425             sub Ecyrillic::chr_();
426             sub Ecyrillic::glob($);
427             sub Ecyrillic::glob_();
428              
429             sub Cyrillic::ord(;$);
430             sub Cyrillic::ord_();
431             sub Cyrillic::reverse(@);
432             sub Cyrillic::getc(;*@);
433             sub Cyrillic::length(;$);
434             sub Cyrillic::substr($$;$$);
435             sub Cyrillic::index($$;$);
436             sub Cyrillic::rindex($$;$);
437             sub Cyrillic::escape(;$);
438              
439             #
440             # Regexp work
441             #
442 200     200   19484 BEGIN { CORE::eval q{ use vars qw(
  200     200   1708  
  200         484  
  200         101211  
443             $Cyrillic::re_a
444             $Cyrillic::re_t
445             $Cyrillic::re_n
446             $Cyrillic::re_r
447             ) } }
448              
449             #
450             # Character class
451             #
452 200     200   19249 BEGIN { CORE::eval q{ use vars qw(
  200     200   1396  
  200         363  
  200         3597020  
453             $dot
454             $dot_s
455             $eD
456             $eS
457             $eW
458             $eH
459             $eV
460             $eR
461             $eN
462             $not_alnum
463             $not_alpha
464             $not_ascii
465             $not_blank
466             $not_cntrl
467             $not_digit
468             $not_graph
469             $not_lower
470             $not_lower_i
471             $not_print
472             $not_punct
473             $not_space
474             $not_upper
475             $not_upper_i
476             $not_word
477             $not_xdigit
478             $eb
479             $eB
480             ) } }
481              
482             ${Ecyrillic::dot} = qr{(?>[^\x0A])};
483             ${Ecyrillic::dot_s} = qr{(?>[\x00-\xFF])};
484             ${Ecyrillic::eD} = qr{(?>[^0-9])};
485              
486             # Vertical tabs are now whitespace
487             # \s in a regex now matches a vertical tab in all circumstances.
488             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#Vertical_tabs_are_now_whitespace
489             # ${Ecyrillic::eS} = qr{(?>[^\x09\x0A \x0C\x0D\x20])};
490             # ${Ecyrillic::eS} = qr{(?>[^\x09\x0A\x0B\x0C\x0D\x20])};
491             ${Ecyrillic::eS} = qr{(?>[^\s])};
492              
493             ${Ecyrillic::eW} = qr{(?>[^0-9A-Z_a-z])};
494             ${Ecyrillic::eH} = qr{(?>[^\x09\x20])};
495             ${Ecyrillic::eV} = qr{(?>[^\x0A\x0B\x0C\x0D])};
496             ${Ecyrillic::eR} = qr{(?>\x0D\x0A|[\x0A\x0D])};
497             ${Ecyrillic::eN} = qr{(?>[^\x0A])};
498             ${Ecyrillic::not_alnum} = qr{(?>[^\x30-\x39\x41-\x5A\x61-\x7A])};
499             ${Ecyrillic::not_alpha} = qr{(?>[^\x41-\x5A\x61-\x7A])};
500             ${Ecyrillic::not_ascii} = qr{(?>[^\x00-\x7F])};
501             ${Ecyrillic::not_blank} = qr{(?>[^\x09\x20])};
502             ${Ecyrillic::not_cntrl} = qr{(?>[^\x00-\x1F\x7F])};
503             ${Ecyrillic::not_digit} = qr{(?>[^\x30-\x39])};
504             ${Ecyrillic::not_graph} = qr{(?>[^\x21-\x7F])};
505             ${Ecyrillic::not_lower} = qr{(?>[^\x61-\x7A])};
506             ${Ecyrillic::not_lower_i} = qr{(?>[^\x41-\x5A\x61-\x7A])}; # Perl 5.16 compatible
507             # ${Ecyrillic::not_lower_i} = qr{(?>[\x00-\xFF])}; # older Perl compatible
508             ${Ecyrillic::not_print} = qr{(?>[^\x20-\x7F])};
509             ${Ecyrillic::not_punct} = qr{(?>[^\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E])};
510             ${Ecyrillic::not_space} = qr{(?>[^\s\x0B])};
511             ${Ecyrillic::not_upper} = qr{(?>[^\x41-\x5A])};
512             ${Ecyrillic::not_upper_i} = qr{(?>[^\x41-\x5A\x61-\x7A])}; # Perl 5.16 compatible
513             # ${Ecyrillic::not_upper_i} = qr{(?>[\x00-\xFF])}; # older Perl compatible
514             ${Ecyrillic::not_word} = qr{(?>[^\x30-\x39\x41-\x5A\x5F\x61-\x7A])};
515             ${Ecyrillic::not_xdigit} = qr{(?>[^\x30-\x39\x41-\x46\x61-\x66])};
516             ${Ecyrillic::eb} = qr{(?:\A(?=[0-9A-Z_a-z])|(?<=[\x00-\x2F\x40\x5B-\x5E\x60\x7B-\xFF])(?=[0-9A-Z_a-z])|(?<=[0-9A-Z_a-z])(?=[\x00-\x2F\x40\x5B-\x5E\x60\x7B-\xFF]|\z))};
517             ${Ecyrillic::eB} = qr{(?:(?<=[0-9A-Z_a-z])(?=[0-9A-Z_a-z])|(?<=[\x00-\x2F\x40\x5B-\x5E\x60\x7B-\xFF])(?=[\x00-\x2F\x40\x5B-\x5E\x60\x7B-\xFF]))};
518              
519             # avoid: Name "Ecyrillic::foo" used only once: possible typo at here.
520             ${Ecyrillic::dot} = ${Ecyrillic::dot};
521             ${Ecyrillic::dot_s} = ${Ecyrillic::dot_s};
522             ${Ecyrillic::eD} = ${Ecyrillic::eD};
523             ${Ecyrillic::eS} = ${Ecyrillic::eS};
524             ${Ecyrillic::eW} = ${Ecyrillic::eW};
525             ${Ecyrillic::eH} = ${Ecyrillic::eH};
526             ${Ecyrillic::eV} = ${Ecyrillic::eV};
527             ${Ecyrillic::eR} = ${Ecyrillic::eR};
528             ${Ecyrillic::eN} = ${Ecyrillic::eN};
529             ${Ecyrillic::not_alnum} = ${Ecyrillic::not_alnum};
530             ${Ecyrillic::not_alpha} = ${Ecyrillic::not_alpha};
531             ${Ecyrillic::not_ascii} = ${Ecyrillic::not_ascii};
532             ${Ecyrillic::not_blank} = ${Ecyrillic::not_blank};
533             ${Ecyrillic::not_cntrl} = ${Ecyrillic::not_cntrl};
534             ${Ecyrillic::not_digit} = ${Ecyrillic::not_digit};
535             ${Ecyrillic::not_graph} = ${Ecyrillic::not_graph};
536             ${Ecyrillic::not_lower} = ${Ecyrillic::not_lower};
537             ${Ecyrillic::not_lower_i} = ${Ecyrillic::not_lower_i};
538             ${Ecyrillic::not_print} = ${Ecyrillic::not_print};
539             ${Ecyrillic::not_punct} = ${Ecyrillic::not_punct};
540             ${Ecyrillic::not_space} = ${Ecyrillic::not_space};
541             ${Ecyrillic::not_upper} = ${Ecyrillic::not_upper};
542             ${Ecyrillic::not_upper_i} = ${Ecyrillic::not_upper_i};
543             ${Ecyrillic::not_word} = ${Ecyrillic::not_word};
544             ${Ecyrillic::not_xdigit} = ${Ecyrillic::not_xdigit};
545             ${Ecyrillic::eb} = ${Ecyrillic::eb};
546             ${Ecyrillic::eB} = ${Ecyrillic::eB};
547              
548             #
549             # Cyrillic split
550             #
551             sub Ecyrillic::split(;$$$) {
552              
553             # P.794 29.2.161. split
554             # in Chapter 29: Functions
555             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
556              
557             # P.951 split
558             # in Chapter 27: Functions
559             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
560              
561 0     0 0 0 my $pattern = $_[0];
562 0         0 my $string = $_[1];
563 0         0 my $limit = $_[2];
564              
565             # if $pattern is also omitted or is the literal space, " "
566 0 0       0 if (not defined $pattern) {
567 0         0 $pattern = ' ';
568             }
569              
570             # if $string is omitted, the function splits the $_ string
571 0 0       0 if (not defined $string) {
572 0 0       0 if (defined $_) {
573 0         0 $string = $_;
574             }
575             else {
576 0         0 $string = '';
577             }
578             }
579              
580 0         0 my @split = ();
581              
582             # when string is empty
583 0 0       0 if ($string eq '') {
    0          
584              
585             # resulting list value in list context
586 0 0       0 if (wantarray) {
587 0         0 return @split;
588             }
589              
590             # count of substrings in scalar context
591             else {
592 0 0       0 carp "Use of implicit split to \@_ is deprecated" if $^W;
593 0         0 @_ = @split;
594 0         0 return scalar @_;
595             }
596             }
597              
598             # split's first argument is more consistently interpreted
599             #
600             # After some changes earlier in v5.17, split's behavior has been simplified:
601             # if the PATTERN argument evaluates to a string containing one space, it is
602             # treated the way that a literal string containing one space once was.
603             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#split's_first_argument_is_more_consistently_interpreted
604              
605             # if $pattern is also omitted or is the literal space, " ", the function splits
606             # on whitespace, /\s+/, after skipping any leading whitespace
607             # (and so on)
608              
609             elsif ($pattern eq ' ') {
610 0 0       0 if (not defined $limit) {
611 0         0 return CORE::split(' ', $string);
612             }
613             else {
614 0         0 return CORE::split(' ', $string, $limit);
615             }
616             }
617              
618             # if $limit is negative, it is treated as if an arbitrarily large $limit has been specified
619 0 0 0     0 if ((not defined $limit) or ($limit <= 0)) {
    0          
620              
621             # a pattern capable of matching either the null string or something longer than the
622             # null string will split the value of $string into separate characters wherever it
623             # matches the null string between characters
624             # (and so on)
625              
626 0 0       0 if ('' =~ / \A $pattern \z /xms) {
627 0         0 my $last_subexpression_offsets = _last_subexpression_offsets($pattern);
628 0         0 my $limit = scalar(() = $string =~ /($pattern)/oxmsg);
629              
630             # P.1024 Appendix W.10 Multibyte Processing
631             # of ISBN 1-56592-224-7 CJKV Information Processing
632             # (and so on)
633              
634             # the //m modifier is assumed when you split on the pattern /^/
635             # (and so on)
636              
637             # V
638 0   0     0 while ((--$limit > 0) and ($string =~ s/\A((?:$q_char)+?)$pattern//m)) {
639              
640             # if the $pattern contains parentheses, then the substring matched by each pair of parentheses
641             # is included in the resulting list, interspersed with the fields that are ordinarily returned
642             # (and so on)
643              
644 0         0 local $@;
645 0         0 for (my $digit=1; $digit <= ($last_subexpression_offsets + 1); $digit++) {
646 0         0 push @split, CORE::eval('$' . $digit);
647             }
648             }
649             }
650              
651             else {
652 0         0 my $last_subexpression_offsets = _last_subexpression_offsets($pattern);
653              
654             # V
655 0         0 while ($string =~ s/\A((?:$q_char)*?)$pattern//m) {
656 0         0 local $@;
657 0         0 for (my $digit=1; $digit <= ($last_subexpression_offsets + 1); $digit++) {
658 0         0 push @split, CORE::eval('$' . $digit);
659             }
660             }
661             }
662             }
663              
664             elsif ($limit > 0) {
665 0 0       0 if ('' =~ / \A $pattern \z /xms) {
666 0         0 my $last_subexpression_offsets = _last_subexpression_offsets($pattern);
667 0   0     0 while ((--$limit > 0) and (CORE::length($string) > 0)) {
668              
669             # V
670 0 0       0 if ($string =~ s/\A((?:$q_char)+?)$pattern//m) {
671 0         0 local $@;
672 0         0 for (my $digit=1; $digit <= ($last_subexpression_offsets + 1); $digit++) {
673 0         0 push @split, CORE::eval('$' . $digit);
674             }
675             }
676             }
677             }
678             else {
679 0         0 my $last_subexpression_offsets = _last_subexpression_offsets($pattern);
680 0   0     0 while ((--$limit > 0) and (CORE::length($string) > 0)) {
681              
682             # V
683 0 0       0 if ($string =~ s/\A((?:$q_char)*?)$pattern//m) {
684 0         0 local $@;
685 0         0 for (my $digit=1; $digit <= ($last_subexpression_offsets + 1); $digit++) {
686 0         0 push @split, CORE::eval('$' . $digit);
687             }
688             }
689             }
690             }
691             }
692              
693 0 0       0 if (CORE::length($string) > 0) {
694 0         0 push @split, $string;
695             }
696              
697             # if $_[2] (NOT "$limit") is omitted or zero, trailing null fields are stripped from the result
698 0 0 0     0 if ((not defined $_[2]) or ($_[2] == 0)) {
699 0   0     0 while ((scalar(@split) >= 1) and ($split[-1] eq '')) {
700 0         0 pop @split;
701             }
702             }
703              
704             # resulting list value in list context
705 0 0       0 if (wantarray) {
706 0         0 return @split;
707             }
708              
709             # count of substrings in scalar context
710             else {
711 0 0       0 carp "Use of implicit split to \@_ is deprecated" if $^W;
712 0         0 @_ = @split;
713 0         0 return scalar @_;
714             }
715             }
716              
717             #
718             # get last subexpression offsets
719             #
720             sub _last_subexpression_offsets {
721 0     0   0 my $pattern = $_[0];
722              
723             # remove comment
724 0         0 $pattern =~ s/\(\?\# .*? \)//oxmsg;
725              
726 0         0 my $modifier = '';
727 0 0       0 if ($pattern =~ /\(\?\^? ([\-A-Za-z]+) :/oxms) {
728 0         0 $modifier = $1;
729 0         0 $modifier =~ s/-[A-Za-z]*//;
730             }
731              
732             # with /x modifier
733 0         0 my @char = ();
734 0 0       0 if ($modifier =~ /x/oxms) {
735 0         0 @char = $pattern =~ /\G((?>
736             [^\\\#\[\(] |
737             \\ $q_char |
738             \# (?>[^\n]*) $ |
739             \[ (?>(?:[^\\\]]|\\\\|\\\]|$q_char)+) \] |
740             \(\? |
741             $q_char
742             ))/oxmsg;
743             }
744              
745             # without /x modifier
746             else {
747 0         0 @char = $pattern =~ /\G((?>
748             [^\\\[\(] |
749             \\ $q_char |
750             \[ (?>(?:[^\\\]]|\\\\|\\\]|$q_char)+) \] |
751             \(\? |
752             $q_char
753             ))/oxmsg;
754             }
755              
756 0         0 return scalar grep { $_ eq '(' } @char;
  0         0  
757             }
758              
759             #
760             # Cyrillic transliteration (tr///)
761             #
762             sub Ecyrillic::tr($$$$;$) {
763              
764 0     0 0 0 my $bind_operator = $_[1];
765 0         0 my $searchlist = $_[2];
766 0         0 my $replacementlist = $_[3];
767 0   0     0 my $modifier = $_[4] || '';
768              
769 0 0       0 if ($modifier =~ /r/oxms) {
770 0 0       0 if ($bind_operator =~ / !~ /oxms) {
771 0         0 croak "Using !~ with tr///r doesn't make sense";
772             }
773             }
774              
775 0         0 my @char = $_[0] =~ /\G (?>$q_char) /oxmsg;
776 0         0 my @searchlist = _charlist_tr($searchlist);
777 0         0 my @replacementlist = _charlist_tr($replacementlist);
778              
779 0         0 my %tr = ();
780 0         0 for (my $i=0; $i <= $#searchlist; $i++) {
781 0 0       0 if (not exists $tr{$searchlist[$i]}) {
782 0 0 0     0 if (defined $replacementlist[$i] and ($replacementlist[$i] ne '')) {
    0 0        
    0          
783 0         0 $tr{$searchlist[$i]} = $replacementlist[$i];
784             }
785             elsif ($modifier =~ /d/oxms) {
786 0         0 $tr{$searchlist[$i]} = '';
787             }
788             elsif (defined $replacementlist[-1] and ($replacementlist[-1] ne '')) {
789 0         0 $tr{$searchlist[$i]} = $replacementlist[-1];
790             }
791             else {
792 0         0 $tr{$searchlist[$i]} = $searchlist[$i];
793             }
794             }
795             }
796              
797 0         0 my $tr = 0;
798 0         0 my $replaced = '';
799 0 0       0 if ($modifier =~ /c/oxms) {
800 0         0 while (defined(my $char = shift @char)) {
801 0 0       0 if (not exists $tr{$char}) {
802 0 0       0 if (defined $replacementlist[0]) {
803 0         0 $replaced .= $replacementlist[0];
804             }
805 0         0 $tr++;
806 0 0       0 if ($modifier =~ /s/oxms) {
807 0   0     0 while (@char and (not exists $tr{$char[0]})) {
808 0         0 shift @char;
809 0         0 $tr++;
810             }
811             }
812             }
813             else {
814 0         0 $replaced .= $char;
815             }
816             }
817             }
818             else {
819 0         0 while (defined(my $char = shift @char)) {
820 0 0       0 if (exists $tr{$char}) {
821 0         0 $replaced .= $tr{$char};
822 0         0 $tr++;
823 0 0       0 if ($modifier =~ /s/oxms) {
824 0   0     0 while (@char and (exists $tr{$char[0]}) and ($tr{$char[0]} eq $tr{$char})) {
      0        
825 0         0 shift @char;
826 0         0 $tr++;
827             }
828             }
829             }
830             else {
831 0         0 $replaced .= $char;
832             }
833             }
834             }
835              
836 0 0       0 if ($modifier =~ /r/oxms) {
837 0         0 return $replaced;
838             }
839             else {
840 0         0 $_[0] = $replaced;
841 0 0       0 if ($bind_operator =~ / !~ /oxms) {
842 0         0 return not $tr;
843             }
844             else {
845 0         0 return $tr;
846             }
847             }
848             }
849              
850             #
851             # Cyrillic chop
852             #
853             sub Ecyrillic::chop(@) {
854              
855 0     0 0 0 my $chop;
856 0 0       0 if (@_ == 0) {
857 0         0 my @char = /\G (?>$q_char) /oxmsg;
858 0         0 $chop = pop @char;
859 0         0 $_ = join '', @char;
860             }
861             else {
862 0         0 for (@_) {
863 0         0 my @char = /\G (?>$q_char) /oxmsg;
864 0         0 $chop = pop @char;
865 0         0 $_ = join '', @char;
866             }
867             }
868 0         0 return $chop;
869             }
870              
871             #
872             # Cyrillic index by octet
873             #
874             sub Ecyrillic::index($$;$) {
875              
876 0     0 1 0 my($str,$substr,$position) = @_;
877 0   0     0 $position ||= 0;
878 0         0 my $pos = 0;
879              
880 0         0 while ($pos < CORE::length($str)) {
881 0 0       0 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
882 0 0       0 if ($pos >= $position) {
883 0         0 return $pos;
884             }
885             }
886 0 0       0 if (CORE::substr($str,$pos) =~ /\A ($q_char) /oxms) {
887 0         0 $pos += CORE::length($1);
888             }
889             else {
890 0         0 $pos += 1;
891             }
892             }
893 0         0 return -1;
894             }
895              
896             #
897             # Cyrillic reverse index
898             #
899             sub Ecyrillic::rindex($$;$) {
900              
901 0     0 0 0 my($str,$substr,$position) = @_;
902 0   0     0 $position ||= CORE::length($str) - 1;
903 0         0 my $pos = 0;
904 0         0 my $rindex = -1;
905              
906 0   0     0 while (($pos < CORE::length($str)) and ($pos <= $position)) {
907 0 0       0 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
908 0         0 $rindex = $pos;
909             }
910 0 0       0 if (CORE::substr($str,$pos) =~ /\A ($q_char) /oxms) {
911 0         0 $pos += CORE::length($1);
912             }
913             else {
914 0         0 $pos += 1;
915             }
916             }
917 0         0 return $rindex;
918             }
919              
920             #
921             # Cyrillic lower case first with parameter
922             #
923             sub Ecyrillic::lcfirst(@) {
924 0 0   0 0 0 if (@_) {
925 0         0 my $s = shift @_;
926 0 0 0     0 if (@_ and wantarray) {
927 0         0 return Ecyrillic::lc(CORE::substr($s,0,1)) . CORE::substr($s,1), @_;
928             }
929             else {
930 0         0 return Ecyrillic::lc(CORE::substr($s,0,1)) . CORE::substr($s,1);
931             }
932             }
933             else {
934 0         0 return Ecyrillic::lc(CORE::substr($_,0,1)) . CORE::substr($_,1);
935             }
936             }
937              
938             #
939             # Cyrillic lower case first without parameter
940             #
941             sub Ecyrillic::lcfirst_() {
942 0     0 0 0 return Ecyrillic::lc(CORE::substr($_,0,1)) . CORE::substr($_,1);
943             }
944              
945             #
946             # Cyrillic lower case with parameter
947             #
948             sub Ecyrillic::lc(@) {
949 0 0   0 0 0 if (@_) {
950 0         0 my $s = shift @_;
951 0 0 0     0 if (@_ and wantarray) {
952 0 0       0 return join('', map {defined($lc{$_}) ? $lc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg)), @_;
  0         0  
953             }
954             else {
955 0 0       0 return join('', map {defined($lc{$_}) ? $lc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg));
  0         0  
956             }
957             }
958             else {
959 0         0 return Ecyrillic::lc_();
960             }
961             }
962              
963             #
964             # Cyrillic lower case without parameter
965             #
966             sub Ecyrillic::lc_() {
967 0     0 0 0 my $s = $_;
968 0 0       0 return join '', map {defined($lc{$_}) ? $lc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg);
  0         0  
969             }
970              
971             #
972             # Cyrillic upper case first with parameter
973             #
974             sub Ecyrillic::ucfirst(@) {
975 0 0   0 0 0 if (@_) {
976 0         0 my $s = shift @_;
977 0 0 0     0 if (@_ and wantarray) {
978 0         0 return Ecyrillic::uc(CORE::substr($s,0,1)) . CORE::substr($s,1), @_;
979             }
980             else {
981 0         0 return Ecyrillic::uc(CORE::substr($s,0,1)) . CORE::substr($s,1);
982             }
983             }
984             else {
985 0         0 return Ecyrillic::uc(CORE::substr($_,0,1)) . CORE::substr($_,1);
986             }
987             }
988              
989             #
990             # Cyrillic upper case first without parameter
991             #
992             sub Ecyrillic::ucfirst_() {
993 0     0 0 0 return Ecyrillic::uc(CORE::substr($_,0,1)) . CORE::substr($_,1);
994             }
995              
996             #
997             # Cyrillic upper case with parameter
998             #
999             sub Ecyrillic::uc(@) {
1000 0 0   0 0 0 if (@_) {
1001 0         0 my $s = shift @_;
1002 0 0 0     0 if (@_ and wantarray) {
1003 0 0       0 return join('', map {defined($uc{$_}) ? $uc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg)), @_;
  0         0  
1004             }
1005             else {
1006 0 0       0 return join('', map {defined($uc{$_}) ? $uc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg));
  0         0  
1007             }
1008             }
1009             else {
1010 0         0 return Ecyrillic::uc_();
1011             }
1012             }
1013              
1014             #
1015             # Cyrillic upper case without parameter
1016             #
1017             sub Ecyrillic::uc_() {
1018 0     0 0 0 my $s = $_;
1019 0 0       0 return join '', map {defined($uc{$_}) ? $uc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg);
  0         0  
1020             }
1021              
1022             #
1023             # Cyrillic fold case with parameter
1024             #
1025             sub Ecyrillic::fc(@) {
1026 0 0   0 0 0 if (@_) {
1027 0         0 my $s = shift @_;
1028 0 0 0     0 if (@_ and wantarray) {
1029 0 0       0 return join('', map {defined($fc{$_}) ? $fc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg)), @_;
  0         0  
1030             }
1031             else {
1032 0 0       0 return join('', map {defined($fc{$_}) ? $fc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg));
  0         0  
1033             }
1034             }
1035             else {
1036 0         0 return Ecyrillic::fc_();
1037             }
1038             }
1039              
1040             #
1041             # Cyrillic fold case without parameter
1042             #
1043             sub Ecyrillic::fc_() {
1044 0     0 0 0 my $s = $_;
1045 0 0       0 return join '', map {defined($fc{$_}) ? $fc{$_} : $_} ($s =~ /\G ($q_char) /oxmsg);
  0         0  
1046             }
1047              
1048             #
1049             # Cyrillic regexp capture
1050             #
1051             {
1052             sub Ecyrillic::capture {
1053 0     0 1 0 return $_[0];
1054             }
1055             }
1056              
1057             #
1058             # Cyrillic regexp ignore case modifier
1059             #
1060             sub Ecyrillic::ignorecase {
1061              
1062 0     0 0 0 my @string = @_;
1063 0         0 my $metachar = qr/[\@\\|[\]{]/oxms;
1064              
1065             # ignore case of $scalar or @array
1066 0         0 for my $string (@string) {
1067              
1068             # split regexp
1069 0         0 my @char = $string =~ /\G (?>\[\^|\\$q_char|$q_char) /oxmsg;
1070              
1071             # unescape character
1072 0         0 for (my $i=0; $i <= $#char; $i++) {
1073 0 0       0 next if not defined $char[$i];
1074              
1075             # open character class [...]
1076 0 0       0 if ($char[$i] eq '[') {
    0          
    0          
    0          
1077 0         0 my $left = $i;
1078              
1079             # [] make die "unmatched [] in regexp ...\n"
1080              
1081 0 0       0 if ($char[$i+1] eq ']') {
1082 0         0 $i++;
1083             }
1084              
1085 0         0 while (1) {
1086 0 0       0 if (++$i > $#char) {
1087 0         0 croak "Unmatched [] in regexp";
1088             }
1089 0 0       0 if ($char[$i] eq ']') {
1090 0         0 my $right = $i;
1091 0         0 my @charlist = charlist_qr(@char[$left+1..$right-1], 'i');
1092              
1093             # escape character
1094 0         0 for my $char (@charlist) {
1095 0 0       0 if (0) {
1096             }
1097              
1098 0         0 elsif ($char =~ /\A [.|)] \z/oxms) {
1099 0         0 $char = '\\' . $char;
1100             }
1101             }
1102              
1103             # [...]
1104 0         0 splice @char, $left, $right-$left+1, '(?:' . join('|', @charlist) . ')';
1105              
1106 0         0 $i = $left;
1107 0         0 last;
1108             }
1109             }
1110             }
1111              
1112             # open character class [^...]
1113             elsif ($char[$i] eq '[^') {
1114 0         0 my $left = $i;
1115              
1116             # [^] make die "unmatched [] in regexp ...\n"
1117              
1118 0 0       0 if ($char[$i+1] eq ']') {
1119 0         0 $i++;
1120             }
1121              
1122 0         0 while (1) {
1123 0 0       0 if (++$i > $#char) {
1124 0         0 croak "Unmatched [] in regexp";
1125             }
1126 0 0       0 if ($char[$i] eq ']') {
1127 0         0 my $right = $i;
1128 0         0 my @charlist = charlist_not_qr(@char[$left+1..$right-1], 'i');
1129              
1130             # escape character
1131 0         0 for my $char (@charlist) {
1132 0 0       0 if (0) {
1133             }
1134              
1135 0         0 elsif ($char =~ /\A [.|)] \z/oxms) {
1136 0         0 $char = '\\' . $char;
1137             }
1138             }
1139              
1140             # [^...]
1141 0         0 splice @char, $left, $right-$left+1, '(?!' . join('|', @charlist) . ")(?:$your_char)";
1142              
1143 0         0 $i = $left;
1144 0         0 last;
1145             }
1146             }
1147             }
1148              
1149             # rewrite classic character class or escape character
1150             elsif (my $char = classic_character_class($char[$i])) {
1151 0         0 $char[$i] = $char;
1152             }
1153              
1154             # with /i modifier
1155             elsif ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) {
1156 0         0 my $uc = Ecyrillic::uc($char[$i]);
1157 0         0 my $fc = Ecyrillic::fc($char[$i]);
1158 0 0       0 if ($uc ne $fc) {
1159 0 0       0 if (CORE::length($fc) == 1) {
1160 0         0 $char[$i] = '[' . $uc . $fc . ']';
1161             }
1162             else {
1163 0         0 $char[$i] = '(?:' . $uc . '|' . $fc . ')';
1164             }
1165             }
1166             }
1167             }
1168              
1169             # characterize
1170 0         0 for (my $i=0; $i <= $#char; $i++) {
1171 0 0       0 next if not defined $char[$i];
1172              
1173 0 0       0 if (0) {
1174             }
1175              
1176             # quote character before ? + * {
1177 0 0       0 elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
1178 0 0       0 if ($char[$i-1] !~ /\A [\x00-\xFF] \z/oxms) {
1179 0         0 $char[$i-1] = '(?:' . $char[$i-1] . ')';
1180             }
1181             }
1182             }
1183              
1184 0         0 $string = join '', @char;
1185             }
1186              
1187             # make regexp string
1188 0         0 return @string;
1189             }
1190              
1191             #
1192             # classic character class ( \D \S \W \d \s \w \C \X \H \V \h \v \R \N \b \B )
1193             #
1194             sub Ecyrillic::classic_character_class {
1195 0     0 0 0 my($char) = @_;
1196              
1197             return {
1198 0   0     0 '\D' => '${Ecyrillic::eD}',
1199             '\S' => '${Ecyrillic::eS}',
1200             '\W' => '${Ecyrillic::eW}',
1201             '\d' => '[0-9]',
1202              
1203             # Before Perl 5.6, \s only matched the five whitespace characters
1204             # tab, newline, form-feed, carriage return, and the space character
1205             # itself, which, taken together, is the character class [\t\n\f\r ].
1206              
1207             # Vertical tabs are now whitespace
1208             # \s in a regex now matches a vertical tab in all circumstances.
1209             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#Vertical_tabs_are_now_whitespace
1210             # \t \n \v \f \r space
1211             # '\s' => '[\x09\x0A \x0C\x0D\x20]',
1212             # '\s' => '[\x09\x0A\x0B\x0C\x0D\x20]',
1213             '\s' => '\s',
1214              
1215             '\w' => '[0-9A-Z_a-z]',
1216             '\C' => '[\x00-\xFF]',
1217             '\X' => 'X',
1218              
1219             # \h \v \H \V
1220              
1221             # P.114 Character Class Shortcuts
1222             # in Chapter 7: In the World of Regular Expressions
1223             # of ISBN 978-0-596-52010-6 Learning Perl, Fifth Edition
1224              
1225             # P.357 13.2.3 Whitespace
1226             # in Chapter 13: perlrecharclass: Perl Regular Expression Character Classes
1227             # of ISBN-13: 978-1-906966-02-7 The Perl Language Reference Manual (for Perl version 5.12.1)
1228             #
1229             # 0x00009 CHARACTER TABULATION h s
1230             # 0x0000a LINE FEED (LF) vs
1231             # 0x0000b LINE TABULATION v
1232             # 0x0000c FORM FEED (FF) vs
1233             # 0x0000d CARRIAGE RETURN (CR) vs
1234             # 0x00020 SPACE h s
1235              
1236             # P.196 Table 5-9. Alphanumeric regex metasymbols
1237             # in Chapter 5. Pattern Matching
1238             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
1239              
1240             # (and so on)
1241              
1242             '\H' => '${Ecyrillic::eH}',
1243             '\V' => '${Ecyrillic::eV}',
1244             '\h' => '[\x09\x20]',
1245             '\v' => '[\x0A\x0B\x0C\x0D]',
1246             '\R' => '${Ecyrillic::eR}',
1247              
1248             # \N
1249             #
1250             # http://perldoc.perl.org/perlre.html
1251             # Character Classes and other Special Escapes
1252             # Any character but \n (experimental). Not affected by /s modifier
1253              
1254             '\N' => '${Ecyrillic::eN}',
1255              
1256             # \b \B
1257              
1258             # P.180 Boundaries: The \b and \B Assertions
1259             # in Chapter 5: Pattern Matching
1260             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
1261              
1262             # P.219 Boundaries: The \b and \B Assertions
1263             # in Chapter 5: Pattern Matching
1264             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
1265              
1266             # \b really means (?:(?<=\w)(?!\w)|(?
1267             # or (?:(?<=\A|\W)(?=\w)|(?<=\w)(?=\W|\z))
1268             '\b' => '${Ecyrillic::eb}',
1269              
1270             # \B really means (?:(?<=\w)(?=\w)|(?
1271             # or (?:(?<=\w)(?=\w)|(?<=\W)(?=\W))
1272             '\B' => '${Ecyrillic::eB}',
1273              
1274             }->{$char} || '';
1275             }
1276              
1277             #
1278             # prepare Cyrillic characters per length
1279             #
1280              
1281             # 1 octet characters
1282             my @chars1 = ();
1283             sub chars1 {
1284 0 0   0 0 0 if (@chars1) {
1285 0         0 return @chars1;
1286             }
1287 0 0       0 if (exists $range_tr{1}) {
1288 0         0 my @ranges = @{ $range_tr{1} };
  0         0  
1289 0         0 while (my @range = splice(@ranges,0,1)) {
1290 0         0 for my $oct0 (@{$range[0]}) {
  0         0  
1291 0         0 push @chars1, pack 'C', $oct0;
1292             }
1293             }
1294             }
1295 0         0 return @chars1;
1296             }
1297              
1298             # 2 octets characters
1299             my @chars2 = ();
1300             sub chars2 {
1301 0 0   0 0 0 if (@chars2) {
1302 0         0 return @chars2;
1303             }
1304 0 0       0 if (exists $range_tr{2}) {
1305 0         0 my @ranges = @{ $range_tr{2} };
  0         0  
1306 0         0 while (my @range = splice(@ranges,0,2)) {
1307 0         0 for my $oct0 (@{$range[0]}) {
  0         0  
1308 0         0 for my $oct1 (@{$range[1]}) {
  0         0  
1309 0         0 push @chars2, pack 'CC', $oct0,$oct1;
1310             }
1311             }
1312             }
1313             }
1314 0         0 return @chars2;
1315             }
1316              
1317             # 3 octets characters
1318             my @chars3 = ();
1319             sub chars3 {
1320 0 0   0 0 0 if (@chars3) {
1321 0         0 return @chars3;
1322             }
1323 0 0       0 if (exists $range_tr{3}) {
1324 0         0 my @ranges = @{ $range_tr{3} };
  0         0  
1325 0         0 while (my @range = splice(@ranges,0,3)) {
1326 0         0 for my $oct0 (@{$range[0]}) {
  0         0  
1327 0         0 for my $oct1 (@{$range[1]}) {
  0         0  
1328 0         0 for my $oct2 (@{$range[2]}) {
  0         0  
1329 0         0 push @chars3, pack 'CCC', $oct0,$oct1,$oct2;
1330             }
1331             }
1332             }
1333             }
1334             }
1335 0         0 return @chars3;
1336             }
1337              
1338             # 4 octets characters
1339             my @chars4 = ();
1340             sub chars4 {
1341 0 0   0 0 0 if (@chars4) {
1342 0         0 return @chars4;
1343             }
1344 0 0       0 if (exists $range_tr{4}) {
1345 0         0 my @ranges = @{ $range_tr{4} };
  0         0  
1346 0         0 while (my @range = splice(@ranges,0,4)) {
1347 0         0 for my $oct0 (@{$range[0]}) {
  0         0  
1348 0         0 for my $oct1 (@{$range[1]}) {
  0         0  
1349 0         0 for my $oct2 (@{$range[2]}) {
  0         0  
1350 0         0 for my $oct3 (@{$range[3]}) {
  0         0  
1351 0         0 push @chars4, pack 'CCCC', $oct0,$oct1,$oct2,$oct3;
1352             }
1353             }
1354             }
1355             }
1356             }
1357             }
1358 0         0 return @chars4;
1359             }
1360              
1361             #
1362             # Cyrillic open character list for tr
1363             #
1364             sub _charlist_tr {
1365              
1366 0     0   0 local $_ = shift @_;
1367              
1368             # unescape character
1369 0         0 my @char = ();
1370 0         0 while (not /\G \z/oxmsgc) {
1371 0 0       0 if (/\G (\\0?55|\\x2[Dd]|\\-) /oxmsgc) {
    0          
    0          
    0          
    0          
    0          
    0          
1372 0         0 push @char, '\-';
1373             }
1374             elsif (/\G \\ ([0-7]{2,3}) /oxmsgc) {
1375 0         0 push @char, CORE::chr(oct $1);
1376             }
1377             elsif (/\G \\x ([0-9A-Fa-f]{1,2}) /oxmsgc) {
1378 0         0 push @char, CORE::chr(hex $1);
1379             }
1380             elsif (/\G \\c ([\x40-\x5F]) /oxmsgc) {
1381 0         0 push @char, CORE::chr(CORE::ord($1) & 0x1F);
1382             }
1383             elsif (/\G (\\ [0nrtfbae]) /oxmsgc) {
1384 0         0 push @char, {
1385             '\0' => "\0",
1386             '\n' => "\n",
1387             '\r' => "\r",
1388             '\t' => "\t",
1389             '\f' => "\f",
1390             '\b' => "\x08", # \b means backspace in character class
1391             '\a' => "\a",
1392             '\e' => "\e",
1393             }->{$1};
1394             }
1395             elsif (/\G \\ ($q_char) /oxmsgc) {
1396 0         0 push @char, $1;
1397             }
1398             elsif (/\G ($q_char) /oxmsgc) {
1399 0         0 push @char, $1;
1400             }
1401             }
1402              
1403             # join separated multiple-octet
1404 0         0 @char = join('',@char) =~ /\G (?>\\-|$q_char) /oxmsg;
1405              
1406             # unescape '-'
1407 0         0 my @i = ();
1408 0         0 for my $i (0 .. $#char) {
1409 0 0       0 if ($char[$i] eq '\-') {
    0          
1410 0         0 $char[$i] = '-';
1411             }
1412             elsif ($char[$i] eq '-') {
1413 0 0 0     0 if ((0 < $i) and ($i < $#char)) {
1414 0         0 push @i, $i;
1415             }
1416             }
1417             }
1418              
1419             # open character list (reverse for splice)
1420 0         0 for my $i (CORE::reverse @i) {
1421 0         0 my @range = ();
1422              
1423             # range error
1424 0 0 0     0 if ((CORE::length($char[$i-1]) > CORE::length($char[$i+1])) or ($char[$i-1] gt $char[$i+1])) {
1425 0         0 croak "Invalid tr/// range \"\\x" . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]) . '"';
1426             }
1427              
1428             # range of multiple-octet code
1429 0 0       0 if (CORE::length($char[$i-1]) == 1) {
    0          
    0          
    0          
1430 0 0       0 if (CORE::length($char[$i+1]) == 1) {
    0          
    0          
    0          
1431 0 0       0 push @range, grep {($char[$i-1] le $_) and ($_ le $char[$i+1])} chars1();
  0         0  
1432             }
1433             elsif (CORE::length($char[$i+1]) == 2) {
1434 0         0 push @range, grep {$char[$i-1] le $_} chars1();
  0         0  
1435 0         0 push @range, grep {$_ le $char[$i+1]} chars2();
  0         0  
1436             }
1437             elsif (CORE::length($char[$i+1]) == 3) {
1438 0         0 push @range, grep {$char[$i-1] le $_} chars1();
  0         0  
1439 0         0 push @range, chars2();
1440 0         0 push @range, grep {$_ le $char[$i+1]} chars3();
  0         0  
1441             }
1442             elsif (CORE::length($char[$i+1]) == 4) {
1443 0         0 push @range, grep {$char[$i-1] le $_} chars1();
  0         0  
1444 0         0 push @range, chars2();
1445 0         0 push @range, chars3();
1446 0         0 push @range, grep {$_ le $char[$i+1]} chars4();
  0         0  
1447             }
1448             else {
1449 0         0 croak "Invalid tr/// range (over 4octets) \"\\x" . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]) . '"';
1450             }
1451             }
1452             elsif (CORE::length($char[$i-1]) == 2) {
1453 0 0       0 if (CORE::length($char[$i+1]) == 2) {
    0          
    0          
1454 0 0       0 push @range, grep {($char[$i-1] le $_) and ($_ le $char[$i+1])} chars2();
  0         0  
1455             }
1456             elsif (CORE::length($char[$i+1]) == 3) {
1457 0         0 push @range, grep {$char[$i-1] le $_} chars2();
  0         0  
1458 0         0 push @range, grep {$_ le $char[$i+1]} chars3();
  0         0  
1459             }
1460             elsif (CORE::length($char[$i+1]) == 4) {
1461 0         0 push @range, grep {$char[$i-1] le $_} chars2();
  0         0  
1462 0         0 push @range, chars3();
1463 0         0 push @range, grep {$_ le $char[$i+1]} chars4();
  0         0  
1464             }
1465             else {
1466 0         0 croak "Invalid tr/// range (over 4octets) \"\\x" . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]) . '"';
1467             }
1468             }
1469             elsif (CORE::length($char[$i-1]) == 3) {
1470 0 0       0 if (CORE::length($char[$i+1]) == 3) {
    0          
1471 0 0       0 push @range, grep {($char[$i-1] le $_) and ($_ le $char[$i+1])} chars3();
  0         0  
1472             }
1473             elsif (CORE::length($char[$i+1]) == 4) {
1474 0         0 push @range, grep {$char[$i-1] le $_} chars3();
  0         0  
1475 0         0 push @range, grep {$_ le $char[$i+1]} chars4();
  0         0  
1476             }
1477             else {
1478 0         0 croak "Invalid tr/// range (over 4octets) \"\\x" . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]) . '"';
1479             }
1480             }
1481             elsif (CORE::length($char[$i-1]) == 4) {
1482 0 0       0 if (CORE::length($char[$i+1]) == 4) {
1483 0 0       0 push @range, grep {($char[$i-1] le $_) and ($_ le $char[$i+1])} chars4();
  0         0  
1484             }
1485             else {
1486 0         0 croak "Invalid tr/// range (over 4octets) \"\\x" . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]) . '"';
1487             }
1488             }
1489             else {
1490 0         0 croak "Invalid tr/// range (over 4octets) \"\\x" . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]) . '"';
1491             }
1492              
1493 0         0 splice @char, $i-1, 3, @range;
1494             }
1495              
1496 0         0 return @char;
1497             }
1498              
1499             #
1500             # Cyrillic open character class
1501             #
1502             sub _cc {
1503 0 0   0   0 if (scalar(@_) == 0) {
    0          
    0          
1504 0         0 die __FILE__, ": subroutine cc got no parameter.\n";
1505             }
1506             elsif (scalar(@_) == 1) {
1507 0         0 return sprintf('\x%02X',$_[0]);
1508             }
1509             elsif (scalar(@_) == 2) {
1510 0 0       0 if ($_[0] > $_[1]) {
    0          
    0          
1511 0         0 die __FILE__, ": subroutine cc got \$_[0] > \$_[1] parameters).\n";
1512             }
1513             elsif ($_[0] == $_[1]) {
1514 0         0 return sprintf('\x%02X',$_[0]);
1515             }
1516             elsif (($_[0]+1) == $_[1]) {
1517 0         0 return sprintf('[\\x%02X\\x%02X]',$_[0],$_[1]);
1518             }
1519             else {
1520 0         0 return sprintf('[\\x%02X-\\x%02X]',$_[0],$_[1]);
1521             }
1522             }
1523             else {
1524 0         0 die __FILE__, ": subroutine cc got 3 or more parameters (@{[scalar(@_)]} parameters).\n";
  0         0  
1525             }
1526             }
1527              
1528             #
1529             # Cyrillic octet range
1530             #
1531             sub _octets {
1532 0     0   0 my $length = shift @_;
1533              
1534 0 0       0 if ($length == 1) {
1535 0         0 my($a1) = unpack 'C', $_[0];
1536 0         0 my($z1) = unpack 'C', $_[1];
1537              
1538 0 0       0 if ($a1 > $z1) {
1539 0         0 croak 'Invalid [] range in regexp (CORE::ord(A) > CORE::ord(B)) ' . '\x' . unpack('H*',$a1) . '-\x' . unpack('H*',$z1);
1540             }
1541              
1542 0 0       0 if ($a1 == $z1) {
    0          
1543 0         0 return sprintf('\x%02X',$a1);
1544             }
1545             elsif (($a1+1) == $z1) {
1546 0         0 return sprintf('\x%02X\x%02X',$a1,$z1);
1547             }
1548             else {
1549 0         0 return sprintf('\x%02X-\x%02X',$a1,$z1);
1550             }
1551             }
1552             else {
1553 0         0 die __FILE__, ": subroutine _octets got invalid length ($length).\n";
1554             }
1555             }
1556              
1557             #
1558             # Cyrillic range regexp
1559             #
1560             sub _range_regexp {
1561 0     0   0 my($length,$first,$last) = @_;
1562              
1563 0         0 my @range_regexp = ();
1564 0 0       0 if (not exists $range_tr{$length}) {
1565 0         0 return @range_regexp;
1566             }
1567              
1568 0         0 my @ranges = @{ $range_tr{$length} };
  0         0  
1569 0         0 while (my @range = splice(@ranges,0,$length)) {
1570 0         0 my $min = '';
1571 0         0 my $max = '';
1572 0         0 for (my $i=0; $i < $length; $i++) {
1573 0         0 $min .= pack 'C', $range[$i][0];
1574 0         0 $max .= pack 'C', $range[$i][-1];
1575             }
1576              
1577             # min___max
1578             # FIRST_____________LAST
1579             # (nothing)
1580              
1581 0 0 0     0 if ($max lt $first) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
1582             }
1583              
1584             # **********
1585             # min_________max
1586             # FIRST_____________LAST
1587             # **********
1588              
1589             elsif (($min le $first) and ($first le $max) and ($max le $last)) {
1590 0         0 push @range_regexp, _octets($length,$first,$max,$min,$max);
1591             }
1592              
1593             # **********************
1594             # min________________max
1595             # FIRST_____________LAST
1596             # **********************
1597              
1598             elsif (($min eq $first) and ($max eq $last)) {
1599 0         0 push @range_regexp, _octets($length,$first,$last,$min,$max);
1600             }
1601              
1602             # *********
1603             # min___max
1604             # FIRST_____________LAST
1605             # *********
1606              
1607             elsif (($first le $min) and ($max le $last)) {
1608 0         0 push @range_regexp, _octets($length,$min,$max,$min,$max);
1609             }
1610              
1611             # **********************
1612             # min__________________________max
1613             # FIRST_____________LAST
1614             # **********************
1615              
1616             elsif (($min le $first) and ($last le $max)) {
1617 0         0 push @range_regexp, _octets($length,$first,$last,$min,$max);
1618             }
1619              
1620             # *********
1621             # min________max
1622             # FIRST_____________LAST
1623             # *********
1624              
1625             elsif (($first le $min) and ($min le $last) and ($last le $max)) {
1626 0         0 push @range_regexp, _octets($length,$min,$last,$min,$max);
1627             }
1628              
1629             # min___max
1630             # FIRST_____________LAST
1631             # (nothing)
1632              
1633             elsif ($last lt $min) {
1634             }
1635              
1636             else {
1637 0         0 die __FILE__, ": subroutine _range_regexp panic.\n";
1638             }
1639             }
1640              
1641 0         0 return @range_regexp;
1642             }
1643              
1644             #
1645             # Cyrillic open character list for qr and not qr
1646             #
1647             sub _charlist {
1648              
1649 0     0   0 my $modifier = pop @_;
1650 0         0 my @char = @_;
1651              
1652 0 0       0 my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
1653              
1654             # unescape character
1655 0         0 for (my $i=0; $i <= $#char; $i++) {
1656              
1657             # escape - to ...
1658 0 0 0     0 if ($char[$i] eq '-') {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
1659 0 0 0     0 if ((0 < $i) and ($i < $#char)) {
1660 0         0 $char[$i] = '...';
1661             }
1662             }
1663              
1664             # octal escape sequence
1665             elsif ($char[$i] =~ /\A \\o \{ ([0-7]+) \} \z/oxms) {
1666 0         0 $char[$i] = octchr($1);
1667             }
1668              
1669             # hexadecimal escape sequence
1670             elsif ($char[$i] =~ /\A \\x \{ ([0-9A-Fa-f]+) \} \z/oxms) {
1671 0         0 $char[$i] = hexchr($1);
1672             }
1673              
1674             # \b{...} --> b\{...}
1675             # \B{...} --> B\{...}
1676             # \N{CHARNAME} --> N\{CHARNAME}
1677             # \p{PROPERTY} --> p\{PROPERTY}
1678             # \P{PROPERTY} --> P\{PROPERTY}
1679             elsif ($char[$i] =~ /\A \\ ([bBNpP]) ( \{ ([^0-9\}][^\}]*) \} ) \z/oxms) {
1680 0         0 $char[$i] = $1 . '\\' . $2;
1681             }
1682              
1683             # \p, \P, \X --> p, P, X
1684             elsif ($char[$i] =~ /\A \\ ( [pPX] ) \z/oxms) {
1685 0         0 $char[$i] = $1;
1686             }
1687              
1688             elsif ($char[$i] =~ /\A \\ ([0-7]{2,3}) \z/oxms) {
1689 0         0 $char[$i] = CORE::chr oct $1;
1690             }
1691             elsif ($char[$i] =~ /\A \\x ([0-9A-Fa-f]{1,2}) \z/oxms) {
1692 0         0 $char[$i] = CORE::chr hex $1;
1693             }
1694             elsif ($char[$i] =~ /\A \\c ([\x40-\x5F]) \z/oxms) {
1695 0         0 $char[$i] = CORE::chr(CORE::ord($1) & 0x1F);
1696             }
1697             elsif ($char[$i] =~ /\A (\\ [0nrtfbaedswDSWHVhvR]) \z/oxms) {
1698 0         0 $char[$i] = {
1699             '\0' => "\0",
1700             '\n' => "\n",
1701             '\r' => "\r",
1702             '\t' => "\t",
1703             '\f' => "\f",
1704             '\b' => "\x08", # \b means backspace in character class
1705             '\a' => "\a",
1706             '\e' => "\e",
1707             '\d' => '[0-9]',
1708              
1709             # Vertical tabs are now whitespace
1710             # \s in a regex now matches a vertical tab in all circumstances.
1711             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#Vertical_tabs_are_now_whitespace
1712             # \t \n \v \f \r space
1713             # '\s' => '[\x09\x0A \x0C\x0D\x20]',
1714             # '\s' => '[\x09\x0A\x0B\x0C\x0D\x20]',
1715             '\s' => '\s',
1716              
1717             '\w' => '[0-9A-Z_a-z]',
1718             '\D' => '${Ecyrillic::eD}',
1719             '\S' => '${Ecyrillic::eS}',
1720             '\W' => '${Ecyrillic::eW}',
1721              
1722             '\H' => '${Ecyrillic::eH}',
1723             '\V' => '${Ecyrillic::eV}',
1724             '\h' => '[\x09\x20]',
1725             '\v' => '[\x0A\x0B\x0C\x0D]',
1726             '\R' => '${Ecyrillic::eR}',
1727              
1728             }->{$1};
1729             }
1730              
1731             # POSIX-style character classes
1732             elsif ($ignorecase and ($char[$i] =~ /\A ( \[\: \^? (?:lower|upper) :\] ) \z/oxms)) {
1733 0         0 $char[$i] = {
1734              
1735             '[:lower:]' => '[\x41-\x5A\x61-\x7A]',
1736             '[:upper:]' => '[\x41-\x5A\x61-\x7A]',
1737             '[:^lower:]' => '${Ecyrillic::not_lower_i}',
1738             '[:^upper:]' => '${Ecyrillic::not_upper_i}',
1739              
1740             }->{$1};
1741             }
1742             elsif ($char[$i] =~ /\A ( \[\: \^? (?:alnum|alpha|ascii|blank|cntrl|digit|graph|lower|print|punct|space|upper|word|xdigit) :\] ) \z/oxms) {
1743 0         0 $char[$i] = {
1744              
1745             '[:alnum:]' => '[\x30-\x39\x41-\x5A\x61-\x7A]',
1746             '[:alpha:]' => '[\x41-\x5A\x61-\x7A]',
1747             '[:ascii:]' => '[\x00-\x7F]',
1748             '[:blank:]' => '[\x09\x20]',
1749             '[:cntrl:]' => '[\x00-\x1F\x7F]',
1750             '[:digit:]' => '[\x30-\x39]',
1751             '[:graph:]' => '[\x21-\x7F]',
1752             '[:lower:]' => '[\x61-\x7A]',
1753             '[:print:]' => '[\x20-\x7F]',
1754             '[:punct:]' => '[\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E]',
1755              
1756             # P.174 POSIX-Style Character Classes
1757             # in Chapter 5: Pattern Matching
1758             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
1759              
1760             # P.311 11.2.4 Character Classes and other Special Escapes
1761             # in Chapter 11: perlre: Perl regular expressions
1762             # of ISBN-13: 978-1-906966-02-7 The Perl Language Reference Manual (for Perl version 5.12.1)
1763              
1764             # P.210 POSIX-Style Character Classes
1765             # in Chapter 5: Pattern Matching
1766             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
1767              
1768             '[:space:]' => '[\s\x0B]', # "\s" plus vertical tab ("\cK")
1769              
1770             '[:upper:]' => '[\x41-\x5A]',
1771             '[:word:]' => '[\x30-\x39\x41-\x5A\x5F\x61-\x7A]',
1772             '[:xdigit:]' => '[\x30-\x39\x41-\x46\x61-\x66]',
1773             '[:^alnum:]' => '${Ecyrillic::not_alnum}',
1774             '[:^alpha:]' => '${Ecyrillic::not_alpha}',
1775             '[:^ascii:]' => '${Ecyrillic::not_ascii}',
1776             '[:^blank:]' => '${Ecyrillic::not_blank}',
1777             '[:^cntrl:]' => '${Ecyrillic::not_cntrl}',
1778             '[:^digit:]' => '${Ecyrillic::not_digit}',
1779             '[:^graph:]' => '${Ecyrillic::not_graph}',
1780             '[:^lower:]' => '${Ecyrillic::not_lower}',
1781             '[:^print:]' => '${Ecyrillic::not_print}',
1782             '[:^punct:]' => '${Ecyrillic::not_punct}',
1783             '[:^space:]' => '${Ecyrillic::not_space}',
1784             '[:^upper:]' => '${Ecyrillic::not_upper}',
1785             '[:^word:]' => '${Ecyrillic::not_word}',
1786             '[:^xdigit:]' => '${Ecyrillic::not_xdigit}',
1787              
1788             }->{$1};
1789             }
1790             elsif ($char[$i] =~ /\A \\ ($q_char) \z/oxms) {
1791 0         0 $char[$i] = $1;
1792             }
1793             }
1794              
1795             # open character list
1796 0         0 my @singleoctet = ();
1797 0         0 my @multipleoctet = ();
1798 0         0 for (my $i=0; $i <= $#char; ) {
1799              
1800             # escaped -
1801 0 0 0     0 if (defined($char[$i+1]) and ($char[$i+1] eq '...')) {
    0          
    0          
    0          
    0          
    0          
1802 0         0 $i += 1;
1803 0         0 next;
1804             }
1805              
1806             # make range regexp
1807             elsif ($char[$i] eq '...') {
1808              
1809             # range error
1810 0 0       0 if (CORE::length($char[$i-1]) > CORE::length($char[$i+1])) {
    0          
1811 0         0 croak 'Invalid [] range in regexp (length(A) > length(B)) ' . '\x' . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]);
1812             }
1813             elsif (CORE::length($char[$i-1]) == CORE::length($char[$i+1])) {
1814 0 0       0 if ($char[$i-1] gt $char[$i+1]) {
1815 0         0 croak 'Invalid [] range in regexp (CORE::ord(A) > CORE::ord(B)) ' . '\x' . unpack('H*',$char[$i-1]) . '-\x' . unpack('H*',$char[$i+1]);
1816             }
1817             }
1818              
1819             # make range regexp per length
1820 0         0 for my $length (CORE::length($char[$i-1]) .. CORE::length($char[$i+1])) {
1821 0         0 my @regexp = ();
1822              
1823             # is first and last
1824 0 0 0     0 if (($length == CORE::length($char[$i-1])) and ($length == CORE::length($char[$i+1]))) {
    0 0        
    0          
    0          
1825 0         0 push @regexp, _range_regexp($length, $char[$i-1], $char[$i+1]);
1826             }
1827              
1828             # is first
1829             elsif ($length == CORE::length($char[$i-1])) {
1830 0         0 push @regexp, _range_regexp($length, $char[$i-1], "\xFF" x $length);
1831             }
1832              
1833             # is inside in first and last
1834             elsif ((CORE::length($char[$i-1]) < $length) and ($length < CORE::length($char[$i+1]))) {
1835 0         0 push @regexp, _range_regexp($length, "\x00" x $length, "\xFF" x $length);
1836             }
1837              
1838             # is last
1839             elsif ($length == CORE::length($char[$i+1])) {
1840 0         0 push @regexp, _range_regexp($length, "\x00" x $length, $char[$i+1]);
1841             }
1842              
1843             else {
1844 0         0 die __FILE__, ": subroutine make_regexp panic.\n";
1845             }
1846              
1847 0 0       0 if ($length == 1) {
1848 0         0 push @singleoctet, @regexp;
1849             }
1850             else {
1851 0         0 push @multipleoctet, @regexp;
1852             }
1853             }
1854              
1855 0         0 $i += 2;
1856             }
1857              
1858             # with /i modifier
1859             elsif ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) {
1860 0 0       0 if ($modifier =~ /i/oxms) {
1861 0         0 my $uc = Ecyrillic::uc($char[$i]);
1862 0         0 my $fc = Ecyrillic::fc($char[$i]);
1863 0 0       0 if ($uc ne $fc) {
1864 0 0       0 if (CORE::length($fc) == 1) {
1865 0         0 push @singleoctet, $uc, $fc;
1866             }
1867             else {
1868 0         0 push @singleoctet, $uc;
1869 0         0 push @multipleoctet, $fc;
1870             }
1871             }
1872             else {
1873 0         0 push @singleoctet, $char[$i];
1874             }
1875             }
1876             else {
1877 0         0 push @singleoctet, $char[$i];
1878             }
1879 0         0 $i += 1;
1880             }
1881              
1882             # single character of single octet code
1883             elsif ($char[$i] =~ /\A (?: \\h ) \z/oxms) {
1884 0         0 push @singleoctet, "\t", "\x20";
1885 0         0 $i += 1;
1886             }
1887             elsif ($char[$i] =~ /\A (?: \\v ) \z/oxms) {
1888 0         0 push @singleoctet, "\x0A", "\x0B", "\x0C", "\x0D";
1889 0         0 $i += 1;
1890             }
1891             elsif ($char[$i] =~ /\A (?: \\d | \\s | \\w ) \z/oxms) {
1892 0         0 push @singleoctet, $char[$i];
1893 0         0 $i += 1;
1894             }
1895              
1896             # single character of multiple-octet code
1897             else {
1898 0         0 push @multipleoctet, $char[$i];
1899 0         0 $i += 1;
1900             }
1901             }
1902              
1903             # quote metachar
1904 0         0 for (@singleoctet) {
1905 0 0       0 if ($_ eq '...') {
    0          
    0          
    0          
    0          
1906 0         0 $_ = '-';
1907             }
1908             elsif (/\A \n \z/oxms) {
1909 0         0 $_ = '\n';
1910             }
1911             elsif (/\A \r \z/oxms) {
1912 0         0 $_ = '\r';
1913             }
1914             elsif (/\A ([\x00-\x20\x7F-\xFF]) \z/oxms) {
1915 0         0 $_ = sprintf('\x%02X', CORE::ord $1);
1916             }
1917             elsif (/\A [\x00-\xFF] \z/oxms) {
1918 0         0 $_ = quotemeta $_;
1919             }
1920             }
1921              
1922             # return character list
1923 0         0 return \@singleoctet, \@multipleoctet;
1924             }
1925              
1926             #
1927             # Cyrillic octal escape sequence
1928             #
1929             sub octchr {
1930 0     0 0 0 my($octdigit) = @_;
1931              
1932 0         0 my @binary = ();
1933 0         0 for my $octal (split(//,$octdigit)) {
1934 0         0 push @binary, {
1935             '0' => '000',
1936             '1' => '001',
1937             '2' => '010',
1938             '3' => '011',
1939             '4' => '100',
1940             '5' => '101',
1941             '6' => '110',
1942             '7' => '111',
1943             }->{$octal};
1944             }
1945 0         0 my $binary = join '', @binary;
1946              
1947 0         0 my $octchr = {
1948             # 1234567
1949             1 => pack('B*', "0000000$binary"),
1950             2 => pack('B*', "000000$binary"),
1951             3 => pack('B*', "00000$binary"),
1952             4 => pack('B*', "0000$binary"),
1953             5 => pack('B*', "000$binary"),
1954             6 => pack('B*', "00$binary"),
1955             7 => pack('B*', "0$binary"),
1956             0 => pack('B*', "$binary"),
1957              
1958             }->{CORE::length($binary) % 8};
1959              
1960 0         0 return $octchr;
1961             }
1962              
1963             #
1964             # Cyrillic hexadecimal escape sequence
1965             #
1966             sub hexchr {
1967 0     0 0 0 my($hexdigit) = @_;
1968              
1969 0         0 my $hexchr = {
1970             1 => pack('H*', "0$hexdigit"),
1971             0 => pack('H*', "$hexdigit"),
1972              
1973             }->{CORE::length($_[0]) % 2};
1974              
1975 0         0 return $hexchr;
1976             }
1977              
1978             #
1979             # Cyrillic open character list for qr
1980             #
1981             sub charlist_qr {
1982              
1983 0     0 0 0 my $modifier = pop @_;
1984 0         0 my @char = @_;
1985              
1986 0         0 my($singleoctet, $multipleoctet) = _charlist(@char, $modifier);
1987 0         0 my @singleoctet = @$singleoctet;
1988 0         0 my @multipleoctet = @$multipleoctet;
1989              
1990             # return character list
1991 0 0       0 if (scalar(@singleoctet) >= 1) {
1992              
1993             # with /i modifier
1994 0 0       0 if ($modifier =~ m/i/oxms) {
1995 0         0 my %singleoctet_ignorecase = ();
1996 0         0 for (@singleoctet) {
1997 0   0     0 while (s/ \A \\x(..) - \\x(..) //oxms or s/ \A \\x((..)) //oxms) {
1998 0         0 for my $ord (hex($1) .. hex($2)) {
1999 0         0 my $char = CORE::chr($ord);
2000 0         0 my $uc = Ecyrillic::uc($char);
2001 0         0 my $fc = Ecyrillic::fc($char);
2002 0 0       0 if ($uc eq $fc) {
2003 0         0 $singleoctet_ignorecase{unpack 'C*', $char} = 1;
2004             }
2005             else {
2006 0 0       0 if (CORE::length($fc) == 1) {
2007 0         0 $singleoctet_ignorecase{unpack 'C*', $uc} = 1;
2008 0         0 $singleoctet_ignorecase{unpack 'C*', $fc} = 1;
2009             }
2010             else {
2011 0         0 $singleoctet_ignorecase{unpack 'C*', $uc} = 1;
2012 0         0 push @multipleoctet, join '', map {sprintf('\x%02X',$_)} unpack 'C*', $fc;
  0         0  
2013             }
2014             }
2015             }
2016             }
2017 0 0       0 if ($_ ne '') {
2018 0         0 $singleoctet_ignorecase{unpack 'C*', $_} = 1;
2019             }
2020             }
2021 0         0 my $i = 0;
2022 0         0 my @singleoctet_ignorecase = ();
2023 0         0 for my $ord (0 .. 255) {
2024 0 0       0 if (exists $singleoctet_ignorecase{$ord}) {
2025 0         0 push @{$singleoctet_ignorecase[$i]}, $ord;
  0         0  
2026             }
2027             else {
2028 0         0 $i++;
2029             }
2030             }
2031 0         0 @singleoctet = ();
2032 0         0 for my $range (@singleoctet_ignorecase) {
2033 0 0       0 if (ref $range) {
2034 0 0       0 if (scalar(@{$range}) == 1) {
  0 0       0  
  0         0  
2035 0         0 push @singleoctet, sprintf('\x%02X', @{$range}[0]);
  0         0  
2036             }
2037             elsif (scalar(@{$range}) == 2) {
2038 0         0 push @singleoctet, sprintf('\x%02X\x%02X', @{$range}[0], @{$range}[-1]);
  0         0  
  0         0  
2039             }
2040             else {
2041 0         0 push @singleoctet, sprintf('\x%02X-\x%02X', @{$range}[0], @{$range}[-1]);
  0         0  
  0         0  
2042             }
2043             }
2044             }
2045             }
2046              
2047 0         0 my $not_anchor = '';
2048              
2049 0         0 push @multipleoctet, join('', $not_anchor, '[', @singleoctet, ']' );
2050             }
2051 0 0       0 if (scalar(@multipleoctet) >= 2) {
2052 0         0 return '(?:' . join('|', @multipleoctet) . ')';
2053             }
2054             else {
2055 0         0 return $multipleoctet[0];
2056             }
2057             }
2058              
2059             #
2060             # Cyrillic open character list for not qr
2061             #
2062             sub charlist_not_qr {
2063              
2064 0     0 0 0 my $modifier = pop @_;
2065 0         0 my @char = @_;
2066              
2067 0         0 my($singleoctet, $multipleoctet) = _charlist(@char, $modifier);
2068 0         0 my @singleoctet = @$singleoctet;
2069 0         0 my @multipleoctet = @$multipleoctet;
2070              
2071             # with /i modifier
2072 0 0       0 if ($modifier =~ m/i/oxms) {
2073 0         0 my %singleoctet_ignorecase = ();
2074 0         0 for (@singleoctet) {
2075 0   0     0 while (s/ \A \\x(..) - \\x(..) //oxms or s/ \A \\x((..)) //oxms) {
2076 0         0 for my $ord (hex($1) .. hex($2)) {
2077 0         0 my $char = CORE::chr($ord);
2078 0         0 my $uc = Ecyrillic::uc($char);
2079 0         0 my $fc = Ecyrillic::fc($char);
2080 0 0       0 if ($uc eq $fc) {
2081 0         0 $singleoctet_ignorecase{unpack 'C*', $char} = 1;
2082             }
2083             else {
2084 0 0       0 if (CORE::length($fc) == 1) {
2085 0         0 $singleoctet_ignorecase{unpack 'C*', $uc} = 1;
2086 0         0 $singleoctet_ignorecase{unpack 'C*', $fc} = 1;
2087             }
2088             else {
2089 0         0 $singleoctet_ignorecase{unpack 'C*', $uc} = 1;
2090 0         0 push @multipleoctet, join '', map {sprintf('\x%02X',$_)} unpack 'C*', $fc;
  0         0  
2091             }
2092             }
2093             }
2094             }
2095 0 0       0 if ($_ ne '') {
2096 0         0 $singleoctet_ignorecase{unpack 'C*', $_} = 1;
2097             }
2098             }
2099 0         0 my $i = 0;
2100 0         0 my @singleoctet_ignorecase = ();
2101 0         0 for my $ord (0 .. 255) {
2102 0 0       0 if (exists $singleoctet_ignorecase{$ord}) {
2103 0         0 push @{$singleoctet_ignorecase[$i]}, $ord;
  0         0  
2104             }
2105             else {
2106 0         0 $i++;
2107             }
2108             }
2109 0         0 @singleoctet = ();
2110 0         0 for my $range (@singleoctet_ignorecase) {
2111 0 0       0 if (ref $range) {
2112 0 0       0 if (scalar(@{$range}) == 1) {
  0 0       0  
  0         0  
2113 0         0 push @singleoctet, sprintf('\x%02X', @{$range}[0]);
  0         0  
2114             }
2115             elsif (scalar(@{$range}) == 2) {
2116 0         0 push @singleoctet, sprintf('\x%02X\x%02X', @{$range}[0], @{$range}[-1]);
  0         0  
  0         0  
2117             }
2118             else {
2119 0         0 push @singleoctet, sprintf('\x%02X-\x%02X', @{$range}[0], @{$range}[-1]);
  0         0  
  0         0  
2120             }
2121             }
2122             }
2123             }
2124              
2125             # return character list
2126 0 0       0 if (scalar(@multipleoctet) >= 1) {
2127 0 0       0 if (scalar(@singleoctet) >= 1) {
2128              
2129             # any character other than multiple-octet and single octet character class
2130 0         0 return '(?!' . join('|', @multipleoctet) . ')(?:[^' . join('', @singleoctet) . '])';
2131             }
2132             else {
2133              
2134             # any character other than multiple-octet character class
2135 0         0 return '(?!' . join('|', @multipleoctet) . ")(?:$your_char)";
2136             }
2137             }
2138             else {
2139 0 0       0 if (scalar(@singleoctet) >= 1) {
2140              
2141             # any character other than single octet character class
2142 0         0 return '(?:[^' . join('', @singleoctet) . '])';
2143             }
2144             else {
2145              
2146             # any character
2147 0         0 return "(?:$your_char)";
2148             }
2149             }
2150             }
2151              
2152             #
2153             # open file in read mode
2154             #
2155             sub _open_r {
2156 200     200   703 my(undef,$file) = @_;
2157 200         822 $file =~ s#\A (\s) #./$1#oxms;
2158 200   33     19518 return CORE::eval(q{open($_[0],'<',$_[1])}) ||
2159             open($_[0],"< $file\0");
2160             }
2161              
2162             #
2163             # open file in write mode
2164             #
2165             sub _open_w {
2166 0     0   0 my(undef,$file) = @_;
2167 0         0 $file =~ s#\A (\s) #./$1#oxms;
2168 0   0     0 return CORE::eval(q{open($_[0],'>',$_[1])}) ||
2169             open($_[0],"> $file\0");
2170             }
2171              
2172             #
2173             # open file in append mode
2174             #
2175             sub _open_a {
2176 0     0   0 my(undef,$file) = @_;
2177 0         0 $file =~ s#\A (\s) #./$1#oxms;
2178 0   0     0 return CORE::eval(q{open($_[0],'>>',$_[1])}) ||
2179             open($_[0],">> $file\0");
2180             }
2181              
2182             #
2183             # safe system
2184             #
2185             sub _systemx {
2186              
2187             # P.707 29.2.33. exec
2188             # in Chapter 29: Functions
2189             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2190             #
2191             # Be aware that in older releases of Perl, exec (and system) did not flush
2192             # your output buffer, so you needed to enable command buffering by setting $|
2193             # on one or more filehandles to avoid lost output in the case of exec, or
2194             # misordererd output in the case of system. This situation was largely remedied
2195             # in the 5.6 release of Perl. (So, 5.005 release not yet.)
2196              
2197             # P.855 exec
2198             # in Chapter 27: Functions
2199             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2200             #
2201             # In very old release of Perl (before v5.6), exec (and system) did not flush
2202             # your output buffer, so you needed to enable command buffering by setting $|
2203             # on one or more filehandles to avoid lost output with exec or misordered
2204             # output with system.
2205              
2206 200     200   779 $| = 1;
2207              
2208             # P.565 23.1.2. Cleaning Up Your Environment
2209             # in Chapter 23: Security
2210             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2211              
2212             # P.656 Cleaning Up Your Environment
2213             # in Chapter 20: Security
2214             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2215              
2216             # local $ENV{'PATH'} = '.';
2217 200         2278 local @ENV{qw(IFS CDPATH ENV BASH_ENV)}; # Make %ENV safer
2218              
2219             # P.707 29.2.33. exec
2220             # in Chapter 29: Functions
2221             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2222             #
2223             # As we mentioned earlier, exec treats a discrete list of arguments as an
2224             # indication that it should bypass shell processing. However, there is one
2225             # place where you might still get tripped up. The exec call (and system, too)
2226             # will not distinguish between a single scalar argument and an array containing
2227             # only one element.
2228             #
2229             # @args = ("echo surprise"); # just one element in list
2230             # exec @args # still subject to shell escapes
2231             # or die "exec: $!"; # because @args == 1
2232             #
2233             # To avoid this, you can use the PATHNAME syntax, explicitly duplicating the
2234             # first argument as the pathname, which forces the rest of the arguments to be
2235             # interpreted as a list, even if there is only one of them:
2236             #
2237             # exec { $args[0] } @args # safe even with one-argument list
2238             # or die "can't exec @args: $!";
2239              
2240             # P.855 exec
2241             # in Chapter 27: Functions
2242             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2243             #
2244             # As we mentioned earlier, exec treats a discrete list of arguments as a
2245             # directive to bypass shell processing. However, there is one place where
2246             # you might still get tripped up. The exec call (and system, too) cannot
2247             # distinguish between a single scalar argument and an array containing
2248             # only one element.
2249             #
2250             # @args = ("echo surprise"); # just one element in list
2251             # exec @args # still subject to shell escapes
2252             # || die "exec: $!"; # because @args == 1
2253             #
2254             # To avoid this, use the PATHNAME syntax, explicitly duplicating the first
2255             # argument as the pathname, which forces the rest of the arguments to be
2256             # interpreted as a list, even if there is only one of them:
2257             #
2258             # exec { $args[0] } @args # safe even with one-argument list
2259             # || die "can't exec @args: $!";
2260              
2261 200         488 return CORE::system { $_[0] } @_; # safe even with one-argument list
  200         25279806  
2262             }
2263              
2264             #
2265             # Cyrillic order to character (with parameter)
2266             #
2267             sub Ecyrillic::chr(;$) {
2268              
2269 0 0   0 0   my $c = @_ ? $_[0] : $_;
2270              
2271 0 0         if ($c == 0x00) {
2272 0           return "\x00";
2273             }
2274             else {
2275 0           my @chr = ();
2276 0           while ($c > 0) {
2277 0           unshift @chr, ($c % 0x100);
2278 0           $c = int($c / 0x100);
2279             }
2280 0           return pack 'C*', @chr;
2281             }
2282             }
2283              
2284             #
2285             # Cyrillic order to character (without parameter)
2286             #
2287             sub Ecyrillic::chr_() {
2288              
2289 0     0 0   my $c = $_;
2290              
2291 0 0         if ($c == 0x00) {
2292 0           return "\x00";
2293             }
2294             else {
2295 0           my @chr = ();
2296 0           while ($c > 0) {
2297 0           unshift @chr, ($c % 0x100);
2298 0           $c = int($c / 0x100);
2299             }
2300 0           return pack 'C*', @chr;
2301             }
2302             }
2303              
2304             #
2305             # Cyrillic path globbing (with parameter)
2306             #
2307             sub Ecyrillic::glob($) {
2308              
2309 0 0   0 0   if (wantarray) {
2310 0           my @glob = _DOS_like_glob(@_);
2311 0           for my $glob (@glob) {
2312 0           $glob =~ s{ \A (?:\./)+ }{}oxms;
2313             }
2314 0           return @glob;
2315             }
2316             else {
2317 0           my $glob = _DOS_like_glob(@_);
2318 0           $glob =~ s{ \A (?:\./)+ }{}oxms;
2319 0           return $glob;
2320             }
2321             }
2322              
2323             #
2324             # Cyrillic path globbing (without parameter)
2325             #
2326             sub Ecyrillic::glob_() {
2327              
2328 0 0   0 0   if (wantarray) {
2329 0           my @glob = _DOS_like_glob();
2330 0           for my $glob (@glob) {
2331 0           $glob =~ s{ \A (?:\./)+ }{}oxms;
2332             }
2333 0           return @glob;
2334             }
2335             else {
2336 0           my $glob = _DOS_like_glob();
2337 0           $glob =~ s{ \A (?:\./)+ }{}oxms;
2338 0           return $glob;
2339             }
2340             }
2341              
2342             #
2343             # Cyrillic path globbing via File::DosGlob 1.10
2344             #
2345             # Often I confuse "_dosglob" and "_doglob".
2346             # So, I renamed "_dosglob" to "_DOS_like_glob".
2347             #
2348             my %iter;
2349             my %entries;
2350             sub _DOS_like_glob {
2351              
2352             # context (keyed by second cxix argument provided by core)
2353 0     0     my($expr,$cxix) = @_;
2354              
2355             # glob without args defaults to $_
2356 0 0         $expr = $_ if not defined $expr;
2357              
2358             # represents the current user's home directory
2359             #
2360             # 7.3. Expanding Tildes in Filenames
2361             # in Chapter 7. File Access
2362             # of ISBN 0-596-00313-7 Perl Cookbook, 2nd Edition.
2363             #
2364             # and File::HomeDir, File::HomeDir::Windows module
2365              
2366             # DOS-like system
2367 0 0         if ($^O =~ /\A (?: MSWin32 | NetWare | symbian | dos ) \z/oxms) {
2368 0           $expr =~ s{ \A ~ (?= [^/\\] ) }
2369 0           { my_home_MSWin32() }oxmse;
2370             }
2371              
2372             # UNIX-like system
2373             else {
2374 0           $expr =~ s{ \A ~ ( (?:[^/])* ) }
2375 0 0 0       { $1 ? (CORE::eval(q{(getpwnam($1))[7]})||my_home()) : my_home() }oxmse;
2376             }
2377              
2378             # assume global context if not provided one
2379 0 0         $cxix = '_G_' if not defined $cxix;
2380 0 0         $iter{$cxix} = 0 if not exists $iter{$cxix};
2381              
2382             # if we're just beginning, do it all first
2383 0 0         if ($iter{$cxix} == 0) {
2384 0           $entries{$cxix} = [ _do_glob(1, _parse_line($expr)) ];
2385             }
2386              
2387             # chuck it all out, quick or slow
2388 0 0         if (wantarray) {
2389 0           delete $iter{$cxix};
2390 0           return @{delete $entries{$cxix}};
  0            
2391             }
2392             else {
2393 0 0         if ($iter{$cxix} = scalar @{$entries{$cxix}}) {
  0            
2394 0           return shift @{$entries{$cxix}};
  0            
2395             }
2396             else {
2397             # return undef for EOL
2398 0           delete $iter{$cxix};
2399 0           delete $entries{$cxix};
2400 0           return undef;
2401             }
2402             }
2403             }
2404              
2405             #
2406             # Cyrillic path globbing subroutine
2407             #
2408             sub _do_glob {
2409              
2410 0     0     my($cond,@expr) = @_;
2411 0           my @glob = ();
2412 0           my $fix_drive_relative_paths = 0;
2413              
2414             OUTER:
2415 0           for my $expr (@expr) {
2416 0 0         next OUTER if not defined $expr;
2417 0 0         next OUTER if $expr eq '';
2418              
2419 0           my @matched = ();
2420 0           my @globdir = ();
2421 0           my $head = '.';
2422 0           my $pathsep = '/';
2423 0           my $tail;
2424              
2425             # if argument is within quotes strip em and do no globbing
2426 0 0         if ($expr =~ /\A " ((?:$q_char)*?) " \z/oxms) {
2427 0           $expr = $1;
2428 0 0         if ($cond eq 'd') {
2429 0 0         if (-d $expr) {
2430 0           push @glob, $expr;
2431             }
2432             }
2433             else {
2434 0 0         if (-e $expr) {
2435 0           push @glob, $expr;
2436             }
2437             }
2438 0           next OUTER;
2439             }
2440              
2441             # wildcards with a drive prefix such as h:*.pm must be changed
2442             # to h:./*.pm to expand correctly
2443 0 0         if ($^O =~ /\A (?: MSWin32 | NetWare | symbian | dos ) \z/oxms) {
2444 0 0         if ($expr =~ s# \A ((?:[A-Za-z]:)?) ([^/\\]) #$1./$2#oxms) {
2445 0           $fix_drive_relative_paths = 1;
2446             }
2447             }
2448              
2449 0 0         if (($head, $tail) = _parse_path($expr,$pathsep)) {
2450 0 0         if ($tail eq '') {
2451 0           push @glob, $expr;
2452 0           next OUTER;
2453             }
2454 0 0         if ($head =~ / \A (?:$q_char)*? [*?] /oxms) {
2455 0 0         if (@globdir = _do_glob('d', $head)) {
2456 0           push @glob, _do_glob($cond, map {"$_$pathsep$tail"} @globdir);
  0            
2457 0           next OUTER;
2458             }
2459             }
2460 0 0 0       if ($head eq '' or $head =~ /\A [A-Za-z]: \z/oxms) {
2461 0           $head .= $pathsep;
2462             }
2463 0           $expr = $tail;
2464             }
2465              
2466             # If file component has no wildcards, we can avoid opendir
2467 0 0         if ($expr !~ / \A (?:$q_char)*? [*?] /oxms) {
2468 0 0         if ($head eq '.') {
2469 0           $head = '';
2470             }
2471 0 0 0       if ($head ne '' and ($head =~ / \G ($q_char) /oxmsg)[-1] ne $pathsep) {
2472 0           $head .= $pathsep;
2473             }
2474 0           $head .= $expr;
2475 0 0         if ($cond eq 'd') {
2476 0 0         if (-d $head) {
2477 0           push @glob, $head;
2478             }
2479             }
2480             else {
2481 0 0         if (-e $head) {
2482 0           push @glob, $head;
2483             }
2484             }
2485 0           next OUTER;
2486             }
2487 0 0         opendir(*DIR, $head) or next OUTER;
2488 0           my @leaf = readdir DIR;
2489 0           closedir DIR;
2490              
2491 0 0         if ($head eq '.') {
2492 0           $head = '';
2493             }
2494 0 0 0       if ($head ne '' and ($head =~ / \G ($q_char) /oxmsg)[-1] ne $pathsep) {
2495 0           $head .= $pathsep;
2496             }
2497              
2498 0           my $pattern = '';
2499 0           while ($expr =~ / \G ($q_char) /oxgc) {
2500 0           my $char = $1;
2501              
2502             # 6.9. Matching Shell Globs as Regular Expressions
2503             # in Chapter 6. Pattern Matching
2504             # of ISBN 0-596-00313-7 Perl Cookbook, 2nd Edition.
2505             # (and so on)
2506              
2507 0 0         if ($char eq '*') {
    0          
    0          
2508 0           $pattern .= "(?:$your_char)*",
2509             }
2510             elsif ($char eq '?') {
2511 0           $pattern .= "(?:$your_char)?", # DOS style
2512             # $pattern .= "(?:$your_char)", # UNIX style
2513             }
2514             elsif ((my $fc = Ecyrillic::fc($char)) ne $char) {
2515 0           $pattern .= $fc;
2516             }
2517             else {
2518 0           $pattern .= quotemeta $char;
2519             }
2520             }
2521 0     0     my $matchsub = sub { Ecyrillic::fc($_[0]) =~ /\A $pattern \z/xms };
  0            
2522              
2523             # if ($@) {
2524             # print STDERR "$0: $@\n";
2525             # next OUTER;
2526             # }
2527              
2528             INNER:
2529 0           for my $leaf (@leaf) {
2530 0 0 0       if ($leaf eq '.' or $leaf eq '..') {
2531 0           next INNER;
2532             }
2533 0 0 0       if ($cond eq 'd' and not -d "$head$leaf") {
2534 0           next INNER;
2535             }
2536              
2537 0 0         if (&$matchsub($leaf)) {
2538 0           push @matched, "$head$leaf";
2539 0           next INNER;
2540             }
2541              
2542             # [DOS compatibility special case]
2543             # Failed, add a trailing dot and try again, but only...
2544              
2545 0 0 0       if (Ecyrillic::index($leaf,'.') == -1 and # if name does not have a dot in it *and*
      0        
2546             CORE::length($leaf) <= 8 and # name is shorter than or equal to 8 chars *and*
2547             Ecyrillic::index($pattern,'\\.') != -1 # pattern has a dot.
2548             ) {
2549 0 0         if (&$matchsub("$leaf.")) {
2550 0           push @matched, "$head$leaf";
2551 0           next INNER;
2552             }
2553             }
2554             }
2555 0 0         if (@matched) {
2556 0           push @glob, @matched;
2557             }
2558             }
2559 0 0         if ($fix_drive_relative_paths) {
2560 0           for my $glob (@glob) {
2561 0           $glob =~ s# \A ([A-Za-z]:) \./ #$1#oxms;
2562             }
2563             }
2564 0           return @glob;
2565             }
2566              
2567             #
2568             # Cyrillic parse line
2569             #
2570             sub _parse_line {
2571              
2572 0     0     my($line) = @_;
2573              
2574 0           $line .= ' ';
2575 0           my @piece = ();
2576 0           while ($line =~ /
2577             " ( (?>(?: [^"] )* ) ) " (?>\s+) |
2578             ( (?>(?: [^"\s] )* ) ) (?>\s+)
2579             /oxmsg
2580             ) {
2581 0 0         push @piece, defined($1) ? $1 : $2;
2582             }
2583 0           return @piece;
2584             }
2585              
2586             #
2587             # Cyrillic parse path
2588             #
2589             sub _parse_path {
2590              
2591 0     0     my($path,$pathsep) = @_;
2592              
2593 0           $path .= '/';
2594 0           my @subpath = ();
2595 0           while ($path =~ /
2596             ((?: [^\/\\] )+?) [\/\\]
2597             /oxmsg
2598             ) {
2599 0           push @subpath, $1;
2600             }
2601              
2602 0           my $tail = pop @subpath;
2603 0           my $head = join $pathsep, @subpath;
2604 0           return $head, $tail;
2605             }
2606              
2607             #
2608             # via File::HomeDir::Windows 1.00
2609             #
2610             sub my_home_MSWin32 {
2611              
2612             # A lot of unix people and unix-derived tools rely on
2613             # the ability to overload HOME. We will support it too
2614             # so that they can replace raw HOME calls with File::HomeDir.
2615 0 0 0 0 0   if (exists $ENV{'HOME'} and $ENV{'HOME'}) {
    0 0        
    0 0        
      0        
      0        
2616 0           return $ENV{'HOME'};
2617             }
2618              
2619             # Do we have a user profile?
2620             elsif (exists $ENV{'USERPROFILE'} and $ENV{'USERPROFILE'}) {
2621 0           return $ENV{'USERPROFILE'};
2622             }
2623              
2624             # Some Windows use something like $ENV{'HOME'}
2625             elsif (exists $ENV{'HOMEDRIVE'} and exists $ENV{'HOMEPATH'} and $ENV{'HOMEDRIVE'} and $ENV{'HOMEPATH'}) {
2626 0           return join '', $ENV{'HOMEDRIVE'}, $ENV{'HOMEPATH'};
2627             }
2628              
2629 0           return undef;
2630             }
2631              
2632             #
2633             # via File::HomeDir::Unix 1.00
2634             #
2635             sub my_home {
2636 0     0 0   my $home;
2637              
2638 0 0 0       if (exists $ENV{'HOME'} and defined $ENV{'HOME'}) {
    0 0        
2639 0           $home = $ENV{'HOME'};
2640             }
2641              
2642             # This is from the original code, but I'm guessing
2643             # it means "login directory" and exists on some Unixes.
2644             elsif (exists $ENV{'LOGDIR'} and $ENV{'LOGDIR'}) {
2645 0           $home = $ENV{'LOGDIR'};
2646             }
2647              
2648             ### More-desperate methods
2649              
2650             # Light desperation on any (Unixish) platform
2651             else {
2652 0           $home = CORE::eval q{ (getpwuid($<))[7] };
2653             }
2654              
2655             # On Unix in general, a non-existant home means "no home"
2656             # For example, "nobody"-like users might use /nonexistant
2657 0 0 0       if (defined $home and ! -d($home)) {
2658 0           $home = undef;
2659             }
2660 0           return $home;
2661             }
2662              
2663             #
2664             # ${^PREMATCH}, $PREMATCH, $` the string preceding what was matched
2665             #
2666             sub Ecyrillic::PREMATCH {
2667 0     0 0   return $`;
2668             }
2669              
2670             #
2671             # ${^MATCH}, $MATCH, $& the string that matched
2672             #
2673             sub Ecyrillic::MATCH {
2674 0     0 0   return $&;
2675             }
2676              
2677             #
2678             # ${^POSTMATCH}, $POSTMATCH, $' the string following what was matched
2679             #
2680             sub Ecyrillic::POSTMATCH {
2681 0     0 0   return $';
2682             }
2683              
2684             #
2685             # Cyrillic character to order (with parameter)
2686             #
2687             sub Cyrillic::ord(;$) {
2688              
2689 0 0   0 1   local $_ = shift if @_;
2690              
2691 0 0         if (/\A ($q_char) /oxms) {
2692 0           my @ord = unpack 'C*', $1;
2693 0           my $ord = 0;
2694 0           while (my $o = shift @ord) {
2695 0           $ord = $ord * 0x100 + $o;
2696             }
2697 0           return $ord;
2698             }
2699             else {
2700 0           return CORE::ord $_;
2701             }
2702             }
2703              
2704             #
2705             # Cyrillic character to order (without parameter)
2706             #
2707             sub Cyrillic::ord_() {
2708              
2709 0 0   0 0   if (/\A ($q_char) /oxms) {
2710 0           my @ord = unpack 'C*', $1;
2711 0           my $ord = 0;
2712 0           while (my $o = shift @ord) {
2713 0           $ord = $ord * 0x100 + $o;
2714             }
2715 0           return $ord;
2716             }
2717             else {
2718 0           return CORE::ord $_;
2719             }
2720             }
2721              
2722             #
2723             # Cyrillic reverse
2724             #
2725             sub Cyrillic::reverse(@) {
2726              
2727 0 0   0 0   if (wantarray) {
2728 0           return CORE::reverse @_;
2729             }
2730             else {
2731              
2732             # One of us once cornered Larry in an elevator and asked him what
2733             # problem he was solving with this, but he looked as far off into
2734             # the distance as he could in an elevator and said, "It seemed like
2735             # a good idea at the time."
2736              
2737 0           return join '', CORE::reverse(join('',@_) =~ /\G ($q_char) /oxmsg);
2738             }
2739             }
2740              
2741             #
2742             # Cyrillic getc (with parameter, without parameter)
2743             #
2744             sub Cyrillic::getc(;*@) {
2745              
2746 0     0 0   my($package) = caller;
2747 0 0         my $fh = @_ ? qualify_to_ref(shift,$package) : \*STDIN;
2748 0 0 0       croak 'Too many arguments for Cyrillic::getc' if @_ and not wantarray;
2749              
2750 0           my @length = sort { $a <=> $b } keys %range_tr;
  0            
2751 0           my $getc = '';
2752 0           for my $length ($length[0] .. $length[-1]) {
2753 0           $getc .= CORE::getc($fh);
2754 0 0         if (exists $range_tr{CORE::length($getc)}) {
2755 0 0         if ($getc =~ /\A ${Ecyrillic::dot_s} \z/oxms) {
2756 0 0         return wantarray ? ($getc,@_) : $getc;
2757             }
2758             }
2759             }
2760 0 0         return wantarray ? ($getc,@_) : $getc;
2761             }
2762              
2763             #
2764             # Cyrillic length by character
2765             #
2766             sub Cyrillic::length(;$) {
2767              
2768 0 0   0 1   local $_ = shift if @_;
2769              
2770 0           local @_ = /\G ($q_char) /oxmsg;
2771 0           return scalar @_;
2772             }
2773              
2774             #
2775             # Cyrillic substr by character
2776             #
2777             BEGIN {
2778              
2779             # P.232 The lvalue Attribute
2780             # in Chapter 6: Subroutines
2781             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2782              
2783             # P.336 The lvalue Attribute
2784             # in Chapter 7: Subroutines
2785             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2786              
2787             # P.144 8.4 Lvalue subroutines
2788             # in Chapter 8: perlsub: Perl subroutines
2789             # of ISBN-13: 978-1-906966-02-7 The Perl Language Reference Manual (for Perl version 5.12.1)
2790              
2791 200 50 0 200 1 174769 CORE::eval sprintf(<<'END', ($] >= 5.014000) ? ':lvalue' : '');
  0 0   0      
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0 0          
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
  0            
2792             # vv----------------------*******
2793             sub Cyrillic::substr($$;$$) %s {
2794              
2795             my @char = $_[0] =~ /\G (?>$q_char) /oxmsg;
2796              
2797             # If the substring is beyond either end of the string, substr() returns the undefined
2798             # value and produces a warning. When used as an lvalue, specifying a substring that
2799             # is entirely outside the string raises an exception.
2800             # http://perldoc.perl.org/functions/substr.html
2801              
2802             # A return with no argument returns the scalar value undef in scalar context,
2803             # an empty list () in list context, and (naturally) nothing at all in void
2804             # context.
2805              
2806             my $offset = $_[1];
2807             if (($offset > scalar(@char)) or ($offset < (-1 * scalar(@char)))) {
2808             return;
2809             }
2810              
2811             # substr($string,$offset,$length,$replacement)
2812             if (@_ == 4) {
2813             my(undef,undef,$length,$replacement) = @_;
2814             my $substr = join '', splice(@char, $offset, $length, $replacement);
2815             $_[0] = join '', @char;
2816              
2817             # return $substr; this doesn't work, don't say "return"
2818             $substr;
2819             }
2820              
2821             # substr($string,$offset,$length)
2822             elsif (@_ == 3) {
2823             my(undef,undef,$length) = @_;
2824             my $octet_offset = 0;
2825             my $octet_length = 0;
2826             if ($offset == 0) {
2827             $octet_offset = 0;
2828             }
2829             elsif ($offset > 0) {
2830             $octet_offset = CORE::length(join '', @char[0..$offset-1]);
2831             }
2832             else {
2833             $octet_offset = -1 * CORE::length(join '', @char[$#char+$offset+1..$#char]);
2834             }
2835             if ($length == 0) {
2836             $octet_length = 0;
2837             }
2838             elsif ($length > 0) {
2839             $octet_length = CORE::length(join '', @char[$offset..$offset+$length-1]);
2840             }
2841             else {
2842             $octet_length = -1 * CORE::length(join '', @char[$#char+$length+1..$#char]);
2843             }
2844             CORE::substr($_[0], $octet_offset, $octet_length);
2845             }
2846              
2847             # substr($string,$offset)
2848             else {
2849             my $octet_offset = 0;
2850             if ($offset == 0) {
2851             $octet_offset = 0;
2852             }
2853             elsif ($offset > 0) {
2854             $octet_offset = CORE::length(join '', @char[0..$offset-1]);
2855             }
2856             else {
2857             $octet_offset = -1 * CORE::length(join '', @char[$#char+$offset+1..$#char]);
2858             }
2859             CORE::substr($_[0], $octet_offset);
2860             }
2861             }
2862             END
2863             }
2864              
2865             #
2866             # Cyrillic index by character
2867             #
2868             sub Cyrillic::index($$;$) {
2869              
2870 0     0 1   my $index;
2871 0 0         if (@_ == 3) {
2872 0           $index = Ecyrillic::index($_[0], $_[1], CORE::length(Cyrillic::substr($_[0], 0, $_[2])));
2873             }
2874             else {
2875 0           $index = Ecyrillic::index($_[0], $_[1]);
2876             }
2877              
2878 0 0         if ($index == -1) {
2879 0           return -1;
2880             }
2881             else {
2882 0           return Cyrillic::length(CORE::substr $_[0], 0, $index);
2883             }
2884             }
2885              
2886             #
2887             # Cyrillic rindex by character
2888             #
2889             sub Cyrillic::rindex($$;$) {
2890              
2891 0     0 1   my $rindex;
2892 0 0         if (@_ == 3) {
2893 0           $rindex = Ecyrillic::rindex($_[0], $_[1], CORE::length(Cyrillic::substr($_[0], 0, $_[2])));
2894             }
2895             else {
2896 0           $rindex = Ecyrillic::rindex($_[0], $_[1]);
2897             }
2898              
2899 0 0         if ($rindex == -1) {
2900 0           return -1;
2901             }
2902             else {
2903 0           return Cyrillic::length(CORE::substr $_[0], 0, $rindex);
2904             }
2905             }
2906              
2907             # when 'm//', '/' means regexp match 'm//' and '?' means regexp match '??'
2908             # when 'div', '/' means division operator and '?' means conditional operator (condition ? then : else)
2909 200     200   19751 BEGIN { CORE::eval q{ use vars qw($slash) } } $slash = 'm//';
  200     200   3965  
  200         446  
  200         23263  
2910              
2911             # ord() to ord() or Cyrillic::ord()
2912 200     200   17159 BEGIN { CORE::eval q{ use vars qw($function_ord) } } $function_ord = 'ord';
  200     200   1590  
  200         463  
  200         15577  
2913              
2914             # ord to ord or Cyrillic::ord_
2915 200     200   15114 BEGIN { CORE::eval q{ use vars qw($function_ord_) } } $function_ord_ = 'ord';
  200     200   1315  
  200         387  
  200         24791  
2916              
2917             # reverse to reverse or Cyrillic::reverse
2918 200     200   22237 BEGIN { CORE::eval q{ use vars qw($function_reverse) } } $function_reverse = 'reverse';
  200     200   1247  
  200         391  
  200         18902  
2919              
2920             # getc to getc or Cyrillic::getc
2921 200     200   15342 BEGIN { CORE::eval q{ use vars qw($function_getc) } } $function_getc = 'getc';
  200     200   1309  
  200         489  
  200         16147  
2922              
2923             # P.1023 Appendix W.9 Multibyte Anchoring
2924             # of ISBN 1-56592-224-7 CJKV Information Processing
2925              
2926             my $anchor = '';
2927              
2928 200     200   15585 BEGIN { CORE::eval q{ use vars qw($nest) } }
  200     200   1362  
  200         446  
  200         13764089  
2929              
2930             # regexp of nested parens in qqXX
2931              
2932             # P.340 Matching Nested Constructs with Embedded Code
2933             # in Chapter 7: Perl
2934             # of ISBN 0-596-00289-0 Mastering Regular Expressions, Second edition
2935              
2936             my $qq_paren = qr{(?{local $nest=0}) (?>(?:
2937             [^\\()] |
2938             \( (?{$nest++}) |
2939             \) (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
2940             \\ [^c] |
2941             \\c[\x40-\x5F] |
2942             [\x00-\xFF]
2943             }xms;
2944              
2945             my $qq_brace = qr{(?{local $nest=0}) (?>(?:
2946             [^\\{}] |
2947             \{ (?{$nest++}) |
2948             \} (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
2949             \\ [^c] |
2950             \\c[\x40-\x5F] |
2951             [\x00-\xFF]
2952             }xms;
2953              
2954             my $qq_bracket = qr{(?{local $nest=0}) (?>(?:
2955             [^\\\[\]] |
2956             \[ (?{$nest++}) |
2957             \] (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
2958             \\ [^c] |
2959             \\c[\x40-\x5F] |
2960             [\x00-\xFF]
2961             }xms;
2962              
2963             my $qq_angle = qr{(?{local $nest=0}) (?>(?:
2964             [^\\<>] |
2965             \< (?{$nest++}) |
2966             \> (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
2967             \\ [^c] |
2968             \\c[\x40-\x5F] |
2969             [\x00-\xFF]
2970             }xms;
2971              
2972             my $qq_scalar = qr{(?: \{ (?:$qq_brace)*? \} |
2973             (?: ::)? (?:
2974             (?> [a-zA-Z_][a-zA-Z_0-9]* (?: ::[a-zA-Z_][a-zA-Z_0-9]*)* )
2975             (?>(?: \[ (?: \$\[ | \$\] | $qq_char )*? \] | \{ (?:$qq_brace)*? \} )*)
2976             (?>(?: (?: -> )? (?: [\$\@\%\&\*]\* | \$\#\* | [\@\%]? \[ (?: \$\[ | \$\] | $qq_char )*? \] | [\@\%\*]? \{ (?:$qq_brace)*? \} ) )*)
2977             ))
2978             }xms;
2979              
2980             my $qq_variable = qr{(?: \{ (?:$qq_brace)*? \} |
2981             (?: ::)? (?:
2982             (?>[0-9]+) |
2983             [^a-zA-Z_0-9\[\]] |
2984             ^[A-Z] |
2985             (?> [a-zA-Z_][a-zA-Z_0-9]* (?: ::[a-zA-Z_][a-zA-Z_0-9]*)* )
2986             (?>(?: \[ (?: \$\[ | \$\] | $qq_char )*? \] | \{ (?:$qq_brace)*? \} )*)
2987             (?>(?: (?: -> )? (?: [\$\@\%\&\*]\* | \$\#\* | [\@\%]? \[ (?: \$\[ | \$\] | $qq_char )*? \] | [\@\%\*]? \{ (?:$qq_brace)*? \} ) )*)
2988             ))
2989             }xms;
2990              
2991             my $qq_substr = qr{(?> Char::substr | Cyrillic::substr | CORE::substr | substr ) (?>\s*) \( $qq_paren \)
2992             }xms;
2993              
2994             # regexp of nested parens in qXX
2995             my $q_paren = qr{(?{local $nest=0}) (?>(?:
2996             [^()] |
2997             \( (?{$nest++}) |
2998             \) (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
2999             [\x00-\xFF]
3000             }xms;
3001              
3002             my $q_brace = qr{(?{local $nest=0}) (?>(?:
3003             [^\{\}] |
3004             \{ (?{$nest++}) |
3005             \} (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
3006             [\x00-\xFF]
3007             }xms;
3008              
3009             my $q_bracket = qr{(?{local $nest=0}) (?>(?:
3010             [^\[\]] |
3011             \[ (?{$nest++}) |
3012             \] (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
3013             [\x00-\xFF]
3014             }xms;
3015              
3016             my $q_angle = qr{(?{local $nest=0}) (?>(?:
3017             [^<>] |
3018             \< (?{$nest++}) |
3019             \> (?(?{$nest>0})(?{$nest--})|(?!)))*) (?(?{$nest!=0})(?!)) |
3020             [\x00-\xFF]
3021             }xms;
3022              
3023             my $matched = '';
3024             my $s_matched = '';
3025              
3026             my $tr_variable = ''; # variable of tr///
3027             my $sub_variable = ''; # variable of s///
3028             my $bind_operator = ''; # =~ or !~
3029              
3030             my @heredoc = (); # here document
3031             my @heredoc_delimiter = ();
3032             my $here_script = ''; # here script
3033              
3034             #
3035             # escape Cyrillic script
3036             #
3037             sub Cyrillic::escape(;$) {
3038 0 0   0 0   local($_) = $_[0] if @_;
3039              
3040             # P.359 The Study Function
3041             # in Chapter 7: Perl
3042             # of ISBN 0-596-00289-0 Mastering Regular Expressions, Second edition
3043              
3044 0           study $_; # Yes, I studied study yesterday.
3045              
3046             # while all script
3047              
3048             # 6.14. Matching from Where the Last Pattern Left Off
3049             # in Chapter 6. Pattern Matching
3050             # of ISBN 0-596-00313-7 Perl Cookbook, 2nd Edition.
3051             # (and so on)
3052              
3053             # one member of Tag-team
3054             #
3055             # P.128 Start of match (or end of previous match): \G
3056             # P.130 Advanced Use of \G with Perl
3057             # in Chapter 3: Overview of Regular Expression Features and Flavors
3058             # P.255 Use leading anchors
3059             # P.256 Expose ^ and \G at the front expressions
3060             # in Chapter 6: Crafting an Efficient Expression
3061             # P.315 "Tag-team" matching with /gc
3062             # in Chapter 7: Perl
3063             # of ISBN 0-596-00289-0 Mastering Regular Expressions, Second edition
3064              
3065 0           my $e_script = '';
3066 0           while (not /\G \z/oxgc) { # member
3067 0           $e_script .= Cyrillic::escape_token();
3068             }
3069              
3070 0           return $e_script;
3071             }
3072              
3073             #
3074             # escape Cyrillic token of script
3075             #
3076             sub Cyrillic::escape_token {
3077              
3078             # \n output here document
3079              
3080 0     0 0   my $ignore_modules = join('|', qw(
3081             utf8
3082             bytes
3083             charnames
3084             I18N::Japanese
3085             I18N::Collate
3086             I18N::JExt
3087             File::DosGlob
3088             Wild
3089             Wildcard
3090             Japanese
3091             ));
3092              
3093             # another member of Tag-team
3094             #
3095             # P.315 "Tag-team" matching with /gc
3096             # in Chapter 7: Perl
3097             # of ISBN 0-596-00289-0 Mastering Regular Expressions, Second edition
3098              
3099 0 0 0       if (/\G ( \n ) /oxgc) { # another member (and so on)
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3100 0           my $heredoc = '';
3101 0 0         if (scalar(@heredoc_delimiter) >= 1) {
3102 0           $slash = 'm//';
3103              
3104 0           $heredoc = join '', @heredoc;
3105 0           @heredoc = ();
3106              
3107             # skip here document
3108 0           for my $heredoc_delimiter (@heredoc_delimiter) {
3109 0           /\G .*? \n $heredoc_delimiter \n/xmsgc;
3110             }
3111 0           @heredoc_delimiter = ();
3112              
3113 0           $here_script = '';
3114             }
3115 0           return "\n" . $heredoc;
3116             }
3117              
3118             # ignore space, comment
3119 0           elsif (/\G ((?>\s+)|\#.*) /oxgc) { return $1; }
3120              
3121             # if (, elsif (, unless (, while (, until (, given (, and when (
3122              
3123             # given, when
3124              
3125             # P.225 The given Statement
3126             # in Chapter 15: Smart Matching and given-when
3127             # of ISBN 978-0-596-52010-6 Learning Perl, Fifth Edition
3128              
3129             # P.133 The given Statement
3130             # in Chapter 4: Statements and Declarations
3131             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
3132              
3133             elsif (/\G ( (?: if | elsif | unless | while | until | given | when ) (?>\s*) \( ) /oxgc) {
3134 0           $slash = 'm//';
3135 0           return $1;
3136             }
3137              
3138             # scalar variable ($scalar = ...) =~ tr///;
3139             # scalar variable ($scalar = ...) =~ s///;
3140              
3141             # state
3142              
3143             # P.68 Persistent, Private Variables
3144             # in Chapter 4: Subroutines
3145             # of ISBN 978-0-596-52010-6 Learning Perl, Fifth Edition
3146              
3147             # P.160 Persistent Lexically Scoped Variables: state
3148             # in Chapter 4: Statements and Declarations
3149             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
3150              
3151             # (and so on)
3152              
3153             elsif (/\G ( \( (?>\s*) (?: local \b | my \b | our \b | state \b )? (?>\s*) \$ $qq_scalar ) /oxgc) {
3154 0           my $e_string = e_string($1);
3155              
3156 0 0         if (/\G ( (?>\s*) = $qq_paren \) ) ( (?>\s*) (?: =~ | !~ ) (?>\s*) ) (?= (?: tr | y ) \b ) /oxgc) {
    0          
3157 0           $tr_variable = $e_string . e_string($1);
3158 0           $bind_operator = $2;
3159 0           $slash = 'm//';
3160 0           return '';
3161             }
3162             elsif (/\G ( (?>\s*) = $qq_paren \) ) ( (?>\s*) (?: =~ | !~ ) (?>\s*) ) (?= s \b ) /oxgc) {
3163 0           $sub_variable = $e_string . e_string($1);
3164 0           $bind_operator = $2;
3165 0           $slash = 'm//';
3166 0           return '';
3167             }
3168             else {
3169 0           $slash = 'div';
3170 0           return $e_string;
3171             }
3172             }
3173              
3174             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> Ecyrillic::PREMATCH()
3175             elsif (/\G ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH \b | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) /oxmsgc) {
3176 0           $slash = 'div';
3177 0           return q{Ecyrillic::PREMATCH()};
3178             }
3179              
3180             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> Ecyrillic::MATCH()
3181             elsif (/\G ( \$& | \$\{&\} | \$ (?>\s*) MATCH \b | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) /oxmsgc) {
3182 0           $slash = 'div';
3183 0           return q{Ecyrillic::MATCH()};
3184             }
3185              
3186             # $', ${'} --> $', ${'}
3187             elsif (/\G ( \$' | \$\{'\} ) /oxmsgc) {
3188 0           $slash = 'div';
3189 0           return $1;
3190             }
3191              
3192             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> Ecyrillic::POSTMATCH()
3193             elsif (/\G ( \$ (?>\s*) POSTMATCH \b | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) /oxmsgc) {
3194 0           $slash = 'div';
3195 0           return q{Ecyrillic::POSTMATCH()};
3196             }
3197              
3198             # scalar variable $scalar =~ tr///;
3199             # scalar variable $scalar =~ s///;
3200             # substr() =~ tr///;
3201             # substr() =~ s///;
3202             elsif (/\G ( \$ $qq_scalar | $qq_substr ) /oxgc) {
3203 0           my $scalar = e_string($1);
3204              
3205 0 0         if (/\G ( (?>\s*) (?: =~ | !~ ) (?>\s*) ) (?= (?: tr | y ) \b ) /oxgc) {
    0          
3206 0           $tr_variable = $scalar;
3207 0           $bind_operator = $1;
3208 0           $slash = 'm//';
3209 0           return '';
3210             }
3211             elsif (/\G ( (?>\s*) (?: =~ | !~ ) (?>\s*) ) (?= s \b ) /oxgc) {
3212 0           $sub_variable = $scalar;
3213 0           $bind_operator = $1;
3214 0           $slash = 'm//';
3215 0           return '';
3216             }
3217             else {
3218 0           $slash = 'div';
3219 0           return $scalar;
3220             }
3221             }
3222              
3223             # end of statement
3224             elsif (/\G ( [,;] ) /oxgc) {
3225 0           $slash = 'm//';
3226              
3227             # clear tr/// variable
3228 0           $tr_variable = '';
3229              
3230             # clear s/// variable
3231 0           $sub_variable = '';
3232              
3233 0           $bind_operator = '';
3234              
3235 0           return $1;
3236             }
3237              
3238             # bareword
3239             elsif (/\G ( \{ (?>\s*) (?: tr | index | rindex | reverse ) (?>\s*) \} ) /oxmsgc) {
3240 0           return $1;
3241             }
3242              
3243             # $0 --> $0
3244             elsif (/\G ( \$ 0 ) /oxmsgc) {
3245 0           $slash = 'div';
3246 0           return $1;
3247             }
3248             elsif (/\G ( \$ \{ (?>\s*) 0 (?>\s*) \} ) /oxmsgc) {
3249 0           $slash = 'div';
3250 0           return $1;
3251             }
3252              
3253             # $$ --> $$
3254             elsif (/\G ( \$ \$ ) (?![\w\{]) /oxmsgc) {
3255 0           $slash = 'div';
3256 0           return $1;
3257             }
3258              
3259             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
3260             # $1, $2, $3 --> $1, $2, $3 otherwise
3261             elsif (/\G \$ ((?>[1-9][0-9]*)) /oxmsgc) {
3262 0           $slash = 'div';
3263 0           return e_capture($1);
3264             }
3265             elsif (/\G \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} /oxmsgc) {
3266 0           $slash = 'div';
3267 0           return e_capture($1);
3268             }
3269              
3270             # $$foo[ ... ] --> $ $foo->[ ... ]
3271             elsif (/\G \$ ( \$ (?> [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ .+? \] ) /oxmsgc) {
3272 0           $slash = 'div';
3273 0           return e_capture($1.'->'.$2);
3274             }
3275              
3276             # $$foo{ ... } --> $ $foo->{ ... }
3277             elsif (/\G \$ ( \$ (?> [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ .+? \} ) /oxmsgc) {
3278 0           $slash = 'div';
3279 0           return e_capture($1.'->'.$2);
3280             }
3281              
3282             # $$foo
3283             elsif (/\G \$ ( \$ (?> [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) /oxmsgc) {
3284 0           $slash = 'div';
3285 0           return e_capture($1);
3286             }
3287              
3288             # ${ foo }
3289             elsif (/\G \$ (?>\s*) \{ ( (?>\s*) (?> [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* ) (?>\s*) ) \} /oxmsgc) {
3290 0           $slash = 'div';
3291 0           return '${' . $1 . '}';
3292             }
3293              
3294             # ${ ... }
3295             elsif (/\G \$ (?>\s*) \{ (?>\s*) ( $qq_brace ) (?>\s*) \} /oxmsgc) {
3296 0           $slash = 'div';
3297 0           return e_capture($1);
3298             }
3299              
3300             # variable or function
3301             # $ @ % & * $ #
3302             elsif (/\G ( (?: [\$\@\%\&\*] | \$\# | -> | \b sub \b) (?>\s*) (?: split | chop | index | rindex | lc | uc | fc | chr | ord | reverse | getc | tr | y | q | qq | qx | qw | m | s | qr | glob | lstat | opendir | stat | unlink | chdir ) ) \b /oxmsgc) {
3303 0           $slash = 'div';
3304 0           return $1;
3305             }
3306             # $ $ $ $ $ $ $ $ $ $ $ $ $ $
3307             # $ @ # \ ' " / ? ( ) [ ] < >
3308             elsif (/\G ( \$[\$\@\#\\\'\"\/\?\(\)\[\]\<\>] ) /oxmsgc) {
3309 0           $slash = 'div';
3310 0           return $1;
3311             }
3312              
3313             # while ()
3314             elsif (/\G \b (while (?>\s*) \( (?>\s*) <[\$]?[A-Za-z_][A-Za-z_0-9]*> (?>\s*) \)) \b /oxgc) {
3315 0           return $1;
3316             }
3317              
3318             # while () --- glob
3319              
3320             # avoid "Error: Runtime exception" of perl version 5.005_03
3321              
3322             elsif (/\G \b while (?>\s*) \( (?>\s*) < ((?:[^>\0\a\e\f\n\r\t])+?) > (?>\s*) \) \b /oxgc) {
3323 0           return 'while ($_ = Ecyrillic::glob("' . $1 . '"))';
3324             }
3325              
3326             # while (glob)
3327             elsif (/\G \b while (?>\s*) \( (?>\s*) glob (?>\s*) \) /oxgc) {
3328 0           return 'while ($_ = Ecyrillic::glob_)';
3329             }
3330              
3331             # while (glob(WILDCARD))
3332             elsif (/\G \b while (?>\s*) \( (?>\s*) glob \b /oxgc) {
3333 0           return 'while ($_ = Ecyrillic::glob';
3334             }
3335              
3336             # doit if, doit unless, doit while, doit until, doit for, doit when
3337 0           elsif (/\G \b ( if | unless | while | until | for | when ) \b /oxgc) { $slash = 'm//'; return $1; }
  0            
3338              
3339             # subroutines of package Ecyrillic
3340 0           elsif (/\G \b (CORE:: | ->(>?\s*) (?: atan2 | [a-z]{2,})) \b /oxgc) { $slash = 'm//'; return $1; }
  0            
3341 0           elsif (/\G \b Char::eval (?= (?>\s*) \{ ) /oxgc) { $slash = 'm//'; return 'eval'; }
  0            
3342 0           elsif (/\G \b Cyrillic::eval (?= (?>\s*) \{ ) /oxgc) { $slash = 'm//'; return 'eval'; }
  0            
3343 0           elsif (/\G \b Char::eval \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'eval Char::escape'; }
  0            
3344 0           elsif (/\G \b Cyrillic::eval \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'eval Cyrillic::escape'; }
  0            
3345 0           elsif (/\G \b bytes::substr \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'substr'; }
  0            
3346 0           elsif (/\G \b chop \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::chop'; }
  0            
3347 0           elsif (/\G \b bytes::index \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'index'; }
  0            
3348 0           elsif (/\G \b Char::index \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Char::index'; }
  0            
3349 0           elsif (/\G \b Cyrillic::index \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Cyrillic::index'; }
  0            
3350 0           elsif (/\G \b index \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::index'; }
  0            
3351 0           elsif (/\G \b bytes::rindex \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'rindex'; }
  0            
3352 0           elsif (/\G \b Char::rindex \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Char::rindex'; }
  0            
3353 0           elsif (/\G \b Cyrillic::rindex \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Cyrillic::rindex'; }
  0            
3354 0           elsif (/\G \b rindex \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::rindex'; }
  0            
3355 0           elsif (/\G \b lc (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::lc'; }
  0            
3356 0           elsif (/\G \b lcfirst (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::lcfirst'; }
  0            
3357 0           elsif (/\G \b uc (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::uc'; }
  0            
3358 0           elsif (/\G \b ucfirst (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::ucfirst'; }
  0            
3359 0           elsif (/\G \b fc (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::fc'; }
  0            
3360              
3361             # "-s '' ..." means file test "-s 'filename' ..." (not means "- s/// ...")
3362 0           elsif (/\G -s (?>\s*) (\") ((?:$qq_char)+?) (\") /oxgc) { $slash = 'm//'; return '-s ' . e_qq('', $1,$3,$2); }
  0            
3363 0           elsif (/\G -s (?>\s+) qq (?>\s*) (\#) ((?:$qq_char)+?) (\#) /oxgc) { $slash = 'm//'; return '-s ' . e_qq('qq',$1,$3,$2); }
  0            
3364 0           elsif (/\G -s (?>\s+) qq (?>\s*) (\() ((?:$qq_paren)+?) (\)) /oxgc) { $slash = 'm//'; return '-s ' . e_qq('qq',$1,$3,$2); }
  0            
3365 0           elsif (/\G -s (?>\s+) qq (?>\s*) (\{) ((?:$qq_brace)+?) (\}) /oxgc) { $slash = 'm//'; return '-s ' . e_qq('qq',$1,$3,$2); }
  0            
3366 0           elsif (/\G -s (?>\s+) qq (?>\s*) (\[) ((?:$qq_bracket)+?) (\]) /oxgc) { $slash = 'm//'; return '-s ' . e_qq('qq',$1,$3,$2); }
  0            
3367 0           elsif (/\G -s (?>\s+) qq (?>\s*) (\<) ((?:$qq_angle)+?) (\>) /oxgc) { $slash = 'm//'; return '-s ' . e_qq('qq',$1,$3,$2); }
  0            
3368 0           elsif (/\G -s (?>\s+) qq (?>\s*) (\S) ((?:$qq_char)+?) (\1) /oxgc) { $slash = 'm//'; return '-s ' . e_qq('qq',$1,$3,$2); }
  0            
3369              
3370 0           elsif (/\G -s (?>\s*) (\') ((?:\\\'|\\\\|$q_char)+?) (\') /oxgc) { $slash = 'm//'; return '-s ' . e_q ('', $1,$3,$2); }
  0            
3371 0           elsif (/\G -s (?>\s+) q (?>\s*) (\#) ((?:\\\#|\\\\|$q_char)+?) (\#) /oxgc) { $slash = 'm//'; return '-s ' . e_q ('q', $1,$3,$2); }
  0            
3372 0           elsif (/\G -s (?>\s+) q (?>\s*) (\() ((?:\\\)|\\\\|$q_paren)+?) (\)) /oxgc) { $slash = 'm//'; return '-s ' . e_q ('q', $1,$3,$2); }
  0            
3373 0           elsif (/\G -s (?>\s+) q (?>\s*) (\{) ((?:\\\}|\\\\|$q_brace)+?) (\}) /oxgc) { $slash = 'm//'; return '-s ' . e_q ('q', $1,$3,$2); }
  0            
3374 0           elsif (/\G -s (?>\s+) q (?>\s*) (\[) ((?:\\\]|\\\\|$q_bracket)+?) (\]) /oxgc) { $slash = 'm//'; return '-s ' . e_q ('q', $1,$3,$2); }
  0            
3375 0           elsif (/\G -s (?>\s+) q (?>\s*) (\<) ((?:\\\>|\\\\|$q_angle)+?) (\>) /oxgc) { $slash = 'm//'; return '-s ' . e_q ('q', $1,$3,$2); }
  0            
3376 0           elsif (/\G -s (?>\s+) q (?>\s*) (\S) ((?:\\\1|\\\\|$q_char)+?) (\1) /oxgc) { $slash = 'm//'; return '-s ' . e_q ('q', $1,$3,$2); }
  0            
3377              
3378             elsif (/\G -s (?>\s*) (\$ (?> \w+ (?: ::\w+)* ) (?: (?: ->)? (?: [\$\@\%\&\*]\* | \$\#\* | \( (?:$qq_paren)*? \) | [\@\%\*]? \{ (?:$qq_brace)+? \} | [\@\%]? \[ (?:$qq_bracket)+? \] ) )*) /oxgc)
3379 0           { $slash = 'm//'; return "-s $1"; }
  0            
3380 0           elsif (/\G -s (?>\s*) \( ((?:$qq_paren)*?) \) /oxgc) { $slash = 'm//'; return "-s ($1)"; }
  0            
3381 0           elsif (/\G -s (?= (?>\s+) [a-z]+) /oxgc) { $slash = 'm//'; return '-s'; }
  0            
3382 0           elsif (/\G -s (?>\s+) ((?>\w+)) /oxgc) { $slash = 'm//'; return "-s $1"; }
  0            
3383              
3384 0           elsif (/\G \b bytes::length (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'length'; }
  0            
3385 0           elsif (/\G \b bytes::chr (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'chr'; }
  0            
3386 0           elsif (/\G \b chr (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::chr'; }
  0            
3387 0           elsif (/\G \b bytes::ord (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'div'; return 'ord'; }
  0            
3388 0           elsif (/\G \b ord (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'div'; return $function_ord; }
  0            
3389 0           elsif (/\G \b glob (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $slash = 'm//'; return 'Ecyrillic::glob'; }
  0            
3390 0           elsif (/\G \b lc \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::lc_'; }
  0            
3391 0           elsif (/\G \b lcfirst \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::lcfirst_'; }
  0            
3392 0           elsif (/\G \b uc \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::uc_'; }
  0            
3393 0           elsif (/\G \b ucfirst \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::ucfirst_'; }
  0            
3394 0           elsif (/\G \b fc \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::fc_'; }
  0            
3395 0           elsif (/\G -s \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return '-s '; }
  0            
3396              
3397 0           elsif (/\G \b bytes::length \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'length'; }
  0            
3398 0           elsif (/\G \b bytes::chr \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'chr'; }
  0            
3399 0           elsif (/\G \b chr \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::chr_'; }
  0            
3400 0           elsif (/\G \b bytes::ord \b (?! (?>\s*) => ) /oxgc) { $slash = 'div'; return 'ord'; }
  0            
3401 0           elsif (/\G \b ord \b (?! (?>\s*) => ) /oxgc) { $slash = 'div'; return $function_ord_; }
  0            
3402 0           elsif (/\G \b glob \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return 'Ecyrillic::glob_'; }
  0            
3403 0           elsif (/\G \b reverse \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return $function_reverse; }
  0            
3404 0           elsif (/\G \b getc \b (?! (?>\s*) => ) /oxgc) { $slash = 'm//'; return $function_getc; }
  0            
3405             # split
3406             elsif (/\G \b (split) \b (?! (?>\s*) => ) /oxgc) {
3407 0           $slash = 'm//';
3408              
3409 0           my $e = '';
3410 0           while (/\G ( (?>\s+) | \( | \#.* ) /oxgc) {
3411 0           $e .= $1;
3412             }
3413              
3414             # end of split
3415 0 0         if (/\G (?= [,;\)\}\]] ) /oxgc) { return 'Ecyrillic::split' . $e; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3416              
3417             # split scalar value
3418 0           elsif (/\G ( [\$\@\&\*] $qq_scalar ) /oxgc) { return 'Ecyrillic::split' . $e . e_string($1); }
3419              
3420             # split literal space
3421 0           elsif (/\G \b qq (\#) [ ] (\#) /oxgc) { return 'Ecyrillic::split' . $e . qq {qq$1 $2}; }
3422 0           elsif (/\G \b qq ((?>\s*)) (\() [ ] (\)) /oxgc) { return 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; }
3423 0           elsif (/\G \b qq ((?>\s*)) (\{) [ ] (\}) /oxgc) { return 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; }
3424 0           elsif (/\G \b qq ((?>\s*)) (\[) [ ] (\]) /oxgc) { return 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; }
3425 0           elsif (/\G \b qq ((?>\s*)) (\<) [ ] (\>) /oxgc) { return 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; }
3426 0           elsif (/\G \b qq ((?>\s*)) (\S) [ ] (\2) /oxgc) { return 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; }
3427 0           elsif (/\G \b q (\#) [ ] (\#) /oxgc) { return 'Ecyrillic::split' . $e . qq {q$1 $2}; }
3428 0           elsif (/\G \b q ((?>\s*)) (\() [ ] (\)) /oxgc) { return 'Ecyrillic::split' . $e . qq {$1q$2 $3}; }
3429 0           elsif (/\G \b q ((?>\s*)) (\{) [ ] (\}) /oxgc) { return 'Ecyrillic::split' . $e . qq {$1q$2 $3}; }
3430 0           elsif (/\G \b q ((?>\s*)) (\[) [ ] (\]) /oxgc) { return 'Ecyrillic::split' . $e . qq {$1q$2 $3}; }
3431 0           elsif (/\G \b q ((?>\s*)) (\<) [ ] (\>) /oxgc) { return 'Ecyrillic::split' . $e . qq {$1q$2 $3}; }
3432 0           elsif (/\G \b q ((?>\s*)) (\S) [ ] (\2) /oxgc) { return 'Ecyrillic::split' . $e . qq {$1q$2 $3}; }
3433 0           elsif (/\G ' [ ] ' /oxgc) { return 'Ecyrillic::split' . $e . qq {' '}; }
3434 0           elsif (/\G " [ ] " /oxgc) { return 'Ecyrillic::split' . $e . qq {" "}; }
3435              
3436             # split qq//
3437             elsif (/\G \b (qq) \b /oxgc) {
3438 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) /oxgc) { return e_split($e.'qr',$1,$3,$2,''); } # qq# # --> qr # #
  0            
3439             else {
3440 0           while (not /\G \z/oxgc) {
3441 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
3442 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) /oxgc) { return e_split($e.'qr',$1,$3,$2,''); } # qq ( ) --> qr ( )
3443 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) { return e_split($e.'qr',$1,$3,$2,''); } # qq { } --> qr { }
3444 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) { return e_split($e.'qr',$1,$3,$2,''); } # qq [ ] --> qr [ ]
3445 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) { return e_split($e.'qr',$1,$3,$2,''); } # qq < > --> qr < >
3446 0           elsif (/\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) /oxgc) { return e_split($e.'qr','{','}',$2,''); } # qq | | --> qr { }
3447 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) /oxgc) { return e_split($e.'qr',$1,$3,$2,''); } # qq * * --> qr * *
3448             }
3449 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3450             }
3451             }
3452              
3453             # split qr//
3454             elsif (/\G \b (qr) \b /oxgc) {
3455 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1,$3,$2,$4); } # qr# #
  0            
3456             else {
3457 0           while (not /\G \z/oxgc) {
3458 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
3459 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # qr ( )
3460 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # qr { }
3461 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # qr [ ]
3462 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # qr < >
3463 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([imosxpadlunbB]*) /oxgc) { return e_split_q($e.'qr',$1, $3, $2,$4); } # qr ' '
3464 0           elsif (/\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr','{','}',$2,$4); } # qr | | --> qr { }
3465 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([imosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # qr * *
3466             }
3467 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3468             }
3469             }
3470              
3471             # split q//
3472             elsif (/\G \b (q) \b /oxgc) {
3473 0 0         if (/\G (\#) ((?:\\\#|\\\\|$q_char)*?) (\#) /oxgc) { return e_split_q($e.'qr',$1,$3,$2,''); } # q# # --> qr # #
  0            
3474             else {
3475 0           while (not /\G \z/oxgc) {
3476 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
3477 0           elsif (/\G (\() ((?:\\\\|\\\)|\\\(|$q_paren)*?) (\)) /oxgc) { return e_split_q($e.'qr',$1,$3,$2,''); } # q ( ) --> qr ( )
3478 0           elsif (/\G (\{) ((?:\\\\|\\\}|\\\{|$q_brace)*?) (\}) /oxgc) { return e_split_q($e.'qr',$1,$3,$2,''); } # q { } --> qr { }
3479 0           elsif (/\G (\[) ((?:\\\\|\\\]|\\\[|$q_bracket)*?) (\]) /oxgc) { return e_split_q($e.'qr',$1,$3,$2,''); } # q [ ] --> qr [ ]
3480 0           elsif (/\G (\<) ((?:\\\\|\\\>|\\\<|$q_angle)*?) (\>) /oxgc) { return e_split_q($e.'qr',$1,$3,$2,''); } # q < > --> qr < >
3481 0           elsif (/\G ([*\-:?\\^|]) ((?:$q_char)*?) (\1) /oxgc) { return e_split_q($e.'qr','{','}',$2,''); } # q | | --> qr { }
3482 0           elsif (/\G (\S) ((?:\\\\|\\\1| $q_char)*?) (\1) /oxgc) { return e_split_q($e.'qr',$1,$3,$2,''); } # q * * --> qr * *
3483             }
3484 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3485             }
3486             }
3487              
3488             # split m//
3489             elsif (/\G \b (m) \b /oxgc) {
3490 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1,$3,$2,$4); } # m# # --> qr # #
  0            
3491             else {
3492 0           while (not /\G \z/oxgc) {
3493 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
3494 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # m ( ) --> qr ( )
3495 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # m { } --> qr { }
3496 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # m [ ] --> qr [ ]
3497 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # m < > --> qr < >
3498 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([cgimosxpadlunbB]*) /oxgc) { return e_split_q($e.'qr',$1, $3, $2,$4); } # m ' ' --> qr ' '
3499 0           elsif (/\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr','{','}',$2,$4); } # m | | --> qr { }
3500 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cgimosxpadlunbB]*) /oxgc) { return e_split ($e.'qr',$1, $3, $2,$4); } # m * * --> qr * *
3501             }
3502 0           die __FILE__, ": Search pattern not terminated\n";
3503             }
3504             }
3505              
3506             # split ''
3507             elsif (/\G (\') /oxgc) {
3508 0           my $q_string = '';
3509 0           while (not /\G \z/oxgc) {
3510 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
3511 0           elsif (/\G (\\\') /oxgc) { $q_string .= $1; } # splitqr'' --> split qr''
3512 0           elsif (/\G \' /oxgc) { return e_split_q($e.q{ qr},"'","'",$q_string,''); } # ' ' --> qr ' '
3513 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3514             }
3515 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3516             }
3517              
3518             # split ""
3519             elsif (/\G (\") /oxgc) {
3520 0           my $qq_string = '';
3521 0           while (not /\G \z/oxgc) {
3522 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
3523 0           elsif (/\G (\\\") /oxgc) { $qq_string .= $1; } # splitqr"" --> split qr""
3524 0           elsif (/\G \" /oxgc) { return e_split($e.q{ qr},'"','"',$qq_string,''); } # " " --> qr " "
3525 0           elsif (/\G ($q_char) /oxgc) { $qq_string .= $1; }
3526             }
3527 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3528             }
3529              
3530             # split //
3531             elsif (/\G (\/) /oxgc) {
3532 0           my $regexp = '';
3533 0           while (not /\G \z/oxgc) {
3534 0 0         if (/\G (\\\\) /oxgc) { $regexp .= $1; }
  0 0          
    0          
    0          
3535 0           elsif (/\G (\\\/) /oxgc) { $regexp .= $1; } # splitqr// --> split qr//
3536 0           elsif (/\G \/ ([cgimosxpadlunbB]*) /oxgc) { return e_split($e.q{ qr}, '/','/',$regexp,$1); } # / / --> qr / /
3537 0           elsif (/\G ($q_char) /oxgc) { $regexp .= $1; }
3538             }
3539 0           die __FILE__, ": Search pattern not terminated\n";
3540             }
3541             }
3542              
3543             # tr/// or y///
3544              
3545             # about [cdsrbB]* (/B modifier)
3546             #
3547             # P.559 appendix C
3548             # of ISBN 4-89052-384-7 Programming perl
3549             # (Japanese title is: Perl puroguramingu)
3550              
3551             elsif (/\G \b ( tr | y ) \b /oxgc) {
3552 0           my $ope = $1;
3553              
3554             # $1 $2 $3 $4 $5 $6
3555 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) ((?:$qq_char)*?) (\#) ([cdsrbB]*) /oxgc) { # tr# # #
3556 0           my @tr = ($tr_variable,$2);
3557 0           return e_tr(@tr,'',$4,$6);
3558             }
3559             else {
3560 0           my $e = '';
3561 0           while (not /\G \z/oxgc) {
3562 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3563             elsif (/\G (\() ((?:$qq_paren)*?) (\)) /oxgc) {
3564 0           my @tr = ($tr_variable,$2);
3565 0           while (not /\G \z/oxgc) {
3566 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3567 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr ( ) ( )
3568 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr ( ) { }
3569 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr ( ) [ ]
3570 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr ( ) < >
3571 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr ( ) * *
3572             }
3573 0           die __FILE__, ": Transliteration replacement not terminated\n";
3574             }
3575             elsif (/\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) {
3576 0           my @tr = ($tr_variable,$2);
3577 0           while (not /\G \z/oxgc) {
3578 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3579 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr { } ( )
3580 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr { } { }
3581 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr { } [ ]
3582 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr { } < >
3583 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr { } * *
3584             }
3585 0           die __FILE__, ": Transliteration replacement not terminated\n";
3586             }
3587             elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) {
3588 0           my @tr = ($tr_variable,$2);
3589 0           while (not /\G \z/oxgc) {
3590 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3591 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr [ ] ( )
3592 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr [ ] { }
3593 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr [ ] [ ]
3594 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr [ ] < >
3595 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr [ ] * *
3596             }
3597 0           die __FILE__, ": Transliteration replacement not terminated\n";
3598             }
3599             elsif (/\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) {
3600 0           my @tr = ($tr_variable,$2);
3601 0           while (not /\G \z/oxgc) {
3602 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3603 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr < > ( )
3604 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr < > { }
3605 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr < > [ ]
3606 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr < > < >
3607 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cdsrbB]*) /oxgc) { return e_tr(@tr,$e,$2,$4); } # tr < > * *
3608             }
3609 0           die __FILE__, ": Transliteration replacement not terminated\n";
3610             }
3611             # $1 $2 $3 $4 $5 $6
3612             elsif (/\G (\S) ((?:$qq_char)*?) (\1) ((?:$qq_char)*?) (\1) ([cdsrbB]*) /oxgc) { # tr * * *
3613 0           my @tr = ($tr_variable,$2);
3614 0           return e_tr(@tr,'',$4,$6);
3615             }
3616             }
3617 0           die __FILE__, ": Transliteration pattern not terminated\n";
3618             }
3619             }
3620              
3621             # qq//
3622             elsif (/\G \b (qq) \b /oxgc) {
3623 0           my $ope = $1;
3624              
3625             # if (/\G (\#) ((?:$qq_char)*?) (\#) /oxgc) { return e_qq($ope,$1,$3,$2); } # qq# #
3626 0 0         if (/\G (\#) /oxgc) { # qq# #
3627 0           my $qq_string = '';
3628 0           while (not /\G \z/oxgc) {
3629 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
3630 0           elsif (/\G (\\\#) /oxgc) { $qq_string .= $1; }
3631 0           elsif (/\G (\#) /oxgc) { return e_qq($ope,'#','#',$qq_string); }
3632 0           elsif (/\G ($qq_char) /oxgc) { $qq_string .= $1; }
3633             }
3634 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3635             }
3636              
3637             else {
3638 0           my $e = '';
3639 0           while (not /\G \z/oxgc) {
3640 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3641              
3642             # elsif (/\G (\() ((?:$qq_paren)*?) (\)) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qq ( )
3643             elsif (/\G (\() /oxgc) { # qq ( )
3644 0           my $qq_string = '';
3645 0           local $nest = 1;
3646 0           while (not /\G \z/oxgc) {
3647 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
    0          
3648 0           elsif (/\G (\\\)) /oxgc) { $qq_string .= $1; }
3649 0           elsif (/\G (\() /oxgc) { $qq_string .= $1; $nest++; }
  0            
3650             elsif (/\G (\)) /oxgc) {
3651 0 0         if (--$nest == 0) { return $e . e_qq($ope,'(',')',$qq_string); }
  0            
3652 0           else { $qq_string .= $1; }
3653             }
3654 0           elsif (/\G ($qq_char) /oxgc) { $qq_string .= $1; }
3655             }
3656 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3657             }
3658              
3659             # elsif (/\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qq { }
3660             elsif (/\G (\{) /oxgc) { # qq { }
3661 0           my $qq_string = '';
3662 0           local $nest = 1;
3663 0           while (not /\G \z/oxgc) {
3664 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
    0          
3665 0           elsif (/\G (\\\}) /oxgc) { $qq_string .= $1; }
3666 0           elsif (/\G (\{) /oxgc) { $qq_string .= $1; $nest++; }
  0            
3667             elsif (/\G (\}) /oxgc) {
3668 0 0         if (--$nest == 0) { return $e . e_qq($ope,'{','}',$qq_string); }
  0            
3669 0           else { $qq_string .= $1; }
3670             }
3671 0           elsif (/\G ($qq_char) /oxgc) { $qq_string .= $1; }
3672             }
3673 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3674             }
3675              
3676             # elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qq [ ]
3677             elsif (/\G (\[) /oxgc) { # qq [ ]
3678 0           my $qq_string = '';
3679 0           local $nest = 1;
3680 0           while (not /\G \z/oxgc) {
3681 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
    0          
3682 0           elsif (/\G (\\\]) /oxgc) { $qq_string .= $1; }
3683 0           elsif (/\G (\[) /oxgc) { $qq_string .= $1; $nest++; }
  0            
3684             elsif (/\G (\]) /oxgc) {
3685 0 0         if (--$nest == 0) { return $e . e_qq($ope,'[',']',$qq_string); }
  0            
3686 0           else { $qq_string .= $1; }
3687             }
3688 0           elsif (/\G ($qq_char) /oxgc) { $qq_string .= $1; }
3689             }
3690 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3691             }
3692              
3693             # elsif (/\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qq < >
3694             elsif (/\G (\<) /oxgc) { # qq < >
3695 0           my $qq_string = '';
3696 0           local $nest = 1;
3697 0           while (not /\G \z/oxgc) {
3698 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
    0          
3699 0           elsif (/\G (\\\>) /oxgc) { $qq_string .= $1; }
3700 0           elsif (/\G (\<) /oxgc) { $qq_string .= $1; $nest++; }
  0            
3701             elsif (/\G (\>) /oxgc) {
3702 0 0         if (--$nest == 0) { return $e . e_qq($ope,'<','>',$qq_string); }
  0            
3703 0           else { $qq_string .= $1; }
3704             }
3705 0           elsif (/\G ($qq_char) /oxgc) { $qq_string .= $1; }
3706             }
3707 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3708             }
3709              
3710             # elsif (/\G (\S) ((?:$qq_char)*?) (\1) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qq * *
3711             elsif (/\G (\S) /oxgc) { # qq * *
3712 0           my $delimiter = $1;
3713 0           my $qq_string = '';
3714 0           while (not /\G \z/oxgc) {
3715 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
3716 0           elsif (/\G (\\\Q$delimiter\E) /oxgc) { $qq_string .= $1; }
3717 0           elsif (/\G (\Q$delimiter\E) /oxgc) { return $e . e_qq($ope,$delimiter,$delimiter,$qq_string); }
3718 0           elsif (/\G ($qq_char) /oxgc) { $qq_string .= $1; }
3719             }
3720 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3721             }
3722             }
3723 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3724             }
3725             }
3726              
3727             # qr//
3728             elsif (/\G \b (qr) \b /oxgc) {
3729 0           my $ope = $1;
3730 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) ([imosxpadlunbB]*) /oxgc) { # qr# # #
3731 0           return e_qr($ope,$1,$3,$2,$4);
3732             }
3733             else {
3734 0           my $e = '';
3735 0           while (not /\G \z/oxgc) {
3736 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
3737 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([imosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # qr ( )
3738 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([imosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # qr { }
3739 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([imosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # qr [ ]
3740 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([imosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # qr < >
3741 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([imosxpadlunbB]*) /oxgc) { return $e . e_qr_q($ope,$1, $3, $2,$4); } # qr ' '
3742 0           elsif (/\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) ([imosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,'{','}',$2,$4); } # qr | | --> qr { }
3743 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([imosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # qr * *
3744             }
3745 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3746             }
3747             }
3748              
3749             # qw//
3750             elsif (/\G \b (qw) \b /oxgc) {
3751 0           my $ope = $1;
3752 0 0         if (/\G (\#) (.*?) (\#) /oxmsgc) { # qw# #
3753 0           return e_qw($ope,$1,$3,$2);
3754             }
3755             else {
3756 0           my $e = '';
3757 0           while (not /\G \z/oxgc) {
3758 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3759              
3760 0           elsif (/\G (\() ([^(]*?) (\)) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw ( )
3761 0           elsif (/\G (\() ((?:$q_paren)*?) (\)) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw ( )
3762              
3763 0           elsif (/\G (\{) ([^{]*?) (\}) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw { }
3764 0           elsif (/\G (\{) ((?:$q_brace)*?) (\}) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw { }
3765              
3766 0           elsif (/\G (\[) ([^[]*?) (\]) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw [ ]
3767 0           elsif (/\G (\[) ((?:$q_bracket)*?) (\]) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw [ ]
3768              
3769 0           elsif (/\G (\<) ([^<]*?) (\>) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw < >
3770 0           elsif (/\G (\<) ((?:$q_angle)*?) (\>) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw < >
3771              
3772 0           elsif (/\G ([\x21-\x3F]) (.*?) (\1) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw * *
3773 0           elsif (/\G (\S) ((?:$q_char)*?) (\1) /oxmsgc) { return $e . e_qw($ope,$1,$3,$2); } # qw * *
3774             }
3775 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3776             }
3777             }
3778              
3779             # qx//
3780             elsif (/\G \b (qx) \b /oxgc) {
3781 0           my $ope = $1;
3782 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) /oxgc) { # qx# #
3783 0           return e_qq($ope,$1,$3,$2);
3784             }
3785             else {
3786 0           my $e = '';
3787 0           while (not /\G \z/oxgc) {
3788 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
3789 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qx ( )
3790 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qx { }
3791 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qx [ ]
3792 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qx < >
3793 0           elsif (/\G (\') ((?:$qq_char)*?) (\') /oxgc) { return $e . e_q ($ope,$1,$3,$2); } # qx ' '
3794 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) /oxgc) { return $e . e_qq($ope,$1,$3,$2); } # qx * *
3795             }
3796 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3797             }
3798             }
3799              
3800             # q//
3801             elsif (/\G \b (q) \b /oxgc) {
3802 0           my $ope = $1;
3803              
3804             # if (/\G (\#) ((?:\\\#|\\\\|$q_char)*?) (\#) /oxgc) { return e_q($ope,$1,$3,$2); } # q# #
3805              
3806             # avoid "Error: Runtime exception" of perl version 5.005_03
3807             # (and so on)
3808              
3809 0 0         if (/\G (\#) /oxgc) { # q# #
3810 0           my $q_string = '';
3811 0           while (not /\G \z/oxgc) {
3812 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
3813 0           elsif (/\G (\\\#) /oxgc) { $q_string .= $1; }
3814 0           elsif (/\G (\#) /oxgc) { return e_q($ope,'#','#',$q_string); }
3815 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3816             }
3817 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3818             }
3819              
3820             else {
3821 0           my $e = '';
3822 0           while (not /\G \z/oxgc) {
3823 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3824              
3825             # elsif (/\G (\() ((?:\\\)|\\\\|$q_paren)*?) (\)) /oxgc) { return $e . e_q($ope,$1,$3,$2); } # q ( )
3826             elsif (/\G (\() /oxgc) { # q ( )
3827 0           my $q_string = '';
3828 0           local $nest = 1;
3829 0           while (not /\G \z/oxgc) {
3830 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3831 0           elsif (/\G (\\\)) /oxgc) { $q_string .= $1; }
3832 0           elsif (/\G (\\\() /oxgc) { $q_string .= $1; }
3833 0           elsif (/\G (\() /oxgc) { $q_string .= $1; $nest++; }
  0            
3834             elsif (/\G (\)) /oxgc) {
3835 0 0         if (--$nest == 0) { return $e . e_q($ope,'(',')',$q_string); }
  0            
3836 0           else { $q_string .= $1; }
3837             }
3838 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3839             }
3840 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3841             }
3842              
3843             # elsif (/\G (\{) ((?:\\\}|\\\\|$q_brace)*?) (\}) /oxgc) { return $e . e_q($ope,$1,$3,$2); } # q { }
3844             elsif (/\G (\{) /oxgc) { # q { }
3845 0           my $q_string = '';
3846 0           local $nest = 1;
3847 0           while (not /\G \z/oxgc) {
3848 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3849 0           elsif (/\G (\\\}) /oxgc) { $q_string .= $1; }
3850 0           elsif (/\G (\\\{) /oxgc) { $q_string .= $1; }
3851 0           elsif (/\G (\{) /oxgc) { $q_string .= $1; $nest++; }
  0            
3852             elsif (/\G (\}) /oxgc) {
3853 0 0         if (--$nest == 0) { return $e . e_q($ope,'{','}',$q_string); }
  0            
3854 0           else { $q_string .= $1; }
3855             }
3856 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3857             }
3858 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3859             }
3860              
3861             # elsif (/\G (\[) ((?:\\\]|\\\\|$q_bracket)*?) (\]) /oxgc) { return $e . e_q($ope,$1,$3,$2); } # q [ ]
3862             elsif (/\G (\[) /oxgc) { # q [ ]
3863 0           my $q_string = '';
3864 0           local $nest = 1;
3865 0           while (not /\G \z/oxgc) {
3866 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3867 0           elsif (/\G (\\\]) /oxgc) { $q_string .= $1; }
3868 0           elsif (/\G (\\\[) /oxgc) { $q_string .= $1; }
3869 0           elsif (/\G (\[) /oxgc) { $q_string .= $1; $nest++; }
  0            
3870             elsif (/\G (\]) /oxgc) {
3871 0 0         if (--$nest == 0) { return $e . e_q($ope,'[',']',$q_string); }
  0            
3872 0           else { $q_string .= $1; }
3873             }
3874 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3875             }
3876 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3877             }
3878              
3879             # elsif (/\G (\<) ((?:\\\>|\\\\|$q_angle)*?) (\>) /oxgc) { return $e . e_q($ope,$1,$3,$2); } # q < >
3880             elsif (/\G (\<) /oxgc) { # q < >
3881 0           my $q_string = '';
3882 0           local $nest = 1;
3883 0           while (not /\G \z/oxgc) {
3884 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
    0          
    0          
3885 0           elsif (/\G (\\\>) /oxgc) { $q_string .= $1; }
3886 0           elsif (/\G (\\\<) /oxgc) { $q_string .= $1; }
3887 0           elsif (/\G (\<) /oxgc) { $q_string .= $1; $nest++; }
  0            
3888             elsif (/\G (\>) /oxgc) {
3889 0 0         if (--$nest == 0) { return $e . e_q($ope,'<','>',$q_string); }
  0            
3890 0           else { $q_string .= $1; }
3891             }
3892 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3893             }
3894 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3895             }
3896              
3897             # elsif (/\G (\S) ((?:\\\1|\\\\|$q_char)*?) (\1) /oxgc) { return $e . e_q($ope,$1,$3,$2); } # q * *
3898             elsif (/\G (\S) /oxgc) { # q * *
3899 0           my $delimiter = $1;
3900 0           my $q_string = '';
3901 0           while (not /\G \z/oxgc) {
3902 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
3903 0           elsif (/\G (\\\Q$delimiter\E) /oxgc) { $q_string .= $1; }
3904 0           elsif (/\G (\Q$delimiter\E) /oxgc) { return $e . e_q($ope,$delimiter,$delimiter,$q_string); }
3905 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
3906             }
3907 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3908             }
3909             }
3910 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
3911             }
3912             }
3913              
3914             # m//
3915             elsif (/\G \b (m) \b /oxgc) {
3916 0           my $ope = $1;
3917 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) ([cgimosxpadlunbB]*) /oxgc) { # m# #
3918 0           return e_qr($ope,$1,$3,$2,$4);
3919             }
3920             else {
3921 0           my $e = '';
3922 0           while (not /\G \z/oxgc) {
3923 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3924 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # m ( )
3925 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # m { }
3926 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # m [ ]
3927 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # m < >
3928 0           elsif (/\G (\?) ((?:$qq_char)*?) (\?) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # m ? ?
3929 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr_q($ope,$1, $3, $2,$4); } # m ' '
3930 0           elsif (/\G ([*\-:\\^|]) ((?:$qq_char)*?) (\1) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,'{','}',$2,$4); } # m | | --> m { }
3931 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cgimosxpadlunbB]*) /oxgc) { return $e . e_qr ($ope,$1, $3, $2,$4); } # m * *
3932             }
3933 0           die __FILE__, ": Search pattern not terminated\n";
3934             }
3935             }
3936              
3937             # s///
3938              
3939             # about [cegimosxpradlunbB]* (/cg modifier)
3940             #
3941             # P.67 Pattern-Matching Operators
3942             # of ISBN 0-596-00241-6 Perl in a Nutshell, Second Edition.
3943              
3944             elsif (/\G \b (s) \b /oxgc) {
3945 0           my $ope = $1;
3946              
3947             # $1 $2 $3 $4 $5 $6
3948 0 0         if (/\G (\#) ((?:$qq_char)*?) (\#) ((?:$qq_char)*?) (\#) ([cegimosxpradlunbB]*) /oxgc) { # s# # #
3949 0           return e_sub($sub_variable,$1,$2,$3,$3,$4,$5,$6);
3950             }
3951             else {
3952 0           my $e = '';
3953 0           while (not /\G \z/oxgc) {
3954 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3955             elsif (/\G (\() ((?:$qq_paren)*?) (\)) /oxgc) {
3956 0           my @s = ($1,$2,$3);
3957 0           while (not /\G \z/oxgc) {
3958 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3959             # $1 $2 $3 $4
3960 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3961 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3962 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3963 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3964 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3965 0           elsif (/\G (\$) ((?:$qq_char)*?) (\$) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3966 0           elsif (/\G (\:) ((?:$qq_char)*?) (\:) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3967 0           elsif (/\G (\@) ((?:$qq_char)*?) (\@) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3968 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3969             }
3970 0           die __FILE__, ": Substitution replacement not terminated\n";
3971             }
3972             elsif (/\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) {
3973 0           my @s = ($1,$2,$3);
3974 0           while (not /\G \z/oxgc) {
3975 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
3976             # $1 $2 $3 $4
3977 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3978 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3979 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3980 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3981 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3982 0           elsif (/\G (\$) ((?:$qq_char)*?) (\$) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3983 0           elsif (/\G (\:) ((?:$qq_char)*?) (\:) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3984 0           elsif (/\G (\@) ((?:$qq_char)*?) (\@) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3985 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3986             }
3987 0           die __FILE__, ": Substitution replacement not terminated\n";
3988             }
3989             elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) {
3990 0           my @s = ($1,$2,$3);
3991 0           while (not /\G \z/oxgc) {
3992 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
3993             # $1 $2 $3 $4
3994 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3995 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3996 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3997 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3998 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
3999 0           elsif (/\G (\$) ((?:$qq_char)*?) (\$) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4000 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4001             }
4002 0           die __FILE__, ": Substitution replacement not terminated\n";
4003             }
4004             elsif (/\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) {
4005 0           my @s = ($1,$2,$3);
4006 0           while (not /\G \z/oxgc) {
4007 0 0         if (/\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4008             # $1 $2 $3 $4
4009 0           elsif (/\G (\() ((?:$qq_paren)*?) (\)) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4010 0           elsif (/\G (\{) ((?:$qq_brace)*?) (\}) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4011 0           elsif (/\G (\[) ((?:$qq_bracket)*?) (\]) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4012 0           elsif (/\G (\<) ((?:$qq_angle)*?) (\>) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4013 0           elsif (/\G (\') ((?:$qq_char)*?) (\') ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4014 0           elsif (/\G (\$) ((?:$qq_char)*?) (\$) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4015 0           elsif (/\G (\:) ((?:$qq_char)*?) (\:) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4016 0           elsif (/\G (\@) ((?:$qq_char)*?) (\@) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4017 0           elsif (/\G (\S) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) { return e_sub($sub_variable,@s,$1,$2,$3,$4); }
4018             }
4019 0           die __FILE__, ": Substitution replacement not terminated\n";
4020             }
4021             # $1 $2 $3 $4 $5 $6
4022             elsif (/\G (\') ((?:$qq_char)*?) (\') ((?:$qq_char)*?) (\') ([cegimosxpradlunbB]*) /oxgc) {
4023 0           return e_sub($sub_variable,$1,$2,$3,$3,$4,$5,$6);
4024             }
4025             # $1 $2 $3 $4 $5 $6
4026             elsif (/\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) {
4027 0           return e_sub($sub_variable,'{',$2,'}','{',$4,'}',$6); # s | | | --> s { } { }
4028             }
4029             # $1 $2 $3 $4 $5 $6
4030             elsif (/\G (\$) ((?:$qq_char)*?) (\1) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) {
4031 0           return e_sub($sub_variable,$1,$2,$3,$3,$4,$5,$6);
4032             }
4033             # $1 $2 $3 $4 $5 $6
4034             elsif (/\G (\S) ((?:$qq_char)*?) (\1) ((?:$qq_char)*?) (\1) ([cegimosxpradlunbB]*) /oxgc) {
4035 0           return e_sub($sub_variable,$1,$2,$3,$3,$4,$5,$6);
4036             }
4037             }
4038 0           die __FILE__, ": Substitution pattern not terminated\n";
4039             }
4040             }
4041              
4042             # require ignore module
4043 0           elsif (/\G \b require ((?>\s+) (?:$ignore_modules) .*? ;) ([ \t]* [#\n]) /oxmsgc) { return "# require$1$2"; }
4044 0           elsif (/\G \b require ((?>\s+) (?:$ignore_modules) .*? ;) ([ \t]* [^#]) /oxmsgc) { return "# require$1\n$2"; }
4045 0           elsif (/\G \b require ((?>\s+) (?:$ignore_modules)) \b /oxmsgc) { return "# require$1"; }
4046              
4047             # use strict; --> use strict; no strict qw(refs);
4048 0           elsif (/\G \b use ((?>\s+) strict .*? ;) ([ \t]* [#\n]) /oxmsgc) { return "use$1 no strict qw(refs);$2"; }
4049 0           elsif (/\G \b use ((?>\s+) strict .*? ;) ([ \t]* [^#]) /oxmsgc) { return "use$1 no strict qw(refs);\n$2"; }
4050 0           elsif (/\G \b use ((?>\s+) strict) \b /oxmsgc) { return "use$1; no strict qw(refs)"; }
4051              
4052             # use 5.12.0; --> use 5.12.0; no strict qw(refs);
4053             elsif (/\G \b use (?>\s+) ((?>([1-9][0-9_]*)(?:\.([0-9_]+))*)) (?>\s*) ; /oxmsgc) {
4054 0 0 0       if (($2 >= 6) or (($2 == 5) and ($3 ge '012'))) {
      0        
4055 0           return "use $1; no strict qw(refs);";
4056             }
4057             else {
4058 0           return "use $1;";
4059             }
4060             }
4061             elsif (/\G \b use (?>\s+) ((?>v([0-9][0-9_]*)(?:\.([0-9_]+))*)) (?>\s*) ; /oxmsgc) {
4062 0 0 0       if (($2 >= 6) or (($2 == 5) and ($3 >= 12))) {
      0        
4063 0           return "use $1; no strict qw(refs);";
4064             }
4065             else {
4066 0           return "use $1;";
4067             }
4068             }
4069              
4070             # ignore use module
4071 0           elsif (/\G \b use ((?>\s+) (?:$ignore_modules) .*? ;) ([ \t]* [#\n]) /oxmsgc) { return "# use$1$2"; }
4072 0           elsif (/\G \b use ((?>\s+) (?:$ignore_modules) .*? ;) ([ \t]* [^#]) /oxmsgc) { return "# use$1\n$2"; }
4073 0           elsif (/\G \b use ((?>\s+) (?:$ignore_modules)) \b /oxmsgc) { return "# use$1"; }
4074              
4075             # ignore no module
4076 0           elsif (/\G \b no ((?>\s+) (?:$ignore_modules) .*? ;) ([ \t]* [#\n]) /oxmsgc) { return "# no$1$2"; }
4077 0           elsif (/\G \b no ((?>\s+) (?:$ignore_modules) .*? ;) ([ \t]* [^#]) /oxmsgc) { return "# no$1\n$2"; }
4078 0           elsif (/\G \b no ((?>\s+) (?:$ignore_modules)) \b /oxmsgc) { return "# no$1"; }
4079              
4080             # use else
4081 0           elsif (/\G \b use \b /oxmsgc) { return "use"; }
4082              
4083             # use else
4084 0           elsif (/\G \b no \b /oxmsgc) { return "no"; }
4085              
4086             # ''
4087             elsif (/\G (?
4088 0           my $q_string = '';
4089 0           while (not /\G \z/oxgc) {
4090 0 0         if (/\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
4091 0           elsif (/\G (\\\') /oxgc) { $q_string .= $1; }
4092 0           elsif (/\G \' /oxgc) { return e_q('', "'","'",$q_string); }
4093 0           elsif (/\G ($q_char) /oxgc) { $q_string .= $1; }
4094             }
4095 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4096             }
4097              
4098             # ""
4099             elsif (/\G (\") /oxgc) {
4100 0           my $qq_string = '';
4101 0           while (not /\G \z/oxgc) {
4102 0 0         if (/\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
4103 0           elsif (/\G (\\\") /oxgc) { $qq_string .= $1; }
4104 0           elsif (/\G \" /oxgc) { return e_qq('', '"','"',$qq_string); }
4105 0           elsif (/\G ($q_char) /oxgc) { $qq_string .= $1; }
4106             }
4107 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4108             }
4109              
4110             # ``
4111             elsif (/\G (\`) /oxgc) {
4112 0           my $qx_string = '';
4113 0           while (not /\G \z/oxgc) {
4114 0 0         if (/\G (\\\\) /oxgc) { $qx_string .= $1; }
  0 0          
    0          
    0          
4115 0           elsif (/\G (\\\`) /oxgc) { $qx_string .= $1; }
4116 0           elsif (/\G \` /oxgc) { return e_qq('', '`','`',$qx_string); }
4117 0           elsif (/\G ($q_char) /oxgc) { $qx_string .= $1; }
4118             }
4119 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4120             }
4121              
4122             # // --- not divide operator (num / num), not defined-or
4123             elsif (($slash eq 'm//') and /\G (\/) /oxgc) {
4124 0           my $regexp = '';
4125 0           while (not /\G \z/oxgc) {
4126 0 0         if (/\G (\\\\) /oxgc) { $regexp .= $1; }
  0 0          
    0          
    0          
4127 0           elsif (/\G (\\\/) /oxgc) { $regexp .= $1; }
4128 0           elsif (/\G \/ ([cgimosxpadlunbB]*) /oxgc) { return e_qr('', '/','/',$regexp,$1); }
4129 0           elsif (/\G ($q_char) /oxgc) { $regexp .= $1; }
4130             }
4131 0           die __FILE__, ": Search pattern not terminated\n";
4132             }
4133              
4134             # ?? --- not conditional operator (condition ? then : else)
4135             elsif (($slash eq 'm//') and /\G (\?) /oxgc) {
4136 0           my $regexp = '';
4137 0           while (not /\G \z/oxgc) {
4138 0 0         if (/\G (\\\\) /oxgc) { $regexp .= $1; }
  0 0          
    0          
    0          
4139 0           elsif (/\G (\\\?) /oxgc) { $regexp .= $1; }
4140 0           elsif (/\G \? ([cgimosxpadlunbB]*) /oxgc) { return e_qr('m','?','?',$regexp,$1); }
4141 0           elsif (/\G ($q_char) /oxgc) { $regexp .= $1; }
4142             }
4143 0           die __FILE__, ": Search pattern not terminated\n";
4144             }
4145              
4146             # <<>> (a safer ARGV)
4147 0           elsif (/\G ( <<>> ) /oxgc) { $slash = 'm//'; return $1; }
  0            
4148              
4149             # << (bit shift) --- not here document
4150 0           elsif (/\G ( << (?>\s*) ) (?= [0-9\$\@\&] ) /oxgc) { $slash = 'm//'; return $1; }
  0            
4151              
4152             # <<'HEREDOC'
4153             elsif (/\G ( << '([a-zA-Z_0-9]*)' ) /oxgc) {
4154 0           $slash = 'm//';
4155 0           my $here_quote = $1;
4156 0           my $delimiter = $2;
4157              
4158             # get here document
4159 0 0         if ($here_script eq '') {
4160 0           $here_script = CORE::substr $_, pos $_;
4161 0           $here_script =~ s/.*?\n//oxm;
4162             }
4163 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4164 0           push @heredoc, $1 . qq{\n$delimiter\n};
4165 0           push @heredoc_delimiter, $delimiter;
4166             }
4167             else {
4168 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4169             }
4170 0           return $here_quote;
4171             }
4172              
4173             # <<\HEREDOC
4174              
4175             # P.66 2.6.6. "Here" Documents
4176             # in Chapter 2: Bits and Pieces
4177             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
4178              
4179             # P.73 "Here" Documents
4180             # in Chapter 2: Bits and Pieces
4181             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
4182              
4183             elsif (/\G ( << \\([a-zA-Z_0-9]+) ) /oxgc) {
4184 0           $slash = 'm//';
4185 0           my $here_quote = $1;
4186 0           my $delimiter = $2;
4187              
4188             # get here document
4189 0 0         if ($here_script eq '') {
4190 0           $here_script = CORE::substr $_, pos $_;
4191 0           $here_script =~ s/.*?\n//oxm;
4192             }
4193 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4194 0           push @heredoc, $1 . qq{\n$delimiter\n};
4195 0           push @heredoc_delimiter, $delimiter;
4196             }
4197             else {
4198 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4199             }
4200 0           return $here_quote;
4201             }
4202              
4203             # <<"HEREDOC"
4204             elsif (/\G ( << "([a-zA-Z_0-9]*)" ) /oxgc) {
4205 0           $slash = 'm//';
4206 0           my $here_quote = $1;
4207 0           my $delimiter = $2;
4208              
4209             # get here document
4210 0 0         if ($here_script eq '') {
4211 0           $here_script = CORE::substr $_, pos $_;
4212 0           $here_script =~ s/.*?\n//oxm;
4213             }
4214 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4215 0           push @heredoc, e_heredoc($1) . qq{\n$delimiter\n};
4216 0           push @heredoc_delimiter, $delimiter;
4217             }
4218             else {
4219 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4220             }
4221 0           return $here_quote;
4222             }
4223              
4224             # <
4225             elsif (/\G ( << ([a-zA-Z_0-9]+) ) /oxgc) {
4226 0           $slash = 'm//';
4227 0           my $here_quote = $1;
4228 0           my $delimiter = $2;
4229              
4230             # get here document
4231 0 0         if ($here_script eq '') {
4232 0           $here_script = CORE::substr $_, pos $_;
4233 0           $here_script =~ s/.*?\n//oxm;
4234             }
4235 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4236 0           push @heredoc, e_heredoc($1) . qq{\n$delimiter\n};
4237 0           push @heredoc_delimiter, $delimiter;
4238             }
4239             else {
4240 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4241             }
4242 0           return $here_quote;
4243             }
4244              
4245             # <<`HEREDOC`
4246             elsif (/\G ( << `([a-zA-Z_0-9]*)` ) /oxgc) {
4247 0           $slash = 'm//';
4248 0           my $here_quote = $1;
4249 0           my $delimiter = $2;
4250              
4251             # get here document
4252 0 0         if ($here_script eq '') {
4253 0           $here_script = CORE::substr $_, pos $_;
4254 0           $here_script =~ s/.*?\n//oxm;
4255             }
4256 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4257 0           push @heredoc, e_heredoc($1) . qq{\n$delimiter\n};
4258 0           push @heredoc_delimiter, $delimiter;
4259             }
4260             else {
4261 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4262             }
4263 0           return $here_quote;
4264             }
4265              
4266             # <<= <=> <= < operator
4267             elsif (/\G ( <<= | <=> | <= | < ) (?= (?>\s*) [A-Za-z_0-9'"`\$\@\&\*\(\+\-] )/oxgc) {
4268 0           return $1;
4269             }
4270              
4271             #
4272             elsif (/\G (<[\$]?[A-Za-z_][A-Za-z_0-9]*>) /oxgc) {
4273 0           return $1;
4274             }
4275              
4276             # --- glob
4277              
4278             # avoid "Error: Runtime exception" of perl version 5.005_03
4279              
4280             elsif (/\G < ((?:[^>\0\a\e\f\n\r\t])+?) > /oxgc) {
4281 0           return 'Ecyrillic::glob("' . $1 . '")';
4282             }
4283              
4284             # __DATA__
4285 0           elsif (/\G ^ ( __DATA__ \n .*) \z /oxmsgc) { return $1; }
4286              
4287             # __END__
4288 0           elsif (/\G ^ ( __END__ \n .*) \z /oxmsgc) { return $1; }
4289              
4290             # \cD Control-D
4291              
4292             # P.68 2.6.8. Other Literal Tokens
4293             # in Chapter 2: Bits and Pieces
4294             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
4295              
4296             # P.76 Other Literal Tokens
4297             # in Chapter 2: Bits and Pieces
4298             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
4299              
4300 0           elsif (/\G ( \cD .*) \z /oxmsgc) { return $1; }
4301              
4302             # \cZ Control-Z
4303 0           elsif (/\G ( \cZ .*) \z /oxmsgc) { return $1; }
4304              
4305             # any operator before div
4306             elsif (/\G (
4307             -- | \+\+ |
4308             [\)\}\]]
4309              
4310 0           ) /oxgc) { $slash = 'div'; return $1; }
  0            
4311              
4312             # yada-yada or triple-dot operator
4313             elsif (/\G (
4314             \.\.\.
4315              
4316 0           ) /oxgc) { $slash = 'm//'; return q{die('Unimplemented')}; }
  0            
4317              
4318             # any operator before m//
4319              
4320             # //, //= (defined-or)
4321              
4322             # P.164 Logical Operators
4323             # in Chapter 10: More Control Structures
4324             # of ISBN 978-0-596-52010-6 Learning Perl, Fifth Edition
4325              
4326             # P.119 C-Style Logical (Short-Circuit) Operators
4327             # in Chapter 3: Unary and Binary Operators
4328             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
4329              
4330             # (and so on)
4331              
4332             # ~~
4333              
4334             # P.221 The Smart Match Operator
4335             # in Chapter 15: Smart Matching and given-when
4336             # of ISBN 978-0-596-52010-6 Learning Perl, Fifth Edition
4337              
4338             # P.112 Smartmatch Operator
4339             # in Chapter 3: Unary and Binary Operators
4340             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
4341              
4342             # (and so on)
4343              
4344             elsif (/\G ((?>
4345              
4346             !~~ | !~ | != | ! |
4347             %= | % |
4348             &&= | && | &= | &\.= | &\. | & |
4349             -= | -> | - |
4350             :(?>\s*)= |
4351             : |
4352             <<>> |
4353             <<= | <=> | <= | < |
4354             == | => | =~ | = |
4355             >>= | >> | >= | > |
4356             \*\*= | \*\* | \*= | \* |
4357             \+= | \+ |
4358             \.\. | \.= | \. |
4359             \/\/= | \/\/ |
4360             \/= | \/ |
4361             \? |
4362             \\ |
4363             \^= | \^\.= | \^\. | \^ |
4364             \b x= |
4365             \|\|= | \|\| | \|= | \|\.= | \|\. | \| |
4366             ~~ | ~\. | ~ |
4367             \b(?: and | cmp | eq | ge | gt | le | lt | ne | not | or | xor | x )\b |
4368             \b(?: print )\b |
4369              
4370             [,;\(\{\[]
4371              
4372 0           )) /oxgc) { $slash = 'm//'; return $1; }
  0            
4373              
4374             # other any character
4375 0           elsif (/\G ($q_char) /oxgc) { $slash = 'div'; return $1; }
  0            
4376              
4377             # system error
4378             else {
4379 0           die __FILE__, ": Oops, this shouldn't happen!\n";
4380             }
4381             }
4382              
4383             # escape Cyrillic string
4384             sub e_string {
4385 0     0 0   my($string) = @_;
4386 0           my $e_string = '';
4387              
4388 0           local $slash = 'm//';
4389              
4390             # P.1024 Appendix W.10 Multibyte Processing
4391             # of ISBN 1-56592-224-7 CJKV Information Processing
4392             # (and so on)
4393              
4394 0           my @char = $string =~ / \G (?>[^\\]|\\$q_char|$q_char) /oxmsg;
4395              
4396             # without { ... }
4397 0 0 0       if (not (grep(/\A \{ \z/xms, @char) and grep(/\A \} \z/xms, @char))) {
4398 0 0         if ($string !~ /<
4399 0           return $string;
4400             }
4401             }
4402              
4403             E_STRING_LOOP:
4404 0           while ($string !~ /\G \z/oxgc) {
4405 0 0         if (0) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4406             }
4407              
4408             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> @{[Ecyrillic::PREMATCH()]}
4409 0           elsif ($string =~ /\G ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH \b | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) /oxmsgc) {
4410 0           $e_string .= q{Ecyrillic::PREMATCH()};
4411 0           $slash = 'div';
4412             }
4413              
4414             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> @{[Ecyrillic::MATCH()]}
4415             elsif ($string =~ /\G ( \$& | \$\{&\} | \$ (?>\s*) MATCH \b | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) /oxmsgc) {
4416 0           $e_string .= q{Ecyrillic::MATCH()};
4417 0           $slash = 'div';
4418             }
4419              
4420             # $', ${'} --> $', ${'}
4421             elsif ($string =~ /\G ( \$' | \$\{'\} ) /oxmsgc) {
4422 0           $e_string .= $1;
4423 0           $slash = 'div';
4424             }
4425              
4426             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> @{[Ecyrillic::POSTMATCH()]}
4427             elsif ($string =~ /\G ( \$ (?>\s*) POSTMATCH \b | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) /oxmsgc) {
4428 0           $e_string .= q{Ecyrillic::POSTMATCH()};
4429 0           $slash = 'div';
4430             }
4431              
4432             # bareword
4433             elsif ($string =~ /\G ( \{ (?>\s*) (?: tr | index | rindex | reverse ) (?>\s*) \} ) /oxmsgc) {
4434 0           $e_string .= $1;
4435 0           $slash = 'div';
4436             }
4437              
4438             # $0 --> $0
4439             elsif ($string =~ /\G ( \$ 0 ) /oxmsgc) {
4440 0           $e_string .= $1;
4441 0           $slash = 'div';
4442             }
4443             elsif ($string =~ /\G ( \$ \{ (?>\s*) 0 (?>\s*) \} ) /oxmsgc) {
4444 0           $e_string .= $1;
4445 0           $slash = 'div';
4446             }
4447              
4448             # $$ --> $$
4449             elsif ($string =~ /\G ( \$ \$ ) (?![\w\{]) /oxmsgc) {
4450 0           $e_string .= $1;
4451 0           $slash = 'div';
4452             }
4453              
4454             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
4455             # $1, $2, $3 --> $1, $2, $3 otherwise
4456             elsif ($string =~ /\G \$ ((?>[1-9][0-9]*)) /oxmsgc) {
4457 0           $e_string .= e_capture($1);
4458 0           $slash = 'div';
4459             }
4460             elsif ($string =~ /\G \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} /oxmsgc) {
4461 0           $e_string .= e_capture($1);
4462 0           $slash = 'div';
4463             }
4464              
4465             # $$foo[ ... ] --> $ $foo->[ ... ]
4466             elsif ($string =~ /\G \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ .+? \] ) /oxmsgc) {
4467 0           $e_string .= e_capture($1.'->'.$2);
4468 0           $slash = 'div';
4469             }
4470              
4471             # $$foo{ ... } --> $ $foo->{ ... }
4472             elsif ($string =~ /\G \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ .+? \} ) /oxmsgc) {
4473 0           $e_string .= e_capture($1.'->'.$2);
4474 0           $slash = 'div';
4475             }
4476              
4477             # $$foo
4478             elsif ($string =~ /\G \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) /oxmsgc) {
4479 0           $e_string .= e_capture($1);
4480 0           $slash = 'div';
4481             }
4482              
4483             # ${ foo }
4484             elsif ($string =~ /\G \$ (?>\s*) \{ ((?> \s* [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* \s* )) \} /oxmsgc) {
4485 0           $e_string .= '${' . $1 . '}';
4486 0           $slash = 'div';
4487             }
4488              
4489             # ${ ... }
4490             elsif ($string =~ /\G \$ (?>\s*) \{ (?>\s*) ( $qq_brace ) (?>\s*) \} /oxmsgc) {
4491 0           $e_string .= e_capture($1);
4492 0           $slash = 'div';
4493             }
4494              
4495             # variable or function
4496             # $ @ % & * $ #
4497             elsif ($string =~ /\G ( (?: [\$\@\%\&\*] | \$\# | -> | \b sub \b) (?>\s*) (?: split | chop | index | rindex | lc | uc | fc | chr | ord | reverse | getc | tr | y | q | qq | qx | qw | m | s | qr | glob | lstat | opendir | stat | unlink | chdir ) ) \b /oxmsgc) {
4498 0           $e_string .= $1;
4499 0           $slash = 'div';
4500             }
4501             # $ $ $ $ $ $ $ $ $ $ $ $ $ $
4502             # $ @ # \ ' " / ? ( ) [ ] < >
4503             elsif ($string =~ /\G ( \$[\$\@\#\\\'\"\/\?\(\)\[\]\<\>] ) /oxmsgc) {
4504 0           $e_string .= $1;
4505 0           $slash = 'div';
4506             }
4507              
4508             # subroutines of package Ecyrillic
4509 0           elsif ($string =~ /\G \b (CORE:: | ->(>?\s*) (?: atan2 | [a-z]{2,})) \b /oxgc) { $e_string .= $1; $slash = 'm//'; }
  0            
4510 0           elsif ($string =~ /\G \b Char::eval (?= (?>\s*) \{ ) /oxgc) { $e_string .= 'eval'; $slash = 'm//'; }
  0            
4511 0           elsif ($string =~ /\G \b Cyrillic::eval (?= (?>\s*) \{ ) /oxgc) { $e_string .= 'eval'; $slash = 'm//'; }
  0            
4512 0           elsif ($string =~ /\G \b Char::eval \b /oxgc) { $e_string .= 'eval Char::escape'; $slash = 'm//'; }
  0            
4513 0           elsif ($string =~ /\G \b Cyrillic::eval \b /oxgc) { $e_string .= 'eval Cyrillic::escape'; $slash = 'm//'; }
  0            
4514 0           elsif ($string =~ /\G \b bytes::substr \b /oxgc) { $e_string .= 'substr'; $slash = 'm//'; }
  0            
4515 0           elsif ($string =~ /\G \b chop \b /oxgc) { $e_string .= 'Ecyrillic::chop'; $slash = 'm//'; }
  0            
4516 0           elsif ($string =~ /\G \b bytes::index \b /oxgc) { $e_string .= 'index'; $slash = 'm//'; }
  0            
4517 0           elsif ($string =~ /\G \b Char::index \b /oxgc) { $e_string .= 'Char::index'; $slash = 'm//'; }
  0            
4518 0           elsif ($string =~ /\G \b Cyrillic::index \b /oxgc) { $e_string .= 'Cyrillic::index'; $slash = 'm//'; }
  0            
4519 0           elsif ($string =~ /\G \b index \b /oxgc) { $e_string .= 'Ecyrillic::index'; $slash = 'm//'; }
  0            
4520 0           elsif ($string =~ /\G \b bytes::rindex \b /oxgc) { $e_string .= 'rindex'; $slash = 'm//'; }
  0            
4521 0           elsif ($string =~ /\G \b Char::rindex \b /oxgc) { $e_string .= 'Char::rindex'; $slash = 'm//'; }
  0            
4522 0           elsif ($string =~ /\G \b Cyrillic::rindex \b /oxgc) { $e_string .= 'Cyrillic::rindex'; $slash = 'm//'; }
  0            
4523 0           elsif ($string =~ /\G \b rindex \b /oxgc) { $e_string .= 'Ecyrillic::rindex'; $slash = 'm//'; }
  0            
4524 0           elsif ($string =~ /\G \b lc (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::lc'; $slash = 'm//'; }
  0            
4525 0           elsif ($string =~ /\G \b lcfirst (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::lcfirst'; $slash = 'm//'; }
  0            
4526 0           elsif ($string =~ /\G \b uc (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::uc'; $slash = 'm//'; }
  0            
4527 0           elsif ($string =~ /\G \b ucfirst (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::ucfirst'; $slash = 'm//'; }
  0            
4528 0           elsif ($string =~ /\G \b fc (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::fc'; $slash = 'm//'; }
  0            
4529              
4530             # "-s '' ..." means file test "-s 'filename' ..." (not means "- s/// ...")
4531 0           elsif ($string =~ /\G -s (?>\s*) (\") ((?:$qq_char)+?) (\") /oxgc) { $e_string .= '-s ' . e_qq('', $1,$3,$2); $slash = 'm//'; }
  0            
4532 0           elsif ($string =~ /\G -s (?>\s+) qq (?>\s*) (\#) ((?:$qq_char)+?) (\#) /oxgc) { $e_string .= '-s ' . e_qq('qq',$1,$3,$2); $slash = 'm//'; }
  0            
4533 0           elsif ($string =~ /\G -s (?>\s+) qq (?>\s*) (\() ((?:$qq_paren)+?) (\)) /oxgc) { $e_string .= '-s ' . e_qq('qq',$1,$3,$2); $slash = 'm//'; }
  0            
4534 0           elsif ($string =~ /\G -s (?>\s+) qq (?>\s*) (\{) ((?:$qq_brace)+?) (\}) /oxgc) { $e_string .= '-s ' . e_qq('qq',$1,$3,$2); $slash = 'm//'; }
  0            
4535 0           elsif ($string =~ /\G -s (?>\s+) qq (?>\s*) (\[) ((?:$qq_bracket)+?) (\]) /oxgc) { $e_string .= '-s ' . e_qq('qq',$1,$3,$2); $slash = 'm//'; }
  0            
4536 0           elsif ($string =~ /\G -s (?>\s+) qq (?>\s*) (\<) ((?:$qq_angle)+?) (\>) /oxgc) { $e_string .= '-s ' . e_qq('qq',$1,$3,$2); $slash = 'm//'; }
  0            
4537 0           elsif ($string =~ /\G -s (?>\s+) qq (?>\s*) (\S) ((?:$qq_char)+?) (\1) /oxgc) { $e_string .= '-s ' . e_qq('qq',$1,$3,$2); $slash = 'm//'; }
  0            
4538              
4539 0           elsif ($string =~ /\G -s (?>\s*) (\') ((?:\\\'|\\\\|$q_char)+?) (\') /oxgc) { $e_string .= '-s ' . e_q ('', $1,$3,$2); $slash = 'm//'; }
  0            
4540 0           elsif ($string =~ /\G -s (?>\s+) q (?>\s*) (\#) ((?:\\\#|\\\\|$q_char)+?) (\#) /oxgc) { $e_string .= '-s ' . e_q ('q', $1,$3,$2); $slash = 'm//'; }
  0            
4541 0           elsif ($string =~ /\G -s (?>\s+) q (?>\s*) (\() ((?:\\\)|\\\\|$q_paren)+?) (\)) /oxgc) { $e_string .= '-s ' . e_q ('q', $1,$3,$2); $slash = 'm//'; }
  0            
4542 0           elsif ($string =~ /\G -s (?>\s+) q (?>\s*) (\{) ((?:\\\}|\\\\|$q_brace)+?) (\}) /oxgc) { $e_string .= '-s ' . e_q ('q', $1,$3,$2); $slash = 'm//'; }
  0            
4543 0           elsif ($string =~ /\G -s (?>\s+) q (?>\s*) (\[) ((?:\\\]|\\\\|$q_bracket)+?) (\]) /oxgc) { $e_string .= '-s ' . e_q ('q', $1,$3,$2); $slash = 'm//'; }
  0            
4544 0           elsif ($string =~ /\G -s (?>\s+) q (?>\s*) (\<) ((?:\\\>|\\\\|$q_angle)+?) (\>) /oxgc) { $e_string .= '-s ' . e_q ('q', $1,$3,$2); $slash = 'm//'; }
  0            
4545 0           elsif ($string =~ /\G -s (?>\s+) q (?>\s*) (\S) ((?:\\\1|\\\\|$q_char)+?) (\1) /oxgc) { $e_string .= '-s ' . e_q ('q', $1,$3,$2); $slash = 'm//'; }
  0            
4546              
4547             elsif ($string =~ /\G -s (?>\s*) (\$ (?> \w+ (?: ::\w+)*) (?: (?: ->)? (?: [\$\@\%\&\*]\* | \$\#\* | \( (?:$qq_paren)*? \) | [\@\%\*]? \{ (?:$qq_brace)+? \} | [\@\%]? \[ (?:$qq_bracket)+? \] ))*) /oxgc)
4548 0           { $e_string .= "-s $1"; $slash = 'm//'; }
  0            
4549 0           elsif ($string =~ /\G -s (?>\s*) \( ((?:$qq_paren)*?) \) /oxgc) { $e_string .= "-s ($1)"; $slash = 'm//'; }
  0            
4550 0           elsif ($string =~ /\G -s (?= (?>\s+) [a-z]+) /oxgc) { $e_string .= '-s'; $slash = 'm//'; }
  0            
4551 0           elsif ($string =~ /\G -s (?>\s+) ((?>\w+)) /oxgc) { $e_string .= "-s $1"; $slash = 'm//'; }
  0            
4552              
4553 0           elsif ($string =~ /\G \b bytes::length (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'length'; $slash = 'm//'; }
  0            
4554 0           elsif ($string =~ /\G \b bytes::chr (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'chr'; $slash = 'm//'; }
  0            
4555 0           elsif ($string =~ /\G \b chr (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::chr'; $slash = 'm//'; }
  0            
4556 0           elsif ($string =~ /\G \b bytes::ord (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'ord'; $slash = 'div'; }
  0            
4557 0           elsif ($string =~ /\G \b ord (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= $function_ord; $slash = 'div'; }
  0            
4558 0           elsif ($string =~ /\G \b glob (?= (?>\s+)[A-Za-z_]|(?>\s*)['"`\$\@\&\*\(]) /oxgc) { $e_string .= 'Ecyrillic::glob'; $slash = 'm//'; }
  0            
4559 0           elsif ($string =~ /\G \b lc \b /oxgc) { $e_string .= 'Ecyrillic::lc_'; $slash = 'm//'; }
  0            
4560 0           elsif ($string =~ /\G \b lcfirst \b /oxgc) { $e_string .= 'Ecyrillic::lcfirst_'; $slash = 'm//'; }
  0            
4561 0           elsif ($string =~ /\G \b uc \b /oxgc) { $e_string .= 'Ecyrillic::uc_'; $slash = 'm//'; }
  0            
4562 0           elsif ($string =~ /\G \b ucfirst \b /oxgc) { $e_string .= 'Ecyrillic::ucfirst_'; $slash = 'm//'; }
  0            
4563 0           elsif ($string =~ /\G \b fc \b /oxgc) { $e_string .= 'Ecyrillic::fc_'; $slash = 'm//'; }
  0            
4564 0           elsif ($string =~ /\G -s \b /oxgc) { $e_string .= '-s '; $slash = 'm//'; }
  0            
4565              
4566 0           elsif ($string =~ /\G \b bytes::length \b /oxgc) { $e_string .= 'length'; $slash = 'm//'; }
  0            
4567 0           elsif ($string =~ /\G \b bytes::chr \b /oxgc) { $e_string .= 'chr'; $slash = 'm//'; }
  0            
4568 0           elsif ($string =~ /\G \b chr \b /oxgc) { $e_string .= 'Ecyrillic::chr_'; $slash = 'm//'; }
  0            
4569 0           elsif ($string =~ /\G \b bytes::ord \b /oxgc) { $e_string .= 'ord'; $slash = 'div'; }
  0            
4570 0           elsif ($string =~ /\G \b ord \b /oxgc) { $e_string .= $function_ord_; $slash = 'div'; }
  0            
4571 0           elsif ($string =~ /\G \b glob \b /oxgc) { $e_string .= 'Ecyrillic::glob_'; $slash = 'm//'; }
  0            
4572 0           elsif ($string =~ /\G \b reverse \b /oxgc) { $e_string .= $function_reverse; $slash = 'm//'; }
  0            
4573 0           elsif ($string =~ /\G \b getc \b /oxgc) { $e_string .= $function_getc; $slash = 'm//'; }
  0            
4574             # split
4575             elsif ($string =~ /\G \b (split) \b (?! (?>\s*) => ) /oxgc) {
4576 0           $slash = 'm//';
4577              
4578 0           my $e = '';
4579 0           while ($string =~ /\G ( (?>\s+) | \( | \#.* ) /oxgc) {
4580 0           $e .= $1;
4581             }
4582              
4583             # end of split
4584 0 0         if ($string =~ /\G (?= [,;\)\}\]] ) /oxgc) { return 'Ecyrillic::split' . $e; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
4585              
4586             # split scalar value
4587 0           elsif ($string =~ /\G ( [\$\@\&\*] $qq_scalar ) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . e_string($1); next E_STRING_LOOP; }
  0            
4588              
4589             # split literal space
4590 0           elsif ($string =~ /\G \b qq (\#) [ ] (\#) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {qq$1 $2}; next E_STRING_LOOP; }
  0            
4591 0           elsif ($string =~ /\G \b qq ((?>\s*)) (\() [ ] (\)) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; next E_STRING_LOOP; }
  0            
4592 0           elsif ($string =~ /\G \b qq ((?>\s*)) (\{) [ ] (\}) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; next E_STRING_LOOP; }
  0            
4593 0           elsif ($string =~ /\G \b qq ((?>\s*)) (\[) [ ] (\]) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; next E_STRING_LOOP; }
  0            
4594 0           elsif ($string =~ /\G \b qq ((?>\s*)) (\<) [ ] (\>) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; next E_STRING_LOOP; }
  0            
4595 0           elsif ($string =~ /\G \b qq ((?>\s*)) (\S) [ ] (\2) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq{$1qq$2 $3}; next E_STRING_LOOP; }
  0            
4596 0           elsif ($string =~ /\G \b q (\#) [ ] (\#) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {q$1 $2}; next E_STRING_LOOP; }
  0            
4597 0           elsif ($string =~ /\G \b q ((?>\s*)) (\() [ ] (\)) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {$1q$2 $3}; next E_STRING_LOOP; }
  0            
4598 0           elsif ($string =~ /\G \b q ((?>\s*)) (\{) [ ] (\}) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {$1q$2 $3}; next E_STRING_LOOP; }
  0            
4599 0           elsif ($string =~ /\G \b q ((?>\s*)) (\[) [ ] (\]) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {$1q$2 $3}; next E_STRING_LOOP; }
  0            
4600 0           elsif ($string =~ /\G \b q ((?>\s*)) (\<) [ ] (\>) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {$1q$2 $3}; next E_STRING_LOOP; }
  0            
4601 0           elsif ($string =~ /\G \b q ((?>\s*)) (\S) [ ] (\2) /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {$1q$2 $3}; next E_STRING_LOOP; }
  0            
4602 0           elsif ($string =~ /\G ' [ ] ' /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {' '}; next E_STRING_LOOP; }
  0            
4603 0           elsif ($string =~ /\G " [ ] " /oxgc) { $e_string .= 'Ecyrillic::split' . $e . qq {" "}; next E_STRING_LOOP; }
  0            
4604              
4605             # split qq//
4606             elsif ($string =~ /\G \b (qq) \b /oxgc) {
4607 0 0         if ($string =~ /\G (\#) ((?:$qq_char)*?) (\#) /oxgc) { $e_string .= e_split($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # qq# # --> qr # #
  0            
  0            
4608             else {
4609 0           while ($string !~ /\G \z/oxgc) {
4610 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e_string .= $e . $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
4611 0           elsif ($string =~ /\G (\() ((?:$qq_paren)*?) (\)) /oxgc) { $e_string .= e_split($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # qq ( ) --> qr ( )
  0            
4612 0           elsif ($string =~ /\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) { $e_string .= e_split($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # qq { } --> qr { }
  0            
4613 0           elsif ($string =~ /\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) { $e_string .= e_split($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # qq [ ] --> qr [ ]
  0            
4614 0           elsif ($string =~ /\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) { $e_string .= e_split($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # qq < > --> qr < >
  0            
4615 0           elsif ($string =~ /\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) /oxgc) { $e_string .= e_split($e.'qr','{','}',$2,''); next E_STRING_LOOP; } # qq | | --> qr { }
  0            
4616 0           elsif ($string =~ /\G (\S) ((?:$qq_char)*?) (\1) /oxgc) { $e_string .= e_split($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # qq * * --> qr * *
  0            
4617             }
4618 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4619             }
4620             }
4621              
4622             # split qr//
4623             elsif ($string =~ /\G \b (qr) \b /oxgc) {
4624 0 0         if ($string =~ /\G (\#) ((?:$qq_char)*?) (\#) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1,$3,$2,$4); next E_STRING_LOOP; } # qr# #
  0            
  0            
4625             else {
4626 0           while ($string !~ /\G \z/oxgc) {
4627 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e_string .= $e . $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
4628 0           elsif ($string =~ /\G (\() ((?:$qq_paren)*?) (\)) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # qr ( )
  0            
4629 0           elsif ($string =~ /\G (\{) ((?:$qq_brace)*?) (\}) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # qr { }
  0            
4630 0           elsif ($string =~ /\G (\[) ((?:$qq_bracket)*?) (\]) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # qr [ ]
  0            
4631 0           elsif ($string =~ /\G (\<) ((?:$qq_angle)*?) (\>) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # qr < >
  0            
4632 0           elsif ($string =~ /\G (\') ((?:$qq_char)*?) (\') ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split_q($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # qr ' '
  0            
4633 0           elsif ($string =~ /\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr','{','}',$2,$4); next E_STRING_LOOP; } # qr | | --> qr { }
  0            
4634 0           elsif ($string =~ /\G (\S) ((?:$qq_char)*?) (\1) ([imosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # qr * *
  0            
4635             }
4636 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4637             }
4638             }
4639              
4640             # split q//
4641             elsif ($string =~ /\G \b (q) \b /oxgc) {
4642 0 0         if ($string =~ /\G (\#) ((?:\\\#|\\\\|$q_char)*?) (\#) /oxgc) { $e_string .= e_split_q($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # q# # --> qr # #
  0            
  0            
4643             else {
4644 0           while ($string !~ /\G \z/oxgc) {
4645 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e_string .= $e . $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
4646 0           elsif ($string =~ /\G (\() ((?:\\\\|\\\)|\\\(|$q_paren)*?) (\)) /oxgc) { $e_string .= e_split_q($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # q ( ) --> qr ( )
  0            
4647 0           elsif ($string =~ /\G (\{) ((?:\\\\|\\\}|\\\{|$q_brace)*?) (\}) /oxgc) { $e_string .= e_split_q($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # q { } --> qr { }
  0            
4648 0           elsif ($string =~ /\G (\[) ((?:\\\\|\\\]|\\\[|$q_bracket)*?) (\]) /oxgc) { $e_string .= e_split_q($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # q [ ] --> qr [ ]
  0            
4649 0           elsif ($string =~ /\G (\<) ((?:\\\\|\\\>|\\\<|$q_angle)*?) (\>) /oxgc) { $e_string .= e_split_q($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # q < > --> qr < >
  0            
4650 0           elsif ($string =~ /\G ([*\-:?\\^|]) ((?:$q_char)*?) (\1) /oxgc) { $e_string .= e_split_q($e.'qr','{','}',$2,''); next E_STRING_LOOP; } # q | | --> qr { }
  0            
4651 0           elsif ($string =~ /\G (\S) ((?:\\\\|\\\1| $q_char)*?) (\1) /oxgc) { $e_string .= e_split_q($e.'qr',$1,$3,$2,''); next E_STRING_LOOP; } # q * * --> qr * *
  0            
4652             }
4653 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4654             }
4655             }
4656              
4657             # split m//
4658             elsif ($string =~ /\G \b (m) \b /oxgc) {
4659 0 0         if ($string =~ /\G (\#) ((?:$qq_char)*?) (\#) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1,$3,$2,$4); next E_STRING_LOOP; } # m# # --> qr # #
  0            
  0            
4660             else {
4661 0           while ($string !~ /\G \z/oxgc) {
4662 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e_string .= $e . $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
    0          
4663 0           elsif ($string =~ /\G (\() ((?:$qq_paren)*?) (\)) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # m ( ) --> qr ( )
  0            
4664 0           elsif ($string =~ /\G (\{) ((?:$qq_brace)*?) (\}) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # m { } --> qr { }
  0            
4665 0           elsif ($string =~ /\G (\[) ((?:$qq_bracket)*?) (\]) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # m [ ] --> qr [ ]
  0            
4666 0           elsif ($string =~ /\G (\<) ((?:$qq_angle)*?) (\>) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # m < > --> qr < >
  0            
4667 0           elsif ($string =~ /\G (\') ((?:$qq_char)*?) (\') ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split_q($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # m ' ' --> qr ' '
  0            
4668 0           elsif ($string =~ /\G ([*\-:?\\^|]) ((?:$qq_char)*?) (\1) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr','{','}',$2,$4); next E_STRING_LOOP; } # m | | --> qr { }
  0            
4669 0           elsif ($string =~ /\G (\S) ((?:$qq_char)*?) (\1) ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split ($e.'qr',$1, $3, $2,$4); next E_STRING_LOOP; } # m * * --> qr * *
  0            
4670             }
4671 0           die __FILE__, ": Search pattern not terminated\n";
4672             }
4673             }
4674              
4675             # split ''
4676             elsif ($string =~ /\G (\') /oxgc) {
4677 0           my $q_string = '';
4678 0           while ($string !~ /\G \z/oxgc) {
4679 0 0         if ($string =~ /\G (\\\\) /oxgc) { $q_string .= $1; }
  0 0          
    0          
    0          
4680 0           elsif ($string =~ /\G (\\\') /oxgc) { $q_string .= $1; } # splitqr'' --> split qr''
4681 0           elsif ($string =~ /\G \' /oxgc) { $e_string .= e_split_q($e.q{ qr},"'","'",$q_string,''); next E_STRING_LOOP; } # ' ' --> qr ' '
  0            
4682 0           elsif ($string =~ /\G ($q_char) /oxgc) { $q_string .= $1; }
4683             }
4684 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4685             }
4686              
4687             # split ""
4688             elsif ($string =~ /\G (\") /oxgc) {
4689 0           my $qq_string = '';
4690 0           while ($string !~ /\G \z/oxgc) {
4691 0 0         if ($string =~ /\G (\\\\) /oxgc) { $qq_string .= $1; }
  0 0          
    0          
    0          
4692 0           elsif ($string =~ /\G (\\\") /oxgc) { $qq_string .= $1; } # splitqr"" --> split qr""
4693 0           elsif ($string =~ /\G \" /oxgc) { $e_string .= e_split($e.q{ qr},'"','"',$qq_string,''); next E_STRING_LOOP; } # " " --> qr " "
  0            
4694 0           elsif ($string =~ /\G ($q_char) /oxgc) { $qq_string .= $1; }
4695             }
4696 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4697             }
4698              
4699             # split //
4700             elsif ($string =~ /\G (\/) /oxgc) {
4701 0           my $regexp = '';
4702 0           while ($string !~ /\G \z/oxgc) {
4703 0 0         if ($string =~ /\G (\\\\) /oxgc) { $regexp .= $1; }
  0 0          
    0          
    0          
4704 0           elsif ($string =~ /\G (\\\/) /oxgc) { $regexp .= $1; } # splitqr// --> split qr//
4705 0           elsif ($string =~ /\G \/ ([cgimosxpadlunbB]*) /oxgc) { $e_string .= e_split($e.q{ qr}, '/','/',$regexp,$1); next E_STRING_LOOP; } # / / --> qr / /
  0            
4706 0           elsif ($string =~ /\G ($q_char) /oxgc) { $regexp .= $1; }
4707             }
4708 0           die __FILE__, ": Search pattern not terminated\n";
4709             }
4710             }
4711              
4712             # qq//
4713             elsif ($string =~ /\G \b (qq) \b /oxgc) {
4714 0           my $ope = $1;
4715 0 0         if ($string =~ /\G (\#) ((?:$qq_char)*?) (\#) /oxgc) { # qq# #
4716 0           $e_string .= e_qq($ope,$1,$3,$2);
4717             }
4718             else {
4719 0           my $e = '';
4720 0           while ($string !~ /\G \z/oxgc) {
4721 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
4722 0           elsif ($string =~ /\G (\() ((?:$qq_paren)*?) (\)) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qq ( )
  0            
4723 0           elsif ($string =~ /\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qq { }
  0            
4724 0           elsif ($string =~ /\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qq [ ]
  0            
4725 0           elsif ($string =~ /\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qq < >
  0            
4726 0           elsif ($string =~ /\G (\S) ((?:$qq_char)*?) (\1) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qq * *
  0            
4727             }
4728 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4729             }
4730             }
4731              
4732             # qx//
4733             elsif ($string =~ /\G \b (qx) \b /oxgc) {
4734 0           my $ope = $1;
4735 0 0         if ($string =~ /\G (\#) ((?:$qq_char)*?) (\#) /oxgc) { # qx# #
4736 0           $e_string .= e_qq($ope,$1,$3,$2);
4737             }
4738             else {
4739 0           my $e = '';
4740 0           while ($string !~ /\G \z/oxgc) {
4741 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
    0          
4742 0           elsif ($string =~ /\G (\() ((?:$qq_paren)*?) (\)) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qx ( )
  0            
4743 0           elsif ($string =~ /\G (\{) ((?:$qq_brace)*?) (\}) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qx { }
  0            
4744 0           elsif ($string =~ /\G (\[) ((?:$qq_bracket)*?) (\]) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qx [ ]
  0            
4745 0           elsif ($string =~ /\G (\<) ((?:$qq_angle)*?) (\>) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qx < >
  0            
4746 0           elsif ($string =~ /\G (\') ((?:$qq_char)*?) (\') /oxgc) { $e_string .= $e . e_q ($ope,$1,$3,$2); next E_STRING_LOOP; } # qx ' '
  0            
4747 0           elsif ($string =~ /\G (\S) ((?:$qq_char)*?) (\1) /oxgc) { $e_string .= $e . e_qq($ope,$1,$3,$2); next E_STRING_LOOP; } # qx * *
  0            
4748             }
4749 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4750             }
4751             }
4752              
4753             # q//
4754             elsif ($string =~ /\G \b (q) \b /oxgc) {
4755 0           my $ope = $1;
4756 0 0         if ($string =~ /\G (\#) ((?:\\\#|\\\\|$q_char)*?) (\#) /oxgc) { # q# #
4757 0           $e_string .= e_q($ope,$1,$3,$2);
4758             }
4759             else {
4760 0           my $e = '';
4761 0           while ($string !~ /\G \z/oxgc) {
4762 0 0         if ($string =~ /\G ((?>\s+)|\#.*) /oxgc) { $e .= $1; }
  0 0          
    0          
    0          
    0          
    0          
4763 0           elsif ($string =~ /\G (\() ((?:\\\\|\\\)|\\\(|$q_paren)*?) (\)) /oxgc) { $e_string .= $e . e_q($ope,$1,$3,$2); next E_STRING_LOOP; } # q ( )
  0            
4764 0           elsif ($string =~ /\G (\{) ((?:\\\\|\\\}|\\\{|$q_brace)*?) (\}) /oxgc) { $e_string .= $e . e_q($ope,$1,$3,$2); next E_STRING_LOOP; } # q { }
  0            
4765 0           elsif ($string =~ /\G (\[) ((?:\\\\|\\\]|\\\[|$q_bracket)*?) (\]) /oxgc) { $e_string .= $e . e_q($ope,$1,$3,$2); next E_STRING_LOOP; } # q [ ]
  0            
4766 0           elsif ($string =~ /\G (\<) ((?:\\\\|\\\>|\\\<|$q_angle)*?) (\>) /oxgc) { $e_string .= $e . e_q($ope,$1,$3,$2); next E_STRING_LOOP; } # q < >
  0            
4767 0           elsif ($string =~ /\G (\S) ((?:\\\\|\\\1| $q_char)*?) (\1) /oxgc) { $e_string .= $e . e_q($ope,$1,$3,$2); next E_STRING_LOOP; } # q * *
  0            
4768             }
4769 0           die __FILE__, ": Can't find string terminator anywhere before EOF\n";
4770             }
4771             }
4772              
4773             # ''
4774 0           elsif ($string =~ /\G (?
4775              
4776             # ""
4777 0           elsif ($string =~ /\G (\") ((?:$qq_char)*?) (\") /oxgc) { $e_string .= e_qq('',$1,$3,$2); }
4778              
4779             # ``
4780 0           elsif ($string =~ /\G (\`) ((?:$qq_char)*?) (\`) /oxgc) { $e_string .= e_qq('',$1,$3,$2); }
4781              
4782             # <<>> (a safer ARGV)
4783 0           elsif ($string =~ /\G ( <<>> ) /oxgc) { $e_string .= $1; }
4784              
4785             # <<= <=> <= < operator
4786 0           elsif ($string =~ /\G ( <<= | <=> | <= | < ) (?= (?>\s*) [A-Za-z_0-9'"`\$\@\&\*\(\+\-] )/oxgc) { $e_string .= $1; }
4787              
4788             #
4789 0           elsif ($string =~ /\G (<[\$]?[A-Za-z_][A-Za-z_0-9]*>) /oxgc) { $e_string .= $1; }
4790              
4791             # --- glob
4792             elsif ($string =~ /\G < ((?:$q_char)+?) > /oxgc) {
4793 0           $e_string .= 'Ecyrillic::glob("' . $1 . '")';
4794             }
4795              
4796             # << (bit shift) --- not here document
4797 0           elsif ($string =~ /\G ( << (?>\s*) ) (?= [0-9\$\@\&] ) /oxgc) { $slash = 'm//'; $e_string .= $1; }
  0            
4798              
4799             # <<'HEREDOC'
4800             elsif ($string =~ /\G ( << '([a-zA-Z_0-9]*)' ) /oxgc) {
4801 0           $slash = 'm//';
4802 0           my $here_quote = $1;
4803 0           my $delimiter = $2;
4804              
4805             # get here document
4806 0 0         if ($here_script eq '') {
4807 0           $here_script = CORE::substr $_, pos $_;
4808 0           $here_script =~ s/.*?\n//oxm;
4809             }
4810 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4811 0           push @heredoc, $1 . qq{\n$delimiter\n};
4812 0           push @heredoc_delimiter, $delimiter;
4813             }
4814             else {
4815 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4816             }
4817 0           $e_string .= $here_quote;
4818             }
4819              
4820             # <<\HEREDOC
4821             elsif ($string =~ /\G ( << \\([a-zA-Z_0-9]+) ) /oxgc) {
4822 0           $slash = 'm//';
4823 0           my $here_quote = $1;
4824 0           my $delimiter = $2;
4825              
4826             # get here document
4827 0 0         if ($here_script eq '') {
4828 0           $here_script = CORE::substr $_, pos $_;
4829 0           $here_script =~ s/.*?\n//oxm;
4830             }
4831 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4832 0           push @heredoc, $1 . qq{\n$delimiter\n};
4833 0           push @heredoc_delimiter, $delimiter;
4834             }
4835             else {
4836 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4837             }
4838 0           $e_string .= $here_quote;
4839             }
4840              
4841             # <<"HEREDOC"
4842             elsif ($string =~ /\G ( << "([a-zA-Z_0-9]*)" ) /oxgc) {
4843 0           $slash = 'm//';
4844 0           my $here_quote = $1;
4845 0           my $delimiter = $2;
4846              
4847             # get here document
4848 0 0         if ($here_script eq '') {
4849 0           $here_script = CORE::substr $_, pos $_;
4850 0           $here_script =~ s/.*?\n//oxm;
4851             }
4852 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4853 0           push @heredoc, e_heredoc($1) . qq{\n$delimiter\n};
4854 0           push @heredoc_delimiter, $delimiter;
4855             }
4856             else {
4857 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4858             }
4859 0           $e_string .= $here_quote;
4860             }
4861              
4862             # <
4863             elsif ($string =~ /\G ( << ([a-zA-Z_0-9]+) ) /oxgc) {
4864 0           $slash = 'm//';
4865 0           my $here_quote = $1;
4866 0           my $delimiter = $2;
4867              
4868             # get here document
4869 0 0         if ($here_script eq '') {
4870 0           $here_script = CORE::substr $_, pos $_;
4871 0           $here_script =~ s/.*?\n//oxm;
4872             }
4873 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4874 0           push @heredoc, e_heredoc($1) . qq{\n$delimiter\n};
4875 0           push @heredoc_delimiter, $delimiter;
4876             }
4877             else {
4878 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4879             }
4880 0           $e_string .= $here_quote;
4881             }
4882              
4883             # <<`HEREDOC`
4884             elsif ($string =~ /\G ( << `([a-zA-Z_0-9]*)` ) /oxgc) {
4885 0           $slash = 'm//';
4886 0           my $here_quote = $1;
4887 0           my $delimiter = $2;
4888              
4889             # get here document
4890 0 0         if ($here_script eq '') {
4891 0           $here_script = CORE::substr $_, pos $_;
4892 0           $here_script =~ s/.*?\n//oxm;
4893             }
4894 0 0         if ($here_script =~ s/\A (.*?) \n $delimiter \n //xms) {
4895 0           push @heredoc, e_heredoc($1) . qq{\n$delimiter\n};
4896 0           push @heredoc_delimiter, $delimiter;
4897             }
4898             else {
4899 0           die __FILE__, ": Can't find string terminator $delimiter anywhere before EOF\n";
4900             }
4901 0           $e_string .= $here_quote;
4902             }
4903              
4904             # any operator before div
4905             elsif ($string =~ /\G (
4906             -- | \+\+ |
4907             [\)\}\]]
4908              
4909 0           ) /oxgc) { $slash = 'div'; $e_string .= $1; }
  0            
4910              
4911             # yada-yada or triple-dot operator
4912             elsif ($string =~ /\G (
4913             \.\.\.
4914              
4915 0           ) /oxgc) { $slash = 'm//'; $e_string .= q{die('Unimplemented')}; }
  0            
4916              
4917             # any operator before m//
4918             elsif ($string =~ /\G ((?>
4919              
4920             !~~ | !~ | != | ! |
4921             %= | % |
4922             &&= | && | &= | &\.= | &\. | & |
4923             -= | -> | - |
4924             :(?>\s*)= |
4925             : |
4926             <<>> |
4927             <<= | <=> | <= | < |
4928             == | => | =~ | = |
4929             >>= | >> | >= | > |
4930             \*\*= | \*\* | \*= | \* |
4931             \+= | \+ |
4932             \.\. | \.= | \. |
4933             \/\/= | \/\/ |
4934             \/= | \/ |
4935             \? |
4936             \\ |
4937             \^= | \^\.= | \^\. | \^ |
4938             \b x= |
4939             \|\|= | \|\| | \|= | \|\.= | \|\. | \| |
4940             ~~ | ~\. | ~ |
4941             \b(?: and | cmp | eq | ge | gt | le | lt | ne | not | or | xor | x )\b |
4942             \b(?: print )\b |
4943              
4944             [,;\(\{\[]
4945              
4946 0           )) /oxgc) { $slash = 'm//'; $e_string .= $1; }
  0            
4947              
4948             # other any character
4949 0           elsif ($string =~ /\G ($q_char) /oxgc) { $e_string .= $1; }
4950              
4951             # system error
4952             else {
4953 0           die __FILE__, ": Oops, this shouldn't happen!\n";
4954             }
4955             }
4956              
4957 0           return $e_string;
4958             }
4959              
4960             #
4961             # character class
4962             #
4963             sub character_class {
4964 0     0 0   my($char,$modifier) = @_;
4965              
4966 0 0         if ($char eq '.') {
4967 0 0         if ($modifier =~ /s/) {
4968 0           return '${Ecyrillic::dot_s}';
4969             }
4970             else {
4971 0           return '${Ecyrillic::dot}';
4972             }
4973             }
4974             else {
4975 0           return Ecyrillic::classic_character_class($char);
4976             }
4977             }
4978              
4979             #
4980             # escape capture ($1, $2, $3, ...)
4981             #
4982             sub e_capture {
4983              
4984 0     0 0   return join '', '${', $_[0], '}';
4985             }
4986              
4987             #
4988             # escape transliteration (tr/// or y///)
4989             #
4990             sub e_tr {
4991 0     0 0   my($variable,$charclass,$e,$charclass2,$modifier) = @_;
4992 0           my $e_tr = '';
4993 0   0       $modifier ||= '';
4994              
4995 0           $slash = 'div';
4996              
4997             # quote character class 1
4998 0           $charclass = q_tr($charclass);
4999              
5000             # quote character class 2
5001 0           $charclass2 = q_tr($charclass2);
5002              
5003             # /b /B modifier
5004 0 0         if ($modifier =~ tr/bB//d) {
5005 0 0         if ($variable eq '') {
5006 0           $e_tr = qq{tr$charclass$e$charclass2$modifier};
5007             }
5008             else {
5009 0           $e_tr = qq{$variable${bind_operator}tr$charclass$e$charclass2$modifier};
5010             }
5011             }
5012             else {
5013 0 0         if ($variable eq '') {
5014 0           $e_tr = qq{Ecyrillic::tr(\$_,' =~ ',$charclass,$e$charclass2,'$modifier')};
5015             }
5016             else {
5017 0           $e_tr = qq{Ecyrillic::tr($variable,'$bind_operator',$charclass,$e$charclass2,'$modifier')};
5018             }
5019             }
5020              
5021             # clear tr/// variable
5022 0           $tr_variable = '';
5023 0           $bind_operator = '';
5024              
5025 0           return $e_tr;
5026             }
5027              
5028             #
5029             # quote for escape transliteration (tr/// or y///)
5030             #
5031             sub q_tr {
5032 0     0 0   my($charclass) = @_;
5033              
5034             # quote character class
5035 0 0         if ($charclass !~ /'/oxms) {
    0          
    0          
    0          
    0          
    0          
5036 0           return e_q('', "'", "'", $charclass); # --> q' '
5037             }
5038             elsif ($charclass !~ /\//oxms) {
5039 0           return e_q('q', '/', '/', $charclass); # --> q/ /
5040             }
5041             elsif ($charclass !~ /\#/oxms) {
5042 0           return e_q('q', '#', '#', $charclass); # --> q# #
5043             }
5044             elsif ($charclass !~ /[\<\>]/oxms) {
5045 0           return e_q('q', '<', '>', $charclass); # --> q< >
5046             }
5047             elsif ($charclass !~ /[\(\)]/oxms) {
5048 0           return e_q('q', '(', ')', $charclass); # --> q( )
5049             }
5050             elsif ($charclass !~ /[\{\}]/oxms) {
5051 0           return e_q('q', '{', '}', $charclass); # --> q{ }
5052             }
5053             else {
5054 0           for my $char (qw( ! " $ % & * + . : = ? @ ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
5055 0 0         if ($charclass !~ /\Q$char\E/xms) {
5056 0           return e_q('q', $char, $char, $charclass);
5057             }
5058             }
5059             }
5060              
5061 0           return e_q('q', '{', '}', $charclass);
5062             }
5063              
5064             #
5065             # escape q string (q//, '')
5066             #
5067             sub e_q {
5068 0     0 0   my($ope,$delimiter,$end_delimiter,$string) = @_;
5069              
5070 0           $slash = 'div';
5071              
5072 0           return join '', $ope, $delimiter, $string, $end_delimiter;
5073             }
5074              
5075             #
5076             # escape qq string (qq//, "", qx//, ``)
5077             #
5078             sub e_qq {
5079 0     0 0   my($ope,$delimiter,$end_delimiter,$string) = @_;
5080              
5081 0           $slash = 'div';
5082              
5083 0           my $left_e = 0;
5084 0           my $right_e = 0;
5085              
5086             # split regexp
5087 0           my @char = $string =~ /\G((?>
5088             [^\\\$] |
5089             \\x\{ (?>[0-9A-Fa-f]+) \} |
5090             \\o\{ (?>[0-7]+) \} |
5091             \\N\{ (?>[^0-9\}][^\}]*) \} |
5092             \\ $q_char |
5093             \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} |
5094             \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} |
5095             \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} |
5096             \$ (?>\s* [0-9]+) |
5097             \$ (?>\s*) \{ (?>\s* [0-9]+ \s*) \} |
5098             \$ \$ (?![\w\{]) |
5099             \$ (?>\s*) \$ (?>\s*) $qq_variable |
5100             $q_char
5101             ))/oxmsg;
5102              
5103 0           for (my $i=0; $i <= $#char; $i++) {
5104              
5105             # "\L\u" --> "\u\L"
5106 0 0 0       if (($char[$i] eq '\L') and ($char[$i+1] eq '\u')) {
    0 0        
    0          
    0          
    0          
5107 0           @char[$i,$i+1] = @char[$i+1,$i];
5108             }
5109              
5110             # "\U\l" --> "\l\U"
5111             elsif (($char[$i] eq '\U') and ($char[$i+1] eq '\l')) {
5112 0           @char[$i,$i+1] = @char[$i+1,$i];
5113             }
5114              
5115             # octal escape sequence
5116             elsif ($char[$i] =~ /\A \\o \{ ([0-7]+) \} \z/oxms) {
5117 0           $char[$i] = Ecyrillic::octchr($1);
5118             }
5119              
5120             # hexadecimal escape sequence
5121             elsif ($char[$i] =~ /\A \\x \{ ([0-9A-Fa-f]+) \} \z/oxms) {
5122 0           $char[$i] = Ecyrillic::hexchr($1);
5123             }
5124              
5125             # \N{CHARNAME} --> N{CHARNAME}
5126             elsif ($char[$i] =~ /\A \\ ( N\{ ([^0-9\}][^\}]*) \} ) \z/oxms) {
5127 0           $char[$i] = $1;
5128             }
5129              
5130 0 0         if (0) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5131             }
5132              
5133             # \F
5134             #
5135             # P.69 Table 2-6. Translation escapes
5136             # in Chapter 2: Bits and Pieces
5137             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
5138             # (and so on)
5139              
5140             # \u \l \U \L \F \Q \E
5141 0           elsif ($char[$i] =~ /\A ([<>]) \z/oxms) {
5142 0 0         if ($right_e < $left_e) {
5143 0           $char[$i] = '\\' . $char[$i];
5144             }
5145             }
5146             elsif ($char[$i] eq '\u') {
5147              
5148             # "STRING @{[ LIST EXPR ]} MORE STRING"
5149              
5150             # P.257 Other Tricks You Can Do with Hard References
5151             # in Chapter 8: References
5152             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
5153              
5154             # P.353 Other Tricks You Can Do with Hard References
5155             # in Chapter 8: References
5156             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
5157              
5158             # (and so on)
5159              
5160 0           $char[$i] = '@{[Ecyrillic::ucfirst qq<';
5161 0           $left_e++;
5162             }
5163             elsif ($char[$i] eq '\l') {
5164 0           $char[$i] = '@{[Ecyrillic::lcfirst qq<';
5165 0           $left_e++;
5166             }
5167             elsif ($char[$i] eq '\U') {
5168 0           $char[$i] = '@{[Ecyrillic::uc qq<';
5169 0           $left_e++;
5170             }
5171             elsif ($char[$i] eq '\L') {
5172 0           $char[$i] = '@{[Ecyrillic::lc qq<';
5173 0           $left_e++;
5174             }
5175             elsif ($char[$i] eq '\F') {
5176 0           $char[$i] = '@{[Ecyrillic::fc qq<';
5177 0           $left_e++;
5178             }
5179             elsif ($char[$i] eq '\Q') {
5180 0           $char[$i] = '@{[CORE::quotemeta qq<';
5181 0           $left_e++;
5182             }
5183             elsif ($char[$i] eq '\E') {
5184 0 0         if ($right_e < $left_e) {
5185 0           $char[$i] = '>]}';
5186 0           $right_e++;
5187             }
5188             else {
5189 0           $char[$i] = '';
5190             }
5191             }
5192             elsif ($char[$i] eq '\Q') {
5193 0           while (1) {
5194 0 0         if (++$i > $#char) {
5195 0           last;
5196             }
5197 0 0         if ($char[$i] eq '\E') {
5198 0           last;
5199             }
5200             }
5201             }
5202             elsif ($char[$i] eq '\E') {
5203             }
5204              
5205             # $0 --> $0
5206             elsif ($char[$i] =~ /\A \$ 0 \z/oxms) {
5207             }
5208             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) 0 (?>\s*) \} \z/oxms) {
5209             }
5210              
5211             # $$ --> $$
5212             elsif ($char[$i] =~ /\A \$\$ \z/oxms) {
5213             }
5214              
5215             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
5216             # $1, $2, $3 --> $1, $2, $3 otherwise
5217             elsif ($char[$i] =~ /\A \$ ((?>[1-9][0-9]*)) \z/oxms) {
5218 0           $char[$i] = e_capture($1);
5219             }
5220             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
5221 0           $char[$i] = e_capture($1);
5222             }
5223              
5224             # $$foo[ ... ] --> $ $foo->[ ... ]
5225             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ (?:$qq_bracket)*? \] ) \z/oxms) {
5226 0           $char[$i] = e_capture($1.'->'.$2);
5227             }
5228              
5229             # $$foo{ ... } --> $ $foo->{ ... }
5230             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ (?:$qq_brace)*? \} ) \z/oxms) {
5231 0           $char[$i] = e_capture($1.'->'.$2);
5232             }
5233              
5234             # $$foo
5235             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) \z/oxms) {
5236 0           $char[$i] = e_capture($1);
5237             }
5238              
5239             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> Ecyrillic::PREMATCH()
5240             elsif ($char[$i] =~ /\A ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) \z/oxmsgc) {
5241 0           $char[$i] = '@{[Ecyrillic::PREMATCH()]}';
5242             }
5243              
5244             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> Ecyrillic::MATCH()
5245             elsif ($char[$i] =~ /\A ( \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) \z/oxmsgc) {
5246 0           $char[$i] = '@{[Ecyrillic::MATCH()]}';
5247             }
5248              
5249             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> Ecyrillic::POSTMATCH()
5250             elsif ($char[$i] =~ /\A ( \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) \z/oxmsgc) {
5251 0           $char[$i] = '@{[Ecyrillic::POSTMATCH()]}';
5252             }
5253              
5254             # ${ foo } --> ${ foo }
5255             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ (?> \s* [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* \s* ) \} \z/oxms) {
5256             }
5257              
5258             # ${ ... }
5259             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ( .+ ) \} \z/oxms) {
5260 0           $char[$i] = e_capture($1);
5261             }
5262             }
5263              
5264             # return string
5265 0 0         if ($left_e > $right_e) {
5266 0           return join '', $ope, $delimiter, @char, '>]}' x ($left_e - $right_e), $end_delimiter;
5267             }
5268 0           return join '', $ope, $delimiter, @char, $end_delimiter;
5269             }
5270              
5271             #
5272             # escape qw string (qw//)
5273             #
5274             sub e_qw {
5275 0     0 0   my($ope,$delimiter,$end_delimiter,$string) = @_;
5276              
5277 0           $slash = 'div';
5278              
5279             # choice again delimiter
5280 0           my %octet = map {$_ => 1} ($string =~ /\G ([\x00-\xFF]) /oxmsg);
  0            
5281 0 0         if (not $octet{$end_delimiter}) {
    0          
    0          
    0          
    0          
5282 0           return join '', $ope, $delimiter, $string, $end_delimiter;
5283             }
5284             elsif (not $octet{')'}) {
5285 0           return join '', $ope, '(', $string, ')';
5286             }
5287             elsif (not $octet{'}'}) {
5288 0           return join '', $ope, '{', $string, '}';
5289             }
5290             elsif (not $octet{']'}) {
5291 0           return join '', $ope, '[', $string, ']';
5292             }
5293             elsif (not $octet{'>'}) {
5294 0           return join '', $ope, '<', $string, '>';
5295             }
5296             else {
5297 0           for my $char (qw( ! " $ % & * + - . / : = ? @ ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
5298 0 0         if (not $octet{$char}) {
5299 0           return join '', $ope, $char, $string, $char;
5300             }
5301             }
5302             }
5303              
5304             # qw/AAA BBB C'CC/ --> ('AAA', 'BBB', 'C\'CC')
5305 0           my @string = CORE::split(/\s+/, $string);
5306 0           for my $string (@string) {
5307 0           my @octet = $string =~ /\G ([\x00-\xFF]) /oxmsg;
5308 0           for my $octet (@octet) {
5309 0 0         if ($octet =~ /\A (['\\]) \z/oxms) {
5310 0           $octet = '\\' . $1;
5311             }
5312             }
5313 0           $string = join '', @octet;
5314             }
5315 0           return join '', '(', (join ', ', map { "'$_'" } @string), ')';
  0            
5316             }
5317              
5318             #
5319             # escape here document (<<"HEREDOC", <
5320             #
5321             sub e_heredoc {
5322 0     0 0   my($string) = @_;
5323              
5324 0           $slash = 'm//';
5325              
5326 0           my $metachar = qr/[\@\\|]/oxms; # '|' is for <<`HEREDOC`
5327              
5328 0           my $left_e = 0;
5329 0           my $right_e = 0;
5330              
5331             # split regexp
5332 0           my @char = $string =~ /\G((?>
5333             [^\\\$] |
5334             \\x\{ (?>[0-9A-Fa-f]+) \} |
5335             \\o\{ (?>[0-7]+) \} |
5336             \\N\{ (?>[^0-9\}][^\}]*) \} |
5337             \\ $q_char |
5338             \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} |
5339             \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} |
5340             \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} |
5341             \$ (?>\s* [0-9]+) |
5342             \$ (?>\s*) \{ (?>\s* [0-9]+ \s*) \} |
5343             \$ \$ (?![\w\{]) |
5344             \$ (?>\s*) \$ (?>\s*) $qq_variable |
5345             $q_char
5346             ))/oxmsg;
5347              
5348 0           for (my $i=0; $i <= $#char; $i++) {
5349              
5350             # "\L\u" --> "\u\L"
5351 0 0 0       if (($char[$i] eq '\L') and ($char[$i+1] eq '\u')) {
    0 0        
    0          
    0          
    0          
5352 0           @char[$i,$i+1] = @char[$i+1,$i];
5353             }
5354              
5355             # "\U\l" --> "\l\U"
5356             elsif (($char[$i] eq '\U') and ($char[$i+1] eq '\l')) {
5357 0           @char[$i,$i+1] = @char[$i+1,$i];
5358             }
5359              
5360             # octal escape sequence
5361             elsif ($char[$i] =~ /\A \\o \{ ([0-7]+) \} \z/oxms) {
5362 0           $char[$i] = Ecyrillic::octchr($1);
5363             }
5364              
5365             # hexadecimal escape sequence
5366             elsif ($char[$i] =~ /\A \\x \{ ([0-9A-Fa-f]+) \} \z/oxms) {
5367 0           $char[$i] = Ecyrillic::hexchr($1);
5368             }
5369              
5370             # \N{CHARNAME} --> N{CHARNAME}
5371             elsif ($char[$i] =~ /\A \\ ( N\{ ([^0-9\}][^\}]*) \} ) \z/oxms) {
5372 0           $char[$i] = $1;
5373             }
5374              
5375 0 0         if (0) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5376             }
5377              
5378             # \u \l \U \L \F \Q \E
5379 0           elsif ($char[$i] =~ /\A ([<>]) \z/oxms) {
5380 0 0         if ($right_e < $left_e) {
5381 0           $char[$i] = '\\' . $char[$i];
5382             }
5383             }
5384             elsif ($char[$i] eq '\u') {
5385 0           $char[$i] = '@{[Ecyrillic::ucfirst qq<';
5386 0           $left_e++;
5387             }
5388             elsif ($char[$i] eq '\l') {
5389 0           $char[$i] = '@{[Ecyrillic::lcfirst qq<';
5390 0           $left_e++;
5391             }
5392             elsif ($char[$i] eq '\U') {
5393 0           $char[$i] = '@{[Ecyrillic::uc qq<';
5394 0           $left_e++;
5395             }
5396             elsif ($char[$i] eq '\L') {
5397 0           $char[$i] = '@{[Ecyrillic::lc qq<';
5398 0           $left_e++;
5399             }
5400             elsif ($char[$i] eq '\F') {
5401 0           $char[$i] = '@{[Ecyrillic::fc qq<';
5402 0           $left_e++;
5403             }
5404             elsif ($char[$i] eq '\Q') {
5405 0           $char[$i] = '@{[CORE::quotemeta qq<';
5406 0           $left_e++;
5407             }
5408             elsif ($char[$i] eq '\E') {
5409 0 0         if ($right_e < $left_e) {
5410 0           $char[$i] = '>]}';
5411 0           $right_e++;
5412             }
5413             else {
5414 0           $char[$i] = '';
5415             }
5416             }
5417             elsif ($char[$i] eq '\Q') {
5418 0           while (1) {
5419 0 0         if (++$i > $#char) {
5420 0           last;
5421             }
5422 0 0         if ($char[$i] eq '\E') {
5423 0           last;
5424             }
5425             }
5426             }
5427             elsif ($char[$i] eq '\E') {
5428             }
5429              
5430             # $0 --> $0
5431             elsif ($char[$i] =~ /\A \$ 0 \z/oxms) {
5432             }
5433             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) 0 (?>\s*) \} \z/oxms) {
5434             }
5435              
5436             # $$ --> $$
5437             elsif ($char[$i] =~ /\A \$\$ \z/oxms) {
5438             }
5439              
5440             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
5441             # $1, $2, $3 --> $1, $2, $3 otherwise
5442             elsif ($char[$i] =~ /\A \$ ((?>[1-9][0-9]*)) \z/oxms) {
5443 0           $char[$i] = e_capture($1);
5444             }
5445             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
5446 0           $char[$i] = e_capture($1);
5447             }
5448              
5449             # $$foo[ ... ] --> $ $foo->[ ... ]
5450             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ (?:$qq_bracket)*? \] ) \z/oxms) {
5451 0           $char[$i] = e_capture($1.'->'.$2);
5452             }
5453              
5454             # $$foo{ ... } --> $ $foo->{ ... }
5455             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ (?:$qq_brace)*? \} ) \z/oxms) {
5456 0           $char[$i] = e_capture($1.'->'.$2);
5457             }
5458              
5459             # $$foo
5460             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) \z/oxms) {
5461 0           $char[$i] = e_capture($1);
5462             }
5463              
5464             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> Ecyrillic::PREMATCH()
5465             elsif ($char[$i] =~ /\A ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) \z/oxmsgc) {
5466 0           $char[$i] = '@{[Ecyrillic::PREMATCH()]}';
5467             }
5468              
5469             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> Ecyrillic::MATCH()
5470             elsif ($char[$i] =~ /\A ( \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) \z/oxmsgc) {
5471 0           $char[$i] = '@{[Ecyrillic::MATCH()]}';
5472             }
5473              
5474             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> Ecyrillic::POSTMATCH()
5475             elsif ($char[$i] =~ /\A ( \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) \z/oxmsgc) {
5476 0           $char[$i] = '@{[Ecyrillic::POSTMATCH()]}';
5477             }
5478              
5479             # ${ foo } --> ${ foo }
5480             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ (?> \s* [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* \s* ) \} \z/oxms) {
5481             }
5482              
5483             # ${ ... }
5484             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ( .+ ) \} \z/oxms) {
5485 0           $char[$i] = e_capture($1);
5486             }
5487             }
5488              
5489             # return string
5490 0 0         if ($left_e > $right_e) {
5491 0           return join '', @char, '>]}' x ($left_e - $right_e);
5492             }
5493 0           return join '', @char;
5494             }
5495              
5496             #
5497             # escape regexp (m//, qr//)
5498             #
5499             sub e_qr {
5500 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
5501 0   0       $modifier ||= '';
5502              
5503 0           $modifier =~ tr/p//d;
5504 0 0         if ($modifier =~ /([adlu])/oxms) {
5505 0           my $line = 0;
5506 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
5507 0 0         if ($filename ne __FILE__) {
5508 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
5509 0           last;
5510             }
5511             }
5512 0           die qq{Unsupported modifier "$1" used at line $line.\n};
5513             }
5514              
5515 0           $slash = 'div';
5516              
5517             # literal null string pattern
5518 0 0         if ($string eq '') {
    0          
5519 0           $modifier =~ tr/bB//d;
5520 0           $modifier =~ tr/i//d;
5521 0           return join '', $ope, $delimiter, $end_delimiter, $modifier;
5522             }
5523              
5524             # /b /B modifier
5525             elsif ($modifier =~ tr/bB//d) {
5526              
5527             # choice again delimiter
5528 0 0         if ($delimiter =~ / [\@:] /oxms) {
5529 0           my @char = $string =~ /\G ([\x00-\xFF]) /oxmsg;
5530 0           my %octet = map {$_ => 1} @char;
  0            
5531 0 0         if (not $octet{')'}) {
    0          
    0          
    0          
5532 0           $delimiter = '(';
5533 0           $end_delimiter = ')';
5534             }
5535             elsif (not $octet{'}'}) {
5536 0           $delimiter = '{';
5537 0           $end_delimiter = '}';
5538             }
5539             elsif (not $octet{']'}) {
5540 0           $delimiter = '[';
5541 0           $end_delimiter = ']';
5542             }
5543             elsif (not $octet{'>'}) {
5544 0           $delimiter = '<';
5545 0           $end_delimiter = '>';
5546             }
5547             else {
5548 0           for my $char (qw( ! " $ % & * + - . / = ? ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
5549 0 0         if (not $octet{$char}) {
5550 0           $delimiter = $char;
5551 0           $end_delimiter = $char;
5552 0           last;
5553             }
5554             }
5555             }
5556             }
5557              
5558 0 0 0       if (($ope =~ /\A m? \z/oxms) and ($delimiter eq '?')) {
5559 0           return join '', $ope, $delimiter, $string, $matched, $end_delimiter, $modifier;
5560             }
5561             else {
5562 0           return join '', $ope, $delimiter, '(?:', $string, ')', $matched, $end_delimiter, $modifier;
5563             }
5564             }
5565              
5566 0 0         my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
5567 0           my $metachar = qr/[\@\\|[\]{^]/oxms;
5568              
5569             # split regexp
5570 0           my @char = $string =~ /\G((?>
5571             [^\\\$\@\[\(] |
5572             \\x (?>[0-9A-Fa-f]{1,2}) |
5573             \\ (?>[0-7]{2,3}) |
5574             \\c [\x40-\x5F] |
5575             \\x\{ (?>[0-9A-Fa-f]+) \} |
5576             \\o\{ (?>[0-7]+) \} |
5577             \\[bBNpP]\{ (?>[^0-9\}][^\}]*) \} |
5578             \\ $q_char |
5579             \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} |
5580             \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} |
5581             \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} |
5582             [\$\@] $qq_variable |
5583             \$ (?>\s* [0-9]+) |
5584             \$ (?>\s*) \{ (?>\s* [0-9]+ \s*) \} |
5585             \$ \$ (?![\w\{]) |
5586             \$ (?>\s*) \$ (?>\s*) $qq_variable |
5587             \[\^ |
5588             \[\: (?>[a-z]+) :\] |
5589             \[\:\^ (?>[a-z]+) :\] |
5590             \(\? |
5591             $q_char
5592             ))/oxmsg;
5593              
5594             # choice again delimiter
5595 0 0         if ($delimiter =~ / [\@:] /oxms) {
5596 0           my %octet = map {$_ => 1} @char;
  0            
5597 0 0         if (not $octet{')'}) {
    0          
    0          
    0          
5598 0           $delimiter = '(';
5599 0           $end_delimiter = ')';
5600             }
5601             elsif (not $octet{'}'}) {
5602 0           $delimiter = '{';
5603 0           $end_delimiter = '}';
5604             }
5605             elsif (not $octet{']'}) {
5606 0           $delimiter = '[';
5607 0           $end_delimiter = ']';
5608             }
5609             elsif (not $octet{'>'}) {
5610 0           $delimiter = '<';
5611 0           $end_delimiter = '>';
5612             }
5613             else {
5614 0           for my $char (qw( ! " $ % & * + - . / = ? ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
5615 0 0         if (not $octet{$char}) {
5616 0           $delimiter = $char;
5617 0           $end_delimiter = $char;
5618 0           last;
5619             }
5620             }
5621             }
5622             }
5623              
5624 0           my $left_e = 0;
5625 0           my $right_e = 0;
5626 0           for (my $i=0; $i <= $#char; $i++) {
5627              
5628             # "\L\u" --> "\u\L"
5629 0 0 0       if (($char[$i] eq '\L') and ($char[$i+1] eq '\u')) {
    0 0        
    0          
    0          
    0          
    0          
5630 0           @char[$i,$i+1] = @char[$i+1,$i];
5631             }
5632              
5633             # "\U\l" --> "\l\U"
5634             elsif (($char[$i] eq '\U') and ($char[$i+1] eq '\l')) {
5635 0           @char[$i,$i+1] = @char[$i+1,$i];
5636             }
5637              
5638             # octal escape sequence
5639             elsif ($char[$i] =~ /\A \\o \{ ([0-7]+) \} \z/oxms) {
5640 0           $char[$i] = Ecyrillic::octchr($1);
5641             }
5642              
5643             # hexadecimal escape sequence
5644             elsif ($char[$i] =~ /\A \\x \{ ([0-9A-Fa-f]+) \} \z/oxms) {
5645 0           $char[$i] = Ecyrillic::hexchr($1);
5646             }
5647              
5648             # \b{...} --> b\{...}
5649             # \B{...} --> B\{...}
5650             # \N{CHARNAME} --> N\{CHARNAME}
5651             # \p{PROPERTY} --> p\{PROPERTY}
5652             # \P{PROPERTY} --> P\{PROPERTY}
5653             elsif ($char[$i] =~ /\A \\ ([bBNpP]) ( \{ ([^0-9\}][^\}]*) \} ) \z/oxms) {
5654 0           $char[$i] = $1 . '\\' . $2;
5655             }
5656              
5657             # \p, \P, \X --> p, P, X
5658             elsif ($char[$i] =~ /\A \\ ( [pPX] ) \z/oxms) {
5659 0           $char[$i] = $1;
5660             }
5661              
5662 0 0 0       if (0) {
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
5663             }
5664              
5665             # join separated multiple-octet
5666 0           elsif ($char[$i] =~ /\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms) {
5667 0 0 0       if ( ($i+3 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, @char[$i+1..$i+3]) == 3) and (CORE::eval(sprintf '"%s%s%s%s"', @char[$i..$i+3]) =~ /\A $q_char \z/oxms)) {
    0 0        
    0 0        
      0        
      0        
      0        
5668 0           $char[$i] .= join '', splice @char, $i+1, 3;
5669             }
5670             elsif (($i+2 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, @char[$i+1..$i+2]) == 2) and (CORE::eval(sprintf '"%s%s%s"', @char[$i..$i+2]) =~ /\A $q_char \z/oxms)) {
5671 0           $char[$i] .= join '', splice @char, $i+1, 2;
5672             }
5673             elsif (($i+1 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, $char[$i+1 ]) == 1) and (CORE::eval(sprintf '"%s%s"', @char[$i..$i+1]) =~ /\A $q_char \z/oxms)) {
5674 0           $char[$i] .= join '', splice @char, $i+1, 1;
5675             }
5676             }
5677              
5678             # open character class [...]
5679             elsif ($char[$i] eq '[') {
5680 0           my $left = $i;
5681              
5682             # [] make die "Unmatched [] in regexp ...\n"
5683             # (and so on)
5684              
5685 0 0         if ($char[$i+1] eq ']') {
5686 0           $i++;
5687             }
5688              
5689 0           while (1) {
5690 0 0         if (++$i > $#char) {
5691 0           die __FILE__, ": Unmatched [] in regexp\n";
5692             }
5693 0 0         if ($char[$i] eq ']') {
5694 0           my $right = $i;
5695              
5696             # [...]
5697 0 0         if (grep(/\A [\$\@]/oxms,@char[$left+1..$right-1]) >= 1) {
5698 0           splice @char, $left, $right-$left+1, sprintf(q{@{[Ecyrillic::charlist_qr(%s,'%s')]}}, join(',', map {qq_stuff($delimiter,$end_delimiter,$_)} @char[$left+1..$right-1]), $modifier);
  0            
5699             }
5700             else {
5701 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_qr(@char[$left+1..$right-1], $modifier);
5702             }
5703              
5704 0           $i = $left;
5705 0           last;
5706             }
5707             }
5708             }
5709              
5710             # open character class [^...]
5711             elsif ($char[$i] eq '[^') {
5712 0           my $left = $i;
5713              
5714             # [^] make die "Unmatched [] in regexp ...\n"
5715             # (and so on)
5716              
5717 0 0         if ($char[$i+1] eq ']') {
5718 0           $i++;
5719             }
5720              
5721 0           while (1) {
5722 0 0         if (++$i > $#char) {
5723 0           die __FILE__, ": Unmatched [] in regexp\n";
5724             }
5725 0 0         if ($char[$i] eq ']') {
5726 0           my $right = $i;
5727              
5728             # [^...]
5729 0 0         if (grep(/\A [\$\@]/oxms,@char[$left+1..$right-1]) >= 1) {
5730 0           splice @char, $left, $right-$left+1, sprintf(q{@{[Ecyrillic::charlist_not_qr(%s,'%s')]}}, join(',', map {qq_stuff($delimiter,$end_delimiter,$_)} @char[$left+1..$right-1]), $modifier);
  0            
5731             }
5732             else {
5733 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_not_qr(@char[$left+1..$right-1], $modifier);
5734             }
5735              
5736 0           $i = $left;
5737 0           last;
5738             }
5739             }
5740             }
5741              
5742             # rewrite character class or escape character
5743             elsif (my $char = character_class($char[$i],$modifier)) {
5744 0           $char[$i] = $char;
5745             }
5746              
5747             # /i modifier
5748             elsif ($ignorecase and ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) and (Ecyrillic::uc($char[$i]) ne Ecyrillic::fc($char[$i]))) {
5749 0 0         if (CORE::length(Ecyrillic::fc($char[$i])) == 1) {
5750 0           $char[$i] = '[' . Ecyrillic::uc($char[$i]) . Ecyrillic::fc($char[$i]) . ']';
5751             }
5752             else {
5753 0           $char[$i] = '(?:' . Ecyrillic::uc($char[$i]) . '|' . Ecyrillic::fc($char[$i]) . ')';
5754             }
5755             }
5756              
5757             # \u \l \U \L \F \Q \E
5758             elsif ($char[$i] =~ /\A [<>] \z/oxms) {
5759 0 0         if ($right_e < $left_e) {
5760 0           $char[$i] = '\\' . $char[$i];
5761             }
5762             }
5763             elsif ($char[$i] eq '\u') {
5764 0           $char[$i] = '@{[Ecyrillic::ucfirst qq<';
5765 0           $left_e++;
5766             }
5767             elsif ($char[$i] eq '\l') {
5768 0           $char[$i] = '@{[Ecyrillic::lcfirst qq<';
5769 0           $left_e++;
5770             }
5771             elsif ($char[$i] eq '\U') {
5772 0           $char[$i] = '@{[Ecyrillic::uc qq<';
5773 0           $left_e++;
5774             }
5775             elsif ($char[$i] eq '\L') {
5776 0           $char[$i] = '@{[Ecyrillic::lc qq<';
5777 0           $left_e++;
5778             }
5779             elsif ($char[$i] eq '\F') {
5780 0           $char[$i] = '@{[Ecyrillic::fc qq<';
5781 0           $left_e++;
5782             }
5783             elsif ($char[$i] eq '\Q') {
5784 0           $char[$i] = '@{[CORE::quotemeta qq<';
5785 0           $left_e++;
5786             }
5787             elsif ($char[$i] eq '\E') {
5788 0 0         if ($right_e < $left_e) {
5789 0           $char[$i] = '>]}';
5790 0           $right_e++;
5791             }
5792             else {
5793 0           $char[$i] = '';
5794             }
5795             }
5796             elsif ($char[$i] eq '\Q') {
5797 0           while (1) {
5798 0 0         if (++$i > $#char) {
5799 0           last;
5800             }
5801 0 0         if ($char[$i] eq '\E') {
5802 0           last;
5803             }
5804             }
5805             }
5806             elsif ($char[$i] eq '\E') {
5807             }
5808              
5809             # $0 --> $0
5810             elsif ($char[$i] =~ /\A \$ 0 \z/oxms) {
5811 0 0         if ($ignorecase) {
5812 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5813             }
5814             }
5815             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) 0 (?>\s*) \} \z/oxms) {
5816 0 0         if ($ignorecase) {
5817 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5818             }
5819             }
5820              
5821             # $$ --> $$
5822             elsif ($char[$i] =~ /\A \$\$ \z/oxms) {
5823             }
5824              
5825             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
5826             # $1, $2, $3 --> $1, $2, $3 otherwise
5827             elsif ($char[$i] =~ /\A \$ ((?>[1-9][0-9]*)) \z/oxms) {
5828 0           $char[$i] = e_capture($1);
5829 0 0         if ($ignorecase) {
5830 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5831             }
5832             }
5833             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
5834 0           $char[$i] = e_capture($1);
5835 0 0         if ($ignorecase) {
5836 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5837             }
5838             }
5839              
5840             # $$foo[ ... ] --> $ $foo->[ ... ]
5841             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ (?:$qq_bracket)*? \] ) \z/oxms) {
5842 0           $char[$i] = e_capture($1.'->'.$2);
5843 0 0         if ($ignorecase) {
5844 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5845             }
5846             }
5847              
5848             # $$foo{ ... } --> $ $foo->{ ... }
5849             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ (?:$qq_brace)*? \} ) \z/oxms) {
5850 0           $char[$i] = e_capture($1.'->'.$2);
5851 0 0         if ($ignorecase) {
5852 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5853             }
5854             }
5855              
5856             # $$foo
5857             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) \z/oxms) {
5858 0           $char[$i] = e_capture($1);
5859 0 0         if ($ignorecase) {
5860 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5861             }
5862             }
5863              
5864             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> Ecyrillic::PREMATCH()
5865             elsif ($char[$i] =~ /\A ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) \z/oxmsgc) {
5866 0 0         if ($ignorecase) {
5867 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::PREMATCH())]}';
5868             }
5869             else {
5870 0           $char[$i] = '@{[Ecyrillic::PREMATCH()]}';
5871             }
5872             }
5873              
5874             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> Ecyrillic::MATCH()
5875             elsif ($char[$i] =~ /\A ( \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) \z/oxmsgc) {
5876 0 0         if ($ignorecase) {
5877 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::MATCH())]}';
5878             }
5879             else {
5880 0           $char[$i] = '@{[Ecyrillic::MATCH()]}';
5881             }
5882             }
5883              
5884             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> Ecyrillic::POSTMATCH()
5885             elsif ($char[$i] =~ /\A ( \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) \z/oxmsgc) {
5886 0 0         if ($ignorecase) {
5887 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::POSTMATCH())]}';
5888             }
5889             else {
5890 0           $char[$i] = '@{[Ecyrillic::POSTMATCH()]}';
5891             }
5892             }
5893              
5894             # ${ foo }
5895             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ((?> \s* [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* \s* )) \} \z/oxms) {
5896 0 0         if ($ignorecase) {
5897 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5898             }
5899             }
5900              
5901             # ${ ... }
5902             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ( .+ ) \} \z/oxms) {
5903 0           $char[$i] = e_capture($1);
5904 0 0         if ($ignorecase) {
5905 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5906             }
5907             }
5908              
5909             # $scalar or @array
5910             elsif ($char[$i] =~ /\A [\$\@].+ /oxms) {
5911 0           $char[$i] = e_string($char[$i]);
5912 0 0         if ($ignorecase) {
5913 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
5914             }
5915             }
5916              
5917             # quote character before ? + * {
5918             elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
5919 0 0 0       if ($char[$i-1] =~ /\A (?:[\x00-\xFF]|\\[0-7]{2,3}|\\x[0-9-A-Fa-f]{1,2}) \z/oxms) {
    0          
5920             }
5921             elsif (($ope =~ /\A m? \z/oxms) and ($delimiter eq '?')) {
5922 0           my $char = $char[$i-1];
5923 0 0         if ($char[$i] eq '{') {
5924 0           die __FILE__, qq{: "MULTIBYTE{n}" should be "(MULTIBYTE){n}" in m?? (and shift \$1,\$2,\$3,...) ($char){n}\n};
5925             }
5926             else {
5927 0           die __FILE__, qq{: "MULTIBYTE$char[$i]" should be "(MULTIBYTE)$char[$i]" in m?? (and shift \$1,\$2,\$3,...) ($char)$char[$i]\n};
5928             }
5929             }
5930             else {
5931 0           $char[$i-1] = '(?:' . $char[$i-1] . ')';
5932             }
5933             }
5934             }
5935              
5936             # make regexp string
5937 0           $modifier =~ tr/i//d;
5938 0 0         if ($left_e > $right_e) {
5939 0 0 0       if (($ope =~ /\A m? \z/oxms) and ($delimiter eq '?')) {
5940 0           return join '', $ope, $delimiter, $anchor, @char, '>]}' x ($left_e - $right_e), $matched, $end_delimiter, $modifier;
5941             }
5942             else {
5943 0           return join '', $ope, $delimiter, $anchor, '(?:', @char, '>]}' x ($left_e - $right_e), ')', $matched, $end_delimiter, $modifier;
5944             }
5945             }
5946 0 0 0       if (($ope =~ /\A m? \z/oxms) and ($delimiter eq '?')) {
5947 0           return join '', $ope, $delimiter, $anchor, @char, $matched, $end_delimiter, $modifier;
5948             }
5949             else {
5950 0           return join '', $ope, $delimiter, $anchor, '(?:', @char, ')', $matched, $end_delimiter, $modifier;
5951             }
5952             }
5953              
5954             #
5955             # double quote stuff
5956             #
5957             sub qq_stuff {
5958 0     0 0   my($delimiter,$end_delimiter,$stuff) = @_;
5959              
5960             # scalar variable or array variable
5961 0 0         if ($stuff =~ /\A [\$\@] /oxms) {
5962 0           return $stuff;
5963             }
5964              
5965             # quote by delimiter
5966 0           my %octet = map {$_ => 1} ($stuff =~ /\G ([\x00-\xFF]) /oxmsg);
  0            
5967 0           for my $char (qw( ! " $ % & * + - . / : = ? @ ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
5968 0 0         next if $char eq $delimiter;
5969 0 0         next if $char eq $end_delimiter;
5970 0 0         if (not $octet{$char}) {
5971 0           return join '', 'qq', $char, $stuff, $char;
5972             }
5973             }
5974 0           return join '', 'qq', '<', $stuff, '>';
5975             }
5976              
5977             #
5978             # escape regexp (m'', qr'', and m''b, qr''b)
5979             #
5980             sub e_qr_q {
5981 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
5982 0   0       $modifier ||= '';
5983              
5984 0           $modifier =~ tr/p//d;
5985 0 0         if ($modifier =~ /([adlu])/oxms) {
5986 0           my $line = 0;
5987 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
5988 0 0         if ($filename ne __FILE__) {
5989 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
5990 0           last;
5991             }
5992             }
5993 0           die qq{Unsupported modifier "$1" used at line $line.\n};
5994             }
5995              
5996 0           $slash = 'div';
5997              
5998             # literal null string pattern
5999 0 0         if ($string eq '') {
    0          
6000 0           $modifier =~ tr/bB//d;
6001 0           $modifier =~ tr/i//d;
6002 0           return join '', $ope, $delimiter, $end_delimiter, $modifier;
6003             }
6004              
6005             # with /b /B modifier
6006             elsif ($modifier =~ tr/bB//d) {
6007 0           return e_qr_qb($ope,$delimiter,$end_delimiter,$string,$modifier);
6008             }
6009              
6010             # without /b /B modifier
6011             else {
6012 0           return e_qr_qt($ope,$delimiter,$end_delimiter,$string,$modifier);
6013             }
6014             }
6015              
6016             #
6017             # escape regexp (m'', qr'')
6018             #
6019             sub e_qr_qt {
6020 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
6021              
6022 0 0         my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
6023              
6024             # split regexp
6025 0           my @char = $string =~ /\G((?>
6026             [^\\\[\$\@\/] |
6027             [\x00-\xFF] |
6028             \[\^ |
6029             \[\: (?>[a-z]+) \:\] |
6030             \[\:\^ (?>[a-z]+) \:\] |
6031             [\$\@\/] |
6032             \\ (?:$q_char) |
6033             (?:$q_char)
6034             ))/oxmsg;
6035              
6036             # unescape character
6037 0           for (my $i=0; $i <= $#char; $i++) {
6038 0 0 0       if (0) {
    0 0        
    0 0        
    0          
    0          
    0          
6039             }
6040              
6041             # open character class [...]
6042 0           elsif ($char[$i] eq '[') {
6043 0           my $left = $i;
6044 0 0         if ($char[$i+1] eq ']') {
6045 0           $i++;
6046             }
6047 0           while (1) {
6048 0 0         if (++$i > $#char) {
6049 0           die __FILE__, ": Unmatched [] in regexp\n";
6050             }
6051 0 0         if ($char[$i] eq ']') {
6052 0           my $right = $i;
6053              
6054             # [...]
6055 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_qr(@char[$left+1..$right-1], $modifier);
6056              
6057 0           $i = $left;
6058 0           last;
6059             }
6060             }
6061             }
6062              
6063             # open character class [^...]
6064             elsif ($char[$i] eq '[^') {
6065 0           my $left = $i;
6066 0 0         if ($char[$i+1] eq ']') {
6067 0           $i++;
6068             }
6069 0           while (1) {
6070 0 0         if (++$i > $#char) {
6071 0           die __FILE__, ": Unmatched [] in regexp\n";
6072             }
6073 0 0         if ($char[$i] eq ']') {
6074 0           my $right = $i;
6075              
6076             # [^...]
6077 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_not_qr(@char[$left+1..$right-1], $modifier);
6078              
6079 0           $i = $left;
6080 0           last;
6081             }
6082             }
6083             }
6084              
6085             # escape $ @ / and \
6086             elsif ($char[$i] =~ /\A [\$\@\/\\] \z/oxms) {
6087 0           $char[$i] = '\\' . $char[$i];
6088             }
6089              
6090             # rewrite character class or escape character
6091             elsif (my $char = character_class($char[$i],$modifier)) {
6092 0           $char[$i] = $char;
6093             }
6094              
6095             # /i modifier
6096             elsif ($ignorecase and ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) and (Ecyrillic::uc($char[$i]) ne Ecyrillic::fc($char[$i]))) {
6097 0 0         if (CORE::length(Ecyrillic::fc($char[$i])) == 1) {
6098 0           $char[$i] = '[' . Ecyrillic::uc($char[$i]) . Ecyrillic::fc($char[$i]) . ']';
6099             }
6100             else {
6101 0           $char[$i] = '(?:' . Ecyrillic::uc($char[$i]) . '|' . Ecyrillic::fc($char[$i]) . ')';
6102             }
6103             }
6104              
6105             # quote character before ? + * {
6106             elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
6107 0 0         if ($char[$i-1] =~ /\A [\x00-\xFF] \z/oxms) {
6108             }
6109             else {
6110 0           $char[$i-1] = '(?:' . $char[$i-1] . ')';
6111             }
6112             }
6113             }
6114              
6115 0           $delimiter = '/';
6116 0           $end_delimiter = '/';
6117              
6118 0           $modifier =~ tr/i//d;
6119 0           return join '', $ope, $delimiter, $anchor, '(?:', @char, ')', $matched, $end_delimiter, $modifier;
6120             }
6121              
6122             #
6123             # escape regexp (m''b, qr''b)
6124             #
6125             sub e_qr_qb {
6126 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
6127              
6128             # split regexp
6129 0           my @char = $string =~ /\G ((?>[^\\]|\\\\)) /oxmsg;
6130              
6131             # unescape character
6132 0           for (my $i=0; $i <= $#char; $i++) {
6133 0 0         if (0) {
    0          
6134             }
6135              
6136             # remain \\
6137 0           elsif ($char[$i] eq '\\\\') {
6138             }
6139              
6140             # escape $ @ / and \
6141             elsif ($char[$i] =~ /\A [\$\@\/\\] \z/oxms) {
6142 0           $char[$i] = '\\' . $char[$i];
6143             }
6144             }
6145              
6146 0           $delimiter = '/';
6147 0           $end_delimiter = '/';
6148 0           return join '', $ope, $delimiter, '(?:', @char, ')', $matched, $end_delimiter, $modifier;
6149             }
6150              
6151             #
6152             # escape regexp (s/here//)
6153             #
6154             sub e_s1 {
6155 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
6156 0   0       $modifier ||= '';
6157              
6158 0           $modifier =~ tr/p//d;
6159 0 0         if ($modifier =~ /([adlu])/oxms) {
6160 0           my $line = 0;
6161 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
6162 0 0         if ($filename ne __FILE__) {
6163 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
6164 0           last;
6165             }
6166             }
6167 0           die qq{Unsupported modifier "$1" used at line $line.\n};
6168             }
6169              
6170 0           $slash = 'div';
6171              
6172             # literal null string pattern
6173 0 0         if ($string eq '') {
    0          
6174 0           $modifier =~ tr/bB//d;
6175 0           $modifier =~ tr/i//d;
6176 0           return join '', $ope, $delimiter, $end_delimiter, $modifier;
6177             }
6178              
6179             # /b /B modifier
6180             elsif ($modifier =~ tr/bB//d) {
6181              
6182             # choice again delimiter
6183 0 0         if ($delimiter =~ / [\@:] /oxms) {
6184 0           my @char = $string =~ /\G ([\x00-\xFF]) /oxmsg;
6185 0           my %octet = map {$_ => 1} @char;
  0            
6186 0 0         if (not $octet{')'}) {
    0          
    0          
    0          
6187 0           $delimiter = '(';
6188 0           $end_delimiter = ')';
6189             }
6190             elsif (not $octet{'}'}) {
6191 0           $delimiter = '{';
6192 0           $end_delimiter = '}';
6193             }
6194             elsif (not $octet{']'}) {
6195 0           $delimiter = '[';
6196 0           $end_delimiter = ']';
6197             }
6198             elsif (not $octet{'>'}) {
6199 0           $delimiter = '<';
6200 0           $end_delimiter = '>';
6201             }
6202             else {
6203 0           for my $char (qw( ! " $ % & * + - . / = ? ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
6204 0 0         if (not $octet{$char}) {
6205 0           $delimiter = $char;
6206 0           $end_delimiter = $char;
6207 0           last;
6208             }
6209             }
6210             }
6211             }
6212              
6213 0           my $prematch = '';
6214 0           return join '', $ope, $delimiter, $prematch, '(?:', $string, ')', $matched, $end_delimiter, $modifier;
6215             }
6216              
6217 0 0         my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
6218 0           my $metachar = qr/[\@\\|[\]{^]/oxms;
6219              
6220             # split regexp
6221 0           my @char = $string =~ /\G((?>
6222             [^\\\$\@\[\(] |
6223             \\ (?>[1-9][0-9]*) |
6224             \\g (?>\s*) (?>[1-9][0-9]*) |
6225             \\g (?>\s*) \{ (?>\s*) (?>[1-9][0-9]*) (?>\s*) \} |
6226             \\g (?>\s*) \{ (?>\s*) - (?>\s*) (?>[1-9][0-9]*) (?>\s*) \} |
6227             \\x (?>[0-9A-Fa-f]{1,2}) |
6228             \\ (?>[0-7]{2,3}) |
6229             \\c [\x40-\x5F] |
6230             \\x\{ (?>[0-9A-Fa-f]+) \} |
6231             \\o\{ (?>[0-7]+) \} |
6232             \\[bBNpP]\{ (?>[^0-9\}][^\}]*) \} |
6233             \\ $q_char |
6234             \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} |
6235             \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} |
6236             \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} |
6237             [\$\@] $qq_variable |
6238             \$ (?>\s* [0-9]+) |
6239             \$ (?>\s*) \{ (?>\s* [0-9]+ \s*) \} |
6240             \$ \$ (?![\w\{]) |
6241             \$ (?>\s*) \$ (?>\s*) $qq_variable |
6242             \[\^ |
6243             \[\: (?>[a-z]+) :\] |
6244             \[\:\^ (?>[a-z]+) :\] |
6245             \(\? |
6246             $q_char
6247             ))/oxmsg;
6248              
6249             # choice again delimiter
6250 0 0         if ($delimiter =~ / [\@:] /oxms) {
6251 0           my %octet = map {$_ => 1} @char;
  0            
6252 0 0         if (not $octet{')'}) {
    0          
    0          
    0          
6253 0           $delimiter = '(';
6254 0           $end_delimiter = ')';
6255             }
6256             elsif (not $octet{'}'}) {
6257 0           $delimiter = '{';
6258 0           $end_delimiter = '}';
6259             }
6260             elsif (not $octet{']'}) {
6261 0           $delimiter = '[';
6262 0           $end_delimiter = ']';
6263             }
6264             elsif (not $octet{'>'}) {
6265 0           $delimiter = '<';
6266 0           $end_delimiter = '>';
6267             }
6268             else {
6269 0           for my $char (qw( ! " $ % & * + - . / = ? ^ ` | ~ ), "\x00".."\x1F", "\x7F", "\xFF") {
6270 0 0         if (not $octet{$char}) {
6271 0           $delimiter = $char;
6272 0           $end_delimiter = $char;
6273 0           last;
6274             }
6275             }
6276             }
6277             }
6278              
6279             # count '('
6280 0           my $parens = grep { $_ eq '(' } @char;
  0            
6281              
6282 0           my $left_e = 0;
6283 0           my $right_e = 0;
6284 0           for (my $i=0; $i <= $#char; $i++) {
6285              
6286             # "\L\u" --> "\u\L"
6287 0 0 0       if (($char[$i] eq '\L') and ($char[$i+1] eq '\u')) {
    0 0        
    0          
    0          
    0          
    0          
6288 0           @char[$i,$i+1] = @char[$i+1,$i];
6289             }
6290              
6291             # "\U\l" --> "\l\U"
6292             elsif (($char[$i] eq '\U') and ($char[$i+1] eq '\l')) {
6293 0           @char[$i,$i+1] = @char[$i+1,$i];
6294             }
6295              
6296             # octal escape sequence
6297             elsif ($char[$i] =~ /\A \\o \{ ([0-7]+) \} \z/oxms) {
6298 0           $char[$i] = Ecyrillic::octchr($1);
6299             }
6300              
6301             # hexadecimal escape sequence
6302             elsif ($char[$i] =~ /\A \\x \{ ([0-9A-Fa-f]+) \} \z/oxms) {
6303 0           $char[$i] = Ecyrillic::hexchr($1);
6304             }
6305              
6306             # \b{...} --> b\{...}
6307             # \B{...} --> B\{...}
6308             # \N{CHARNAME} --> N\{CHARNAME}
6309             # \p{PROPERTY} --> p\{PROPERTY}
6310             # \P{PROPERTY} --> P\{PROPERTY}
6311             elsif ($char[$i] =~ /\A \\ ([bBNpP]) ( \{ ([^0-9\}][^\}]*) \} ) \z/oxms) {
6312 0           $char[$i] = $1 . '\\' . $2;
6313             }
6314              
6315             # \p, \P, \X --> p, P, X
6316             elsif ($char[$i] =~ /\A \\ ( [pPX] ) \z/oxms) {
6317 0           $char[$i] = $1;
6318             }
6319              
6320 0 0 0       if (0) {
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
6321             }
6322              
6323             # join separated multiple-octet
6324 0           elsif ($char[$i] =~ /\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms) {
6325 0 0 0       if ( ($i+3 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, @char[$i+1..$i+3]) == 3) and (CORE::eval(sprintf '"%s%s%s%s"', @char[$i..$i+3]) =~ /\A $q_char \z/oxms)) {
    0 0        
    0 0        
      0        
      0        
      0        
6326 0           $char[$i] .= join '', splice @char, $i+1, 3;
6327             }
6328             elsif (($i+2 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, @char[$i+1..$i+2]) == 2) and (CORE::eval(sprintf '"%s%s%s"', @char[$i..$i+2]) =~ /\A $q_char \z/oxms)) {
6329 0           $char[$i] .= join '', splice @char, $i+1, 2;
6330             }
6331             elsif (($i+1 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, $char[$i+1 ]) == 1) and (CORE::eval(sprintf '"%s%s"', @char[$i..$i+1]) =~ /\A $q_char \z/oxms)) {
6332 0           $char[$i] .= join '', splice @char, $i+1, 1;
6333             }
6334             }
6335              
6336             # open character class [...]
6337             elsif ($char[$i] eq '[') {
6338 0           my $left = $i;
6339 0 0         if ($char[$i+1] eq ']') {
6340 0           $i++;
6341             }
6342 0           while (1) {
6343 0 0         if (++$i > $#char) {
6344 0           die __FILE__, ": Unmatched [] in regexp\n";
6345             }
6346 0 0         if ($char[$i] eq ']') {
6347 0           my $right = $i;
6348              
6349             # [...]
6350 0 0         if (grep(/\A [\$\@]/oxms,@char[$left+1..$right-1]) >= 1) {
6351 0           splice @char, $left, $right-$left+1, sprintf(q{@{[Ecyrillic::charlist_qr(%s,'%s')]}}, join(',', map {qq_stuff($delimiter,$end_delimiter,$_)} @char[$left+1..$right-1]), $modifier);
  0            
6352             }
6353             else {
6354 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_qr(@char[$left+1..$right-1], $modifier);
6355             }
6356              
6357 0           $i = $left;
6358 0           last;
6359             }
6360             }
6361             }
6362              
6363             # open character class [^...]
6364             elsif ($char[$i] eq '[^') {
6365 0           my $left = $i;
6366 0 0         if ($char[$i+1] eq ']') {
6367 0           $i++;
6368             }
6369 0           while (1) {
6370 0 0         if (++$i > $#char) {
6371 0           die __FILE__, ": Unmatched [] in regexp\n";
6372             }
6373 0 0         if ($char[$i] eq ']') {
6374 0           my $right = $i;
6375              
6376             # [^...]
6377 0 0         if (grep(/\A [\$\@]/oxms,@char[$left+1..$right-1]) >= 1) {
6378 0           splice @char, $left, $right-$left+1, sprintf(q{@{[Ecyrillic::charlist_not_qr(%s,'%s')]}}, join(',', map {qq_stuff($delimiter,$end_delimiter,$_)} @char[$left+1..$right-1]), $modifier);
  0            
6379             }
6380             else {
6381 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_not_qr(@char[$left+1..$right-1], $modifier);
6382             }
6383              
6384 0           $i = $left;
6385 0           last;
6386             }
6387             }
6388             }
6389              
6390             # rewrite character class or escape character
6391             elsif (my $char = character_class($char[$i],$modifier)) {
6392 0           $char[$i] = $char;
6393             }
6394              
6395             # /i modifier
6396             elsif ($ignorecase and ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) and (Ecyrillic::uc($char[$i]) ne Ecyrillic::fc($char[$i]))) {
6397 0 0         if (CORE::length(Ecyrillic::fc($char[$i])) == 1) {
6398 0           $char[$i] = '[' . Ecyrillic::uc($char[$i]) . Ecyrillic::fc($char[$i]) . ']';
6399             }
6400             else {
6401 0           $char[$i] = '(?:' . Ecyrillic::uc($char[$i]) . '|' . Ecyrillic::fc($char[$i]) . ')';
6402             }
6403             }
6404              
6405             # \u \l \U \L \F \Q \E
6406             elsif ($char[$i] =~ /\A [<>] \z/oxms) {
6407 0 0         if ($right_e < $left_e) {
6408 0           $char[$i] = '\\' . $char[$i];
6409             }
6410             }
6411             elsif ($char[$i] eq '\u') {
6412 0           $char[$i] = '@{[Ecyrillic::ucfirst qq<';
6413 0           $left_e++;
6414             }
6415             elsif ($char[$i] eq '\l') {
6416 0           $char[$i] = '@{[Ecyrillic::lcfirst qq<';
6417 0           $left_e++;
6418             }
6419             elsif ($char[$i] eq '\U') {
6420 0           $char[$i] = '@{[Ecyrillic::uc qq<';
6421 0           $left_e++;
6422             }
6423             elsif ($char[$i] eq '\L') {
6424 0           $char[$i] = '@{[Ecyrillic::lc qq<';
6425 0           $left_e++;
6426             }
6427             elsif ($char[$i] eq '\F') {
6428 0           $char[$i] = '@{[Ecyrillic::fc qq<';
6429 0           $left_e++;
6430             }
6431             elsif ($char[$i] eq '\Q') {
6432 0           $char[$i] = '@{[CORE::quotemeta qq<';
6433 0           $left_e++;
6434             }
6435             elsif ($char[$i] eq '\E') {
6436 0 0         if ($right_e < $left_e) {
6437 0           $char[$i] = '>]}';
6438 0           $right_e++;
6439             }
6440             else {
6441 0           $char[$i] = '';
6442             }
6443             }
6444             elsif ($char[$i] eq '\Q') {
6445 0           while (1) {
6446 0 0         if (++$i > $#char) {
6447 0           last;
6448             }
6449 0 0         if ($char[$i] eq '\E') {
6450 0           last;
6451             }
6452             }
6453             }
6454             elsif ($char[$i] eq '\E') {
6455             }
6456              
6457             # \0 --> \0
6458             elsif ($char[$i] =~ /\A \\ (?>\s*) 0 \z/oxms) {
6459             }
6460              
6461             # \g{N}, \g{-N}
6462              
6463             # P.108 Using Simple Patterns
6464             # in Chapter 7: In the World of Regular Expressions
6465             # of ISBN 978-0-596-52010-6 Learning Perl, Fifth Edition
6466              
6467             # P.221 Capturing
6468             # in Chapter 5: Pattern Matching
6469             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
6470              
6471             # \g{-1}, \g{-2}, \g{-3} --> \g{-1}, \g{-2}, \g{-3}
6472             elsif ($char[$i] =~ /\A \\g (?>\s*) \{ (?>\s*) - (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
6473             }
6474              
6475             # \g{1}, \g{2}, \g{3} --> \g{2}, \g{3}, \g{4} (only when multibyte anchoring is enable)
6476             elsif ($char[$i] =~ /\A \\g (?>\s*) \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
6477             }
6478              
6479             # \g1, \g2, \g3 --> \g2, \g3, \g4 (only when multibyte anchoring is enable)
6480             elsif ($char[$i] =~ /\A \\g (?>\s*) ((?>[1-9][0-9]*)) \z/oxms) {
6481             }
6482              
6483             # \1, \2, \3 --> \2, \3, \4 (only when multibyte anchoring is enable)
6484             elsif ($char[$i] =~ /\A \\ (?>\s*) ((?>[1-9][0-9]*)) \z/oxms) {
6485             }
6486              
6487             # $0 --> $0
6488             elsif ($char[$i] =~ /\A \$ 0 \z/oxms) {
6489 0 0         if ($ignorecase) {
6490 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6491             }
6492             }
6493             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) 0 (?>\s*) \} \z/oxms) {
6494 0 0         if ($ignorecase) {
6495 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6496             }
6497             }
6498              
6499             # $$ --> $$
6500             elsif ($char[$i] =~ /\A \$\$ \z/oxms) {
6501             }
6502              
6503             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
6504             # $1, $2, $3 --> $1, $2, $3 otherwise
6505             elsif ($char[$i] =~ /\A \$ ((?>[1-9][0-9]*)) \z/oxms) {
6506 0           $char[$i] = e_capture($1);
6507 0 0         if ($ignorecase) {
6508 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6509             }
6510             }
6511             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
6512 0           $char[$i] = e_capture($1);
6513 0 0         if ($ignorecase) {
6514 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6515             }
6516             }
6517              
6518             # $$foo[ ... ] --> $ $foo->[ ... ]
6519             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ (?:$qq_bracket)*? \] ) \z/oxms) {
6520 0           $char[$i] = e_capture($1.'->'.$2);
6521 0 0         if ($ignorecase) {
6522 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6523             }
6524             }
6525              
6526             # $$foo{ ... } --> $ $foo->{ ... }
6527             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ (?:$qq_brace)*? \} ) \z/oxms) {
6528 0           $char[$i] = e_capture($1.'->'.$2);
6529 0 0         if ($ignorecase) {
6530 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6531             }
6532             }
6533              
6534             # $$foo
6535             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) \z/oxms) {
6536 0           $char[$i] = e_capture($1);
6537 0 0         if ($ignorecase) {
6538 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6539             }
6540             }
6541              
6542             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> Ecyrillic::PREMATCH()
6543             elsif ($char[$i] =~ /\A ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) \z/oxmsgc) {
6544 0 0         if ($ignorecase) {
6545 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::PREMATCH())]}';
6546             }
6547             else {
6548 0           $char[$i] = '@{[Ecyrillic::PREMATCH()]}';
6549             }
6550             }
6551              
6552             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> Ecyrillic::MATCH()
6553             elsif ($char[$i] =~ /\A ( \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) \z/oxmsgc) {
6554 0 0         if ($ignorecase) {
6555 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::MATCH())]}';
6556             }
6557             else {
6558 0           $char[$i] = '@{[Ecyrillic::MATCH()]}';
6559             }
6560             }
6561              
6562             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> Ecyrillic::POSTMATCH()
6563             elsif ($char[$i] =~ /\A ( \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) \z/oxmsgc) {
6564 0 0         if ($ignorecase) {
6565 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::POSTMATCH())]}';
6566             }
6567             else {
6568 0           $char[$i] = '@{[Ecyrillic::POSTMATCH()]}';
6569             }
6570             }
6571              
6572             # ${ foo }
6573             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ((?> \s* [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* \s* )) \} \z/oxms) {
6574 0 0         if ($ignorecase) {
6575 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6576             }
6577             }
6578              
6579             # ${ ... }
6580             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ( .+ ) \} \z/oxms) {
6581 0           $char[$i] = e_capture($1);
6582 0 0         if ($ignorecase) {
6583 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6584             }
6585             }
6586              
6587             # $scalar or @array
6588             elsif ($char[$i] =~ /\A [\$\@].+ /oxms) {
6589 0           $char[$i] = e_string($char[$i]);
6590 0 0         if ($ignorecase) {
6591 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
6592             }
6593             }
6594              
6595             # quote character before ? + * {
6596             elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
6597 0 0         if ($char[$i-1] =~ /\A (?:[\x00-\xFF]|\\[0-7]{2,3}|\\x[0-9-A-Fa-f]{1,2}) \z/oxms) {
6598             }
6599             else {
6600 0           $char[$i-1] = '(?:' . $char[$i-1] . ')';
6601             }
6602             }
6603             }
6604              
6605             # make regexp string
6606 0           my $prematch = '';
6607 0           $modifier =~ tr/i//d;
6608 0 0         if ($left_e > $right_e) {
6609 0           return join '', $ope, $delimiter, $prematch, '(?:', @char, '>]}' x ($left_e - $right_e), ')', $matched, $end_delimiter, $modifier;
6610             }
6611 0           return join '', $ope, $delimiter, $prematch, '(?:', @char, ')', $matched, $end_delimiter, $modifier;
6612             }
6613              
6614             #
6615             # escape regexp (s'here'' or s'here''b)
6616             #
6617             sub e_s1_q {
6618 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
6619 0   0       $modifier ||= '';
6620              
6621 0           $modifier =~ tr/p//d;
6622 0 0         if ($modifier =~ /([adlu])/oxms) {
6623 0           my $line = 0;
6624 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
6625 0 0         if ($filename ne __FILE__) {
6626 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
6627 0           last;
6628             }
6629             }
6630 0           die qq{Unsupported modifier "$1" used at line $line.\n};
6631             }
6632              
6633 0           $slash = 'div';
6634              
6635             # literal null string pattern
6636 0 0         if ($string eq '') {
    0          
6637 0           $modifier =~ tr/bB//d;
6638 0           $modifier =~ tr/i//d;
6639 0           return join '', $ope, $delimiter, $end_delimiter, $modifier;
6640             }
6641              
6642             # with /b /B modifier
6643             elsif ($modifier =~ tr/bB//d) {
6644 0           return e_s1_qb($ope,$delimiter,$end_delimiter,$string,$modifier);
6645             }
6646              
6647             # without /b /B modifier
6648             else {
6649 0           return e_s1_qt($ope,$delimiter,$end_delimiter,$string,$modifier);
6650             }
6651             }
6652              
6653             #
6654             # escape regexp (s'here'')
6655             #
6656             sub e_s1_qt {
6657 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
6658              
6659 0 0         my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
6660              
6661             # split regexp
6662 0           my @char = $string =~ /\G((?>
6663             [^\\\[\$\@\/] |
6664             [\x00-\xFF] |
6665             \[\^ |
6666             \[\: (?>[a-z]+) \:\] |
6667             \[\:\^ (?>[a-z]+) \:\] |
6668             [\$\@\/] |
6669             \\ (?:$q_char) |
6670             (?:$q_char)
6671             ))/oxmsg;
6672              
6673             # unescape character
6674 0           for (my $i=0; $i <= $#char; $i++) {
6675 0 0 0       if (0) {
    0 0        
    0 0        
    0          
    0          
    0          
6676             }
6677              
6678             # open character class [...]
6679 0           elsif ($char[$i] eq '[') {
6680 0           my $left = $i;
6681 0 0         if ($char[$i+1] eq ']') {
6682 0           $i++;
6683             }
6684 0           while (1) {
6685 0 0         if (++$i > $#char) {
6686 0           die __FILE__, ": Unmatched [] in regexp\n";
6687             }
6688 0 0         if ($char[$i] eq ']') {
6689 0           my $right = $i;
6690              
6691             # [...]
6692 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_qr(@char[$left+1..$right-1], $modifier);
6693              
6694 0           $i = $left;
6695 0           last;
6696             }
6697             }
6698             }
6699              
6700             # open character class [^...]
6701             elsif ($char[$i] eq '[^') {
6702 0           my $left = $i;
6703 0 0         if ($char[$i+1] eq ']') {
6704 0           $i++;
6705             }
6706 0           while (1) {
6707 0 0         if (++$i > $#char) {
6708 0           die __FILE__, ": Unmatched [] in regexp\n";
6709             }
6710 0 0         if ($char[$i] eq ']') {
6711 0           my $right = $i;
6712              
6713             # [^...]
6714 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_not_qr(@char[$left+1..$right-1], $modifier);
6715              
6716 0           $i = $left;
6717 0           last;
6718             }
6719             }
6720             }
6721              
6722             # escape $ @ / and \
6723             elsif ($char[$i] =~ /\A [\$\@\/\\] \z/oxms) {
6724 0           $char[$i] = '\\' . $char[$i];
6725             }
6726              
6727             # rewrite character class or escape character
6728             elsif (my $char = character_class($char[$i],$modifier)) {
6729 0           $char[$i] = $char;
6730             }
6731              
6732             # /i modifier
6733             elsif ($ignorecase and ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) and (Ecyrillic::uc($char[$i]) ne Ecyrillic::fc($char[$i]))) {
6734 0 0         if (CORE::length(Ecyrillic::fc($char[$i])) == 1) {
6735 0           $char[$i] = '[' . Ecyrillic::uc($char[$i]) . Ecyrillic::fc($char[$i]) . ']';
6736             }
6737             else {
6738 0           $char[$i] = '(?:' . Ecyrillic::uc($char[$i]) . '|' . Ecyrillic::fc($char[$i]) . ')';
6739             }
6740             }
6741              
6742             # quote character before ? + * {
6743             elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
6744 0 0         if ($char[$i-1] =~ /\A [\x00-\xFF] \z/oxms) {
6745             }
6746             else {
6747 0           $char[$i-1] = '(?:' . $char[$i-1] . ')';
6748             }
6749             }
6750             }
6751              
6752 0           $modifier =~ tr/i//d;
6753 0           $delimiter = '/';
6754 0           $end_delimiter = '/';
6755 0           my $prematch = '';
6756 0           return join '', $ope, $delimiter, $prematch, '(?:', @char, ')', $matched, $end_delimiter, $modifier;
6757             }
6758              
6759             #
6760             # escape regexp (s'here''b)
6761             #
6762             sub e_s1_qb {
6763 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
6764              
6765             # split regexp
6766 0           my @char = $string =~ /\G (?>[^\\]|\\\\) /oxmsg;
6767              
6768             # unescape character
6769 0           for (my $i=0; $i <= $#char; $i++) {
6770 0 0         if (0) {
    0          
6771             }
6772              
6773             # remain \\
6774 0           elsif ($char[$i] eq '\\\\') {
6775             }
6776              
6777             # escape $ @ / and \
6778             elsif ($char[$i] =~ /\A [\$\@\/\\] \z/oxms) {
6779 0           $char[$i] = '\\' . $char[$i];
6780             }
6781             }
6782              
6783 0           $delimiter = '/';
6784 0           $end_delimiter = '/';
6785 0           my $prematch = '';
6786 0           return join '', $ope, $delimiter, $prematch, '(?:', @char, ')', $matched, $end_delimiter, $modifier;
6787             }
6788              
6789             #
6790             # escape regexp (s''here')
6791             #
6792             sub e_s2_q {
6793 0     0 0   my($ope,$delimiter,$end_delimiter,$string) = @_;
6794              
6795 0           $slash = 'div';
6796              
6797 0           my @char = $string =~ / \G (?>[^\\]|\\\\|$q_char) /oxmsg;
6798 0           for (my $i=0; $i <= $#char; $i++) {
6799 0 0         if (0) {
    0          
6800             }
6801              
6802             # not escape \\
6803 0           elsif ($char[$i] =~ /\A \\\\ \z/oxms) {
6804             }
6805              
6806             # escape $ @ / and \
6807             elsif ($char[$i] =~ /\A [\$\@\/\\] \z/oxms) {
6808 0           $char[$i] = '\\' . $char[$i];
6809             }
6810             }
6811              
6812 0           return join '', $ope, $delimiter, @char, $end_delimiter;
6813             }
6814              
6815             #
6816             # escape regexp (s/here/and here/modifier)
6817             #
6818             sub e_sub {
6819 0     0 0   my($variable,$delimiter1,$pattern,$end_delimiter1,$delimiter2,$replacement,$end_delimiter2,$modifier) = @_;
6820 0   0       $modifier ||= '';
6821              
6822 0           $modifier =~ tr/p//d;
6823 0 0         if ($modifier =~ /([adlu])/oxms) {
6824 0           my $line = 0;
6825 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
6826 0 0         if ($filename ne __FILE__) {
6827 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
6828 0           last;
6829             }
6830             }
6831 0           die qq{Unsupported modifier "$1" used at line $line.\n};
6832             }
6833              
6834 0 0         if ($variable eq '') {
6835 0           $variable = '$_';
6836 0           $bind_operator = ' =~ ';
6837             }
6838              
6839 0           $slash = 'div';
6840              
6841             # P.128 Start of match (or end of previous match): \G
6842             # P.130 Advanced Use of \G with Perl
6843             # in Chapter 3: Overview of Regular Expression Features and Flavors
6844             # P.312 Iterative Matching: Scalar Context, with /g
6845             # in Chapter 7: Perl
6846             # of ISBN 0-596-00289-0 Mastering Regular Expressions, Second edition
6847              
6848             # P.181 Where You Left Off: The \G Assertion
6849             # in Chapter 5: Pattern Matching
6850             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
6851              
6852             # P.220 Where You Left Off: The \G Assertion
6853             # in Chapter 5: Pattern Matching
6854             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
6855              
6856 0           my $e_modifier = $modifier =~ tr/e//d;
6857 0           my $r_modifier = $modifier =~ tr/r//d;
6858              
6859 0           my $my = '';
6860 0 0         if ($variable =~ s/\A \( (?>\s*) ( (?>(?: local \b | my \b | our \b | state \b )?) .+ ) \) \z/$1/oxms) {
6861 0           $my = $variable;
6862 0           $variable =~ s/ (?: local \b | my \b | our \b | state \b ) (?>\s*) //oxms;
6863 0           $variable =~ s/ = .+ \z//oxms;
6864             }
6865              
6866 0           (my $variable_basename = $variable) =~ s/ [\[\{].* \z//oxms;
6867 0           $variable_basename =~ s/ \s+ \z//oxms;
6868              
6869             # quote replacement string
6870 0           my $e_replacement = '';
6871 0 0         if ($e_modifier >= 1) {
6872 0           $e_replacement = e_qq('', '', '', $replacement);
6873 0           $e_modifier--;
6874             }
6875             else {
6876 0 0         if ($delimiter2 eq "'") {
6877 0           $e_replacement = e_s2_q('qq', '/', '/', $replacement);
6878             }
6879             else {
6880 0           $e_replacement = e_qq ('qq', $delimiter2, $end_delimiter2, $replacement);
6881             }
6882             }
6883              
6884 0           my $sub = '';
6885              
6886             # with /r
6887 0 0         if ($r_modifier) {
6888 0 0         if (0) {
6889             }
6890              
6891             # s///gr without multibyte anchoring
6892 0           elsif ($modifier =~ /g/oxms) {
6893 0 0         $sub = sprintf(
6894             # 1 2 3 4 5
6895             q,
6896              
6897             $variable, # 1
6898             ($delimiter1 eq "'") ? # 2
6899             e_s1_q('m', $delimiter1, $end_delimiter1, $pattern, $modifier) : # :
6900             e_s1 ('m', $delimiter1, $end_delimiter1, $pattern, $modifier), # :
6901             $s_matched, # 3
6902             $e_replacement, # 4
6903             '$Cyrillic::re_r=CORE::eval $Cyrillic::re_r; ' x $e_modifier, # 5
6904             );
6905             }
6906              
6907             # s///r
6908             else {
6909              
6910 0           my $prematch = q{$`};
6911              
6912 0 0         $sub = sprintf(
6913             # 1 2 3 4 5 6 7
6914             q<(%s =~ %s) ? CORE::eval{%s local $^W=0; local $Cyrillic::re_r=%s; %s"%s$Cyrillic::re_r$'" } : %s>,
6915              
6916             $variable, # 1
6917             ($delimiter1 eq "'") ? # 2
6918             e_s1_q('m', $delimiter1, $end_delimiter1, $pattern, $modifier) : # :
6919             e_s1 ('m', $delimiter1, $end_delimiter1, $pattern, $modifier), # :
6920             $s_matched, # 3
6921             $e_replacement, # 4
6922             '$Cyrillic::re_r=CORE::eval $Cyrillic::re_r; ' x $e_modifier, # 5
6923             $prematch, # 6
6924             $variable, # 7
6925             );
6926             }
6927              
6928             # $var !~ s///r doesn't make sense
6929 0 0         if ($bind_operator =~ / !~ /oxms) {
6930 0           $sub = q{die("$0: Using !~ with s///r doesn't make sense"), } . $sub;
6931             }
6932             }
6933              
6934             # without /r
6935             else {
6936 0 0         if (0) {
6937             }
6938              
6939             # s///g without multibyte anchoring
6940 0           elsif ($modifier =~ /g/oxms) {
6941 0 0         $sub = sprintf(
    0          
6942             # 1 2 3 4 5 6 7 8
6943             q,
6944              
6945             $variable, # 1
6946             ($delimiter1 eq "'") ? # 2
6947             e_s1_q('m', $delimiter1, $end_delimiter1, $pattern, $modifier) : # :
6948             e_s1 ('m', $delimiter1, $end_delimiter1, $pattern, $modifier), # :
6949             $s_matched, # 3
6950             $e_replacement, # 4
6951             '$Cyrillic::re_r=CORE::eval $Cyrillic::re_r; ' x $e_modifier, # 5
6952             $variable, # 6
6953             $variable, # 7
6954             ($bind_operator =~ / !~ /oxms) ? '!' : '', # 8
6955             );
6956             }
6957              
6958             # s///
6959             else {
6960              
6961 0           my $prematch = q{$`};
6962              
6963 0 0         $sub = sprintf(
    0          
6964              
6965             ($bind_operator =~ / =~ /oxms) ?
6966              
6967             # 1 2 3 4 5 6 7 8
6968             q<(%s%s%s) ? CORE::eval{%s local $^W=0; local $Cyrillic::re_r=%s; %s%s="%s$Cyrillic::re_r$'"; 1 } : undef> :
6969              
6970             # 1 2 3 4 5 6 7 8
6971             q<(%s%s%s) ? 1 : CORE::eval{%s local $^W=0; local $Cyrillic::re_r=%s; %s%s="%s$Cyrillic::re_r$'"; undef }>,
6972              
6973             $variable, # 1
6974             $bind_operator, # 2
6975             ($delimiter1 eq "'") ? # 3
6976             e_s1_q('m', $delimiter1, $end_delimiter1, $pattern, $modifier) : # :
6977             e_s1 ('m', $delimiter1, $end_delimiter1, $pattern, $modifier), # :
6978             $s_matched, # 4
6979             $e_replacement, # 5
6980             '$Cyrillic::re_r=CORE::eval $Cyrillic::re_r; ' x $e_modifier, # 6
6981             $variable, # 7
6982             $prematch, # 8
6983             );
6984             }
6985             }
6986              
6987             # (my $foo = $bar) =~ s/// --> (my $foo = $bar, CORE::eval { ... })[1]
6988 0 0         if ($my ne '') {
6989 0           $sub = "($my, $sub)[1]";
6990             }
6991              
6992             # clear s/// variable
6993 0           $sub_variable = '';
6994 0           $bind_operator = '';
6995              
6996 0           return $sub;
6997             }
6998              
6999             #
7000             # escape regexp of split qr//
7001             #
7002             sub e_split {
7003 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
7004 0   0       $modifier ||= '';
7005              
7006 0           $modifier =~ tr/p//d;
7007 0 0         if ($modifier =~ /([adlu])/oxms) {
7008 0           my $line = 0;
7009 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
7010 0 0         if ($filename ne __FILE__) {
7011 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
7012 0           last;
7013             }
7014             }
7015 0           die qq{Unsupported modifier "$1" used at line $line.\n};
7016             }
7017              
7018 0           $slash = 'div';
7019              
7020             # /b /B modifier
7021 0 0         if ($modifier =~ tr/bB//d) {
7022 0           return join '', 'split', $ope, $delimiter, $string, $end_delimiter, $modifier;
7023             }
7024              
7025 0 0         my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
7026 0           my $metachar = qr/[\@\\|[\]{^]/oxms;
7027              
7028             # split regexp
7029 0           my @char = $string =~ /\G((?>
7030             [^\\\$\@\[\(] |
7031             \\x (?>[0-9A-Fa-f]{1,2}) |
7032             \\ (?>[0-7]{2,3}) |
7033             \\c [\x40-\x5F] |
7034             \\x\{ (?>[0-9A-Fa-f]+) \} |
7035             \\o\{ (?>[0-7]+) \} |
7036             \\[bBNpP]\{ (?>[^0-9\}][^\}]*) \} |
7037             \\ $q_char |
7038             \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} |
7039             \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} |
7040             \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} |
7041             [\$\@] $qq_variable |
7042             \$ (?>\s* [0-9]+) |
7043             \$ (?>\s*) \{ (?>\s* [0-9]+ \s*) \} |
7044             \$ \$ (?![\w\{]) |
7045             \$ (?>\s*) \$ (?>\s*) $qq_variable |
7046             \[\^ |
7047             \[\: (?>[a-z]+) :\] |
7048             \[\:\^ (?>[a-z]+) :\] |
7049             \(\? |
7050             $q_char
7051             ))/oxmsg;
7052              
7053 0           my $left_e = 0;
7054 0           my $right_e = 0;
7055 0           for (my $i=0; $i <= $#char; $i++) {
7056              
7057             # "\L\u" --> "\u\L"
7058 0 0 0       if (($char[$i] eq '\L') and ($char[$i+1] eq '\u')) {
    0 0        
    0          
    0          
    0          
    0          
7059 0           @char[$i,$i+1] = @char[$i+1,$i];
7060             }
7061              
7062             # "\U\l" --> "\l\U"
7063             elsif (($char[$i] eq '\U') and ($char[$i+1] eq '\l')) {
7064 0           @char[$i,$i+1] = @char[$i+1,$i];
7065             }
7066              
7067             # octal escape sequence
7068             elsif ($char[$i] =~ /\A \\o \{ ([0-7]+) \} \z/oxms) {
7069 0           $char[$i] = Ecyrillic::octchr($1);
7070             }
7071              
7072             # hexadecimal escape sequence
7073             elsif ($char[$i] =~ /\A \\x \{ ([0-9A-Fa-f]+) \} \z/oxms) {
7074 0           $char[$i] = Ecyrillic::hexchr($1);
7075             }
7076              
7077             # \b{...} --> b\{...}
7078             # \B{...} --> B\{...}
7079             # \N{CHARNAME} --> N\{CHARNAME}
7080             # \p{PROPERTY} --> p\{PROPERTY}
7081             # \P{PROPERTY} --> P\{PROPERTY}
7082             elsif ($char[$i] =~ /\A \\ ([bBNpP]) ( \{ ([^0-9\}][^\}]*) \} ) \z/oxms) {
7083 0           $char[$i] = $1 . '\\' . $2;
7084             }
7085              
7086             # \p, \P, \X --> p, P, X
7087             elsif ($char[$i] =~ /\A \\ ( [pPX] ) \z/oxms) {
7088 0           $char[$i] = $1;
7089             }
7090              
7091 0 0 0       if (0) {
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
7092             }
7093              
7094             # join separated multiple-octet
7095 0           elsif ($char[$i] =~ /\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms) {
7096 0 0 0       if ( ($i+3 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, @char[$i+1..$i+3]) == 3) and (CORE::eval(sprintf '"%s%s%s%s"', @char[$i..$i+3]) =~ /\A $q_char \z/oxms)) {
    0 0        
    0 0        
      0        
      0        
      0        
7097 0           $char[$i] .= join '', splice @char, $i+1, 3;
7098             }
7099             elsif (($i+2 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, @char[$i+1..$i+2]) == 2) and (CORE::eval(sprintf '"%s%s%s"', @char[$i..$i+2]) =~ /\A $q_char \z/oxms)) {
7100 0           $char[$i] .= join '', splice @char, $i+1, 2;
7101             }
7102             elsif (($i+1 <= $#char) and (grep(/\A (?: \\ [0-7]{2,3} | \\x [0-9A-Fa-f]{1,2}) \z/oxms, $char[$i+1 ]) == 1) and (CORE::eval(sprintf '"%s%s"', @char[$i..$i+1]) =~ /\A $q_char \z/oxms)) {
7103 0           $char[$i] .= join '', splice @char, $i+1, 1;
7104             }
7105             }
7106              
7107             # open character class [...]
7108             elsif ($char[$i] eq '[') {
7109 0           my $left = $i;
7110 0 0         if ($char[$i+1] eq ']') {
7111 0           $i++;
7112             }
7113 0           while (1) {
7114 0 0         if (++$i > $#char) {
7115 0           die __FILE__, ": Unmatched [] in regexp\n";
7116             }
7117 0 0         if ($char[$i] eq ']') {
7118 0           my $right = $i;
7119              
7120             # [...]
7121 0 0         if (grep(/\A [\$\@]/oxms,@char[$left+1..$right-1]) >= 1) {
7122 0           splice @char, $left, $right-$left+1, sprintf(q{@{[Ecyrillic::charlist_qr(%s,'%s')]}}, join(',', map {qq_stuff($delimiter,$end_delimiter,$_)} @char[$left+1..$right-1]), $modifier);
  0            
7123             }
7124             else {
7125 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_qr(@char[$left+1..$right-1], $modifier);
7126             }
7127              
7128 0           $i = $left;
7129 0           last;
7130             }
7131             }
7132             }
7133              
7134             # open character class [^...]
7135             elsif ($char[$i] eq '[^') {
7136 0           my $left = $i;
7137 0 0         if ($char[$i+1] eq ']') {
7138 0           $i++;
7139             }
7140 0           while (1) {
7141 0 0         if (++$i > $#char) {
7142 0           die __FILE__, ": Unmatched [] in regexp\n";
7143             }
7144 0 0         if ($char[$i] eq ']') {
7145 0           my $right = $i;
7146              
7147             # [^...]
7148 0 0         if (grep(/\A [\$\@]/oxms,@char[$left+1..$right-1]) >= 1) {
7149 0           splice @char, $left, $right-$left+1, sprintf(q{@{[Ecyrillic::charlist_not_qr(%s,'%s')]}}, join(',', map {qq_stuff($delimiter,$end_delimiter,$_)} @char[$left+1..$right-1]), $modifier);
  0            
7150             }
7151             else {
7152 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_not_qr(@char[$left+1..$right-1], $modifier);
7153             }
7154              
7155 0           $i = $left;
7156 0           last;
7157             }
7158             }
7159             }
7160              
7161             # rewrite character class or escape character
7162             elsif (my $char = character_class($char[$i],$modifier)) {
7163 0           $char[$i] = $char;
7164             }
7165              
7166             # P.794 29.2.161. split
7167             # in Chapter 29: Functions
7168             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
7169              
7170             # P.951 split
7171             # in Chapter 27: Functions
7172             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
7173              
7174             # said "The //m modifier is assumed when you split on the pattern /^/",
7175             # but perl5.008 is not so. Therefore, this software adds //m.
7176             # (and so on)
7177              
7178             # split(m/^/) --> split(m/^/m)
7179             elsif (($char[$i] eq '^') and ($modifier !~ /m/oxms)) {
7180 0           $modifier .= 'm';
7181             }
7182              
7183             # /i modifier
7184             elsif ($ignorecase and ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) and (Ecyrillic::uc($char[$i]) ne Ecyrillic::fc($char[$i]))) {
7185 0 0         if (CORE::length(Ecyrillic::fc($char[$i])) == 1) {
7186 0           $char[$i] = '[' . Ecyrillic::uc($char[$i]) . Ecyrillic::fc($char[$i]) . ']';
7187             }
7188             else {
7189 0           $char[$i] = '(?:' . Ecyrillic::uc($char[$i]) . '|' . Ecyrillic::fc($char[$i]) . ')';
7190             }
7191             }
7192              
7193             # \u \l \U \L \F \Q \E
7194             elsif ($char[$i] =~ /\A ([<>]) \z/oxms) {
7195 0 0         if ($right_e < $left_e) {
7196 0           $char[$i] = '\\' . $char[$i];
7197             }
7198             }
7199             elsif ($char[$i] eq '\u') {
7200 0           $char[$i] = '@{[Ecyrillic::ucfirst qq<';
7201 0           $left_e++;
7202             }
7203             elsif ($char[$i] eq '\l') {
7204 0           $char[$i] = '@{[Ecyrillic::lcfirst qq<';
7205 0           $left_e++;
7206             }
7207             elsif ($char[$i] eq '\U') {
7208 0           $char[$i] = '@{[Ecyrillic::uc qq<';
7209 0           $left_e++;
7210             }
7211             elsif ($char[$i] eq '\L') {
7212 0           $char[$i] = '@{[Ecyrillic::lc qq<';
7213 0           $left_e++;
7214             }
7215             elsif ($char[$i] eq '\F') {
7216 0           $char[$i] = '@{[Ecyrillic::fc qq<';
7217 0           $left_e++;
7218             }
7219             elsif ($char[$i] eq '\Q') {
7220 0           $char[$i] = '@{[CORE::quotemeta qq<';
7221 0           $left_e++;
7222             }
7223             elsif ($char[$i] eq '\E') {
7224 0 0         if ($right_e < $left_e) {
7225 0           $char[$i] = '>]}';
7226 0           $right_e++;
7227             }
7228             else {
7229 0           $char[$i] = '';
7230             }
7231             }
7232             elsif ($char[$i] eq '\Q') {
7233 0           while (1) {
7234 0 0         if (++$i > $#char) {
7235 0           last;
7236             }
7237 0 0         if ($char[$i] eq '\E') {
7238 0           last;
7239             }
7240             }
7241             }
7242             elsif ($char[$i] eq '\E') {
7243             }
7244              
7245             # $0 --> $0
7246             elsif ($char[$i] =~ /\A \$ 0 \z/oxms) {
7247 0 0         if ($ignorecase) {
7248 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7249             }
7250             }
7251             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) 0 (?>\s*) \} \z/oxms) {
7252 0 0         if ($ignorecase) {
7253 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7254             }
7255             }
7256              
7257             # $$ --> $$
7258             elsif ($char[$i] =~ /\A \$\$ \z/oxms) {
7259             }
7260              
7261             # $1, $2, $3 --> $2, $3, $4 after s/// with multibyte anchoring
7262             # $1, $2, $3 --> $1, $2, $3 otherwise
7263             elsif ($char[$i] =~ /\A \$ ((?>[1-9][0-9]*)) \z/oxms) {
7264 0           $char[$i] = e_capture($1);
7265 0 0         if ($ignorecase) {
7266 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7267             }
7268             }
7269             elsif ($char[$i] =~ /\A \$ \{ (?>\s*) ((?>[1-9][0-9]*)) (?>\s*) \} \z/oxms) {
7270 0           $char[$i] = e_capture($1);
7271 0 0         if ($ignorecase) {
7272 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7273             }
7274             }
7275              
7276             # $$foo[ ... ] --> $ $foo->[ ... ]
7277             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \[ (?:$qq_bracket)*? \] ) \z/oxms) {
7278 0           $char[$i] = e_capture($1.'->'.$2);
7279 0 0         if ($ignorecase) {
7280 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7281             }
7282             }
7283              
7284             # $$foo{ ... } --> $ $foo->{ ... }
7285             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) ( \{ (?:$qq_brace)*? \} ) \z/oxms) {
7286 0           $char[$i] = e_capture($1.'->'.$2);
7287 0 0         if ($ignorecase) {
7288 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7289             }
7290             }
7291              
7292             # $$foo
7293             elsif ($char[$i] =~ /\A \$ ((?> \$ [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* )) \z/oxms) {
7294 0           $char[$i] = e_capture($1);
7295 0 0         if ($ignorecase) {
7296 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7297             }
7298             }
7299              
7300             # $`, ${`}, $PREMATCH, ${PREMATCH}, ${^PREMATCH} --> Ecyrillic::PREMATCH()
7301             elsif ($char[$i] =~ /\A ( \$` | \$\{`\} | \$ (?>\s*) PREMATCH | \$ (?>\s*) \{ (?>\s*) PREMATCH (?>\s*) \} | \$ (?>\s*) \{\^PREMATCH\} ) \z/oxmsgc) {
7302 0 0         if ($ignorecase) {
7303 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::PREMATCH())]}';
7304             }
7305             else {
7306 0           $char[$i] = '@{[Ecyrillic::PREMATCH()]}';
7307             }
7308             }
7309              
7310             # $&, ${&}, $MATCH, ${MATCH}, ${^MATCH} --> Ecyrillic::MATCH()
7311             elsif ($char[$i] =~ /\A ( \$& | \$\{&\} | \$ (?>\s*) MATCH | \$ (?>\s*) \{ (?>\s*) MATCH (?>\s*) \} | \$ (?>\s*) \{\^MATCH\} ) \z/oxmsgc) {
7312 0 0         if ($ignorecase) {
7313 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::MATCH())]}';
7314             }
7315             else {
7316 0           $char[$i] = '@{[Ecyrillic::MATCH()]}';
7317             }
7318             }
7319              
7320             # $POSTMATCH, ${POSTMATCH}, ${^POSTMATCH} --> Ecyrillic::POSTMATCH()
7321             elsif ($char[$i] =~ /\A ( \$ (?>\s*) POSTMATCH | \$ (?>\s*) \{ (?>\s*) POSTMATCH (?>\s*) \} | \$ (?>\s*) \{\^POSTMATCH\} ) \z/oxmsgc) {
7322 0 0         if ($ignorecase) {
7323 0           $char[$i] = '@{[Ecyrillic::ignorecase(Ecyrillic::POSTMATCH())]}';
7324             }
7325             else {
7326 0           $char[$i] = '@{[Ecyrillic::POSTMATCH()]}';
7327             }
7328             }
7329              
7330             # ${ foo }
7331             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ((?> \s* [A-Za-z_][A-Za-z0-9_]*(?: ::[A-Za-z_][A-Za-z0-9_]*)* \s* )) \} \z/oxms) {
7332 0 0         if ($ignorecase) {
7333 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $1 . ')]}';
7334             }
7335             }
7336              
7337             # ${ ... }
7338             elsif ($char[$i] =~ /\A \$ (?>\s*) \{ ( .+ ) \} \z/oxms) {
7339 0           $char[$i] = e_capture($1);
7340 0 0         if ($ignorecase) {
7341 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7342             }
7343             }
7344              
7345             # $scalar or @array
7346             elsif ($char[$i] =~ /\A [\$\@].+ /oxms) {
7347 0           $char[$i] = e_string($char[$i]);
7348 0 0         if ($ignorecase) {
7349 0           $char[$i] = '@{[Ecyrillic::ignorecase(' . $char[$i] . ')]}';
7350             }
7351             }
7352              
7353             # quote character before ? + * {
7354             elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
7355 0 0         if ($char[$i-1] =~ /\A (?:[\x00-\xFF]|\\[0-7]{2,3}|\\x[0-9-A-Fa-f]{1,2}) \z/oxms) {
7356             }
7357             else {
7358 0           $char[$i-1] = '(?:' . $char[$i-1] . ')';
7359             }
7360             }
7361             }
7362              
7363             # make regexp string
7364 0           $modifier =~ tr/i//d;
7365 0 0         if ($left_e > $right_e) {
7366 0           return join '', 'Ecyrillic::split', $ope, $delimiter, @char, '>]}' x ($left_e - $right_e), $end_delimiter, $modifier;
7367             }
7368 0           return join '', 'Ecyrillic::split', $ope, $delimiter, @char, $end_delimiter, $modifier;
7369             }
7370              
7371             #
7372             # escape regexp of split qr''
7373             #
7374             sub e_split_q {
7375 0     0 0   my($ope,$delimiter,$end_delimiter,$string,$modifier) = @_;
7376 0   0       $modifier ||= '';
7377              
7378 0           $modifier =~ tr/p//d;
7379 0 0         if ($modifier =~ /([adlu])/oxms) {
7380 0           my $line = 0;
7381 0           for (my $i=0; my($package,$filename,$use_line,$subroutine) = caller($i); $i++) {
7382 0 0         if ($filename ne __FILE__) {
7383 0           $line = $use_line + (CORE::substr($_,0,pos($_)) =~ tr/\n//) + 1;
7384 0           last;
7385             }
7386             }
7387 0           die qq{Unsupported modifier "$1" used at line $line.\n};
7388             }
7389              
7390 0           $slash = 'div';
7391              
7392             # /b /B modifier
7393 0 0         if ($modifier =~ tr/bB//d) {
7394 0           return join '', 'split', $ope, $delimiter, $string, $end_delimiter, $modifier;
7395             }
7396              
7397 0 0         my $ignorecase = ($modifier =~ /i/oxms) ? 1 : 0;
7398              
7399             # split regexp
7400 0           my @char = $string =~ /\G((?>
7401             [^\\\[] |
7402             [\x00-\xFF] |
7403             \[\^ |
7404             \[\: (?>[a-z]+) \:\] |
7405             \[\:\^ (?>[a-z]+) \:\] |
7406             \\ (?:$q_char) |
7407             (?:$q_char)
7408             ))/oxmsg;
7409              
7410             # unescape character
7411 0           for (my $i=0; $i <= $#char; $i++) {
7412 0 0 0       if (0) {
    0 0        
    0 0        
    0 0        
    0          
    0          
7413             }
7414              
7415             # open character class [...]
7416 0           elsif ($char[$i] eq '[') {
7417 0           my $left = $i;
7418 0 0         if ($char[$i+1] eq ']') {
7419 0           $i++;
7420             }
7421 0           while (1) {
7422 0 0         if (++$i > $#char) {
7423 0           die __FILE__, ": Unmatched [] in regexp\n";
7424             }
7425 0 0         if ($char[$i] eq ']') {
7426 0           my $right = $i;
7427              
7428             # [...]
7429 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_qr(@char[$left+1..$right-1], $modifier);
7430              
7431 0           $i = $left;
7432 0           last;
7433             }
7434             }
7435             }
7436              
7437             # open character class [^...]
7438             elsif ($char[$i] eq '[^') {
7439 0           my $left = $i;
7440 0 0         if ($char[$i+1] eq ']') {
7441 0           $i++;
7442             }
7443 0           while (1) {
7444 0 0         if (++$i > $#char) {
7445 0           die __FILE__, ": Unmatched [] in regexp\n";
7446             }
7447 0 0         if ($char[$i] eq ']') {
7448 0           my $right = $i;
7449              
7450             # [^...]
7451 0           splice @char, $left, $right-$left+1, Ecyrillic::charlist_not_qr(@char[$left+1..$right-1], $modifier);
7452              
7453 0           $i = $left;
7454 0           last;
7455             }
7456             }
7457             }
7458              
7459             # rewrite character class or escape character
7460             elsif (my $char = character_class($char[$i],$modifier)) {
7461 0           $char[$i] = $char;
7462             }
7463              
7464             # split(m/^/) --> split(m/^/m)
7465             elsif (($char[$i] eq '^') and ($modifier !~ /m/oxms)) {
7466 0           $modifier .= 'm';
7467             }
7468              
7469             # /i modifier
7470             elsif ($ignorecase and ($char[$i] =~ /\A [\x00-\xFF] \z/oxms) and (Ecyrillic::uc($char[$i]) ne Ecyrillic::fc($char[$i]))) {
7471 0 0         if (CORE::length(Ecyrillic::fc($char[$i])) == 1) {
7472 0           $char[$i] = '[' . Ecyrillic::uc($char[$i]) . Ecyrillic::fc($char[$i]) . ']';
7473             }
7474             else {
7475 0           $char[$i] = '(?:' . Ecyrillic::uc($char[$i]) . '|' . Ecyrillic::fc($char[$i]) . ')';
7476             }
7477             }
7478              
7479             # quote character before ? + * {
7480             elsif (($i >= 1) and ($char[$i] =~ /\A [\?\+\*\{] \z/oxms)) {
7481 0 0         if ($char[$i-1] =~ /\A [\x00-\xFF] \z/oxms) {
7482             }
7483             else {
7484 0           $char[$i-1] = '(?:' . $char[$i-1] . ')';
7485             }
7486             }
7487             }
7488              
7489 0           $modifier =~ tr/i//d;
7490 0           return join '', 'Ecyrillic::split', $ope, $delimiter, @char, $end_delimiter, $modifier;
7491             }
7492              
7493             #
7494             # instead of Carp::carp
7495             #
7496             sub carp {
7497 0     0 0   my($package,$filename,$line) = caller(1);
7498 0           print STDERR "@_ at $filename line $line.\n";
7499             }
7500              
7501             #
7502             # instead of Carp::croak
7503             #
7504             sub croak {
7505 0     0 0   my($package,$filename,$line) = caller(1);
7506 0           print STDERR "@_ at $filename line $line.\n";
7507 0           die "\n";
7508             }
7509              
7510             #
7511             # instead of Carp::cluck
7512             #
7513             sub cluck {
7514 0     0 0   my $i = 0;
7515 0           my @cluck = ();
7516 0           while (my($package,$filename,$line,$subroutine) = caller($i)) {
7517 0           push @cluck, "[$i] $filename($line) $package::$subroutine\n";
7518 0           $i++;
7519             }
7520 0           print STDERR CORE::reverse @cluck;
7521 0           print STDERR "\n";
7522 0           carp @_;
7523             }
7524              
7525             #
7526             # instead of Carp::confess
7527             #
7528             sub confess {
7529 0     0 0   my $i = 0;
7530 0           my @confess = ();
7531 0           while (my($package,$filename,$line,$subroutine) = caller($i)) {
7532 0           push @confess, "[$i] $filename($line) $package::$subroutine\n";
7533 0           $i++;
7534             }
7535 0           print STDERR CORE::reverse @confess;
7536 0           print STDERR "\n";
7537 0           croak @_;
7538             }
7539              
7540             1;
7541              
7542             __END__