File Coverage

lib/ExtUtils/MakeMaker/version/vpp.pm
Criterion Covered Total %
statement 41 549 7.4
branch 0 280 0.0
condition 0 174 0.0
subroutine 14 50 28.0
pod 0 16 0.0
total 55 1069 5.1


line stmt bran cond sub pod time code
1             #--------------------------------------------------------------------------#
2             # This is a modified copy of version.pm 0.9909, bundled exclusively for
3             # use by ExtUtils::Makemaker and its dependencies to bootstrap when
4             # version.pm is not available. It should not be used by ordinary modules.
5             #--------------------------------------------------------------------------#
6              
7             # a little helper class to emulate C char* semantics in Perl
8             # so that prescan_version can use the same code as in C
9              
10             use overload (
11             '""' => \&thischar,
12 1         14 '0+' => \&thischar,
13             '++' => \&increment,
14             '--' => \&decrement,
15             '+' => \&plus,
16             '-' => \&minus,
17             '*' => \&multiply,
18             'cmp' => \&cmp,
19             '<=>' => \&spaceship,
20             'bool' => \&thischar,
21             '=' => \&clone,
22             );
23 1     1   4655  
  1         2  
24             my ($self, $string) = @_;
25             my $class = ref($self) || $self;
26 0     0      
27 0   0       my $obj = {
28             string => [split(//,$string)],
29 0           current => 0,
30             };
31             return bless $obj, $class;
32             }
33 0            
34             my ($self) = @_;
35             my $last = $#{$self->{string}};
36             my $curr = $self->{current};
37 0     0     if ($curr >= 0 && $curr <= $last) {
38 0           return $self->{string}->[$curr];
  0            
39 0           }
40 0 0 0       else {
41 0           return '';
42             }
43             }
44 0            
45             my ($self) = @_;
46             $self->{current}++;
47             }
48              
49 0     0     my ($self) = @_;
50 0           $self->{current}--;
51             }
52              
53             my ($self, $offset) = @_;
54 0     0     my $rself = $self->clone;
55 0           $rself->{current} += $offset;
56             return $rself;
57             }
58              
59 0     0     my ($self, $offset) = @_;
60 0           my $rself = $self->clone;
61 0           $rself->{current} -= $offset;
62 0           return $rself;
63             }
64              
65             my ($left, $right, $swapped) = @_;
66 0     0     my $char = $left->thischar();
67 0           return $char * $right;
68 0           }
69 0            
70             my ($left, $right, $swapped) = @_;
71             unless (ref($right)) { # not an object already
72             $right = $left->new($right);
73 0     0     }
74 0           return $left->{current} <=> $right->{current};
75 0           }
76              
77             my ($left, $right, $swapped) = @_;
78             unless (ref($right)) { # not an object already
79 0     0     if (length($right) == 1) { # comparing single character only
80 0 0         return $left->thischar cmp $right;
81 0           }
82             $right = $left->new($right);
83 0           }
84             return $left->currstr cmp $right->currstr;
85             }
86              
87 0     0     my ($self) = @_;
88 0 0         my $char = $self->thischar;
89 0 0         return ($char ne '');
90 0           }
91              
92 0           my ($left, $right, $swapped) = @_;
93             $right = {
94 0           string => [@{$left->{string}}],
95             current => $left->{current},
96             };
97             return bless $right, ref($left);
98 0     0     }
99 0            
100 0           my ($self, $s) = @_;
101             my $curr = $self->{current};
102             my $last = $#{$self->{string}};
103             if (defined($s) && $s->{current} < $last) {
104 0     0     $last = $s->{current};
105             }
106 0            
107             my $string = join('', @{$self->{string}}[$curr..$last]);
108 0           return $string;
109 0           }
110              
111              
112             use 5.006001;
113 0     0     use strict;
114 0           use warnings;
115 0            
  0            
116 0 0 0       use Config;
117 0           use vars qw($VERSION $CLASS @ISA $LAX $STRICT);
118             $VERSION = '7.64';
119             $VERSION =~ tr/_//d;
120 0           $CLASS = 'ExtUtils::MakeMaker::version::vpp';
  0            
121 0            
122             require ExtUtils::MakeMaker::version::regex;
123             *ExtUtils::MakeMaker::version::vpp::is_strict = \&ExtUtils::MakeMaker::version::regex::is_strict;
124             *ExtUtils::MakeMaker::version::vpp::is_lax = \&ExtUtils::MakeMaker::version::regex::is_lax;
125             *LAX = \$ExtUtils::MakeMaker::version::regex::LAX;
126 1     1   580 *STRICT = \$ExtUtils::MakeMaker::version::regex::STRICT;
  1         2  
127 1     1   5  
  1         2  
  1         17  
128 1     1   3 use overload (
  1         1  
  1         31  
129             '""' => \&stringify,
130 1     1   5 '0+' => \&numify,
  1         1  
  1         39  
131 1     1   4 'cmp' => \&vcmp,
  1         1  
  1         223  
132             '<=>' => \&vcmp,
133             'bool' => \&vbool,
134             '+' => \&vnoop,
135             '-' => \&vnoop,
136             '*' => \&vnoop,
137             '/' => \&vnoop,
138             '+=' => \&vnoop,
139             '-=' => \&vnoop,
140             '*=' => \&vnoop,
141             '/=' => \&vnoop,
142             'abs' => \&vnoop,
143 1         7 );
144              
145             eval "use warnings";
146             if ($@) {
147             eval '
148             package
149             warnings;
150             sub enabled {return $^W;}
151             1;
152             ';
153             }
154              
155             no strict 'refs';
156             my ($class) = shift;
157 1     1   6  
  1         1  
158             # Set up any derived class
159 1     1   5 unless ($class eq $CLASS) {
  1         2  
  1         17  
160             no warnings;
161             *{$class.'::declare'} = \&{$CLASS.'::declare'};
162             *{$class.'::qv'} = \&{$CLASS.'::qv'};
163             }
164              
165             my %args;
166             if (@_) { # any remaining terms are arguments
167             map { $args{$_} = 1 } @_
168             }
169             else { # no parameters at all on use line
170 1     1   200 %args =
  1         2  
  1         55  
171 0     0     (
172             qv => 1,
173             'UNIVERSAL::VERSION' => 1,
174 0 0         );
175 1     1   6 }
  1         1  
  1         211  
176 0            
  0            
  0            
177 0           my $callpkg = caller();
  0            
  0            
178              
179             if (exists($args{declare})) {
180 0           *{$callpkg.'::declare'} =
181 0 0         sub {return $class->declare(shift) }
182 0           unless defined(&{$callpkg.'::declare'});
  0            
183             }
184              
185 0           if (exists($args{qv})) {
186             *{$callpkg.'::qv'} =
187             sub {return $class->qv(shift) }
188             unless defined(&{$callpkg.'::qv'});
189             }
190              
191             if (exists($args{'UNIVERSAL::VERSION'})) {
192 0           no warnings;
193             *UNIVERSAL::VERSION
194 0 0         = \&{$CLASS.'::_VERSION'};
195 0           }
196 0     0      
197 0 0         if (exists($args{'VERSION'})) {
  0            
198             *{$callpkg.'::VERSION'} = \&{$CLASS.'::_VERSION'};
199             }
200 0 0          
201 0           if (exists($args{'is_strict'})) {
202 0     0     *{$callpkg.'::is_strict'} = \&{$CLASS.'::is_strict'}
203 0 0         unless defined(&{$callpkg.'::is_strict'});
  0            
204             }
205              
206 0 0         if (exists($args{'is_lax'})) {
207 1     1   6 *{$callpkg.'::is_lax'} = \&{$CLASS.'::is_lax'}
  1         1  
  1         160  
208             unless defined(&{$callpkg.'::is_lax'});
209 0           }
  0            
210             }
211              
212 0 0         my $VERSION_MAX = 0x7FFFFFFF;
213 0            
  0            
  0            
214             # implement prescan_version as closely to the C version as possible
215             use constant TRUE => 1;
216 0 0         use constant FALSE => 0;
217 0            
  0            
218 0 0         my ($char) = shift->thischar();
  0            
219             return ($char =~ /\d/);
220             }
221 0 0          
222 0           my ($char) = shift->thischar();
  0            
223 0 0         return ($char =~ /[a-zA-Z]/);
  0            
224             }
225              
226             my ($char) = shift->thischar();
227             return ($char =~ /\s/);
228             }
229              
230 1     1   7 my ($s, $errstr, $error) = @_;
  1         1  
  1         81  
231 1     1   5 if ($errstr) {
  1         2  
  1         3302  
232             $$errstr = $error;
233             }
234 0     0 0   return $s;
235 0           }
236              
237             my ($s, $strict, $errstr, $sqv, $ssaw_decimal, $swidth, $salpha) = @_;
238             my $qv = defined $sqv ? $$sqv : FALSE;
239 0     0 0   my $saw_decimal = defined $ssaw_decimal ? $$ssaw_decimal : 0;
240 0           my $width = defined $swidth ? $$swidth : 3;
241             my $alpha = defined $salpha ? $$salpha : FALSE;
242              
243             my $d = $s;
244 0     0 0    
245 0           if ($qv && isDIGIT($d)) {
246             goto dotted_decimal_version;
247             }
248              
249 0     0 0   if ($d eq 'v') { # explicit v-string
250 0 0         $d++;
251 0           if (isDIGIT($d)) {
252             $qv = TRUE;
253 0           }
254             else { # degenerate v-string
255             # requires v1.2.3
256             return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
257 0     0 0   }
258 0 0          
259 0 0         dotted_decimal_version:
260 0 0         if ($strict && $d eq '0' && isDIGIT($d+1)) {
261 0 0         # no leading zeros allowed
262             return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)");
263 0           }
264              
265 0 0 0       while (isDIGIT($d)) { # integer part
266 0           $d++;
267             }
268              
269 0 0         if ($d eq '.')
270 0           {
271 0 0         $saw_decimal++;
272 0           $d++; # decimal point
273             }
274             else
275             {
276 0           if ($strict) {
277             # require v1.2.3
278             return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
279             }
280 0 0 0       else {
      0        
281             goto version_prescan_finish;
282 0           }
283             }
284              
285 0           {
286 0           my $i = 0;
287             my $j = 0;
288             while (isDIGIT($d)) { # just keep reading
289 0 0         $i++;
290             while (isDIGIT($d)) {
291 0           $d++; $j++;
292 0           # maximum 3 digits between decimal
293             if ($strict && $j > 3) {
294             return BADVERSION($s,$errstr,"Invalid version format (maximum 3 digits between decimals)");
295             }
296 0 0         }
297             if ($d eq '_') {
298 0           if ($strict) {
299             return BADVERSION($s,$errstr,"Invalid version format (no underscores)");
300             }
301 0           if ( $alpha ) {
302             return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)");
303             }
304             $d++;
305             $alpha = TRUE;
306 0           }
  0            
307 0           elsif ($d eq '.') {
308 0           if ($alpha) {
309 0           return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)");
310 0           }
311 0           $saw_decimal++;
  0            
312             $d++;
313 0 0 0       }
314 0           elsif (!isDIGIT($d)) {
315             last;
316             }
317 0 0         $j = 0;
    0          
    0          
318 0 0         }
319 0            
320             if ($strict && $i < 2) {
321 0 0         # requires v1.2.3
322 0           return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
323             }
324 0           }
325 0           } # end if dotted-decimal
326             else
327             { # decimal versions
328 0 0         my $j = 0;
329 0           # special $strict case for leading '.' or '0'
330             if ($strict) {
331 0           if ($d eq '.') {
332 0           return BADVERSION($s,$errstr,"Invalid version format (0 before decimal required)");
333             }
334             if ($d eq '0' && isDIGIT($d+1)) {
335 0           return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)");
336             }
337 0           }
338              
339             # and we never support negative version numbers
340 0 0 0       if ($d eq '-') {
341             return BADVERSION($s,$errstr,"Invalid version format (negative version number)");
342 0           }
343              
344             # consume all of the integer part
345             while (isDIGIT($d)) {
346             $d++;
347             }
348 0            
349             # look for a fractional part
350 0 0         if ($d eq '.') {
351 0 0         # we found it, so consume it
352 0           $saw_decimal++;
353             $d++;
354 0 0 0       }
355 0           elsif (!$d || $d eq ';' || isSPACE($d) || $d eq '}') {
356             if ( $d == $s ) {
357             # found nothing
358             return BADVERSION($s,$errstr,"Invalid version format (version required)");
359             }
360 0 0         # found just an integer
361 0           goto version_prescan_finish;
362             }
363             elsif ( $d == $s ) {
364             # didn't find either integer or period
365 0           return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)");
366 0           }
367             elsif ($d eq '_') {
368             # underscore can't come after integer part
369             if ($strict) {
370 0 0 0       return BADVERSION($s,$errstr,"Invalid version format (no underscores)");
    0 0        
    0 0        
    0          
    0          
371             }
372 0           elsif (isDIGIT($d+1)) {
373 0           return BADVERSION($s,$errstr,"Invalid version format (alpha without decimal)");
374             }
375             else {
376 0 0         return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)");
377             }
378 0           }
379             elsif ($d) {
380             # anything else after integer part is just invalid data
381 0           return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)");
382             }
383              
384             # scan the fractional part after the decimal point
385 0           if ($d && !isDIGIT($d) && ($strict || ! ($d eq ';' || isSPACE($d) || $d eq '}') )) {
386             # $strict or lax-but-not-the-end
387             return BADVERSION($s,$errstr,"Invalid version format (fractional part required)");
388             }
389 0 0          
    0          
390 0           while (isDIGIT($d)) {
391             $d++; $j++;
392             if ($d eq '.' && isDIGIT($d-1)) {
393 0           if ($alpha) {
394             return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)");
395             }
396 0           if ($strict) {
397             return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions must begin with 'v')");
398             }
399             $d = $s; # start all over again
400             $qv = TRUE;
401 0           goto dotted_decimal_version;
402             }
403             if ($d eq '_') {
404             if ($strict) {
405 0 0 0       return BADVERSION($s,$errstr,"Invalid version format (no underscores)");
      0        
      0        
406             }
407 0           if ( $alpha ) {
408             return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)");
409             }
410 0           if ( ! isDIGIT($d+1) ) {
411 0           return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)");
  0            
412 0 0 0       }
413 0 0         $width = $j;
414 0           $d++;
415             $alpha = TRUE;
416 0 0         }
417 0           }
418             }
419 0            
420 0           version_prescan_finish:
421 0           while (isSPACE($d)) {
422             $d++;
423 0 0         }
424 0 0          
425 0           if ($d && !isDIGIT($d) && (! ($d eq ';' || $d eq '}') )) {
426             # trailing non-numeric data
427 0 0         return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)");
428 0           }
429              
430 0 0         if (defined $sqv) {
431 0           $$sqv = $qv;
432             }
433 0           if (defined $swidth) {
434 0           $$swidth = $width;
435 0           }
436             if (defined $ssaw_decimal) {
437             $$ssaw_decimal = $saw_decimal;
438             }
439             if (defined $salpha) {
440             $$salpha = $alpha;
441 0           }
442 0           return $d;
443             }
444              
445 0 0 0       my ($s, $rv, $qv) = @_;
      0        
      0        
446             my $start;
447 0           my $pos;
448             my $last;
449             my $errstr;
450 0 0         my $saw_decimal = 0;
451 0           my $width = 3;
452             my $alpha = FALSE;
453 0 0         my $vinf = FALSE;
454 0           my @av;
455              
456 0 0         $s = new ExtUtils::MakeMaker::charstar $s;
457 0            
458             while (isSPACE($s)) { # leading whitespace is OK
459 0 0         $s++;
460 0           }
461              
462 0           $last = prescan_version($s, FALSE, \$errstr, \$qv, \$saw_decimal,
463             \$width, \$alpha);
464              
465             if ($errstr) {
466 0     0 0   # 'undef' is a special case and not an error
467 0           if ( $s ne 'undef') {
468             require Carp;
469 0           Carp::croak($errstr);
470 0           }
471 0           }
472 0            
473 0           $start = $s;
474 0           if ($s eq 'v') {
475 0           $s++;
476             }
477 0           $pos = $s;
478              
479 0           if ( $qv ) {
480 0           $$rv->{qv} = $qv;
481             }
482             if ( $alpha ) {
483 0           $$rv->{alpha} = $alpha;
484             }
485             if ( !$qv && $width < 3 ) {
486 0 0         $$rv->{width} = $width;
487             }
488 0 0          
489 0           while (isDIGIT($pos)) {
490 0           $pos++;
491             }
492             if (!isALPHA($pos)) {
493             my $rev;
494 0            
495 0 0         for (;;) {
496 0           $rev = 0;
497             {
498 0           # this is atoi() that delimits on underscores
499             my $end = $pos;
500 0 0         my $mult = 1;
501 0           my $orev;
502              
503 0 0         # the following if() will only be true after the decimal
504 0           # point of a version originally created with a bare
505             # floating point number, i.e. not quoted in any way
506 0 0 0       #
507 0           if ( !$qv && $s > $start && $saw_decimal == 1 ) {
508             $mult *= 100;
509             while ( $s < $end ) {
510 0           $orev = $rev;
511 0           $rev += $s * $mult;
512             $mult /= 10;
513 0 0         if ( (abs($orev) > abs($rev))
514 0           || (abs($rev) > $VERSION_MAX )) {
515             warn("Integer overflow in version %d",
516 0           $VERSION_MAX);
517 0           $s = $end - 1;
518             $rev = $VERSION_MAX;
519             $vinf = 1;
520 0           }
  0            
521 0           $s++;
522 0           if ( $s eq '_' ) {
523             $s++;
524             }
525             }
526             }
527             else {
528 0 0 0       while (--$end >= $s) {
      0        
529 0           $orev = $rev;
530 0           $rev += $end * $mult;
531 0           $mult *= 10;
532 0           if ( (abs($orev) > abs($rev))
533 0           || (abs($rev) > $VERSION_MAX )) {
534 0 0 0       warn("Integer overflow in version");
535             $end = $s - 1;
536 0           $rev = $VERSION_MAX;
537             $vinf = 1;
538 0           }
539 0           }
540 0           }
541             }
542 0            
543 0 0         # Append revision
544 0           push @av, $rev;
545             if ( $vinf ) {
546             $s = $last;
547             last;
548             }
549 0           elsif ( $pos eq '.' ) {
550 0           $s = ++$pos;
551 0           }
552 0           elsif ( $pos eq '_' && isDIGIT($pos+1) ) {
553 0 0 0       $s = ++$pos;
554             }
555 0           elsif ( $pos eq ',' && isDIGIT($pos+1) ) {
556 0           $s = ++$pos;
557 0           }
558 0           elsif ( isDIGIT($pos) ) {
559             $s = $pos;
560             }
561             else {
562             $s = $pos;
563             last;
564             }
565 0           if ( $qv ) {
566 0 0 0       while ( isDIGIT($pos) ) {
    0 0        
    0          
    0          
    0          
567 0           $pos++;
568 0           }
569             }
570             else {
571 0           my $digits = 0;
572             while ( ( isDIGIT($pos) || $pos eq '_' ) && $digits < 3 ) {
573             if ( $pos ne '_' ) {
574 0           $digits++;
575             }
576             $pos++;
577 0           }
578             }
579             }
580 0           }
581             if ( $qv ) { # quoted versions always get at least three terms
582             my $len = $#av;
583 0           # This for loop appears to trigger a compiler bug on OS X, as it
584 0           # loops infinitely. Yes, len is negative. No, it makes no sense.
585             # Compiler in question is:
586 0 0         # gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
587 0           # for ( len = 2 - len; len > 0; len-- )
588 0           # av_push(MUTABLE_AV(sv), newSViv(0));
589             #
590             $len = 2 - $len;
591             while ($len-- > 0) {
592 0           push @av, 0;
593 0   0       }
      0        
594 0 0         }
595 0            
596             # need to save off the current version string for later
597 0           if ( $vinf ) {
598             $$rv->{original} = "v.Inf";
599             $$rv->{vinf} = 1;
600             }
601             elsif ( $s > $start ) {
602 0 0         $$rv->{original} = $start->currstr($s);
603 0           if ( $qv && $saw_decimal == 1 && $start ne 'v' ) {
604             # need to insert a v to be consistent
605             $$rv->{original} = 'v' . $$rv->{original};
606             }
607             }
608             else {
609             $$rv->{original} = '0';
610             push(@av, 0);
611 0           }
612 0            
613 0           # And finally, store the AV in the hash
614             $$rv->{version} = \@av;
615              
616             # fix RT#19517 - special case 'undef' as string
617             if ($s eq 'undef') {
618 0 0         $s += 5;
    0          
619 0           }
620 0            
621             return $s;
622             }
623 0            
624 0 0 0       my $class = shift;
      0        
625             unless (defined $class or $#_ > 1) {
626 0           require Carp;
627             Carp::croak('Usage: version::new(class, version)');
628             }
629              
630 0           my $self = bless ({}, ref ($class) || $class);
631 0           my $qv = FALSE;
632              
633             if ( $#_ == 1 ) { # must be CVS-style
634             $qv = TRUE;
635 0           }
636             my $value = pop; # always going to be the last element
637              
638 0 0         if ( ref($value) && eval('$value->isa("version")') ) {
639 0           # Can copy the elements directly
640             $self->{version} = [ @{$value->{version} } ];
641             $self->{qv} = 1 if $value->{qv};
642 0           $self->{alpha} = 1 if $value->{alpha};
643             $self->{original} = ''.$value->{original};
644             return $self;
645             }
646 0     0 0    
647 0 0 0       if ( not defined $value or $value =~ /^undef$/ ) {
648 0           # RT #19517 - special case for undef comparison
649 0           # or someone forgot to pass a value
650             push @{$self->{version}}, 0;
651             $self->{original} = "0";
652 0   0       return ($self);
653 0           }
654              
655 0 0          
656 0           if (ref($value) =~ m/ARRAY|HASH/) {
657             require Carp;
658 0           Carp::croak("Invalid version format (non-numeric data)");
659             }
660 0 0 0        
661             $value = _un_vstring($value);
662 0            
  0            
663 0 0         if ($Config{d_setlocale} && eval { require POSIX } ) {
664 0 0         require locale;
665 0           my $currlocale = POSIX::setlocale(&POSIX::LC_ALL);
666 0            
667             # if the current locale uses commas for decimal points, we
668             # just replace commas with decimal places, rather than changing
669 0 0 0       # locales
670             if ( POSIX::localeconv()->{decimal_point} eq ',' ) {
671             $value =~ tr/,/./;
672 0           }
  0            
673 0           }
674 0            
675             # exponential notation
676             if ( $value =~ /\d+.?\d*e[-+]?\d+/ ) {
677             $value = sprintf("%.9f",$value);
678 0 0         $value =~ s/(0+)$//; # trim trailing zeros
679 0           }
680 0            
681             my $s = scan_version($value, \$self, $qv);
682              
683 0           if ($s) { # must be something left over
684             warn("Version string '%s' contains invalid data; "
685 0 0 0       ."ignoring: '%s'", $value, $s);
  0            
686 0           }
687 0            
688             return ($self);
689             }
690              
691             *parse = \&new;
692 0 0          
693 0           my ($self) = @_;
694             unless (_verify($self)) {
695             require Carp;
696             Carp::croak("Invalid version object");
697             }
698 0 0         my $width = $self->{width} || 3;
699 0           my $alpha = $self->{alpha} || "";
700 0           my $len = $#{$self->{version}};
701             my $digit = $self->{version}[0];
702             my $string = sprintf("%d.", $digit );
703 0            
704             for ( my $i = 1 ; $i < $len ; $i++ ) {
705 0 0         $digit = $self->{version}[$i];
706 0           if ( $width < 3 ) {
707             my $denom = 10**(3-$width);
708             my $quot = int($digit/$denom);
709             my $rem = $digit - ($quot * $denom);
710 0           $string .= sprintf("%0".$width."d_%d", $quot, $rem);
711             }
712             else {
713             $string .= sprintf("%03d", $digit);
714             }
715             }
716 0     0 0    
717 0 0         if ( $len > 0 ) {
718 0           $digit = $self->{version}[$len];
719 0           if ( $alpha && $width == 3 ) {
720             $string .= "_";
721 0   0       }
722 0   0       $string .= sprintf("%0".$width."d", $digit);
723 0           }
  0            
724 0           else # $len = 0
725 0           {
726             $string .= sprintf("000");
727 0           }
728 0            
729 0 0         return $string;
730 0           }
731 0            
732 0           my ($self) = @_;
733 0           unless (_verify($self)) {
734             require Carp;
735             Carp::croak("Invalid version object");
736 0           }
737             my $alpha = $self->{alpha} || "";
738             my $len = $#{$self->{version}};
739             my $digit = $self->{version}[0];
740 0 0         my $string = sprintf("v%d", $digit );
741 0            
742 0 0 0       for ( my $i = 1 ; $i < $len ; $i++ ) {
743 0           $digit = $self->{version}[$i];
744             $string .= sprintf(".%d", $digit);
745 0           }
746              
747             if ( $len > 0 ) {
748             $digit = $self->{version}[$len];
749 0           if ( $alpha ) {
750             $string .= sprintf("_%0d", $digit);
751             }
752 0           else {
753             $string .= sprintf(".%0d", $digit);
754             }
755             }
756 0     0 0    
757 0 0         if ( $len <= 2 ) {
758 0           for ( $len = 2 - $len; $len != 0; $len-- ) {
759 0           $string .= sprintf(".%0d", 0);
760             }
761 0   0       }
762 0            
  0            
763 0           return $string;
764 0           }
765              
766 0           my ($self) = @_;
767 0           unless (_verify($self)) {
768 0           require Carp;
769             Carp::croak("Invalid version object");
770             }
771 0 0         return exists $self->{original}
772 0           ? $self->{original}
773 0 0         : exists $self->{qv}
774 0           ? $self->normal
775             : $self->numify;
776             }
777 0            
778             require UNIVERSAL;
779             my ($left,$right,$swap) = @_;
780             my $class = ref($left);
781 0 0         unless ( UNIVERSAL::isa($right, $class) ) {
782 0           $right = $class->new($right);
783 0           }
784              
785             if ( $swap ) {
786             ($left, $right) = ($right, $left);
787 0           }
788             unless (_verify($left)) {
789             require Carp;
790             Carp::croak("Invalid version object");
791 0     0 0   }
792 0 0         unless (_verify($right)) {
793 0           require Carp;
794 0           Carp::croak("Invalid version format");
795             }
796             my $l = $#{$left->{version}};
797             my $r = $#{$right->{version}};
798             my $m = $l < $r ? $l : $r;
799 0 0         my $lalpha = $left->is_alpha;
    0          
800             my $ralpha = $right->is_alpha;
801             my $retval = 0;
802             my $i = 0;
803             while ( $i <= $m && $retval == 0 ) {
804 0     0 0   $retval = $left->{version}[$i] <=> $right->{version}[$i];
805 0           $i++;
806 0           }
807 0 0          
808 0           # tiebreaker for alpha with identical terms
809             if ( $retval == 0
810             && $l == $r
811 0 0         && $left->{version}[$m] == $right->{version}[$m]
812 0           && ( $lalpha || $ralpha ) ) {
813              
814 0 0         if ( $lalpha && !$ralpha ) {
815 0           $retval = -1;
816 0           }
817             elsif ( $ralpha && !$lalpha) {
818 0 0         $retval = +1;
819 0           }
820 0           }
821              
822 0           # possible match except for trailing 0's
  0            
823 0           if ( $retval == 0 && $l != $r ) {
  0            
824 0 0         if ( $l < $r ) {
825 0           while ( $i <= $r && $retval == 0 ) {
826 0           if ( $right->{version}[$i] != 0 ) {
827 0           $retval = -1; # not a match after all
828 0           }
829 0   0       $i++;
830 0           }
831 0           }
832             else {
833             while ( $i <= $l && $retval == 0 ) {
834             if ( $left->{version}[$i] != 0 ) {
835 0 0 0       $retval = +1; # not a match after all
      0        
      0        
      0        
836             }
837             $i++;
838             }
839             }
840 0 0 0       }
    0 0        
841 0            
842             return $retval;
843             }
844 0            
845             my ($self) = @_;
846             return vcmp($self,$self->new("0"),1);
847             }
848              
849 0 0 0       require Carp;
850 0 0         Carp::croak("operation not supported with version object");
851 0   0       }
852 0 0          
853 0           my ($self) = @_;
854             return (exists $self->{alpha});
855 0           }
856              
857             my $value = shift;
858             my $class = $CLASS;
859 0   0       if (@_) {
860 0 0         $class = ref($value) || $value;
861 0           $value = shift;
862             }
863 0            
864             $value = _un_vstring($value);
865             $value = 'v'.$value unless $value =~ /(^v|\d+\.\d+\.\d)/;
866             my $obj = $CLASS->new($value);
867             return bless $obj, $class;
868 0           }
869              
870             *declare = \&qv;
871              
872 0     0 0   my ($self) = @_;
873 0           return (exists $self->{qv});
874             }
875              
876              
877 0     0 0   my ($self) = @_;
878 0           if ( ref($self)
879             && eval { exists $self->{version} }
880             && ref($self->{version}) eq 'ARRAY'
881             ) {
882 0     0 0   return 1;
883 0           }
884             else {
885             return 0;
886             }
887 0     0 0   }
888 0            
889 0 0         my $s = shift;
890 0   0       $s = new ExtUtils::MakeMaker::charstar $s;
891 0           while ($s) {
892             return 0 if isSPACE($s); # early out
893             return 1 unless (isALPHA($s) || isDIGIT($s) || $s =~ /[.-]/);
894 0           $s++;
895 0 0         }
896 0           return 0;
897 0           }
898              
899             my $value = shift;
900             # may be a v-string
901             if ( length($value) >= 3 && $value !~ /[._]/
902             && _is_non_alphanumeric($value)) {
903 0     0 0   my $tvalue;
904 0           if ( "$]" >= 5.008_001 ) {
905             $tvalue = _find_magic_vstring($value);
906             $value = $tvalue if length $tvalue;
907             }
908             elsif ( "$]" >= 5.006_000 ) {
909 0     0     $tvalue = sprintf("v%vd",$value);
910 0 0 0       if ( $tvalue =~ /^v\d+(\.\d+){2,}$/ ) {
      0        
911 0           # must be a v-string
912             $value = $tvalue;
913             }
914 0           }
915             }
916             return $value;
917 0           }
918              
919             my $value = shift;
920             my $tvalue = '';
921             require B;
922 0     0     my $sv = B::svref_2object(\$value);
923 0           my $magic = ref($sv) eq 'B::PVMG' ? $sv->MAGIC : undef;
924 0           while ( $magic ) {
925 0 0         if ( $magic->TYPE eq 'V' ) {
926 0 0 0       $tvalue = $magic->PTR;
      0        
927 0           $tvalue =~ s/^v?(.+)$/v$1/;
928             last;
929 0           }
930             else {
931             $magic = $magic->MOREMAGIC;
932             }
933 0     0     }
934             return $tvalue;
935 0 0 0       }
      0        
936              
937 0           my ($obj, $req) = @_;
938 0 0         my $class = ref($obj) || $obj;
    0          
939 0            
940 0 0         no strict 'refs';
941             if ( exists $INC{"$class.pm"} and not %{"$class\::"} and "$]" >= 5.008) {
942             # file but no package
943 0           require Carp;
944 0 0         Carp::croak( "$class defines neither package nor VERSION"
945             ."--version check failed");
946 0           }
947              
948             my $version = eval "\$$class\::VERSION";
949             if ( defined $version ) {
950 0           local $^W if "$]" <= 5.008;
951             $version = ExtUtils::MakeMaker::version::vpp->new($version);
952             }
953              
954 0     0     if ( defined $req ) {
955 0           unless ( defined $version ) {
956 0           require Carp;
957 0           my $msg = "$]" < 5.006
958 0 0         ? "$class version $req required--this is only version "
959 0           : "$class does not define \$$class\::VERSION"
960 0 0         ."--version check failed";
961 0            
962 0           if ( $ENV{VERSION_DEBUG} ) {
963 0           Carp::confess($msg);
964             }
965             else {
966 0           Carp::croak($msg);
967             }
968             }
969 0            
970             $req = ExtUtils::MakeMaker::version::vpp->new($req);
971              
972             if ( $req > $version ) {
973 0     0     require Carp;
974 0   0       if ( $req->is_qv ) {
975             Carp::croak(
976 1     1   8 sprintf ("%s version %s required--".
  1         10  
  1         307  
977 0 0 0       "this is only version %s", $class,
  0   0        
978             $req->normal, $version->normal)
979 0           );
980 0           }
981             else {
982             Carp::croak(
983             sprintf ("%s version %s required--".
984 0           "this is only version %s", $class,
985 0 0         $req->stringify, $version->stringify)
986 0 0         );
987 0           }
988             }
989             }
990 0 0          
991 0 0         return defined $version ? $version->stringify : undef;
992 0           }
993 0 0          
994             1; #this line is important and will help the module return a true value