File Coverage

blib/lib/String/RexxParse.pm
Criterion Covered Total %
statement 321 360 89.1
branch 128 160 80.0
condition 7 12 58.3
subroutine 17 20 85.0
pod 2 6 33.3
total 475 558 85.1


line stmt bran cond sub pod time code
1             # String::RexxParse.pm
2             #
3             # Copyright (c) 1999, 2000, 2001, 2002 Dan Campbell (String::RexxParse->email).
4             # All rights reserved.
5             #
6             # This program is free software; you can redistribute it and/or
7             # modify it under the same terms as Perl itself.
8             #
9             # This module is intended to provide REXX-like parsing in Perl.
10             #
11             # Documentation at http://www.danofsteel.com/Parser
12              
13             package String::RexxParse;
14              
15 11     11   7657 use strict;
  11         19  
  11         414  
16 11     11   60 use vars qw(@ISA @EXPORT_OK $VERSION $debug);
  11         17  
  11         1156  
17              
18             require Exporter;
19              
20             @ISA = qw(Exporter);
21             @EXPORT_OK = qw(parse drop);
22             $VERSION = "1.10";
23              
24 11     11   63 use Carp;
  11         43  
  11         64828  
25              
26             require 5.003; # 5.003 is required to support subroutine prototypes.
27              
28              
29             sub _packagize
30             {
31 101     101   124 my $in = shift;
32 101         126 my $callpkg = shift;
33 101         460 while ($in =~ /\$(\w+(?=\W|$)(?!::))/g)
34             {
35 101         753 substr($in,pos($in)-length($1),length($1)) = "$callpkg\:\:$1";
36             }
37 101         583 return $in;
38             }
39              
40              
41              
42 10 50   10 0 238 sub max { $_[0] >= $_[1] ? $_[0] : $_[1] }
43 16 100   16 0 725 sub min { $_[0] <= $_[1] ? $_[0] : $_[1] }
44 0     0 0 0 sub email { reverse 'moc.leetsfonad' . '@' . 'esrapxxer' }
45              
46              
47              
48             sub _tokens
49             {
50 19     19   40 my $template = shift;
51 19         30 my $callpkg = shift;
52 19         31 my $matchpos = 0;
53              
54 19         45 my ($tok,@tok) = ("");
55              
56 19         33 my $tokexp = <<'TOK';
57             \G(
58             \'[^']*\' |
59             \"[^"]*\" |
60             \([^()]*\) |
61             [=]?\d+ |
62             [=]\([^()]*\) |
63             [-+]\d+ |
64             [-+]\([^()]*\) |
65             [.] |
66             (?:\w|[$&])\S* |
67             \s+
68             )
69             TOK
70              
71 19         1856 while ( $template =~ m/$tokexp/gox)
72             {
73 347         733 my $match = $1;
74 347 100       1167 unless ($match =~ /^\s*$/)
75             {
76 183         302 for ($match)
77             {
78 188 100       489 if (/^[.]$/)
79             {
80 21         31 push @tok,$match;
81 21         30 $tok .= 'v';
82 21         27 last;
83             }
84 167 100       329 if (/^\(/)
85             {
86 3 50       19 if ($tok =~ /(?:^$|[LP]$)/)
87             {
88 0         0 push @tok, '.';
89 0         0 $tok .= 'v';
90 0         0 redo;
91             }
92 3         11 $match =~ s/^\(//;
93 3         12 $match =~ s/\)$//;
94 3         13 push @tok,_packagize('quotemeta('.$match.')',$callpkg);
95 3         8 $tok .= 'P';
96 3         6 last;
97             }
98 164 100       392 if (/^['"]/)
99             {
100 44 100       531 if ($tok =~ /(?:^$|[LP]$)/)
101             {
102 5         12 push @tok, '.';
103 5         9 $tok .= 'v';
104 5         9 redo;
105             }
106 39         114 $match =~ s/^['"]//;
107 39         114 $match =~ s/['"]$//;
108 39         99 push @tok,quotemeta($match);
109 39         55 $tok .= 'L';
110 39         56 last;
111             }
112 120 100       324 if (/^[=]?\d+/)
113             {
114 7         11 $match =~ s/^=//;
115 7         13 push @tok,$match;
116 7         14 $tok .= 'N';
117 7         11 last;
118             }
119 113 50       260 if (/^[=]\(/)
120             {
121 0         0 $match =~ s/(?:^=\(|\)$)//g;
122 0         0 push @tok,_packagize($match,$callpkg);
123 0         0 $tok .= 'n';
124 0         0 last;
125             }
126 113 100       399 if (/^[-+]\d+/)
127             {
128 15         30 push @tok,$match;
129 15         28 $tok .= 'R';
130 15         20 last;
131             }
132 98 100       236 if (/^[-+]\(/)
133             {
134 3         13 $match =~ s/^([-+])\(/$1/;
135 3         10 $match =~ s/\)$//;
136 3         7 push @tok,_packagize($match,$callpkg);
137 3         6 $tok .= 'r';
138 3         5 last;
139             }
140 95 50       458 if (/^\S+$/)
141             {
142 95         208 push @tok, _packagize($match,$callpkg);
143 95         165 $tok .= 'V';
144 95         143 last;
145             }
146             }
147 183 100       781 if ($tok =~ /L$/)
    100          
    100          
148             {
149 39         2623 eval "my \$test = \"$tok[$#tok]\"";
150 39 50       165 if ($@) { croak "Syntax error in template near >$match<" }
  0         0  
151             }
152             elsif ($tok =~ /V$/)
153             {
154 95         5550 eval "$tok[$#tok] = $tok[$#tok]";
155 95 50       340 if ($@) { croak "Syntax error in template near >$match<" }
  0         0  
156             }
157             elsif ($tok !~ /v$/)
158             {
159 28         1476 eval "my \$test = $tok[$#tok]";
160 28 50       114 if ($@) { croak "Syntax error in template near >$match<" }
  0         0  
161             }
162             }
163 347         1647 $matchpos = pos($template);
164              
165             }
166              
167 19 50       76 croak "Syntax error in template near position $matchpos\n===>$template<===\n"
168             unless $matchpos == length($template);
169              
170 19 100       85 if ($tok =~ /[PL]$/)
171             {
172 3         9 push @tok, '.';
173 3         7 $tok .= 'v';
174             }
175 19         148 return ($tok,@tok);
176              
177             }
178              
179              
180              
181              
182              
183              
184             sub _VvRN (\@\$)
185             {
186 2     2   5 my ($value,$type) = @_;
187 2         5 my $utemplate = "";
188 2         3 my $tmp = "";
189 2         4 my $pos = 0;
190 2         3 my $next = 0;
191 2         4 my @vars = ();
192 2         4 my @tvars = ();
193 2         5 my $max = 0;
194 2         3 my $cur = 0;
195              
196 2         4 my $parser = "sub\n{\n my \@list = ();\n eval\n {\n my \$source = shift;\n my \@tlist = ();\n" . " \@list = ";
197 2         8 for my $i (0..$#$value)
198             {
199 23         53 for (substr($$type,$i,1))
200             {
201 23 100       95 if (/^[Vv]$/)
    100          
    50          
202             {
203 12         44 push @tvars, $$value[$i];
204             }
205             elsif (/^R$/)
206             {
207 8 50       21 if (@tvars > 1)
208             {
209 0         0 $tmp .= ' @tlist = split(q( ),splice(@list,'.$next.',1),' .
210             scalar(@tvars) . ');'."\n";
211 0         0 $tmp .= ' push @tlist, ("") x ('.scalar(@tvars).'-@tlist);' ."\n";
212 0         0 $tmp .= ' splice @list,'.$next.',0,splice(@tlist,0);' . "\n";
213 0         0 $next += $#tvars;
214             }
215 8         12 push @vars, @tvars;
216 8         15 @tvars = ();
217 8 100       21 if ($$value[$i] =~ /^[+]/)
218             {
219 6 100       16 unless ($i > 0) { $utemplate .= 'x' . eval $$value[$i] }
  1         53  
220             else
221             {
222 5         178 $utemplate .= 'a' . eval $$value[$i];
223             }
224 6         213 $pos = $pos + eval $$value[$i];
225 6         11 $next++;
226             }
227             else
228             {
229 2 50       7 if ($i > 0)
230             {
231 2         96 $pos = max(0,$pos + eval $$value[$i]);
232 2         7 $utemplate .= 'a*X*x' . $pos;
233 2         4 $next++;
234             }
235             }
236 8         279 $cur += eval $$value[$i];
237 8 100       40 $max= $cur if $cur > $max;
238             }
239             elsif (/^N$/)
240             {
241 3 50       10 if (@tvars > 1)
242             {
243 0         0 $tmp .= ' @tlist = split(q( ),splice(@list,'.$next.',1),' .
244             scalar(@tvars) . ');'."\n";
245 0         0 $tmp .= ' push @tlist, ("") x ('.scalar(@tvars).'-@tlist);' ."\n";
246 0         0 $tmp .= ' splice @list,'.$next.',0,splice(@tlist,0);' . "\n";
247 0         0 $next += $#tvars;
248             }
249 3         5 push @vars, @tvars;
250 3         5 @tvars = ();
251 3 50       119 if ($pos < eval $$value[$i])
252             {
253 3 50       8 unless ($i > 0) { $utemplate .= 'x' . eval $$value[$i] }
  0         0  
254             else
255             {
256 3         151 $utemplate .= 'a' . eval $$value[$i] - $pos;
257             }
258 3         117 $pos = eval $$value[$i];
259 3         7 $next++;
260             }
261             else
262             {
263 0 0       0 if ($i > 0)
264             {
265 0         0 $pos = eval $$value[$i];
266 0         0 $utemplate .= 'a*X*x' . $pos;
267 0         0 $next++;
268             }
269             }
270 3         116 $cur = eval $$value[$i];
271 3 50       16 $max = $cur if $cur > $max;
272             }
273             }
274             }
275 2 50       8 if (@tvars)
276             {
277 2         4 $utemplate .= 'a*';
278 2         8 push @vars,splice(@tvars,0);
279             }
280 2         11 $parser .= 'unpack("' . $utemplate . '",sprintf("%-'.$max.'s",$source));'
281             . "\n" . $tmp;
282 2         5 for my $n (0..$#vars)
283             {
284 12 50 33     64 if (defined($vars[$n]) and $vars[$n] eq '.')
285             {
286 0         0 $parser .= ' splice @list,' . $n . ',1;' . "\n";
287 0         0 splice @vars,$n,1;
288 0         0 redo;
289             }
290             }
291 2         13 $parser .= ' (' . join(',',@vars) . ') = @list;' . "\n";
292 2         5 $parser .= " };\n croak \"String too short for pattern\" if \$@ =~ /x outside/;\n croak \"\$@\" if \$@;\n \@list;\n}\n";
293 2         6 $parser .= "#MAX: $max\n";
294              
295 2         8 return $parser;
296             }
297              
298              
299              
300              
301              
302              
303              
304             sub _anything (\@\$)
305             {
306 5     5   11 my ($value,$type) = @_;
307 5         11 my @vars = ();
308 5         9 my @tvars = ();
309              
310 5         12 my $parser = "sub\n{\n my \$source = shift;\n" .
311             " my \@list = (\$source);\n my \@tlist = ();\n my \$tmp = '';\n my \$pos = 0;\n";
312 5         18 for my $i (0..$#$value)
313             {
314 60         332 for (substr($$type,$i,1))
315             {
316 60 100       177 if (/^[Vv]$/)
317             {
318 35         231 push @tvars, $$value[$i];
319             }
320             else
321             {
322 25 100       195 if (/^[PL]$/)
    100          
    100          
    50          
323             {
324 11         17 my $regex;
325 11 100       52 if (/L$/)
326             {
327 10 100       68 $regex = (substr($$type,$i+1) =~ /^[Vv]*[Rr]/) ?
328             q!'(?=! . $$value[$i] . q!)'! :
329             q!'! . $$value[$i] . q!'!;
330             }
331             else
332             {
333 1 50       20 $regex = (substr($$type,$i+1) =~ /^[Vv]*[Rr]/) ?
334             q!'(?='.! . $$value[$i] . q!.')'! : $$value[$i];
335             }
336 11         35 $parser .= ' @tlist = split('.$regex.',pop @list,2);' . "\n";
337 11         18 $parser .= ' push @tlist,("") x (2-@tlist);' . "\n";
338 11         25 $parser .= ' push @list, splice(@tlist,0);' . "\n";
339             }
340             elsif (/^[Nn]$/)
341             {
342 4         8 $parser .= ' $pos = length($source) - length($list[-1]);' . "\n";
343 4         12 $parser .= ' if ( '.$$value[$i].' > $pos )' . "\n";
344 4         7 $parser .= ' {' . "\n";
345 4         6 $parser .= ' $tmp = pop @list;' . "\n";
346 4         25 $parser .= ' push @list, substr($tmp,0,max(0,'.$$value[$i].
347             '-$pos)),substr($tmp,max(0,'.$$value[$i].'-$pos));' . "\n";
348 4         6 $parser .= ' }' ."\n";
349 4         6 $parser .= ' else' ."\n";
350 4         6 $parser .= ' {' ."\n";
351 4         11 $parser .= ' push @list, substr($source,'.$$value[$i].');' . "\n";
352 4         8 $parser .= ' }' ."\n";
353             }
354             elsif (/^R$/)
355             {
356 7 100       24 if ( $$value[$i] > 0 )
357             {
358 5         9 $parser .= ' $tmp = pop @list;' . "\n";
359 5         18 $parser .= ' push @list, substr($tmp,0,min(length($tmp),'.
360             $$value[$i].')),substr($tmp,min(length($tmp),'.$$value[$i].
361             '));' . "\n";
362             }
363             else
364             {
365 2         6 $parser .= ' $pos = length($source) - length($list[-1]);' . "\n";
366 2         9 $parser .= ' push @list, substr($source,max(0,$pos + '.
367             $$value[$i].'));' . "\n";
368             }
369             }
370             elsif (/^r$/)
371             {
372 3         10 $parser .= ' if ( '.$$value[$i].' > 0 )' . "\n";
373 3         7 $parser .= ' {' ."\n";
374 3         13 $parser .= ' $tmp = pop @list;' . "\n";
375 3         11 $parser .= ' push @list, substr($tmp,0,min(length($tmp),'.
376             $$value[$i].')),substr($tmp,min(length($tmp),'.$$value[$i].
377             '));' . "\n";
378 3         4 $parser .= ' }' ."\n";
379 3         5 $parser .= ' else' ."\n";
380 3         4 $parser .= ' {' ."\n";
381 3         5 $parser .= ' $pos = length($source) - length($list[-1]);' . "\n";
382 3         14 $parser .= ' push @list, substr($source,max(0,$pos + '.
383             $$value[$i].'));' . "\n";
384 3         4 $parser .= ' }' ."\n";
385             }
386              
387 25 100       151 if (@tvars > 1)
    100          
388             {
389 6         30 $parser .= ' @tlist = split(q( ),splice(@list,-2,1),'.
390             scalar(@tvars).');' . "\n";
391 6         20 $parser .= ' push @tlist, ("") x ('.scalar(@tvars).'-@tlist);' . "\n";
392 6         12 $parser .= ' splice @list,-1,0, splice(@tlist,0);' . "\n";
393             }
394             elsif (@tvars == 0)
395             {
396 3         6 $parser .= ' splice @list,-2,1;' . "\n";
397             }
398 25         104 push @vars, splice(@tvars,0);
399             }
400             }
401             }
402 5 100       21 if (@tvars > 1)
403             {
404 2         8 $parser .= ' @tlist = split(q( ),pop @list,'.scalar(@tvars).');' . "\n";
405 2         6 $parser .= ' push @tlist, ("") x ('.scalar(@tvars).'-@tlist);' . "\n";
406 2         10 $parser .= ' push @list, splice(@tlist,0);' . "\n";
407             }
408 5         21 push @vars,splice(@tvars,0);
409 5         17 for my $n (0..$#vars)
410             {
411            
412 40 100 100     172 if (defined($vars[$n]) and $vars[$n] eq '.' )
413             {
414 5         21 $parser .= ' splice @list,' . $n . ',1;' . "\n";
415 5         9 splice @vars,$n,1;
416 5         10 redo;
417             }
418             }
419 5         29 $parser .= ' (' . join(',',@vars) . ') = @list;' . "\n";
420 5         13 $parser .= " \@list;\n}\n";
421              
422 5         55 return $parser;
423             }
424              
425              
426              
427              
428              
429              
430              
431              
432              
433              
434              
435              
436              
437             sub _Vv (\@\$)
438             {
439 4     4   9 my $value = shift;
440 4         6 my $type = shift;
441              
442 4         7 my $parser = "sub\n{\n" ;
443 4         11 $parser .= ' my @list = ' ."\n";
444 4         6 $parser .= ' $_[0] =~ /^';
445 4         15 for my $n (0..$#$value-1)
446             {
447 26 100       58 $parser .= $$value[$n] eq '.' ? '\s*\S*' : '\s*(\S*)';
448             }
449 4 50       14 if (@$value > 1)
450             {
451 4         10 $parser .= '\s*';
452             }
453 4 100       13 $parser .= $$value[-1] eq '.' ? '.*' : '(.*)';
454 4         7 $parser .= '$/;' . "\n";
455 4         8 $parser .= ' ('. join(',',grep { !/^\.$/ } @$value). ') = @list;' ."\n";
  30         99  
456 4         9 $parser .= ' @list;' . "\n";
457 4         5 $parser .= "}\n";
458 4         11 return $parser;
459             }
460              
461              
462              
463              
464              
465              
466              
467              
468             sub _VvPL (\@\$)
469             {
470 6     6   14 my ($value,$type) = @_;
471 6         12 my @vars = ();
472 6         14 my @tvars = ();
473 6         12 my $tvars = "";
474 6         11 my @patts = ();
475 6         14 my $patts = "";
476 6         11 my $re = "";
477              
478 6         10 my $parser = "sub\n{\n" ;
479 6         21 for my $i (0..$#$value)
480             {
481 69 100       252 push @patts, $$value[$i] if substr($$type,$i,1) =~ /^[LP]$/;
482             }
483 6         46 for my $i (0..$#$value)
484             {
485 69         149 for (substr($$type,$i,1))
486             {
487 69 100       201 if (/^[Vv]$/)
488             {
489 41         70 push @tvars, $$value[$i];
490 41 100       144 push @vars, $$value[$i] if /^[V]$/;
491 41         131 $tvars .= substr($$type,$i,1);
492             }
493             else # (/^[PL]$/)
494             {
495 28         64 for my $nv (0..$#tvars-1)
496             {
497 4         5 $re .= '\s*';
498 4 50       15 $re .= substr($tvars,$nv,1) eq 'v'
499             ? _Y($patts[0]).'*' : '('._Y($patts[0]).'*)';
500             }
501 28 100       67 $re .= '\s*' if @tvars > 1;
502 28 100       118 $re .= substr($tvars,-1,1) eq 'v'
503             ? _K($patts[0]).'*' : '('._K($patts[0]).'*)';
504 28         72 $re .= _X($patts[0]);
505 28         93 shift @patts;
506 28         47 @tvars = ();
507 28         82 $tvars = "";
508             }
509             }
510             }
511 6 50       39 if (@tvars)
512             {
513 6         11 $patts = '$';
514 6         22 for my $nv (0..$#tvars-1)
515             {
516 3         5 $re .= '\s*';
517 3 100       12 $re .= (substr($tvars,$nv,1) eq 'v' ? '\S*' : '(\S*)' ) ;
518             }
519 6 100       24 $re .= '\s*' if @tvars > 1;
520 6 100       30 $re .= substr($tvars,-1,1) eq 'v' ? '.*' : '(.*)';
521 6         16 @tvars = ();
522 6         12 $tvars = "";
523             }
524              
525 6         13 $parser .= ' my @list = ' ."\n";
526 6         17 $parser .= ' $_[0] =~ /^' . $re;
527 6         19 $parser .= "\$/;\n";
528 6         32 $parser .= ' ('. join(',',@vars). ') = @list;' ."\n";
529 6         11 $parser .= ' @list;' . "\n";
530 6         11 $parser .= "}\n";
531              
532 6         19 return $parser;
533             }
534              
535              
536              
537              
538              
539             sub _parser
540             {
541 19     19   38 my $template = shift;
542 19         32 my $callpkg = shift;
543 19         37 my $parser = "";
544              
545 19         64 my ($type,@value) = _tokens($template,$callpkg);
546              
547 19         54 my @vars = ();
548 19         33 my @tokens = ();
549 19         32 my $regex = "";
550              
551 19         43 for ($type)
552             {
553              
554             # no variables to assign data
555             /^[^V]+$/ and do
556 19 100       109 {
557 1         2 $parser = "sub {return};\n";
558 1         2 last;
559             };
560              
561             # only one variable to assign data
562             /^[V]$/ and do
563 18 100       65 {
564 1         4 $parser = "sub\n{\n " . $value[0] .
565             ' = $_[0];' . "\n};\n";
566 1         2 last;
567             };
568              
569             # only variables and placeholders
570             /^[Vv]+$/ and do
571 17 100       83 {
572 4         17 $parser = _Vv(@value,$type);
573 4         9 last;
574             };
575            
576             # only variables and hard-coded numeric patterns
577             /^[VvRN]+$/ and do
578 13 100       64 {
579 2         10 $parser = _VvRN(@value,$type);
580 2         5 last;
581             };
582              
583             # only variables and patterns (character or variable)
584             /^[VvPL]+$/ and do
585 11 100       57 {
586 6         27 $parser = _VvPL(@value,$type);
587 6         16 last;
588             };
589              
590             # any valid template not caught by previous cases
591             /^[VvNnRrPL]+$/ and do
592 5 50       28 {
593 5         28 $parser = _anything(@value,$type);
594 5         13 last;
595             };
596              
597 0         0 croak "This should never happen!\n($type)\n:" . join(":\n:",@value) . ":\n";
598              
599             }
600            
601 19         109 $parser = "# ($VERSION) Template: $template\n$parser";
602              
603 19 50       67 _debug("$parser\n") if $debug;
604              
605 19         6023 my $parseref = eval $parser;
606 19 50       77 if ($@) { die "$@" }
  0         0  
607 19         105 return $parseref;
608             }
609              
610              
611             sub _debug
612             {
613 0     0   0 my @list = @_;
614 0         0 open(DEBUG,">>Parser.debug");
615 0         0 for my $item (@list)
616             {
617 0         0 print DEBUG "$item";
618             }
619 0         0 close DEBUG;
620             }
621              
622              
623              
624             sub new
625             {
626 19     19 1 44 my $self = shift;
627 19         34 my $template = shift;
628 19   33     174 my $type = ref($self) || $self;
629 19         46 my $obj = {};
630 19         35 my $caller = 0;
631 19         31 my $callpkg;
632              
633 19         171 $template =~ s/(?:^\s+|\s+$)//g;
634 19         33 do { $callpkg = (caller($caller++))[0] } until $callpkg ne $type;
  37         262  
635              
636 19         71 $$obj{PARSER} = _parser($template,$callpkg);
637              
638 19         169 return bless $obj , $type;
639             }
640              
641              
642             {
643             my %parser = ();
644              
645              
646             sub parse ($$)
647             {
648 27     27 1 366 my $obj = shift;
649 27 100       85 if (ref $obj )
650             {
651 1         34 return $obj->{PARSER}->(shift);
652             }
653 26         48 my $template = shift;
654 26         578 $template =~ s/(?:^\s+|\s+$)//g;
655 26   66     203 $parser{$template} ||= String::RexxParse->new($template);
656 26         755 $parser{$template}->{PARSER}->($obj);
657             }
658              
659              
660             sub drop ($)
661             {
662 0     0 0 0 my $template = shift;
663 0 0       0 if (exists $parser{$template})
664             {
665 0         0 $parser{$template} = "";
666 0         0 delete($parser{$template});
667             }
668             }
669              
670             }
671              
672              
673             sub _Y
674             {
675 4     4   5 my $str = shift;
676 4 50       10 return '@{[_Y('.$str.')]}' if $str =~ /^quotemeta\(.*\)$/;
677 4         12 $str =~ s/\\(.)/$1/g;
678 4         13 my ($first,$rest) = $str =~ /^(.)(.*)$/;
679 4 50       11 $first = quotemeta($first) if $first =~ /\$|\\/;
680 4         5 my $re;
681 4 50       6 if ($rest)
682             {
683 0         0 $re = '(?:[^' . $first . '\s]|\S(?!' . quotemeta($rest) . '))';
684             }
685             else
686             {
687 4         7 $re = '[^' . $first . '\s]';
688             }
689 4         12 $re;
690             }
691              
692             sub _K
693             {
694 29     29   44 my $str = shift;
695 29 100       74 return '@{[_K('.$str.')]}' if $str =~ /^quotemeta\(.*\)$/;
696 28         106 $str =~ s/\\(.)/$1/g;
697 28         105 my ($first,$rest) = $str =~ /^(.)(.*)$/;
698 28 100       102 $first = quotemeta($first) if $first =~ /\$|\\/;
699 28         33 my $re;
700 28 100       47 if ($rest)
701             {
702 6         21 $re = '(?:[^' . $first . ']|.(?!' . quotemeta($rest) . '))';
703             }
704             else
705             {
706 22         40 $re = '[^' . $first . ']' ;
707             }
708 28         101 $re;
709             }
710              
711             sub _X
712             {
713 29     29   44 my $str = shift;
714 29 100       80 return '@{[_X('.$str.')]}' if $str =~ /^quotemeta\(.*\)$/;
715 28         99 $str =~ s/\\(.)/$1/g;
716 28         102 my ($first,$rest) = $str =~ /^(.)(.*)$/;
717 28 100       99 $first = quotemeta($first) if $first =~ /\$|\\/;
718 28         35 my $re;
719 28         67 $re = '(?:'. quotemeta($str) . ')?';
720 28         216 $re;
721             }
722              
723              
724             1;
725              
726              
727             __END__