This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Integrate CPAN version.pm release into core
authorJohn Peacock <jpeacock@cpan.org>
Mon, 9 Dec 2013 23:23:20 +0000 (18:23 -0500)
committerFather Chrysostomos <sprout@cpan.org>
Sat, 4 Jan 2014 13:10:04 +0000 (05:10 -0800)
14 files changed:
cpan/version/lib/version.pm
cpan/version/lib/version/regex.pm [new file with mode: 0644]
cpan/version/lib/version/vpp.pm [new file with mode: 0644]
cpan/version/t/00impl-pp.t [new file with mode: 0644]
cpan/version/t/01base.t
cpan/version/t/02derived.t
cpan/version/t/03require.t
cpan/version/t/05sigdie.t
cpan/version/t/06noop.t
cpan/version/t/07locale.t
cpan/version/t/08_corelist.t
cpan/version/t/coretests.pm
vutil.c
vxs.inc

index 1e86ac2..7e548a8 100644 (file)
 #!perl -w
 package version;
 
-use 5.005_04;
+use 5.005_05;
 use strict;
 
 use vars qw(@ISA $VERSION $CLASS $STRICT $LAX *declare *qv);
 
-$VERSION = 0.9904;
-
+$VERSION = 0.9905;
 $CLASS = 'version';
 
-#--------------------------------------------------------------------------#
-# Version regexp components
-#--------------------------------------------------------------------------#
-
-# Fraction part of a decimal version number.  This is a common part of
-# both strict and lax decimal versions
-
-my $FRACTION_PART = qr/\.[0-9]+/;
-
-# First part of either decimal or dotted-decimal strict version number.
-# Unsigned integer with no leading zeroes (except for zero itself) to
-# avoid confusion with octal.
-
-my $STRICT_INTEGER_PART = qr/0|[1-9][0-9]*/;
-
-# First part of either decimal or dotted-decimal lax version number.
-# Unsigned integer, but allowing leading zeros.  Always interpreted
-# as decimal.  However, some forms of the resulting syntax give odd
-# results if used as ordinary Perl expressions, due to how perl treats
-# octals.  E.g.
-#   version->new("010" ) == 10
-#   version->new( 010  ) == 8
-#   version->new( 010.2) == 82  # "8" . "2"
-
-my $LAX_INTEGER_PART = qr/[0-9]+/;
-
-# Second and subsequent part of a strict dotted-decimal version number.
-# Leading zeroes are permitted, and the number is always decimal.
-# Limited to three digits to avoid overflow when converting to decimal
-# form and also avoid problematic style with excessive leading zeroes.
-
-my $STRICT_DOTTED_DECIMAL_PART = qr/\.[0-9]{1,3}/;
-
-# Second and subsequent part of a lax dotted-decimal version number.
-# Leading zeroes are permitted, and the number is always decimal.  No
-# limit on the numerical value or number of digits, so there is the
-# possibility of overflow when converting to decimal form.
-
-my $LAX_DOTTED_DECIMAL_PART = qr/\.[0-9]+/;
-
-# Alpha suffix part of lax version number syntax.  Acts like a
-# dotted-decimal part.
-
-my $LAX_ALPHA_PART = qr/_[0-9]+/;
-
-#--------------------------------------------------------------------------#
-# Strict version regexp definitions
-#--------------------------------------------------------------------------#
-
-# Strict decimal version number.
-
-my $STRICT_DECIMAL_VERSION =
-    qr/ $STRICT_INTEGER_PART $FRACTION_PART? /x;
-
-# Strict dotted-decimal version number.  Must have both leading "v" and
-# at least three parts, to avoid confusion with decimal syntax.
-
-my $STRICT_DOTTED_DECIMAL_VERSION =
-    qr/ v $STRICT_INTEGER_PART $STRICT_DOTTED_DECIMAL_PART{2,} /x;
-
-# Complete strict version number syntax -- should generally be used
-# anchored: qr/ \A $STRICT \z /x
-
-$STRICT =
-    qr/ $STRICT_DECIMAL_VERSION | $STRICT_DOTTED_DECIMAL_VERSION /x;
-
-#--------------------------------------------------------------------------#
-# Lax version regexp definitions
-#--------------------------------------------------------------------------#
-
-# Lax decimal version number.  Just like the strict one except for
-# allowing an alpha suffix or allowing a leading or trailing
-# decimal-point
-
-my $LAX_DECIMAL_VERSION =
-    qr/ $LAX_INTEGER_PART (?: \. | $FRACTION_PART $LAX_ALPHA_PART? )?
-       |
-       $FRACTION_PART $LAX_ALPHA_PART?
-    /x;
-
-# Lax dotted-decimal version number.  Distinguished by having either
-# leading "v" or at least three non-alpha parts.  Alpha part is only
-# permitted if there are at least two non-alpha parts. Strangely
-# enough, without the leading "v", Perl takes .1.2 to mean v0.1.2,
-# so when there is no "v", the leading part is optional
-
-my $LAX_DOTTED_DECIMAL_VERSION =
-    qr/
-       v $LAX_INTEGER_PART (?: $LAX_DOTTED_DECIMAL_PART+ $LAX_ALPHA_PART? )?
-       |
-       $LAX_INTEGER_PART? $LAX_DOTTED_DECIMAL_PART{2,} $LAX_ALPHA_PART?
-    /x;
-
-# Complete lax version number syntax -- should generally be used
-# anchored: qr/ \A $LAX \z /x
-#
-# The string 'undef' is a special case to make for easier handling
-# of return values from ExtUtils::MM->parse_version
-
-$LAX =
-    qr/ undef | $LAX_DECIMAL_VERSION | $LAX_DOTTED_DECIMAL_VERSION /x;
-
-#--------------------------------------------------------------------------#
+{
+    local $SIG{'__DIE__'};
+    eval "use version::vxs $VERSION";
+    if ( $@ ) { # don't have the XS version installed
+       eval "use version::vpp $VERSION"; # don't tempt fate
+       die "$@" if ( $@ );
+       push @ISA, "version::vpp";
+       local $^W;
+       *version::qv = \&version::vpp::qv;
+       *version::declare = \&version::vpp::declare;
+       *version::_VERSION = \&version::vpp::_VERSION;
+       *version::vcmp = \&version::vpp::vcmp;
+       *version::new = \&version::vpp::new;
+       if ($] >= 5.009000) {
+           no strict 'refs';
+           *version::stringify = \&version::vpp::stringify;
+           *{'version::(""'} = \&version::vpp::stringify;
+           *{'version::(<=>'} = \&version::vpp::vcmp;
+           *version::parse = \&version::vpp::parse;
+       }
+       *version::is_strict = \&version::vpp::is_strict;
+       *version::is_lax = \&version::vpp::is_lax;
+    }
+    else { # use XS module
+       push @ISA, "version::vxs";
+       local $^W;
+       *version::declare = \&version::vxs::declare;
+       *version::qv = \&version::vxs::qv;
+       *version::_VERSION = \&version::vxs::_VERSION;
+       *version::vcmp = \&version::vxs::VCMP;
+       *version::new = \&version::vxs::new;
+       if ($] >= 5.009000) {
+           no strict 'refs';
+           *version::stringify = \&version::vxs::stringify;
+           *{'version::(""'} = \&version::vxs::stringify;
+           *{'version::(<=>'} = \&version::vxs::VCMP;
+           *version::parse = \&version::vxs::parse;
+       }
+       *version::is_strict = \&version::vxs::is_strict;
+       *version::is_lax = \&version::vxs::is_lax;
+    }
+}
 
-# Preloaded methods go here.
 sub import {
     no strict 'refs';
     my ($class) = shift;
 
     # Set up any derived class
-    unless ($class eq 'version') {
+    unless ($class eq $CLASS) {
        local $^W;
-       *{$class.'::declare'} =  \&version::declare;
-       *{$class.'::qv'} = \&version::qv;
+       *{$class.'::declare'} =  \&{$CLASS.'::declare'};
+       *{$class.'::qv'} = \&{$CLASS.'::qv'};
     }
 
     my %args;
@@ -152,22 +89,26 @@ sub import {
          unless defined(&{$callpkg.'::qv'});
     }
 
+    if (exists($args{'UNIVERSAL::VERSION'})) {
+       local $^W;
+       *UNIVERSAL::VERSION
+               = \&{$CLASS.'::_VERSION'};
+    }
+
     if (exists($args{'VERSION'})) {
-       *{$callpkg.'::VERSION'} = \&version::_VERSION;
+       *{$callpkg.'::VERSION'} = \&{$CLASS.'::_VERSION'};
     }
 
     if (exists($args{'is_strict'})) {
-       *{$callpkg.'::is_strict'} = \&version::is_strict
+       *{$callpkg.'::is_strict'} = \&{$CLASS.'::is_strict'}
          unless defined(&{$callpkg.'::is_strict'});
     }
 
     if (exists($args{'is_lax'})) {
-       *{$callpkg.'::is_lax'} = \&version::is_lax
+       *{$callpkg.'::is_lax'} = \&{$CLASS.'::is_lax'}
          unless defined(&{$callpkg.'::is_lax'});
     }
 }
 
-sub is_strict  { defined $_[0] && $_[0] =~ qr/ \A $STRICT \z /x }
-sub is_lax     { defined $_[0] && $_[0] =~ qr/ \A $LAX \z /x }
 
 1;
diff --git a/cpan/version/lib/version/regex.pm b/cpan/version/lib/version/regex.pm
new file mode 100644 (file)
index 0000000..7370b5b
--- /dev/null
@@ -0,0 +1,117 @@
+package version::regex;
+
+use strict;
+
+use vars qw($VERSION $CLASS $STRICT $LAX);
+
+$VERSION = 0.9905;
+
+#--------------------------------------------------------------------------#
+# Version regexp components
+#--------------------------------------------------------------------------#
+
+# Fraction part of a decimal version number.  This is a common part of
+# both strict and lax decimal versions
+
+my $FRACTION_PART = qr/\.[0-9]+/;
+
+# First part of either decimal or dotted-decimal strict version number.
+# Unsigned integer with no leading zeroes (except for zero itself) to
+# avoid confusion with octal.
+
+my $STRICT_INTEGER_PART = qr/0|[1-9][0-9]*/;
+
+# First part of either decimal or dotted-decimal lax version number.
+# Unsigned integer, but allowing leading zeros.  Always interpreted
+# as decimal.  However, some forms of the resulting syntax give odd
+# results if used as ordinary Perl expressions, due to how perl treats
+# octals.  E.g.
+#   version->new("010" ) == 10
+#   version->new( 010  ) == 8
+#   version->new( 010.2) == 82  # "8" . "2"
+
+my $LAX_INTEGER_PART = qr/[0-9]+/;
+
+# Second and subsequent part of a strict dotted-decimal version number.
+# Leading zeroes are permitted, and the number is always decimal.
+# Limited to three digits to avoid overflow when converting to decimal
+# form and also avoid problematic style with excessive leading zeroes.
+
+my $STRICT_DOTTED_DECIMAL_PART = qr/\.[0-9]{1,3}/;
+
+# Second and subsequent part of a lax dotted-decimal version number.
+# Leading zeroes are permitted, and the number is always decimal.  No
+# limit on the numerical value or number of digits, so there is the
+# possibility of overflow when converting to decimal form.
+
+my $LAX_DOTTED_DECIMAL_PART = qr/\.[0-9]+/;
+
+# Alpha suffix part of lax version number syntax.  Acts like a
+# dotted-decimal part.
+
+my $LAX_ALPHA_PART = qr/_[0-9]+/;
+
+#--------------------------------------------------------------------------#
+# Strict version regexp definitions
+#--------------------------------------------------------------------------#
+
+# Strict decimal version number.
+
+my $STRICT_DECIMAL_VERSION =
+    qr/ $STRICT_INTEGER_PART $FRACTION_PART? /x;
+
+# Strict dotted-decimal version number.  Must have both leading "v" and
+# at least three parts, to avoid confusion with decimal syntax.
+
+my $STRICT_DOTTED_DECIMAL_VERSION =
+    qr/ v $STRICT_INTEGER_PART $STRICT_DOTTED_DECIMAL_PART{2,} /x;
+
+# Complete strict version number syntax -- should generally be used
+# anchored: qr/ \A $STRICT \z /x
+
+$STRICT =
+    qr/ $STRICT_DECIMAL_VERSION | $STRICT_DOTTED_DECIMAL_VERSION /x;
+
+#--------------------------------------------------------------------------#
+# Lax version regexp definitions
+#--------------------------------------------------------------------------#
+
+# Lax decimal version number.  Just like the strict one except for
+# allowing an alpha suffix or allowing a leading or trailing
+# decimal-point
+
+my $LAX_DECIMAL_VERSION =
+    qr/ $LAX_INTEGER_PART (?: \. | $FRACTION_PART $LAX_ALPHA_PART? )?
+       |
+       $FRACTION_PART $LAX_ALPHA_PART?
+    /x;
+
+# Lax dotted-decimal version number.  Distinguished by having either
+# leading "v" or at least three non-alpha parts.  Alpha part is only
+# permitted if there are at least two non-alpha parts. Strangely
+# enough, without the leading "v", Perl takes .1.2 to mean v0.1.2,
+# so when there is no "v", the leading part is optional
+
+my $LAX_DOTTED_DECIMAL_VERSION =
+    qr/
+       v $LAX_INTEGER_PART (?: $LAX_DOTTED_DECIMAL_PART+ $LAX_ALPHA_PART? )?
+       |
+       $LAX_INTEGER_PART? $LAX_DOTTED_DECIMAL_PART{2,} $LAX_ALPHA_PART?
+    /x;
+
+# Complete lax version number syntax -- should generally be used
+# anchored: qr/ \A $LAX \z /x
+#
+# The string 'undef' is a special case to make for easier handling
+# of return values from ExtUtils::MM->parse_version
+
+$LAX =
+    qr/ undef | $LAX_DECIMAL_VERSION | $LAX_DOTTED_DECIMAL_VERSION /x;
+
+#--------------------------------------------------------------------------#
+
+# Preloaded methods go here.
+sub is_strict  { defined $_[0] && $_[0] =~ qr/ \A $STRICT \z /x }
+sub is_lax     { defined $_[0] && $_[0] =~ qr/ \A $LAX \z /x }
+
+1;
diff --git a/cpan/version/lib/version/vpp.pm b/cpan/version/lib/version/vpp.pm
new file mode 100644 (file)
index 0000000..f6153a6
--- /dev/null
@@ -0,0 +1,1016 @@
+package charstar;
+# a little helper class to emulate C char* semantics in Perl
+# so that prescan_version can use the same code as in C
+
+use overload (
+    '""'       => \&thischar,
+    '0+'       => \&thischar,
+    '++'       => \&increment,
+    '--'       => \&decrement,
+    '+'                => \&plus,
+    '-'                => \&minus,
+    '*'                => \&multiply,
+    'cmp'      => \&cmp,
+    '<=>'      => \&spaceship,
+    'bool'     => \&thischar,
+    '='                => \&clone,
+);
+
+sub new {
+    my ($self, $string) = @_;
+    my $class = ref($self) || $self;
+
+    my $obj = {
+       string  => [split(//,$string)],
+       current => 0,
+    };
+    return bless $obj, $class;
+}
+
+sub thischar {
+    my ($self) = @_;
+    my $last = $#{$self->{string}};
+    my $curr = $self->{current};
+    if ($curr >= 0 && $curr <= $last) {
+       return $self->{string}->[$curr];
+    }
+    else {
+       return '';
+    }
+}
+
+sub increment {
+    my ($self) = @_;
+    $self->{current}++;
+}
+
+sub decrement {
+    my ($self) = @_;
+    $self->{current}--;
+}
+
+sub plus {
+    my ($self, $offset) = @_;
+    my $rself = $self->clone;
+    $rself->{current} += $offset;
+    return $rself;
+}
+
+sub minus {
+    my ($self, $offset) = @_;
+    my $rself = $self->clone;
+    $rself->{current} -= $offset;
+    return $rself;
+}
+
+sub multiply {
+    my ($left, $right, $swapped) = @_;
+    my $char = $left->thischar();
+    return $char * $right;
+}
+
+sub spaceship {
+    my ($left, $right, $swapped) = @_;
+    unless (ref($right)) { # not an object already
+       $right = $left->new($right);
+    }
+    return $left->{current} <=> $right->{current};
+}
+
+sub cmp {
+    my ($left, $right, $swapped) = @_;
+    unless (ref($right)) { # not an object already
+       if (length($right) == 1) { # comparing single character only
+           return $left->thischar cmp $right;
+       }
+       $right = $left->new($right);
+    }
+    return $left->currstr cmp $right->currstr;
+}
+
+sub bool {
+    my ($self) = @_;
+    my $char = $self->thischar;
+    return ($char ne '');
+}
+
+sub clone {
+    my ($left, $right, $swapped) = @_;
+    $right = {
+       string  => [@{$left->{string}}],
+       current => $left->{current},
+    };
+    return bless $right, ref($left);
+}
+
+sub currstr {
+    my ($self, $s) = @_;
+    my $curr = $self->{current};
+    my $last = $#{$self->{string}};
+    if (defined($s) && $s->{current} < $last) {
+       $last = $s->{current};
+    }
+
+    my $string = join('', @{$self->{string}}[$curr..$last]);
+    return $string;
+}
+
+package version::vpp;
+
+use 5.005_05;
+use strict;
+
+use POSIX qw/locale_h/;
+use locale;
+use vars qw($VERSION $CLASS @ISA);
+$VERSION = 0.9905;
+$CLASS = 'version::vpp';
+
+require version::regex;
+*version::vpp::is_strict = \&version::regex::is_strict;
+*version::vpp::is_lax = \&version::regex::is_lax;
+
+use overload (
+    '""'       => \&stringify,
+    '0+'       => \&numify,
+    'cmp'      => \&vcmp,
+    '<=>'      => \&vcmp,
+    'bool'     => \&vbool,
+    '+'        => \&vnoop,
+    '-'        => \&vnoop,
+    '*'        => \&vnoop,
+    '/'        => \&vnoop,
+    '+='        => \&vnoop,
+    '-='        => \&vnoop,
+    '*='        => \&vnoop,
+    '/='        => \&vnoop,
+    'abs'      => \&vnoop,
+);
+
+eval "use warnings";
+if ($@) {
+    eval '
+       package
+       warnings;
+       sub enabled {return $^W;}
+       1;
+    ';
+}
+
+sub import {
+    no strict 'refs';
+    my ($class) = shift;
+
+    # Set up any derived class
+    unless ($class eq $CLASS) {
+       local $^W;
+       *{$class.'::declare'} =  \&{$CLASS.'::declare'};
+       *{$class.'::qv'} = \&{$CLASS.'::qv'};
+    }
+
+    my %args;
+    if (@_) { # any remaining terms are arguments
+       map { $args{$_} = 1 } @_
+    }
+    else { # no parameters at all on use line
+       %args =
+       (
+           qv => 1,
+           'UNIVERSAL::VERSION' => 1,
+       );
+    }
+
+    my $callpkg = caller();
+
+    if (exists($args{declare})) {
+       *{$callpkg.'::declare'} =
+           sub {return $class->declare(shift) }
+         unless defined(&{$callpkg.'::declare'});
+    }
+
+    if (exists($args{qv})) {
+       *{$callpkg.'::qv'} =
+           sub {return $class->qv(shift) }
+         unless defined(&{$callpkg.'::qv'});
+    }
+
+    if (exists($args{'UNIVERSAL::VERSION'})) {
+       local $^W;
+       *UNIVERSAL::VERSION
+               = \&{$CLASS.'::_VERSION'};
+    }
+
+    if (exists($args{'VERSION'})) {
+       *{$callpkg.'::VERSION'} = \&{$CLASS.'::_VERSION'};
+    }
+
+    if (exists($args{'is_strict'})) {
+       *{$callpkg.'::is_strict'} = \&{$CLASS.'::is_strict'}
+         unless defined(&{$callpkg.'::is_strict'});
+    }
+
+    if (exists($args{'is_lax'})) {
+       *{$callpkg.'::is_lax'} = \&{$CLASS.'::is_lax'}
+         unless defined(&{$callpkg.'::is_lax'});
+    }
+}
+
+my $VERSION_MAX = 0x7FFFFFFF;
+
+# implement prescan_version as closely to the C version as possible
+use constant TRUE  => 1;
+use constant FALSE => 0;
+
+sub isDIGIT {
+    my ($char) = shift->thischar();
+    return ($char =~ /\d/);
+}
+
+sub isALPHA {
+    my ($char) = shift->thischar();
+    return ($char =~ /[a-zA-Z]/);
+}
+
+sub isSPACE {
+    my ($char) = shift->thischar();
+    return ($char =~ /\s/);
+}
+
+sub BADVERSION {
+    my ($s, $errstr, $error) = @_;
+    if ($errstr) {
+       $$errstr = $error;
+    }
+    return $s;
+}
+
+sub prescan_version {
+    my ($s, $strict, $errstr, $sqv, $ssaw_decimal, $swidth, $salpha) = @_;
+    my $qv          = defined $sqv          ? $$sqv          : FALSE;
+    my $saw_decimal = defined $ssaw_decimal ? $$ssaw_decimal : 0;
+    my $width       = defined $swidth       ? $$swidth       : 3;
+    my $alpha       = defined $salpha       ? $$salpha       : FALSE;
+
+    my $d = $s;
+
+    if ($qv && isDIGIT($d)) {
+       goto dotted_decimal_version;
+    }
+
+    if ($d eq 'v') { # explicit v-string
+       $d++;
+       if (isDIGIT($d)) {
+           $qv = TRUE;
+       }
+       else { # degenerate v-string
+           # requires v1.2.3
+           return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
+       }
+
+dotted_decimal_version:
+       if ($strict && $d eq '0' && isDIGIT($d+1)) {
+           # no leading zeros allowed
+           return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)");
+       }
+
+       while (isDIGIT($d)) {   # integer part
+           $d++;
+       }
+
+       if ($d eq '.')
+       {
+           $saw_decimal++;
+           $d++;               # decimal point
+       }
+       else
+       {
+           if ($strict) {
+               # require v1.2.3
+               return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
+           }
+           else {
+               goto version_prescan_finish;
+           }
+       }
+
+       {
+           my $i = 0;
+           my $j = 0;
+           while (isDIGIT($d)) {       # just keep reading
+               $i++;
+               while (isDIGIT($d)) {
+                   $d++; $j++;
+                   # maximum 3 digits between decimal
+                   if ($strict && $j > 3) {
+                       return BADVERSION($s,$errstr,"Invalid version format (maximum 3 digits between decimals)");
+                   }
+               }
+               if ($d eq '_') {
+                   if ($strict) {
+                       return BADVERSION($s,$errstr,"Invalid version format (no underscores)");
+                   }
+                   if ( $alpha ) {
+                       return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)");
+                   }
+                   $d++;
+                   $alpha = TRUE;
+               }
+               elsif ($d eq '.') {
+                   if ($alpha) {
+                       return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)");
+                   }
+                   $saw_decimal++;
+                   $d++;
+               }
+               elsif (!isDIGIT($d)) {
+                   last;
+               }
+               $j = 0;
+           }
+
+           if ($strict && $i < 2) {
+               # requires v1.2.3
+               return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
+           }
+       }
+    }                                  # end if dotted-decimal
+    else
+    {                                  # decimal versions
+       my $j = 0;
+       # special $strict case for leading '.' or '0'
+       if ($strict) {
+           if ($d eq '.') {
+               return BADVERSION($s,$errstr,"Invalid version format (0 before decimal required)");
+           }
+           if ($d eq '0' && isDIGIT($d+1)) {
+               return BADVERSION($s,$errstr,"Invalid version format (no leading zeros)");
+           }
+       }
+
+       # and we never support negative version numbers
+       if ($d eq '-') {
+           return BADVERSION($s,$errstr,"Invalid version format (negative version number)");
+       }
+
+       # consume all of the integer part
+       while (isDIGIT($d)) {
+           $d++;
+       }
+
+       # look for a fractional part
+       if ($d eq '.') {
+           # we found it, so consume it
+           $saw_decimal++;
+           $d++;
+       }
+       elsif (!$d || $d eq ';' || isSPACE($d) || $d eq '}') {
+           if ( $d == $s ) {
+               # found nothing
+               return BADVERSION($s,$errstr,"Invalid version format (version required)");
+           }
+           # found just an integer
+           goto version_prescan_finish;
+       }
+       elsif ( $d == $s ) {
+           # didn't find either integer or period
+           return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)");
+       }
+       elsif ($d eq '_') {
+           # underscore can't come after integer part
+           if ($strict) {
+               return BADVERSION($s,$errstr,"Invalid version format (no underscores)");
+           }
+           elsif (isDIGIT($d+1)) {
+               return BADVERSION($s,$errstr,"Invalid version format (alpha without decimal)");
+           }
+           else {
+               return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)");
+           }
+       }
+       elsif ($d) {
+           # anything else after integer part is just invalid data
+           return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)");
+       }
+
+       # scan the fractional part after the decimal point
+       if ($d && !isDIGIT($d) && ($strict || ! ($d eq ';' || isSPACE($d) || $d eq '}') )) {
+               # $strict or lax-but-not-the-end
+               return BADVERSION($s,$errstr,"Invalid version format (fractional part required)");
+       }
+
+       while (isDIGIT($d)) {
+           $d++; $j++;
+           if ($d eq '.' && isDIGIT($d-1)) {
+               if ($alpha) {
+                   return BADVERSION($s,$errstr,"Invalid version format (underscores before decimal)");
+               }
+               if ($strict) {
+                   return BADVERSION($s,$errstr,"Invalid version format (dotted-decimal versions must begin with 'v')");
+               }
+               $d = $s; # start all over again
+               $qv = TRUE;
+               goto dotted_decimal_version;
+           }
+           if ($d eq '_') {
+               if ($strict) {
+                   return BADVERSION($s,$errstr,"Invalid version format (no underscores)");
+               }
+               if ( $alpha ) {
+                   return BADVERSION($s,$errstr,"Invalid version format (multiple underscores)");
+               }
+               if ( ! isDIGIT($d+1) ) {
+                   return BADVERSION($s,$errstr,"Invalid version format (misplaced underscore)");
+               }
+               $width = $j;
+               $d++;
+               $alpha = TRUE;
+           }
+       }
+    }
+
+version_prescan_finish:
+    while (isSPACE($d)) {
+       $d++;
+    }
+
+    if ($d && !isDIGIT($d) && (! ($d eq ';' || $d eq '}') )) {
+       # trailing non-numeric data
+       return BADVERSION($s,$errstr,"Invalid version format (non-numeric data)");
+    }
+
+    if (defined $sqv) {
+       $$sqv = $qv;
+    }
+    if (defined $swidth) {
+       $$swidth = $width;
+    }
+    if (defined $ssaw_decimal) {
+       $$ssaw_decimal = $saw_decimal;
+    }
+    if (defined $salpha) {
+       $$salpha = $alpha;
+    }
+    return $d;
+}
+
+sub scan_version {
+    my ($s, $rv, $qv) = @_;
+    my $start;
+    my $pos;
+    my $last;
+    my $errstr;
+    my $saw_decimal = 0;
+    my $width = 3;
+    my $alpha = FALSE;
+    my $vinf = FALSE;
+    my @av;
+
+    $s = new charstar $s;
+
+    while (isSPACE($s)) { # leading whitespace is OK
+       $s++;
+    }
+
+    $last = prescan_version($s, FALSE, \$errstr, \$qv, \$saw_decimal,
+       \$width, \$alpha);
+
+    if ($errstr) {
+       # 'undef' is a special case and not an error
+       if ( $s ne 'undef') {
+           use Carp;
+           Carp::croak($errstr);
+       }
+    }
+
+    $start = $s;
+    if ($s eq 'v') {
+       $s++;
+    }
+    $pos = $s;
+
+    if ( $qv ) {
+       $$rv->{qv} = $qv;
+    }
+    if ( $alpha ) {
+       $$rv->{alpha} = $alpha;
+    }
+    if ( !$qv && $width < 3 ) {
+       $$rv->{width} = $width;
+    }
+
+    while (isDIGIT($pos)) {
+       $pos++;
+    }
+    if (!isALPHA($pos)) {
+       my $rev;
+
+       for (;;) {
+           $rev = 0;
+           {
+               # this is atoi() that delimits on underscores
+               my $end = $pos;
+               my $mult = 1;
+               my $orev;
+
+               #  the following if() will only be true after the decimal
+               #  point of a version originally created with a bare
+               #  floating point number, i.e. not quoted in any way
+               #
+               if ( !$qv && $s > $start && $saw_decimal == 1 ) {
+                   $mult *= 100;
+                   while ( $s < $end ) {
+                       $orev = $rev;
+                       $rev += $s * $mult;
+                       $mult /= 10;
+                       if (   (abs($orev) > abs($rev))
+                           || (abs($rev) > $VERSION_MAX )) {
+                           warn("Integer overflow in version %d",
+                                          $VERSION_MAX);
+                           $s = $end - 1;
+                           $rev = $VERSION_MAX;
+                           $vinf = 1;
+                       }
+                       $s++;
+                       if ( $s eq '_' ) {
+                           $s++;
+                       }
+                   }
+               }
+               else {
+                   while (--$end >= $s) {
+                       $orev = $rev;
+                       $rev += $end * $mult;
+                       $mult *= 10;
+                       if (   (abs($orev) > abs($rev))
+                           || (abs($rev) > $VERSION_MAX )) {
+                           warn("Integer overflow in version");
+                           $end = $s - 1;
+                           $rev = $VERSION_MAX;
+                           $vinf = 1;
+                       }
+                   }
+               }
+           }
+
+           # Append revision
+           push @av, $rev;
+           if ( $vinf ) {
+               $s = $last;
+               last;
+           }
+           elsif ( $pos eq '.' ) {
+               $s = ++$pos;
+           }
+           elsif ( $pos eq '_' && isDIGIT($pos+1) ) {
+               $s = ++$pos;
+           }
+           elsif ( $pos eq ',' && isDIGIT($pos+1) ) {
+               $s = ++$pos;
+           }
+           elsif ( isDIGIT($pos) ) {
+               $s = $pos;
+           }
+           else {
+               $s = $pos;
+               last;
+           }
+           if ( $qv ) {
+               while ( isDIGIT($pos) ) {
+                   $pos++;
+               }
+           }
+           else {
+               my $digits = 0;
+               while ( ( isDIGIT($pos) || $pos eq '_' ) && $digits < 3 ) {
+                   if ( $pos ne '_' ) {
+                       $digits++;
+                   }
+                   $pos++;
+               }
+           }
+       }
+    }
+    if ( $qv ) { # quoted versions always get at least three terms
+       my $len = $#av;
+       #  This for loop appears to trigger a compiler bug on OS X, as it
+       #  loops infinitely. Yes, len is negative. No, it makes no sense.
+       #  Compiler in question is:
+       #  gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
+       #  for ( len = 2 - len; len > 0; len-- )
+       #  av_push(MUTABLE_AV(sv), newSViv(0));
+       #
+       $len = 2 - $len;
+       while ($len-- > 0) {
+           push @av, 0;
+       }
+    }
+
+    # need to save off the current version string for later
+    if ( $vinf ) {
+       $$rv->{original} = "v.Inf";
+       $$rv->{vinf} = 1;
+    }
+    elsif ( $s > $start ) {
+       $$rv->{original} = $start->currstr($s);
+       if ( $qv && $saw_decimal == 1 && $start ne 'v' ) {
+           # need to insert a v to be consistent
+           $$rv->{original} = 'v' . $$rv->{original};
+       }
+    }
+    else {
+       $$rv->{original} = '0';
+       push(@av, 0);
+    }
+
+    # And finally, store the AV in the hash
+    $$rv->{version} = \@av;
+
+    # fix RT#19517 - special case 'undef' as string
+    if ($s eq 'undef') {
+       $s += 5;
+    }
+
+    return $s;
+}
+
+sub new
+{
+       my ($class, $value) = @_;
+       unless (defined $class) {
+           require Carp;
+           Carp::croak('Usage: version::new(class, version)');
+       }
+       my $self = bless ({}, ref ($class) || $class);
+       my $qv = FALSE;
+
+       if ( ref($value) && eval('$value->isa("version")') ) {
+           # Can copy the elements directly
+           $self->{version} = [ @{$value->{version} } ];
+           $self->{qv} = 1 if $value->{qv};
+           $self->{alpha} = 1 if $value->{alpha};
+           $self->{original} = ''.$value->{original};
+           return $self;
+       }
+
+       my $currlocale = setlocale(LC_ALL);
+
+       # if the current locale uses commas for decimal points, we
+       # just replace commas with decimal places, rather than changing
+       # locales
+       if ( localeconv()->{decimal_point} eq ',' ) {
+           $value =~ tr/,/./;
+       }
+
+       if ( not defined $value or $value =~ /^undef$/ ) {
+           # RT #19517 - special case for undef comparison
+           # or someone forgot to pass a value
+           push @{$self->{version}}, 0;
+           $self->{original} = "0";
+           return ($self);
+       }
+
+       if ( $#_ == 2 ) { # must be CVS-style
+           $value = $_[2];
+           $qv = TRUE;
+       }
+
+       $value = _un_vstring($value);
+
+       # exponential notation
+       if ( $value =~ /\d+.?\d*e[-+]?\d+/ ) {
+           $value = sprintf("%.9f",$value);
+           $value =~ s/(0+)$//; # trim trailing zeros
+       }
+
+       my $s = scan_version($value, \$self, $qv);
+
+       if ($s) { # must be something left over
+           warn("Version string '%s' contains invalid data; "
+                       ."ignoring: '%s'", $value, $s);
+       }
+
+       return ($self);
+}
+
+*parse = \&new;
+
+sub numify
+{
+    my ($self) = @_;
+    unless (_verify($self)) {
+       require Carp;
+       Carp::croak("Invalid version object");
+    }
+    my $width = $self->{width} || 3;
+    my $alpha = $self->{alpha} || "";
+    my $len = $#{$self->{version}};
+    my $digit = $self->{version}[0];
+    my $string = sprintf("%d.", $digit );
+
+    for ( my $i = 1 ; $i < $len ; $i++ ) {
+       $digit = $self->{version}[$i];
+       if ( $width < 3 ) {
+           my $denom = 10**(3-$width);
+           my $quot = int($digit/$denom);
+           my $rem = $digit - ($quot * $denom);
+           $string .= sprintf("%0".$width."d_%d", $quot, $rem);
+       }
+       else {
+           $string .= sprintf("%03d", $digit);
+       }
+    }
+
+    if ( $len > 0 ) {
+       $digit = $self->{version}[$len];
+       if ( $alpha && $width == 3 ) {
+           $string .= "_";
+       }
+       $string .= sprintf("%0".$width."d", $digit);
+    }
+    else # $len = 0
+    {
+       $string .= sprintf("000");
+    }
+
+    return $string;
+}
+
+sub normal
+{
+    my ($self) = @_;
+    unless (_verify($self)) {
+       require Carp;
+       Carp::croak("Invalid version object");
+    }
+    my $alpha = $self->{alpha} || "";
+    my $len = $#{$self->{version}};
+    my $digit = $self->{version}[0];
+    my $string = sprintf("v%d", $digit );
+
+    for ( my $i = 1 ; $i < $len ; $i++ ) {
+       $digit = $self->{version}[$i];
+       $string .= sprintf(".%d", $digit);
+    }
+
+    if ( $len > 0 ) {
+       $digit = $self->{version}[$len];
+       if ( $alpha ) {
+           $string .= sprintf("_%0d", $digit);
+       }
+       else {
+           $string .= sprintf(".%0d", $digit);
+       }
+    }
+
+    if ( $len <= 2 ) {
+       for ( $len = 2 - $len; $len != 0; $len-- ) {
+           $string .= sprintf(".%0d", 0);
+       }
+    }
+
+    return $string;
+}
+
+sub stringify
+{
+    my ($self) = @_;
+    unless (_verify($self)) {
+       require Carp;
+       Carp::croak("Invalid version object");
+    }
+    return exists $self->{original}
+       ? $self->{original}
+       : exists $self->{qv}
+           ? $self->normal
+           : $self->numify;
+}
+
+sub vcmp
+{
+    require UNIVERSAL;
+    my ($left,$right,$swap) = @_;
+    my $class = ref($left);
+    unless ( UNIVERSAL::isa($right, $class) ) {
+       $right = $class->new($right);
+    }
+
+    if ( $swap ) {
+       ($left, $right) = ($right, $left);
+    }
+    unless (_verify($left)) {
+       require Carp;
+       Carp::croak("Invalid version object");
+    }
+    unless (_verify($right)) {
+       require Carp;
+       Carp::croak("Invalid version format");
+    }
+    my $l = $#{$left->{version}};
+    my $r = $#{$right->{version}};
+    my $m = $l < $r ? $l : $r;
+    my $lalpha = $left->is_alpha;
+    my $ralpha = $right->is_alpha;
+    my $retval = 0;
+    my $i = 0;
+    while ( $i <= $m && $retval == 0 ) {
+       $retval = $left->{version}[$i] <=> $right->{version}[$i];
+       $i++;
+    }
+
+    # tiebreaker for alpha with identical terms
+    if ( $retval == 0
+       && $l == $r
+       && $left->{version}[$m] == $right->{version}[$m]
+       && ( $lalpha || $ralpha ) ) {
+
+       if ( $lalpha && !$ralpha ) {
+           $retval = -1;
+       }
+       elsif ( $ralpha && !$lalpha) {
+           $retval = +1;
+       }
+    }
+
+    # possible match except for trailing 0's
+    if ( $retval == 0 && $l != $r ) {
+       if ( $l < $r ) {
+           while ( $i <= $r && $retval == 0 ) {
+               if ( $right->{version}[$i] != 0 ) {
+                   $retval = -1; # not a match after all
+               }
+               $i++;
+           }
+       }
+       else {
+           while ( $i <= $l && $retval == 0 ) {
+               if ( $left->{version}[$i] != 0 ) {
+                   $retval = +1; # not a match after all
+               }
+               $i++;
+           }
+       }
+    }
+
+    return $retval;
+}
+
+sub vbool {
+    my ($self) = @_;
+    return vcmp($self,$self->new("0"),1);
+}
+
+sub vnoop {
+    require Carp;
+    Carp::croak("operation not supported with version object");
+}
+
+sub is_alpha {
+    my ($self) = @_;
+    return (exists $self->{alpha});
+}
+
+sub qv {
+    my $value = shift;
+    my $class = $CLASS;
+    if (@_) {
+       $class = ref($value) || $value;
+       $value = shift;
+    }
+
+    $value = _un_vstring($value);
+    $value = 'v'.$value unless $value =~ /(^v|\d+\.\d+\.\d)/;
+    my $obj = $CLASS->new($value);
+    return bless $obj, $class;
+}
+
+*declare = \&qv;
+
+sub is_qv {
+    my ($self) = @_;
+    return (exists $self->{qv});
+}
+
+
+sub _verify {
+    my ($self) = @_;
+    if ( ref($self)
+       && eval { exists $self->{version} }
+       && ref($self->{version}) eq 'ARRAY'
+       ) {
+       return 1;
+    }
+    else {
+       return 0;
+    }
+}
+
+sub _is_non_alphanumeric {
+    my $s = shift;
+    $s = new charstar $s;
+    while ($s) {
+       return 0 if isSPACE($s); # early out
+       return 1 unless (isALPHA($s) || isDIGIT($s) || $s =~ /[.-]/);
+       $s++;
+    }
+    return 0;
+}
+
+sub _un_vstring {
+    my $value = shift;
+    # may be a v-string
+    if ( length($value) >= 3 && $value !~ /[._]/
+       && _is_non_alphanumeric($value)) {
+       my $tvalue;
+       if ( $] ge 5.008_001 ) {
+           $tvalue = _find_magic_vstring($value);
+           $value = $tvalue if length $tvalue;
+       }
+       elsif ( $] ge 5.006_000 ) {
+           $tvalue = sprintf("v%vd",$value);
+           if ( $tvalue =~ /^v\d+(\.\d+){2,}$/ ) {
+               # must be a v-string
+               $value = $tvalue;
+           }
+       }
+    }
+    return $value;
+}
+
+sub _find_magic_vstring {
+    my $value = shift;
+    my $tvalue = '';
+    require B;
+    my $sv = B::svref_2object(\$value);
+    my $magic = ref($sv) eq 'B::PVMG' ? $sv->MAGIC : undef;
+    while ( $magic ) {
+       if ( $magic->TYPE eq 'V' ) {
+           $tvalue = $magic->PTR;
+           $tvalue =~ s/^v?(.+)$/v$1/;
+           last;
+       }
+       else {
+           $magic = $magic->MOREMAGIC;
+       }
+    }
+    return $tvalue;
+}
+
+sub _VERSION {
+    my ($obj, $req) = @_;
+    my $class = ref($obj) || $obj;
+
+    no strict 'refs';
+    if ( exists $INC{"$class.pm"} and not %{"$class\::"} and $] >= 5.008) {
+        # file but no package
+       require Carp;
+       Carp::croak( "$class defines neither package nor VERSION"
+           ."--version check failed");
+    }
+
+    my $version = eval "\$$class\::VERSION";
+    if ( defined $version ) {
+       local $^W if $] <= 5.008;
+       $version = version::vpp->new($version);
+    }
+
+    if ( defined $req ) {
+       unless ( defined $version ) {
+           require Carp;
+           my $msg =  $] < 5.006
+           ? "$class version $req required--this is only version "
+           : "$class does not define \$$class\::VERSION"
+             ."--version check failed";
+
+           if ( $ENV{VERSION_DEBUG} ) {
+               Carp::confess($msg);
+           }
+           else {
+               Carp::croak($msg);
+           }
+       }
+
+       $req = version::vpp->new($req);
+
+       if ( $req > $version ) {
+           require Carp;
+           if ( $req->is_qv ) {
+               Carp::croak(
+                   sprintf ("%s version %s required--".
+                       "this is only version %s", $class,
+                       $req->normal, $version->normal)
+               );
+           }
+           else {
+               Carp::croak(
+                   sprintf ("%s version %s required--".
+                       "this is only version %s", $class,
+                       $req->stringify, $version->stringify)
+               );
+           }
+       }
+    }
+
+    return defined $version ? $version->stringify : undef;
+}
+
+1; #this line is important and will help the module return a true value
diff --git a/cpan/version/t/00impl-pp.t b/cpan/version/t/00impl-pp.t
new file mode 100644 (file)
index 0000000..36026aa
--- /dev/null
@@ -0,0 +1,18 @@
+#! /usr/local/perl -w
+# Before `make install' is performed this script should be runnable with
+# `make test'. After `make install' it should work as `perl test.pl'
+
+#########################
+
+use Test::More qw/no_plan/;
+
+BEGIN {
+    (my $coretests = $0) =~ s'[^/]+\.t'coretests.pm';
+    require $coretests;
+    use_ok('version::vpp', 0.9905);
+}
+
+BaseTests("version::vpp","new","qv");
+BaseTests("version::vpp","new","declare");
+BaseTests("version::vpp","parse", "qv");
+BaseTests("version::vpp","parse", "declare");
index 7e83058..681a0ff 100644 (file)
@@ -9,7 +9,7 @@ use Test::More qw/no_plan/;
 BEGIN {
     (my $coretests = $0) =~ s'[^/]+\.t'coretests.pm';
     require $coretests;
-    use_ok('version', 0.9904);
+    use_ok('version', 0.9905);
 }
 
 BaseTests("version","new","qv");
index 6ed9524..8cf2743 100644 (file)
@@ -10,19 +10,19 @@ use File::Temp qw/tempfile/;
 BEGIN {
     (my $coretests = $0) =~ s'[^/]+\.t'coretests.pm';
     require $coretests;
-    use_ok("version", 0.9904);
+    use_ok("version", 0.9905);
     # If we made it this far, we are ok.
 }
 
 use lib qw/./;
 
 package version::Bad;
-use base 'version';
+use parent 'version';
 sub new { my($self,$n)=@_;  bless \$n, $self }
 
 # Bad subclass for SemVer failures seen with pure Perl version.pm only
 package version::Bad2;
-use base 'version';
+use parent 'version';
 sub new {
     my ($class, $val) = @_;
     die 'Invalid version string format' unless version::is_strict($val);
@@ -45,7 +45,7 @@ my ($fh, $filename) = tempfile('tXXXXXXX', SUFFIX => '.pm', UNLINK => 1);
 print $fh <<"EOF";
 # This is an empty subclass
 package $package;
-use base 'version';
+use parent 'version';
 use vars '\$VERSION';
 \$VERSION=0.001;
 EOF
index d579579..873fada 100644 (file)
@@ -14,7 +14,7 @@ BEGIN {
 # Don't want to use, because we need to make sure that the import doesn't
 # fire just yet (some code does this to avoid importing qv() and delare()).
 require_ok("version");
-is $version::VERSION, 0.9904, "Make sure we have the correct class";
+is $version::VERSION, 0.9905, "Make sure we have the correct class";
 ok(!"main"->can("qv"), "We don't have the imported qv()");
 ok(!"main"->can("declare"), "We don't have the imported declare()");
 
index bac5534..3496f57 100644 (file)
@@ -14,7 +14,7 @@ BEGIN {
 }
 
 BEGIN {
-    use version 0.9904;
+    use version 0.9905;
 }
 
 pass "Didn't get caught by the wrong DIE handler, which is a good thing";
index e26532f..74e7251 100644 (file)
@@ -7,7 +7,7 @@
 use Test::More qw/no_plan/;
 
 BEGIN {
-    use_ok('version', 0.9904);
+    use_ok('version', 0.9905);
 }
 
 my $v1 = version->new('1.2');
index 93662ed..15247d0 100644 (file)
@@ -11,7 +11,7 @@ use Test::More tests => 7;
 use Config;
 
 BEGIN {
-    use_ok('version', 0.9904);
+    use_ok('version', 0.9905);
 }
 
 SKIP: {
@@ -42,6 +42,7 @@ SKIP: {
            unless $loc and localeconv()->{decimal_point} eq ',';
 
        setlocale(LC_NUMERIC, $loc);
+       $ver = 1.23;  # has to be floating point number
        ok ($ver eq "1,23", "Using locale: $loc");
        $v = version->new($ver);
        unlike($warning, qr/Version string '1,23' contains invalid data/,
index 5e548a9..9a8e474 100644 (file)
@@ -4,17 +4,19 @@
 
 #########################
 
-use Test::More tests => 2;
-use_ok("version", 0.9904);
+use Test::More tests => 3;
+use_ok("version", 0.9905);
 
 # do strict lax tests in a sub to isolate a package to test importing
 SKIP: {
     eval "use Module::CoreList 2.76";
-    skip 'No tied hash in Modules::CoreList in Perl', 1
+    skip 'No tied hash in Modules::CoreList in Perl', 2
        if $@;
 
     my $foo = version->parse($Module::CoreList::version{5.008_000}{base});
 
-    is $foo, $Module::CoreList::version{5.008_000}{base},
-       'Correctly handle tied hash';
+    is $foo, 1.03, 'Correctly handle tied hash';
+
+    $foo = version->qv($Module::CoreList::version{5.008_000}{Unicode});
+    is $foo, '3.2.0', 'Correctly handle tied hash with dotted decimal';
 }
index 7ece45b..b7b690a 100644 (file)
@@ -426,13 +426,13 @@ EOF
     }
 
 SKIP: {
-    skip 'Cannot test "use parent qw(version)"  when require is used', 3
+    skip "Cannot test \"use parent $CLASS\"  when require is used", 3
        unless defined $qv_declare;
     my ($fh, $filename) = tempfile('tXXXXXXX', SUFFIX => '.pm', UNLINK => 1);
     (my $package = basename($filename)) =~ s/\.pm$//;
     print $fh <<"EOF";
 package $package;
-use parent qw(version);
+use parent $CLASS;
 1;
 EOF
     close $fh;
@@ -490,9 +490,9 @@ EOF
 
     {
        # http://rt.perl.org/rt3/Ticket/Display.html?id=56606
-       my $badv = bless { version => [1,2,3] }, "version";
+       my $badv = bless { version => [1,2,3] }, $CLASS;
        is $badv, '1.002003', "Deal with badly serialized versions from YAML";
-       my $badv2 = bless { qv => 1, version => [1,2,3] }, "version";
+       my $badv2 = bless { qv => 1, version => [1,2,3] }, $CLASS;
        is $badv2, 'v1.2.3', "Deal with badly serialized versions from YAML ";
     }
 
@@ -577,7 +577,7 @@ SKIP: {
     }
 
     { # https://rt.cpan.org/Ticket/Display.html?id=88495
-       @ver::ISA = "version";
+       @ver::ISA = $CLASS;
        is ref(ver->new), 'ver', 'ver can inherit from version';
        is ref(ver->qv("1.2.3")), 'ver', 'ver can inherit from version';
     }
diff --git a/vutil.c b/vutil.c
index 08b2373..303e76c 100644 (file)
--- a/vutil.c
+++ b/vutil.c
@@ -596,10 +596,19 @@ Perl_upg_version(pTHX_ SV *ver, bool qv)
        qv = TRUE;
     }
 #endif
+    else if ( (SvUOK(ver) && SvUVX(ver) > VERSION_MAX)
+          || (SvIOK(ver) && SvIVX(ver) > VERSION_MAX) ) {
+       STRLEN len;
+       char tbuf[64];
+       len = my_snprintf(tbuf, sizeof(tbuf), "%d", VERSION_MAX);
+       version = savepvn(tbuf, len);
+       Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
+                      "Integer overflow in version %d",VERSION_MAX);
+    }
     else /* must be a string or something like a string */
     {
        STRLEN len;
-       version = savepv(SvPV(ver,len));
+       version = savepvn(SvPV(ver,len), SvCUR(ver));
 #ifndef SvVOK
 #  if PERL_VERSION > 5
        /* This will only be executed for 5.6.0 - 5.8.0 inclusive */
diff --git a/vxs.inc b/vxs.inc
index e63173b..78b1fef 100644 (file)
--- a/vxs.inc
+++ b/vxs.inc
@@ -98,7 +98,7 @@ VXS(UNIVERSAL_VERSION)
 
     if (gvp && isGV(gv = *gvp) && (sv = GvSV(gv)) && SvOK(sv)) {
         sv = sv_mortalcopy(sv);
-       if ( ! ISA_CLASS_OBJ(sv, "version::vxs"))
+       if ( ! ISA_CLASS_OBJ(sv, "version"))
            UPG_VERSION(sv, FALSE);
         undef = NULL;
     }
@@ -304,7 +304,7 @@ VXS(version_vcmp)
               SV * robj = ST(1);
               const IV  swap = (IV)SvIV(ST(2));
 
-              if ( !ISA_CLASS_OBJ(robj, "version::vxs") )
+              if ( !ISA_CLASS_OBJ(robj, "version") )
               {
                    robj = NEW_VERSION(SvOK(robj) ? robj : newSVpvs_flags("0", SVs_TEMP));
                    sv_2mortal(robj);