File Coverage

blib/lib/Text/DelimMatch.pm
Criterion Covered Total %
statement 315 381 82.6
branch 134 212 63.2
condition 40 72 55.5
subroutine 18 24 75.0
pod 19 19 100.0
total 526 708 74.2


line stmt bran cond sub pod time code
1             package Text::DelimMatch;
2              
3 1     1   754 use strict;
  1         2  
  1         36  
4 1     1   5 use vars qw($VERSION @ISA @EXPORT $case_sensitive);
  1         2  
  1         4574  
5              
6             require 5.000;
7             require Exporter;
8             require AutoLoader;
9              
10             @ISA = qw(Exporter AutoLoader);
11             @EXPORT = qw();
12             $VERSION = '1.06';
13              
14             sub new {
15 4     4 1 146 my $type = shift;
16 4         8 my $start = shift;
17 4   66     21 my $end = shift || $start;
18 4         7 my $esc = shift;
19 4         7 my $dblesc= shift;
20 4   33     19 my $class = ref($type) || $type;
21 4         17 my $self = bless {}, $class;
22 4         8 local $_ = "no -w warning in evals now";
23              
24 4 50       837 eval "/$start/" if defined($start);
25 4 50 33     348 eval "/$end/" if !$@ && defined($end);
26              
27 4         32 $self->{'STARTREGEXP'} = $start; # a regexp
28 4         10 $self->{'ENDREGEXP'} = $end; # a regexp
29 4         9 $self->{'QUOTE'} = {}; # a hash of regexp, start => end
30 4         10 $self->{'ESCAPE'} = ""; # a regexp set of chars
31 4         8 $self->{'DBLESCAPE'} = ""; # a regexp set of chars
32              
33 4         10 $self->{'ERROR'} = $@; # false if OK
34 4         8 $self->{'DEBUG'} = 0; # boolean
35 4         13 $self->{'CASESENSE'} = 0; # boolean
36 4         8 $self->{'FORCESLOW'} = 0; # boolean
37 4         8 $self->{'KEEP'} = 1; # boolean
38 4         6 $self->{'RETURNDELIM'} = 1; # boolean
39              
40 4         7 $self->{'BUFFER'} = "";
41 4         7 $self->{'PRE'} = "";
42 4         10 $self->{'MATCH'} = "";
43 4         7 $self->{'POST'} = "";
44              
45 4 50       10 $self->escape($esc) if $esc;
46 4 50       11 $self->double_escape($dblesc) if $dblesc;
47 4 50       14 $self->quote(@_) if @_;
48              
49 4         18 return $self;
50             }
51              
52             sub delim {
53 3     3 1 46 my $self = shift;
54 3         7 my $start = shift;
55 3   33     8 my $end = shift || $start;
56 3         7 my $curs = $self->{'STARTREGEXP'};
57 3         6 my $cure = $self->{'ENDREGEXP'};
58 3         6 local $_ = "no -w warning in evals now";
59              
60 3 50       642 eval "/$start/" if defined($start);
61 3 50 33     189 eval "/$end/" if !$@ && defined($end);
62              
63 3         9 $self->{'ERROR'} = $@; # false if OK
64 3         7 $self->{'STARTREGEXP'} = $start;
65 3         4 $self->{'ENDREGEXP'} = $end;
66              
67 3 50       12 if ($self->{'DEBUG'}) {
68 0         0 print "DELIM : $start, $end";
69 0 0       0 print ": ", $self->{'ERROR'} if $self->{'ERROR'};
70 0         0 print "\n";
71             }
72              
73 3         8 return ($curs, $cure);
74             }
75              
76             sub quote {
77 5     5 1 136 my $self = shift;
78 5         6 my (%oldq) = %{$self->{'QUOTE'}};
  5         19  
79 5         11 local $_ = "no -w warning in evals now";
80 5         6 my ($key, $val);
81              
82 5         9 $key = shift @_;
83              
84 5 100       1117 if (!defined($key)) {
85 2         6 $self->{'QUOTE'} = {};
86             } else {
87 3         12 while ($key) {
88 3   66     15 $val = shift @_ || $key;
89              
90 3 50       286 eval "/$key/" if defined($key);
91 3 50 33     180 eval "/$val/" if !$@ && defined($val);
92 3 50       10 $self->{'ERROR'} = $@ if $@;
93              
94 3 50       10 if ($self->{'DEBUG'}) {
95 0         0 print "QUOTE : $key = $val";
96 0 0       0 print ": ", $self->{'ERROR'} if $self->{'ERROR'};
97 0         0 print "\n";
98             }
99              
100 3         8 $self->{'QUOTE'}->{$key} = $val;
101 3         9 $key = shift @_;
102             }
103             }
104              
105 5         272 return %oldq;
106             }
107              
108             sub escape {
109 3     3 1 47 my $self = shift;
110 3         5 my $esc = shift;
111 3         7 my $curesc = $self->{'ESCAPE'};
112 3         6 local $_ = "no -w warning in evals now";
113              
114 3 100 66     20 $esc = '[' . quotemeta($esc) . ']' if defined($esc) && ($esc ne "");
115              
116 3 100 66     19 if (defined($esc) && ($esc ne "")) {
117 2         153 eval "/$esc/";
118 2 50       9 $self->{'ERROR'} = $@ if $@;
119             }
120              
121 3         6 $self->{'ESCAPE'} = $esc;
122              
123 3 50       10 if ($self->{'DEBUG'}) {
124 0         0 print "ESCAPE: $esc";
125 0 0       0 print ": ", $self->{'ERROR'} if $self->{'ERROR'};
126 0         0 print "\n";
127             }
128              
129 3         8 return $curesc;
130             }
131              
132             sub double_escape {
133 1     1 1 48 my $self = shift;
134 1         3 my $esc = shift;
135 1         3 my $curesc = $self->{'DBLESCAPE'};
136 1         2 local $_ = "no -w warning in evals now";
137              
138 1 50 33     12 $esc = '[' . quotemeta($esc) . ']' if defined($esc) && ($esc ne "");
139              
140 1 50 33     8 if (defined($esc) && ($esc ne "")) {
141 1         74 eval "/$esc/";
142 1 50       6 $self->{'ERROR'} = $@ if $@;
143             }
144              
145 1         3 $self->{'DBLESCAPE'} = $esc;
146              
147 1 50       5 if ($self->{'DEBUG'}) {
148 0         0 print "DBLESC: $esc";
149 0 0       0 print ": ", $self->{'ERROR'} if $self->{'ERROR'};
150 0         0 print "\n";
151             }
152              
153 1         3 return $curesc;
154             }
155              
156             sub case_sensitive {
157 1     1 1 47 my $self = shift;
158 1         3 my $setsense = shift;
159 1         2 my $cursense = $self->{'CASESENSE'};
160              
161 1   33     6 $self->{'CASESENSE'} = $setsense || !defined($setsense);
162              
163 1 50       4 print "CASE : ", $self->{'CASESENSE'}, "\n"
164             if $self->{'DEBUG'};
165              
166 1         2 return $cursense;
167             }
168              
169             sub slow {
170 4     4 1 140 my $self = shift;
171 4         5 my $setslow = shift;
172 4         12 my $curslow = $self->{'FORCESLOW'};
173              
174 4   66     18 $self->{'FORCESLOW'} = $setslow || !defined($setslow);
175              
176 4 50       10 print "GOSLOW: ", $self->{'FORCESLOW'}, "\n"
177             if $self->{'DEBUG'};
178              
179 4         10 return $curslow;
180             }
181              
182             sub keep {
183 1     1 1 41 my $self = shift;
184 1         2 my $setkeep = shift;
185 1         3 my $curkeep = $self->{'KEEP'};
186              
187 1   33     8 $self->{'KEEP'} = $setkeep || !defined($setkeep);
188              
189 1 50       5 print "KEEP : ", $self->{'KEEP'}, "\n"
190             if $self->{'DEBUG'};
191              
192 1         3 return $curkeep;
193             }
194              
195             sub returndelim {
196 2     2 1 49 my $self = shift;
197 2         4 my $setrd = shift;
198 2         4 my $currd = $self->{'RETURNDELIM'};
199              
200 2   66     13 $self->{'RETURNDELIM'} = $setrd || !defined($setrd);
201              
202 2 50       5 print "RETURNDELIM : ", $self->{'RETURNDELIM'}, "\n"
203             if $self->{'DEBUG'};
204              
205 2         6 return $currd;
206             }
207              
208             sub debug {
209 0     0 1 0 my $self = shift;
210 0         0 my $setdebug = shift;
211 0         0 my $curdebug = $self->{'DEBUG'};
212              
213 0   0     0 $self->{'DEBUG'} = $setdebug || !defined($setdebug);
214              
215 0 0       0 print "DEBUG : ", $self->{'DEBUG'}, "\n"
216             if $self->{'DEBUG'};
217              
218 0         0 return $curdebug;
219             }
220              
221             sub error {
222 0     0 1 0 my $self = shift;
223 0         0 my $seterr = shift;
224 0         0 my $curerr = $self->{'ERROR'};
225              
226 0 0       0 $self->{'ERROR'} = $seterr if defined($seterr);
227 0         0 return $curerr;
228             }
229              
230             sub pre_matched {
231 0     0 1 0 my $self = shift;
232 0 0       0 $self->{'ERROR'} = "pre_matched requires keep" if !$self->{'KEEP'};
233 0         0 return $self->{'PRE'};
234             }
235              
236             sub matched {
237 0     0 1 0 my $self = shift;
238 0 0       0 $self->{'ERROR'} = "matched requires keep" if !$self->{'KEEP'};
239 0         0 return $self->{'MATCH'};
240             }
241              
242             sub post_matched {
243 0     0 1 0 my $self = shift;
244 0 0       0 $self->{'ERROR'} = "post_matched requires keep" if !$self->{'KEEP'};
245 0         0 return $self->{'POST'};
246             }
247              
248             sub dump {
249 0     0 1 0 my $self = shift;
250 0         0 my ($key, $val);
251              
252 0         0 print "Dump of Text::DelimMatch:\n";
253              
254 0 0       0 print "\n\tERROR : ", $self->{'ERROR'}, "\n"
255             if $self->{'ERROR'};
256              
257 0         0 print "\tStart : ", $self->{'STARTREGEXP'}, "\n";
258 0         0 print "\tEnd : ", $self->{'ENDREGEXP'}, "\n";
259 0         0 print "\tEscape: ", $self->{'ESCAPE'}, "\n";
260 0         0 print "\tDblEsc: ", $self->{'DBLESCAPE'}, "\n";
261 0         0 print "\tDebug : ", $self->{'DEBUG'}, "\n";
262 0         0 print "\tCase : ", $self->{'CASESENSE'}, "\n";
263 0         0 print "\tSlow : ", $self->{'FORCESLOW'}, "\n";
264 0         0 print "\tKeep : ", $self->{'KEEP'}, "\n";
265 0         0 print "\tQuote :\n";
266 0         0 while (($key, $val) = each %{$self->{'QUOTE'}}) {
  0         0  
267 0         0 print "\t\t$key ... $val\n";
268             }
269 0         0 print "\tBuffer: ", $self->{'BUFFER'}, "\n";
270 0         0 print "\tPrefix: ", $self->{'PRE'}, "\n";
271 0         0 print "\tMatch : ", $self->{'MATCH'}, "\n";
272 0         0 print "\tPost : ", $self->{'POST'}, "\n\n";
273             }
274              
275             sub match {
276 46     46 1 1489 my $self = shift;
277 46         52 my $string = shift;
278 46         50 my $state = 0;
279 46         76 my $start = $self->{'STARTREGEXP'};
280 46         56 my $end = $self->{'ENDREGEXP'};
281 46         46 my %quote = %{$self->{'QUOTE'}};
  46         143  
282 46         77 my $escape = $self->{'ESCAPE'};
283 46         54 my $dblesc = $self->{'DBLESCAPE'};
284 46         191 my $debug = $self->{'DEBUG'};
285 46         78 my ($startq, $endq, $specialq) = ("", "", "");
286 46         51 my ($done) = 0;
287 46         50 my ($depth) = 0;
288 46         60 my (@states) = ();
289 46         59 my ($accum) = "";
290 46         47 my ($regexp, $match, $pre, $matched, $post);
291 0         0 my ($scratch);
292 46         55 local $_ = "no -w warning in evals now";
293              
294 46 50       141 return if $self->{'ERROR'};
295              
296 46 100       85 if (defined($string)) {
297 44         78 $self->{'BUFFER'} = $string;
298             } else {
299             # use post of previous match, if there was a match previously
300 2 100       6 $self->{'BUFFER'} = $self->{'POST'} if $self->{'MATCH'}
301             }
302              
303 46         65 $self->{'PRE'} = "";
304 46         65 $self->{'MATCH'} = "";
305 46         86 $self->{'POST'} = "";
306              
307 46 100 66     249 if (!%quote && !$escape && !$dblesc && !$self->{'FORCESLOW'}) {
      66        
      33        
308 17 50       32 print "FAST: $start, $end\n" if $debug;
309 17 100       44 return $self->_fast0() if $start eq $end;
310 12         29 return $self->_fast1();
311             }
312              
313             # build the regexp that matches the next important thing
314              
315 29 100       65 if (%quote) {
316 15         37 $startq = join (")|(", keys %quote);
317 15         29 $startq = "($startq)";
318             }
319              
320 29 100 100     104 if ($escape || $dblesc) {
321 13 100 100     56 if ($escape && $dblesc) {
    100          
322 10         21 $specialq = "($escape)|($dblesc)";
323             } elsif ($escape) {
324 2         6 $specialq = "($escape)";
325             } else {
326 1         6 $specialq = "($dblesc)";
327             }
328             }
329              
330 29         49 $_ = $self->{'BUFFER'};
331 29         179 $self->{'BUFFER'} = "";
332 29         71 while ($state != 3) {
333 103 100       512 if ($state == 0) { # before start tag
    100          
    50          
334 44         63 $regexp = "($start)";
335 44 100       147 $regexp .= "|$startq" if $startq;
336 44 100       95 $regexp .= "|($escape)" if $escape;
337             } elsif ($state == 1) { # in start tag
338 47         74 $regexp = "($start)|($end)";
339 47 100       87 $regexp .= "|$startq" if $startq;
340 47 100       91 $regexp .= "|($escape)" if $escape;
341             } elsif ($state == 2) { # in quote
342 12         14 $regexp = $endq;
343 12 100       28 $regexp .= "|$specialq" if $specialq;
344             } else {
345 0         0 $self->{'ERROR'} = "BAD STATE! THIS CAN'T HAPPEN!";
346 0         0 return;
347             }
348              
349 103 50       174 print "STATE: $state: $regexp\n" if $debug;
350              
351 103         420 ($pre, $matched, $post) = $self->_match($regexp, $_);
352              
353 103 50       293 print "\tSTR : $_\n" if $debug;
354 103 50       288 print "\tPRE : $pre\n" if $debug;
355 103 50       164 print "\tMTCH: $matched\n" if $debug;
356 103 50       168 print "\tPOST: $post\n" if $debug;
357              
358 103 100       184 last if !$matched;
359              
360             # First things first, if we've encountered an escaped
361             # character, move along
362 96 100 100     409 if ($escape && $self->_match ($escape, $matched)) {
363 10         13 $accum .= $pre . $matched;
364 10         15 $accum .= substr($post, 0, 1);
365 10         17 $_ = substr ($post, 1);
366 10         23 next;
367             }
368              
369 86 100       187 if ($state == 0) { # looking for start or startq
    100          
    50          
370 34 100       279 if ($self->_match($start, $matched)) { # matched start
371 26         30 $state = 1;
372 26         25 $depth++;
373 26 50       50 print "START: $depth\n" if $debug;
374              
375 26         57 $self->{'PRE'} = $accum . $pre;
376 26         27 $accum = $matched;
377 26         73 $_ = $post;
378             } else { # (must have) matched startq
379 8         11 push (@states, $state);
380 8         13 $state = 2;
381 8         12 $accum .= $pre . $matched;
382 8         24 foreach $scratch (keys %quote) {
383 8 50       18 if ($self->_match ($scratch, $matched)) {
384 8         13 $endq = $quote{$scratch};
385 8         14 last;
386             }
387             }
388 8         25 $_ = $post;
389             }
390             } elsif ($state == 1) {
391 41 100       86 if ($self->_match($end, $matched)) { # matched end
    100          
392 31         37 $state = 1;
393 31         31 $depth--;
394              
395 31 50       54 print "END : $depth\n" if $debug;
396 31         46 $accum .= $pre . $matched;
397 31 100       47 if ($depth == 0) {
398 22         27 $state = 3;
399 22         48 $self->{'MATCH'} = $accum;
400 22         28 $self->{'POST'} = $post;
401 22         66 $_ = "";
402             } else {
403 9         30 $_ = $post;
404             }
405             } elsif ($self->_match($start, $matched)) { # matched start
406 9         63 $state = 1;
407 9         12 $depth++;
408 9 50       16 print "START: $depth\n" if $debug;
409              
410 9         15 $accum .= $pre . $matched;
411 9         27 $_ = $post;
412             } else { # (must have) matched startq
413 1         2 push (@states, $state);
414 1         2 $state = 2;
415 1         3 $accum .= $pre . $matched;
416 1         2 foreach $scratch (keys %quote) {
417 1 50       3 if ($self->_match ($scratch, $matched)) {
418 1         2 $endq = $quote{$scratch};
419 1         2 last;
420             }
421             }
422 1         4 $_ = $post;
423             }
424             } elsif ($state == 2) {
425             # case 1, matched dblesc and is a doubled char
426 11 100 66     28 if ($dblesc
      100        
427             && $self->_match ($dblesc, $matched)
428             && ($matched eq substr($post, 0, 1))) { # skip forward
429 2         3 $accum .= $pre . $matched;
430 2         5 $accum .= substr($post, 0, 1);
431 2         3 $_ = substr($post, 1);
432 2         8 next;
433             } # otherwise check for other things then revisit
434            
435 9 50       20 if ($self->_match ($endq, $matched)) { # matched endq
436 9         15 $state = pop (@states);
437 9         13 $accum .= $pre . $matched;
438 9         26 $_ = $post;
439             } else { # (must have) matched a undoubled dblesc
440             # usually this ends a quoted string
441             # (and we'd never get here)
442             # but since it didn't, just skip along
443 0         0 $accum .= $pre . $matched;
444 0         0 $_ = $post;
445             }
446             } else {
447 0         0 $self->{'ERROR'} = "BAD STATE! THIS CAN'T HAPPEN!";
448 0         0 return;
449             }
450             }
451              
452 29 100       53 if ($state == 3) {
453 22         33 $pre = $self->{'PRE'};
454 22         28 $match = $self->{'MATCH'};
455 22         26 $post = $self->{'POST'};
456              
457 22 50       114 $match = $self->strip_delim($match) if !$self->{'RETURNDELIM'};
458             } else {
459 7         14 $self->{'PRE'} = "";
460 7         11 $self->{'MATCH'} = "";
461 7         10 $self->{'POST'} = "";
462 7         11 undef $pre;
463 7         19 undef $match;
464 7         9 undef $post;
465             }
466            
467 29 100       97 if (!$self->{'KEEP'}) {
468 2         5 $self->{'PRE'} = "";
469 2         3 $self->{'MATCH'} = "";
470 2         2 $self->{'POST'} = "";
471             }
472              
473 29 50       195 return wantarray ? ($pre, $match, $post) : $match;
474             }
475              
476             sub _fast0 {
477 5     5   29 my $self = shift;
478 5         9 my $delim = $self->{'STARTREGEXP'};
479 5         11 local $_ = $self->{'BUFFER'};
480 5         6 my ($pre, $match, $post);
481              
482 5 50       11 if ($self->{'CASESENSE'}) {
483 0         0 $match = /^(.*?)($delim.*?$delim)(.*)$/s;
484 0         0 ($pre, $match, $post) = ($1, $2, $3);
485             } else {
486 5         96 $match = /^(.*?)($delim.*?$delim)(.*)$/si;
487 5         21 ($pre, $match, $post) = ($1, $2, $3);
488             }
489              
490 5 100       11 if ($match) {
491 3 50       37 $match = $self->strip_delim($match) if !$self->{'RETURNDELIM'};
492              
493 3 50       10 if ($self->{'KEEP'}) {
494 3         7 $self->{'PRE'} = $pre;
495 3         5 $self->{'MATCH'} = $match;
496 3         5 $self->{'POST'} = $post;
497             }
498              
499 3 50       37 return wantarray ? ($pre, $match, $post) : $match;
500             } else {
501 2 50       137 return wantarray ? (undef, undef, undef) : undef;
502             }
503             }
504              
505             sub _fast1 {
506 12     12   15 my $self = shift;
507 12         23 my $string = $self->{'BUFFER'};
508 12         17 my $start = $self->{'STARTREGEXP'};
509 12         16 my $end = $self->{'ENDREGEXP'};
510 12         24 my $regexp = "($start)|($end)";
511 12         12 my $count = 0;
512 12         12 my ($match, $realpre, $pre, $post, $matched);
513              
514 12         23 ($realpre, $match, $post) = $self->_match($start, $string);
515              
516 12 100       30 if (defined($match)) {
517 10         12 $matched = $match;
518 10         10 $string = $post;
519 10         12 $count++;
520              
521 10         20 ($pre, $match, $post) = $self->_match($regexp, $string);
522              
523 10         27 while (defined($match)) {
524 26         40 $matched .= $pre . $match;
525              
526 26 100       48 if ($self->_match($end, $match)) {
527 17         22 $count--;
528             } else {
529 9         12 $count++;
530             }
531              
532 26         34 $string = $post;
533 26 100       70 last if $count == 0;
534              
535 18         35 ($pre, $match, $post) = $self->_match($regexp, $string);
536             }
537              
538 10 100       23 if ($count == 0) {
539 8 100       22 $matched = $self->strip_delim($matched) if !$self->{'RETURNDELIM'};
540              
541 8 50       18 if ($self->{'KEEP'}) {
542 8         14 $self->{'PRE'} = $realpre;
543 8         9 $self->{'MATCH'} = $matched;
544 8         14 $self->{'POST'} = $post;
545             }
546            
547 8 100       55 return wantarray ? ($realpre, $matched, $post) : $matched;
548             }
549             }
550              
551 4 50       22 return wantarray ? (undef, undef, undef) : undef;
552             }
553              
554             sub strip_delim {
555 2     2 1 3 my $self = shift;
556 2         3 my $string = shift;
557 2         4 my $start = $self->{'STARTREGEXP'};
558 2         3 my $end = $self->{'ENDREGEXP'};
559 2         3 my $ok = 1;
560 2         4 local $_ = "no -w warning in evals now";
561              
562 2 50       5 return if $self->{'ERROR'};
563              
564 2 50       7 $string = $self->{'MATCH'} if !defined($string);
565              
566 2 50       18 if ($string =~ /^$start/s) {
567 2         5 my($rest) = $';
568 2 50       29 if ($rest =~ /^(.*)$end$/s) {
569 2         9 return $1;
570             } else {
571 0         0 $self->{'ERROR'} = "FAILED TO MATCH END DELIMITER";
572             }
573             } else {
574 0         0 $self->{'ERROR'} = "FAILED TO MATCH START DELIMITER";
575             }
576              
577 0         0 return;
578             }
579              
580             sub _match {
581 320     320   407 my $self = shift;
582 320         442 my $regexp = shift;
583 320         419 local $_ = shift;
584 320         318 my $match = 0;
585 320         290 my ($pre, $matched, $post);
586              
587 320 100       578 if ($self->{'CASESENSE'}) {
588 19         289 $match = /$regexp/s;
589 19         59 ($pre, $matched, $post) = ($`, $&, $');
590             } else {
591 301         3859 $match = /$regexp/si;
592 301         1117 ($pre, $matched, $post) = ($`, $&, $');
593             }
594              
595 320 100       763 if ($match) {
596 248 100       1477 wantarray ? ($pre, $matched, $post) : $matched;
597             } else {
598 72 100       290 wantarray ? (undef, undef, undef) : undef;
599             }
600             }
601              
602             sub nested_match {
603 1     1 1 44 my ($search, $start, $end, $three) = @_;
604 1         7 my $mc = new Text::DelimMatch $start, $end;
605 1         4 my ($p, $m, $s) = $mc->match($search);
606              
607 1 50       4 if (defined($three)) {
608 0 0       0 return wantarray ? ($p, $m, $s) : $m;
609             } else {
610 1 50       22 return wantarray ? ("$p$m", $s) : $m;
611             }
612             }
613              
614             sub skip_nested_match {
615 1     1 1 51 my ($search, $start, $end, $three) = @_;
616 1         5 my $mc = new Text::DelimMatch $start, $end;
617 1         7 my ($p, $m, $s) = $mc->match($search);
618              
619 1 50       8 if (defined($three)) {
620 0 0       0 return wantarray ? ($p, $m, $s) : $s;
621             } else {
622 1 50       8 return wantarray ? ("$p$m", $s) : $s;
623             }
624             }
625              
626             1;
627             __END__