=== embed.fnc
==================================================================
--- embed.fnc  (revision 18135)
+++ embed.fnc  (local)
@@ -554,6 +554,7 @@
 Apd	|const char*	|scan_version	|NN const char *vstr|NN SV *sv|bool qv
 Apd	|SV*	|new_version	|NN SV *ver
 Apd	|SV*	|upg_version	|NN SV *ver
+Apd	|bool	|vverify	|NN SV *vs
 Apd	|SV*	|vnumify	|NN SV *vs
 Apd	|SV*	|vnormal	|NN SV *vs
 Apd	|SV*	|vstringify	|NN SV *vs
=== lib/version.pm
==================================================================
--- lib/version.pm  (revision 18135)
+++ lib/version.pm  (local)
@@ -12,7 +12,7 @@
 
 @EXPORT = qw(qv);
 
-$VERSION = "0.44"; 
+$VERSION = "0.47"; 
 
 $CLASS = 'version';
 
@@ -538,6 +538,28 @@
 $module->VERSION function returns a string (PV) that can be converted to a 
 number following the normal Perl rules, when used in a numeric context.
 
+=head1 SUBCLASSING
+
+This module is specifically designed and tested to be easily subclassed.
+In practice, you only need to override the methods you want to change, but
+you have to take some care when overriding new() (since that is where all
+of the parsing takes place).  For example, this is a perfect acceptable
+derived class:
+
+  package myversion;
+  use base version;
+  sub new { 
+      my($self,$n)=@_;
+      my $obj;
+      # perform any special input handling here
+      $obj = $self->SUPER::new($n);
+      # and/or add additional hash elements here
+      return $obj;
+  }
+
+See also L<version::AlphaBeta> on CPAN for an alternate representation of
+version strings.
+
 =head1 EXPORT
 
 qv - quoted version initialization operator
=== lib/version.t
==================================================================
--- lib/version.t  (revision 18135)
+++ lib/version.t  (local)
@@ -4,12 +4,12 @@
 
 #########################
 
-use Test::More tests => 183;
+use Test::More tests => 200;
 
 diag "Tests with base class" unless $ENV{PERL_CORE};
 
 BEGIN {
-    use_ok("version", 0.30); # If we made it this far, we are ok.
+    use_ok("version", 0.47); # If we made it this far, we are ok.
 }
 
 BaseTests("version");
@@ -22,18 +22,38 @@
 @ISA = qw(version);
 $VERSION = 0.01;
 
+package version::Bad;
+use base version;
+sub new { my($self,$n)=@_;  bless \$n, $self }
+
 package main;
-my $testobj = new version::Empty 1.002_003;
+my $testobj = version::Empty->new(1.002_003);
 isa_ok( $testobj, "version::Empty" );
 ok( $testobj->numify == 1.002003, "Numified correctly" );
 ok( $testobj->stringify eq "1.002003", "Stringified correctly" );
 ok( $testobj->normal eq "v1.2.3", "Normalified correctly" );
 
-my $verobj = new version "1.2.4";
+my $verobj = version->new("1.2.4");
 ok( $verobj > $testobj, "Comparison vs parent class" );
 ok( $verobj gt $testobj, "Comparison vs parent class" );
 BaseTests("version::Empty");
 
+diag "tests with bad subclass" unless $ENV{PERL_CORE};
+$testobj = version::Bad->new(1.002_003);
+isa_ok( $testobj, "version::Bad" );
+eval { my $string = $testobj->numify };
+like($@, qr/Invalid version object/,
+    "Bad subclass numify");
+eval { my $string = $testobj->normal };
+like($@, qr/Invalid version object/,
+    "Bad subclass normal");
+eval { my $string = $testobj->stringify };
+like($@, qr/Invalid version object/,
+    "Bad subclass stringify");
+eval { my $test = $testobj > 1.0 };
+like($@, qr/Invalid version object/,
+    "Bad subclass vcmp");
+
 sub BaseTests {
 
 	my $CLASS = shift;
@@ -278,4 +298,25 @@
 	    $version = qv(1.2.3);
 	    ok("$version" eq "v1.2.3", 'v-string initialized qv()');
 	}
+
+	diag "Tests with real-world (malformed) data" unless $ENV{PERL_CORE};
+
+	# trailing zero testing (reported by Andreas Koenig).
+	$version = $CLASS->new("1");
+	ok($version->numify eq "1.000", "trailing zeros preserved");
+	$version = $CLASS->new("1.0");
+	ok($version->numify eq "1.000", "trailing zeros preserved");
+	$version = $CLASS->new("1.0.0");
+	ok($version->numify eq "1.000000", "trailing zeros preserved");
+	$version = $CLASS->new("1.0.0.0");
+	ok($version->numify eq "1.000000000", "trailing zeros preserved");
+	
+	# leading zero testing (reported by Andreas Koenig).
+	$version = $CLASS->new(".7");
+	ok($version->numify eq "0.700", "leading zero inferred");
+
+	# leading space testing (reported by Andreas Koenig).
+	$version = $CLASS->new(" 1.7");
+	ok($version->numify eq "1.700", "leading space ignored");
+
 }
=== t/comp/use.t
==================================================================
--- t/comp/use.t  (revision 18135)
+++ t/comp/use.t  (local)
@@ -153,7 +153,7 @@
     print "ok ",$i++,"\n";
 
     eval "use lib v100.105";
-    unless ($@ =~ /lib version 100.105 \(v100\.105\.0\) required--this is only version 35.036 \(v35\.36\.0\)/) {
+    unless ($@ =~ /lib version 100.105 \(v100\.105\.0\) required--this is only version 35.036000 \(v35\.36\.0\)/) {
 	print "not ";
     }
     print "ok ",$i++,"\n";
@@ -163,7 +163,7 @@
     print "ok ",$i++,"\n";
 
     eval "use lib 100.105";
-    unless ($@ =~ /lib version 100.105 \(v100\.105\.0\) required--this is only version 35.036 \(v35\.36\.0\)/) {
+    unless ($@ =~ /lib version 100.105 \(v100\.105\.0\) required--this is only version 35.036000 \(v35\.36\.0\)/) {
 	print "not ";
     }
     print "ok ",$i++,"\n";
=== util.c
==================================================================
--- util.c  (revision 18135)
+++ util.c  (local)
@@ -3878,7 +3878,7 @@
 const char *
 Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
 {
-    const char *start = s;
+    const char *start;
     const char *pos;
     const char *last;
     int saw_period = 0;
@@ -3891,12 +3891,15 @@
     HvSHAREKEYS_on(hv);         /* key-sharing on by default */
 #endif
 
+    while (isSPACE(*s)) /* leading whitespace is OK */
+	s++;
+
     if (*s == 'v') {
 	s++;  /* get past 'v' */
 	qv = 1; /* force quoted version processing */
     }
 
-    last = pos = s;
+    start = last = pos = s;
 
     /* pre-scan the input string to check for decimals/underbars */
     while ( *pos == '.' || *pos == '_' || isDIGIT(*pos) )
@@ -3918,17 +3921,15 @@
 	pos++;
     }
 
-    if ( saw_period > 1 ) {
+    if ( saw_period > 1 )
 	qv = 1; /* force quoted version processing */
-    }
 
     pos = s;
 
     if ( qv )
 	hv_store((HV *)hv, "qv", 2, &PL_sv_yes, 0);
-    if ( saw_under ) {
+    if ( saw_under )
 	hv_store((HV *)hv, "alpha", 5, &PL_sv_yes, 0);
-    }
     if ( !qv && width < 3 )
 	hv_store((HV *)hv, "width", 5, newSViv(width), 0);
     
@@ -3949,7 +3950,7 @@
 		 * point of a version originally created with a bare
 		 * floating point number, i.e. not quoted in any way
 		 */
- 		if ( !qv && s > start+1 && saw_period == 1 ) {
+ 		if ( !qv && s > start && saw_period == 1 ) {
 		    mult *= 100;
  		    while ( s < end ) {
  			orev = rev;
@@ -4044,7 +4045,7 @@
 	AV * const av = newAV();
 	AV *sav;
 	/* This will get reblessed later if a derived class*/
-	SV*  const hv = newSVrv(rv, "version"); 
+	SV * const hv = newSVrv(rv, "version"); 
 	(void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */
 #ifndef NODEFAULT_SHAREKEYS
 	HvSHAREKEYS_on(hv);         /* key-sharing on by default */
@@ -4079,7 +4080,7 @@
     }
 #ifdef SvVOK
     if ( SvVOK(ver) ) { /* already a v-string */
-	MAGIC* mg = mg_find(ver,PERL_MAGIC_vstring);
+	const MAGIC* const mg = mg_find(ver,PERL_MAGIC_vstring);
 	const STRLEN len = mg->mg_len;
 	char * const version = savepvn( (const char*)mg->mg_ptr, len);
 	sv_setpvn(rv,version,len);
@@ -4135,7 +4136,46 @@
     return ver;
 }
 
+/*
+=for apidoc vverify
 
+Validates that the SV contains a valid version object.
+
+    bool vverify(SV *vobj);
+
+Note that it only confirms the bare minimum structure (so as not to get
+confused by derived classes which may contain additional hash entries):
+
+=over 4
+
+=item * The SV contains a hash (or a reference to one)
+
+=item * The hash contains a "version" key
+
+=item * The "version" key has an AV as its value
+
+=back
+
+=cut
+*/
+
+bool
+Perl_vverify(pTHX_ SV *vs)
+{
+    SV *sv;
+    if ( SvROK(vs) )
+	vs = SvRV(vs);
+
+    /* see if the appropriate elements exist */
+    if ( SvTYPE(vs) == SVt_PVHV
+	 && hv_exists((HV*)vs, "version", 7)
+	 && (sv = *hv_fetch((HV*)vs, "version", 7, FALSE))
+	 && SvTYPE(sv) == SVt_PVAV )
+	return TRUE;
+    else
+	return FALSE;
+}
+
 /*
 =for apidoc vnumify
 
@@ -4161,6 +4201,9 @@
     if ( SvROK(vs) )
 	vs = SvRV(vs);
 
+    if ( !vverify(vs) )
+	Perl_croak(aTHX_ "Invalid version object");
+
     /* see if various flags exist */
     if ( hv_exists((HV*)vs, "alpha", 5 ) )
 	alpha = TRUE;
@@ -4184,17 +4227,17 @@
     }
 
     digit = SvIV(*av_fetch(av, 0, 0));
-    Perl_sv_setpvf(aTHX_ sv,"%d.", (int)PERL_ABS(digit));
+    sv_setpvf(sv, "%d.", (int)PERL_ABS(digit));
     for ( i = 1 ; i < len ; i++ )
     {
 	digit = SvIV(*av_fetch(av, i, 0));
 	if ( width < 3 ) {
 	    const int denom = (int)pow(10,(3-width));
 	    const div_t term = div((int)PERL_ABS(digit),denom);
-	    Perl_sv_catpvf(aTHX_ sv,"%0*d_%d", width, term.quot, term.rem);
+	    sv_catpvf(sv, "%0*d_%d", width, term.quot, term.rem);
 	}
 	else {
-	    Perl_sv_catpvf(aTHX_ sv,"%0*d", width, (int)digit);
+	    sv_catpvf(sv, "%0*d", width, (int)digit);
 	}
     }
 
@@ -4202,14 +4245,12 @@
     {
 	digit = SvIV(*av_fetch(av, len, 0));
 	if ( alpha && width == 3 ) /* alpha version */
-	    Perl_sv_catpv(aTHX_ sv,"_");
-	/* Don't display additional trailing zeros */
-	if ( digit > 0 )
-	    Perl_sv_catpvf(aTHX_ sv,"%0*d", width, (int)digit);
+	    sv_catpvn(sv,"_",1);
+	sv_catpvf(sv, "%0*d", width, (int)digit);
     }
-    else /* len == 1 */
+    else /* len == 0 */
     {
-	 sv_catpvn(sv,"000",3);
+	sv_catpvn(sv,"000",3);
     }
     return sv;
 }
@@ -4238,36 +4279,40 @@
     if ( SvROK(vs) )
 	vs = SvRV(vs);
 
+    if ( !vverify(vs) )
+	Perl_croak(aTHX_ "Invalid version object");
+
     if ( hv_exists((HV*)vs, "alpha", 5 ) )
 	alpha = TRUE;
     av = (AV *)*hv_fetch((HV*)vs, "version", 7, FALSE);
 
     len = av_len(av);
-    if ( len == -1 ) {
+    if ( len == -1 )
+    {
 	sv_catpvn(sv,"",0);
 	return sv;
     }
     digit = SvIV(*av_fetch(av, 0, 0));
-    Perl_sv_setpvf(aTHX_ sv,"v%"IVdf,(IV)digit);
+    sv_setpvf(sv, "v%"IVdf, (IV)digit);
     for ( i = 1 ; i <= len-1 ; i++ ) {
 	digit = SvIV(*av_fetch(av, i, 0));
-	Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit);
+	sv_catpvf(sv, ".%"IVdf, (IV)digit);
     }
 
-    if ( len > 0 ) {
+    if ( len > 0 )
+    {
 	/* handle last digit specially */
 	digit = SvIV(*av_fetch(av, len, 0));
 	if ( alpha )
-	    Perl_sv_catpvf(aTHX_ sv, "_%"IVdf, (IV)digit);
+	    sv_catpvf(sv, "_%"IVdf, (IV)digit);
 	else
-	    Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit);
+	    sv_catpvf(sv, ".%"IVdf, (IV)digit);
     }
 
     if ( len <= 2 ) { /* short version, must be at least three */
 	for ( len = 2 - len; len != 0; len-- )
 	    sv_catpvn(sv,".0",2);
     }
-
     return sv;
 }
 
@@ -4285,9 +4330,17 @@
 SV *
 Perl_vstringify(pTHX_ SV *vs)
 {
+    I32 qv = 0;
     if ( SvROK(vs) )
 	vs = SvRV(vs);
+    
+    if ( !vverify(vs) )
+	Perl_croak(aTHX_ "Invalid version object");
+
     if ( hv_exists((HV *)vs, "qv", 2) )
+	qv = 1;
+    
+    if ( qv )
 	return vnormal(vs);
     else
 	return vnumify(vs);
@@ -4316,6 +4369,12 @@
     if ( SvROK(rhv) )
 	rhv = SvRV(rhv);
 
+    if ( !vverify(lhv) )
+	Perl_croak(aTHX_ "Invalid version object");
+
+    if ( !vverify(rhv) )
+	Perl_croak(aTHX_ "Invalid version object");
+
     /* get the left hand term */
     lav = (AV *)*hv_fetch((HV*)lhv, "version", 7, FALSE);
     if ( hv_exists((HV*)lhv, "alpha", 5 ) )
