diff --git a/t/porting/customized.dat b/t/porting/customized.dat index 1156cd9fa207..916b27ad0543 100644 --- a/t/porting/customized.dat +++ b/t/porting/customized.dat @@ -24,5 +24,5 @@ Test::Harness cpan/Test-Harness/t/source.t aaa3939591114c0c52ecd44159218336d1f76 Win32API::File cpan/Win32API-File/File.pm 8fd212857f821cb26648878b96e57f13bf21b99e Win32API::File cpan/Win32API-File/File.xs beb870fed4490d2faa547b4a8576b8d64d1d27c5 version cpan/version/lib/version.pm 9a4d4c2a89cc95c0c946de6742d6df41e546c12c -version vutil.c 5fd47f345ad3e612f9f3fe440cccbcbf88264bb6 +version vutil.c 88855f7eb6ce443f57565d287ff2a0bbcd443bd2 version vxs.inc d23e4fac6211d3b35b367e80ef23b8ab5fa9d0eb diff --git a/vutil.c b/vutil.c index 341eb9b8dc48..4cf549f23ad3 100644 --- a/vutil.c +++ b/vutil.c @@ -25,8 +25,8 @@ Perl_prescan_version2(pTHX_ const char *s, bool strict, #else Perl_prescan_version(pTHX_ const char *s, bool strict, #endif - const char **errstr, - bool *sqv, int *ssaw_decimal, int *swidth, bool *salpha) { + const char **errstr, + bool *sqv, int *ssaw_decimal, int *swidth, bool *salpha) { bool qv = (sqv ? *sqv : FALSE); int width = 3; int saw_decimal = 0; @@ -37,200 +37,200 @@ Perl_prescan_version(pTHX_ const char *s, bool strict, PERL_UNUSED_CONTEXT; if (qv && isDIGIT(*d)) - goto dotted_decimal_version; + goto dotted_decimal_version; if (*d == 'v') { /* explicit v-string */ - d++; - if (isDIGIT(*d)) { - qv = TRUE; - } - else { /* degenerate v-string */ - /* requires v1.2.3 */ - BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); - } + d++; + if (isDIGIT(*d)) { + qv = TRUE; + } + else { /* degenerate v-string */ + /* requires v1.2.3 */ + BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); + } dotted_decimal_version: - if (strict && d[0] == '0' && isDIGIT(d[1])) { - /* no leading zeros allowed */ - BADVERSION(s,errstr,"Invalid version format (no leading zeros)"); - } - - while (isDIGIT(*d)) /* integer part */ - d++; - - if (*d == '.') - { - saw_decimal++; - d++; /* decimal point */ - } - else - { - if (strict) { - /* require v1.2.3 */ - BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); - } - else { - goto version_prescan_finish; - } - } - - { - int i = 0; - int j = 0; - while (isDIGIT(*d)) { /* just keep reading */ - i++; - while (isDIGIT(*d)) { - d++; j++; - /* maximum 3 digits between decimal */ - if (strict && j > 3) { - BADVERSION(s,errstr,"Invalid version format (maximum 3 digits between decimals)"); - } - } - if (*d == '_') { - if (strict) { - BADVERSION(s,errstr,"Invalid version format (no underscores)"); - } - if ( alpha ) { - BADVERSION(s,errstr,"Invalid version format (multiple underscores)"); - } - d++; - alpha = TRUE; - } - else if (*d == '.') { - if (alpha) { - BADVERSION(s,errstr,"Invalid version format (underscores before decimal)"); - } - saw_decimal++; - d++; - } - else if (!isDIGIT(*d)) { - break; - } - j = 0; - } - - if (strict && i < 2) { - /* requires v1.2.3 */ - BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); - } - } - } /* end if dotted-decimal */ + if (strict && d[0] == '0' && isDIGIT(d[1])) { + /* no leading zeros allowed */ + BADVERSION(s,errstr,"Invalid version format (no leading zeros)"); + } + + while (isDIGIT(*d)) /* integer part */ + d++; + + if (*d == '.') + { + saw_decimal++; + d++; /* decimal point */ + } + else + { + if (strict) { + /* require v1.2.3 */ + BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); + } + else { + goto version_prescan_finish; + } + } + + { + int i = 0; + int j = 0; + while (isDIGIT(*d)) { /* just keep reading */ + i++; + while (isDIGIT(*d)) { + d++; j++; + /* maximum 3 digits between decimal */ + if (strict && j > 3) { + BADVERSION(s,errstr,"Invalid version format (maximum 3 digits between decimals)"); + } + } + if (*d == '_') { + if (strict) { + BADVERSION(s,errstr,"Invalid version format (no underscores)"); + } + if ( alpha ) { + BADVERSION(s,errstr,"Invalid version format (multiple underscores)"); + } + d++; + alpha = TRUE; + } + else if (*d == '.') { + if (alpha) { + BADVERSION(s,errstr,"Invalid version format (underscores before decimal)"); + } + saw_decimal++; + d++; + } + else if (!isDIGIT(*d)) { + break; + } + j = 0; + } + + if (strict && i < 2) { + /* requires v1.2.3 */ + BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); + } + } + } /* end if dotted-decimal */ else - { /* decimal versions */ - int j = 0; /* may need this later */ - /* special strict case for leading '.' or '0' */ - if (strict) { - if (*d == '.') { - BADVERSION(s,errstr,"Invalid version format (0 before decimal required)"); - } - if (*d == '0' && isDIGIT(d[1])) { - BADVERSION(s,errstr,"Invalid version format (no leading zeros)"); - } - } - - /* and we never support negative versions */ - if ( *d == '-') { - 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 == '.') { - /* we found it, so consume it */ - saw_decimal++; - d++; - } - else if (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') { - if ( d == s ) { - /* found nothing */ - BADVERSION(s,errstr,"Invalid version format (version required)"); - } - /* found just an integer */ - goto version_prescan_finish; - } - else if ( d == s ) { - /* didn't find either integer or period */ - BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); - } - else if (*d == '_') { - /* underscore can't come after integer part */ - if (strict) { - BADVERSION(s,errstr,"Invalid version format (no underscores)"); - } - else if (isDIGIT(d[1])) { - BADVERSION(s,errstr,"Invalid version format (alpha without decimal)"); - } - else { - BADVERSION(s,errstr,"Invalid version format (misplaced underscore)"); - } - } - else { - /* anything else after integer part is just invalid data */ - BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); - } - - /* scan the fractional part after the decimal point*/ - - if (!isDIGIT(*d) && (strict || ! (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') )) { - /* strict or lax-but-not-the-end */ - BADVERSION(s,errstr,"Invalid version format (fractional part required)"); - } - - while (isDIGIT(*d)) { - d++; j++; - if (*d == '.' && isDIGIT(d[-1])) { - if (alpha) { - BADVERSION(s,errstr,"Invalid version format (underscores before decimal)"); - } - if (strict) { - BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions must begin with 'v')"); - } - d = (char *)s; /* start all over again */ - qv = TRUE; - goto dotted_decimal_version; - } - if (*d == '_') { - if (strict) { - BADVERSION(s,errstr,"Invalid version format (no underscores)"); - } - if ( alpha ) { - BADVERSION(s,errstr,"Invalid version format (multiple underscores)"); - } - if ( ! isDIGIT(d[1]) ) { - BADVERSION(s,errstr,"Invalid version format (misplaced underscore)"); - } - width = j; - d++; - alpha = TRUE; - } - } + { /* decimal versions */ + int j = 0; /* may need this later */ + /* special strict case for leading '.' or '0' */ + if (strict) { + if (*d == '.') { + BADVERSION(s,errstr,"Invalid version format (0 before decimal required)"); + } + if (*d == '0' && isDIGIT(d[1])) { + BADVERSION(s,errstr,"Invalid version format (no leading zeros)"); + } + } + + /* and we never support negative versions */ + if ( *d == '-') { + 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 == '.') { + /* we found it, so consume it */ + saw_decimal++; + d++; + } + else if (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') { + if ( d == s ) { + /* found nothing */ + BADVERSION(s,errstr,"Invalid version format (version required)"); + } + /* found just an integer */ + goto version_prescan_finish; + } + else if ( d == s ) { + /* didn't find either integer or period */ + BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); + } + else if (*d == '_') { + /* underscore can't come after integer part */ + if (strict) { + BADVERSION(s,errstr,"Invalid version format (no underscores)"); + } + else if (isDIGIT(d[1])) { + BADVERSION(s,errstr,"Invalid version format (alpha without decimal)"); + } + else { + BADVERSION(s,errstr,"Invalid version format (misplaced underscore)"); + } + } + else { + /* anything else after integer part is just invalid data */ + BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); + } + + /* scan the fractional part after the decimal point*/ + + if (!isDIGIT(*d) && (strict || ! (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') )) { + /* strict or lax-but-not-the-end */ + BADVERSION(s,errstr,"Invalid version format (fractional part required)"); + } + + while (isDIGIT(*d)) { + d++; j++; + if (*d == '.' && isDIGIT(d[-1])) { + if (alpha) { + BADVERSION(s,errstr,"Invalid version format (underscores before decimal)"); + } + if (strict) { + BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions must begin with 'v')"); + } + d = (char *)s; /* start all over again */ + qv = TRUE; + goto dotted_decimal_version; + } + if (*d == '_') { + if (strict) { + BADVERSION(s,errstr,"Invalid version format (no underscores)"); + } + if ( alpha ) { + BADVERSION(s,errstr,"Invalid version format (multiple underscores)"); + } + if ( ! isDIGIT(d[1]) ) { + BADVERSION(s,errstr,"Invalid version format (misplaced underscore)"); + } + width = j; + d++; + alpha = TRUE; + } + } } version_prescan_finish: while (isSPACE(*d)) - d++; + d++; if (!isDIGIT(*d) && (! (!*d || *d == ';' || *d == '{' || *d == '}') )) { - /* trailing non-numeric data */ - BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); + /* trailing non-numeric data */ + BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); } if (saw_decimal > 1 && d[-1] == '.') { - /* no trailing period allowed */ - BADVERSION(s,errstr,"Invalid version format (trailing decimal)"); + /* no trailing period allowed */ + BADVERSION(s,errstr,"Invalid version format (trailing decimal)"); } if (sqv) - *sqv = qv; + *sqv = qv; if (swidth) - *swidth = width; + *swidth = width; if (ssaw_decimal) - *ssaw_decimal = saw_decimal; + *ssaw_decimal = saw_decimal; if (salpha) - *salpha = alpha; + *salpha = alpha; return d; } @@ -277,19 +277,19 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) PERL_ARGS_ASSERT_SCAN_VERSION; while (isSPACE(*s)) /* leading whitespace is OK */ - s++; + 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 == 'u' && strEQ(s+1,"ndef")) ) { - Perl_croak(aTHX_ "%s", errstr); - } + /* "undef" is a special case and not an error */ + if ( ! ( *s == 'u' && strEQ(s+1,"ndef")) ) { + Perl_croak(aTHX_ "%s", errstr); + } } start = s; if (*s == 'v') - s++; + s++; pos = s; /* Now that we are through the prescan, start creating the object */ @@ -302,66 +302,66 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) #endif if ( qv ) - (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(qv)); + (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(qv)); if ( alpha ) - (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(alpha)); + (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(alpha)); if ( !qv && width < 3 ) - (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width)); + (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width)); while (isDIGIT(*pos) || *pos == '_') - pos++; + pos++; if (!isALPHA(*pos)) { - I32 rev; - - for (;;) { - rev = 0; - { - /* this is atoi() that delimits on underscores */ - const char *end = pos; - I32 mult = 1; - I32 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 ) { - if (*s == '_') - continue; - orev = rev; - rev += (*s - '0') * mult; - mult /= 10; - if ( (PERL_ABS(orev) > PERL_ABS(rev)) - || (PERL_ABS(rev) > VERSION_MAX )) { - Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), - "Integer overflow in version %d",VERSION_MAX); - s = end - 1; - rev = VERSION_MAX; - vinf = 1; - } - s++; - if ( *s == '_' ) - s++; - } - } - else { - while (--end >= s) { - int i; - if (*end == '_') - continue; - i = (*end - '0'); + I32 rev; + + for (;;) { + rev = 0; + { + /* this is atoi() that delimits on underscores */ + const char *end = pos; + I32 mult = 1; + I32 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 ) { + if (*s == '_') + continue; + orev = rev; + rev += (*s - '0') * mult; + mult /= 10; + if ( (PERL_ABS(orev) > PERL_ABS(rev)) + || (PERL_ABS(rev) > VERSION_MAX )) { + Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), + "Integer overflow in version %d",VERSION_MAX); + s = end - 1; + rev = VERSION_MAX; + vinf = 1; + } + s++; + if ( *s == '_' ) + s++; + } + } + else { + while (--end >= s) { + int i; + if (*end == '_') + continue; + i = (*end - '0'); if ( (mult == VERSION_MAX) || (i > VERSION_MAX / mult) || (i * mult > VERSION_MAX - rev)) { - Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), - "Integer overflow in version"); - end = s - 1; - rev = VERSION_MAX; - vinf = 1; - } + Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), + "Integer overflow in version"); + end = s - 1; + rev = VERSION_MAX; + vinf = 1; + } else rev += i * mult; @@ -369,79 +369,79 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) mult = VERSION_MAX; else mult *= 10; - } - } - } - - /* Append revision */ - av_push(av, newSViv(rev)); - if ( vinf ) { - s = last; - break; - } - else if ( *pos == '.' ) { - pos++; - if (qv) { - while (*pos == '0') - ++pos; - } - s = pos; - } - else if ( *pos == '_' && isDIGIT(pos[1]) ) - s = ++pos; - else if ( *pos == ',' && isDIGIT(pos[1]) ) - s = ++pos; - else if ( isDIGIT(*pos) ) - s = pos; - else { - s = pos; - break; - } - if ( qv ) { - while ( isDIGIT(*pos) || *pos == '_') - pos++; - } - else { - int digits = 0; - while ( ( isDIGIT(*pos) || *pos == '_' ) && digits < 3 ) { - if ( *pos != '_' ) - digits++; - pos++; - } - } - } + } + } + } + + /* Append revision */ + av_push(av, newSViv(rev)); + if ( vinf ) { + s = last; + break; + } + else if ( *pos == '.' ) { + pos++; + if (qv) { + while (*pos == '0') + ++pos; + } + s = pos; + } + else if ( *pos == '_' && isDIGIT(pos[1]) ) + s = ++pos; + else if ( *pos == ',' && isDIGIT(pos[1]) ) + s = ++pos; + else if ( isDIGIT(*pos) ) + s = pos; + else { + s = pos; + break; + } + if ( qv ) { + while ( isDIGIT(*pos) || *pos == '_') + pos++; + } + else { + int digits = 0; + while ( ( isDIGIT(*pos) || *pos == '_' ) && digits < 3 ) { + if ( *pos != '_' ) + digits++; + pos++; + } + } + } } if ( qv ) { /* quoted versions always get at least three terms*/ - SSize_t len = AvFILLp(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) - av_push(av, newSViv(0)); + SSize_t len = AvFILLp(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) + av_push(av, newSViv(0)); } /* need to save off the current version string for later */ if ( vinf ) { - SV * orig = newSVpvn("v.Inf", sizeof("v.Inf")-1); - (void)hv_stores(MUTABLE_HV(hv), "original", orig); - (void)hv_stores(MUTABLE_HV(hv), "vinf", newSViv(1)); + SV * orig = newSVpvn("v.Inf", sizeof("v.Inf")-1); + (void)hv_stores(MUTABLE_HV(hv), "original", orig); + (void)hv_stores(MUTABLE_HV(hv), "vinf", newSViv(1)); } else if ( s > start ) { - SV * orig = newSVpvn(start,s-start); - if ( qv && saw_decimal == 1 && *start != 'v' ) { - /* need to insert a v to be consistent */ - sv_insert(orig, 0, 0, "v", 1); - } - (void)hv_stores(MUTABLE_HV(hv), "original", orig); + SV * orig = newSVpvn(start,s-start); + if ( qv && saw_decimal == 1 && *start != 'v' ) { + /* need to insert a v to be consistent */ + sv_insert(orig, 0, 0, "v", 1); + } + (void)hv_stores(MUTABLE_HV(hv), "original", orig); } else { - (void)hv_stores(MUTABLE_HV(hv), "original", newSVpvs("0")); - av_push(av, newSViv(0)); + (void)hv_stores(MUTABLE_HV(hv), "original", newSVpvs("0")); + av_push(av, newSViv(0)); } /* And finally, store the AV in the hash */ @@ -449,7 +449,7 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) /* fix RT#19517 - special case 'undef' as string */ if ( *s == 'u' && strEQ(s+1,"ndef") ) { - s += 5; + s += 5; } return s; @@ -479,74 +479,74 @@ Perl_new_version(pTHX_ SV *ver) PERL_ARGS_ASSERT_NEW_VERSION; if ( ISA_VERSION_OBJ(ver) ) /* can just copy directly */ { - SSize_t key; - AV * const av = newAV(); - AV *sav; - /* This will get reblessed later if a derived class*/ - SV * const hv = newSVrv(rv, "version"); - (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */ + SSize_t key; + AV * const av = newAV(); + AV *sav; + /* This will get reblessed later if a derived class*/ + 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 */ + HvSHAREKEYS_on(hv); /* key-sharing on by default */ #endif - if ( SvROK(ver) ) - ver = SvRV(ver); - - /* Begin copying all of the elements */ - if ( hv_exists(MUTABLE_HV(ver), "qv", 2) ) - (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(1)); - - if ( hv_exists(MUTABLE_HV(ver), "alpha", 5) ) - (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(1)); - { - SV ** svp = hv_fetchs(MUTABLE_HV(ver), "width", FALSE); - if(svp) { - const I32 width = SvIV(*svp); - (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width)); - } - } - { - SV ** svp = hv_fetchs(MUTABLE_HV(ver), "original", FALSE); - if(svp) - (void)hv_stores(MUTABLE_HV(hv), "original", newSVsv(*svp)); - } - sav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(ver), "version", FALSE))); - /* This will get reblessed later if a derived class*/ - for ( key = 0; key <= av_len(sav); key++ ) - { - SV * const sv = *av_fetch(sav, key, FALSE); - const I32 rev = SvIV(sv); - av_push(av, newSViv(rev)); - } - - (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av))); - return rv; + if ( SvROK(ver) ) + ver = SvRV(ver); + + /* Begin copying all of the elements */ + if ( hv_exists(MUTABLE_HV(ver), "qv", 2) ) + (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(1)); + + if ( hv_exists(MUTABLE_HV(ver), "alpha", 5) ) + (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(1)); + { + SV ** svp = hv_fetchs(MUTABLE_HV(ver), "width", FALSE); + if(svp) { + const I32 width = SvIV(*svp); + (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width)); + } + } + { + SV ** svp = hv_fetchs(MUTABLE_HV(ver), "original", FALSE); + if(svp) + (void)hv_stores(MUTABLE_HV(hv), "original", newSVsv(*svp)); + } + sav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(ver), "version", FALSE))); + /* This will get reblessed later if a derived class*/ + for ( key = 0; key <= av_len(sav); key++ ) + { + SV * const sv = *av_fetch(sav, key, FALSE); + const I32 rev = SvIV(sv); + av_push(av, newSViv(rev)); + } + + (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av))); + return rv; } #ifdef SvVOK { - const MAGIC* const mg = SvVSTRING_mg(ver); - if ( mg ) { /* already a v-string */ - const STRLEN len = mg->mg_len; - const char * const version = (const char*)mg->mg_ptr; - char *raw, *under; - static const char underscore[] = "_"; - sv_setpvn(rv,version,len); - raw = SvPV_nolen(rv); - under = ninstr(raw, raw+len, underscore, underscore + 1); - if (under) { - Move(under + 1, under, raw + len - under - 1, char); - SvCUR_set(rv, SvCUR(rv) - 1); - *SvEND(rv) = '\0'; - } - /* this is for consistency with the pure Perl class */ - if ( isDIGIT(*version) ) - sv_insert(rv, 0, 0, "v", 1); - } - else { + const MAGIC* const mg = SvVSTRING_mg(ver); + if ( mg ) { /* already a v-string */ + const STRLEN len = mg->mg_len; + const char * const version = (const char*)mg->mg_ptr; + char *raw, *under; + static const char underscore[] = "_"; + sv_setpvn(rv,version,len); + raw = SvPV_nolen(rv); + under = ninstr(raw, raw+len, underscore, underscore + 1); + if (under) { + Move(under + 1, under, raw + len - under - 1, char); + SvCUR_set(rv, SvCUR(rv) - 1); + *SvEND(rv) = '\0'; + } + /* this is for consistency with the pure Perl class */ + if ( isDIGIT(*version) ) + sv_insert(rv, 0, 0, "v", 1); + } + else { #endif - SvSetSV_nosteal(rv, ver); /* make a duplicate */ + SvSetSV_nosteal(rv, ver); /* make a duplicate */ #ifdef SvVOK - } + } } #endif sv_2mortal(rv); /* in case upg_version croaks before it returns */ @@ -583,46 +583,47 @@ Perl_upg_version(pTHX_ SV *ver, bool qv) #endif PERL_ARGS_ASSERT_UPG_VERSION; - if ( (SvUOK(ver) && SvUVX(ver) > VERSION_MAX) - || (SvIOK(ver) && SvIVX(ver) > VERSION_MAX) ) { - /* out of bounds [unsigned] integer */ - STRLEN len; - char tbuf[64]; - len = my_snprintf(tbuf, sizeof(tbuf), "%d", VERSION_MAX); - version = savepvn(tbuf, len); - SAVEFREEPV(version); - Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), - "Integer overflow in version %d",VERSION_MAX); + if ( (SvUOK(ver) && SvUVX(ver) > VERSION_MAX) + || (SvIOK(ver) && SvIVX(ver) > VERSION_MAX) ) + { + /* out of bounds [unsigned] integer */ + STRLEN len; + char tbuf[64]; + len = my_snprintf(tbuf, sizeof(tbuf), "%d", VERSION_MAX); + version = savepvn(tbuf, len); + SAVEFREEPV(version); + Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), + "Integer overflow in version %d",VERSION_MAX); } else if ( SvUOK(ver) || SvIOK(ver)) #if PERL_VERSION_LT(5,17,2) VER_IV: #endif { - version = savesvpv(ver); - SAVEFREEPV(version); + version = savesvpv(ver); + SAVEFREEPV(version); } else if (SvNOK(ver) && !( SvPOK(ver) && SvCUR(ver) == 3 ) ) #if PERL_VERSION_LT(5,17,2) VER_NV: #endif { - STRLEN len; + STRLEN len; - /* may get too much accuracy */ - char tbuf[64]; - SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0; - char *buf; + /* may get too much accuracy */ + char tbuf[64]; + SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0; + char *buf; #if PERL_VERSION_GE(5,19,0) - if (SvPOK(ver)) { - /* dualvar? */ - goto VER_PV; - } + if (SvPOK(ver)) { + /* dualvar? */ + goto VER_PV; + } #endif #ifdef USE_LOCALE_NUMERIC - { + { /* This may or may not be called from code that has switched * locales without letting perl know, therefore we have to find it * from first principals. See [perl #121930]. */ @@ -672,8 +673,8 @@ Perl_upg_version(pTHX_ SV *ver, bool qv) else { /* This value indicates to the restore code that we didn't change the locale */ locale_name_on_entry = NULL; - } - } + } + } else if (locale_obj_on_entry == PL_underlying_numeric_obj) { /* Here, the locale appears to have been changed to use the * program's underlying locale. Just use our mechanisms to @@ -692,21 +693,18 @@ Perl_upg_version(pTHX_ SV *ver, bool qv) } # endif - /* Prevent recursed calls from trying to change back */ LOCK_LC_NUMERIC_STANDARD(); - #endif - - if (sv) { + if (sv) { Perl_sv_setpvf(aTHX_ sv, "%.9" NVff, SvNVX(ver)); - len = SvCUR(sv); - buf = SvPVX(sv); - } - else { + len = SvCUR(sv); + buf = SvPVX(sv); + } + else { len = my_snprintf(tbuf, sizeof(tbuf), "%.9" NVff, SvNVX(ver)); - buf = tbuf; - } + buf = tbuf; + } #ifdef USE_LOCALE_NUMERIC @@ -720,7 +718,6 @@ Perl_upg_version(pTHX_ SV *ver, bool qv) } LC_NUMERIC_UNLOCK; /* End critical section */ - # else if (locale_name_on_entry) { @@ -741,82 +738,82 @@ Perl_upg_version(pTHX_ SV *ver, bool qv) #endif /* USE_LOCALE_NUMERIC */ - while (buf[len-1] == '0' && len > 0) len--; - if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */ - version = savepvn(buf, len); - SAVEFREEPV(version); - SvREFCNT_dec(sv); + while (buf[len-1] == '0' && len > 0) len--; + if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */ + version = savepvn(buf, len); + SAVEFREEPV(version); + SvREFCNT_dec(sv); } #ifdef SvVOK else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */ - version = savepvn( (const char*)mg->mg_ptr,mg->mg_len ); - SAVEFREEPV(version); - qv = TRUE; + version = savepvn( (const char*)mg->mg_ptr,mg->mg_len ); + SAVEFREEPV(version); + qv = TRUE; } #endif else if ( SvPOK(ver))/* must be a string or something like a string */ VER_PV: { - STRLEN len; - version = savepvn(SvPV(ver,len), SvCUR(ver)); - SAVEFREEPV(version); + STRLEN len; + version = savepvn(SvPV(ver,len), SvCUR(ver)); + SAVEFREEPV(version); #ifndef SvVOK - /* This will only be executed for 5.6.0 - 5.8.0 inclusive */ - if ( len >= 3 && !instr(version,".") && !instr(version,"_")) { - /* may be a v-string */ - char *testv = (char *)version; - STRLEN tlen = len; - for (tlen=0; tlen < len; tlen++, testv++) { - /* if one of the characters is non-text assume v-string */ - if (testv[0] < ' ') { - SV * const nsv = sv_newmortal(); - const char *nver; - const char *pos; - int saw_decimal = 0; - sv_setpvf(nsv,"v%vd",ver); - pos = nver = savepv(SvPV_nolen(nsv)); + /* This will only be executed for 5.6.0 - 5.8.0 inclusive */ + if ( len >= 3 && !instr(version,".") && !instr(version,"_")) { + /* may be a v-string */ + char *testv = (char *)version; + STRLEN tlen = len; + for (tlen=0; tlen < len; tlen++, testv++) { + /* if one of the characters is non-text assume v-string */ + if (testv[0] < ' ') { + SV * const nsv = sv_newmortal(); + const char *nver; + const char *pos; + int saw_decimal = 0; + sv_setpvf(nsv,"v%vd",ver); + pos = nver = savepv(SvPV_nolen(nsv)); SAVEFREEPV(pos); - /* scan the resulting formatted string */ - pos++; /* skip the leading 'v' */ - while ( *pos == '.' || isDIGIT(*pos) ) { - if ( *pos == '.' ) - saw_decimal++ ; - pos++; - } - - /* is definitely a v-string */ - if ( saw_decimal >= 2 ) { - version = nver; - } - break; - } - } - } + /* scan the resulting formatted string */ + pos++; /* skip the leading 'v' */ + while ( *pos == '.' || isDIGIT(*pos) ) { + if ( *pos == '.' ) + saw_decimal++ ; + pos++; + } + + /* is definitely a v-string */ + if ( saw_decimal >= 2 ) { + version = nver; + } + break; + } + } + } #endif } #if PERL_VERSION_LT(5,17,2) else if (SvIOKp(ver)) { - goto VER_IV; + goto VER_IV; } else if (SvNOKp(ver)) { - goto VER_NV; + goto VER_NV; } else if (SvPOKp(ver)) { - goto VER_PV; + goto VER_PV; } #endif else { - /* no idea what this is */ - Perl_croak(aTHX_ "Invalid version format (non-numeric data)"); + /* no idea what this is */ + Perl_croak(aTHX_ "Invalid version format (non-numeric data)"); } s = SCAN_VERSION(version, ver, qv); - if ( *s != '\0' ) - Perl_ck_warner(aTHX_ packWARN(WARN_MISC), - "Version string '%s' contains invalid data; " - "ignoring: '%s'", version, s); + if ( *s != '\0' ) + Perl_ck_warner(aTHX_ packWARN(WARN_MISC), + "Version string '%s' contains invalid data; " + "ignoring: '%s'", version, s); #if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS) LEAVE; @@ -864,16 +861,16 @@ Perl_vverify(pTHX_ SV *vs) PERL_ARGS_ASSERT_VVERIFY; if ( SvROK(vs) ) - vs = SvRV(vs); + vs = SvRV(vs); /* see if the appropriate elements exist */ if ( SvTYPE(vs) == SVt_PVHV - && (svp = hv_fetchs(MUTABLE_HV(vs), "version", FALSE)) - && (sv = SvRV(*svp)) - && SvTYPE(sv) == SVt_PVAV ) - return vs; + && (svp = hv_fetchs(MUTABLE_HV(vs), "version", FALSE)) + && (sv = SvRV(*svp)) + && SvTYPE(sv) == SVt_PVAV ) + return vs; else - return NULL; + return NULL; } /* @@ -910,42 +907,42 @@ Perl_vnumify(pTHX_ SV *vs) /* extract the HV from the object */ vs = VVERIFY(vs); if ( ! vs ) - Perl_croak(aTHX_ "Invalid version object"); + Perl_croak(aTHX_ "Invalid version object"); /* see if various flags exist */ if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) ) - alpha = TRUE; + alpha = TRUE; if (alpha) { - Perl_ck_warner(aTHX_ packWARN(WARN_NUMERIC), - "alpha->numify() is lossy"); + Perl_ck_warner(aTHX_ packWARN(WARN_NUMERIC), + "alpha->numify() is lossy"); } /* attempt to retrieve the version array */ if ( !(av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))) ) ) { - return newSVpvs("0"); + return newSVpvs("0"); } len = av_len(av); if ( len == -1 ) { - return newSVpvs("0"); + return newSVpvs("0"); } { - SV * tsv = *av_fetch(av, 0, 0); - digit = SvIV(tsv); + SV * tsv = *av_fetch(av, 0, 0); + digit = SvIV(tsv); } sv = Perl_newSVpvf(aTHX_ "%d.", (int)PERL_ABS(digit)); for ( i = 1 ; i <= len ; i++ ) { - SV * tsv = *av_fetch(av, i, 0); - digit = SvIV(tsv); - Perl_sv_catpvf(aTHX_ sv, "%03d", (int)digit); + SV * tsv = *av_fetch(av, i, 0); + digit = SvIV(tsv); + Perl_sv_catpvf(aTHX_ sv, "%03d", (int)digit); } if ( len == 0 ) { - sv_catpvs(sv, "000"); + sv_catpvs(sv, "000"); } return sv; } @@ -982,29 +979,29 @@ Perl_vnormal(pTHX_ SV *vs) /* extract the HV from the object */ vs = VVERIFY(vs); if ( ! vs ) - Perl_croak(aTHX_ "Invalid version object"); + Perl_croak(aTHX_ "Invalid version object"); av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))); len = av_len(av); if ( len == -1 ) { - return newSVpvs(""); + return newSVpvs(""); } { - SV * tsv = *av_fetch(av, 0, 0); - digit = SvIV(tsv); + SV * tsv = *av_fetch(av, 0, 0); + digit = SvIV(tsv); } sv = Perl_newSVpvf(aTHX_ "v%" IVdf, (IV)digit); for ( i = 1 ; i <= len ; i++ ) { - SV * tsv = *av_fetch(av, i, 0); - digit = SvIV(tsv); - Perl_sv_catpvf(aTHX_ sv, ".%" IVdf, (IV)digit); + SV * tsv = *av_fetch(av, i, 0); + digit = SvIV(tsv); + Perl_sv_catpvf(aTHX_ sv, ".%" IVdf, (IV)digit); } if ( len <= 2 ) { /* short version, must be at least three */ - for ( len = 2 - len; len != 0; len-- ) - sv_catpvs(sv,".0"); + for ( len = 2 - len; len != 0; len-- ) + sv_catpvs(sv,".0"); } return sv; } @@ -1035,33 +1032,33 @@ Perl_vstringify(pTHX_ SV *vs) /* extract the HV from the object */ vs = VVERIFY(vs); if ( ! vs ) - Perl_croak(aTHX_ "Invalid version object"); + Perl_croak(aTHX_ "Invalid version object"); svp = hv_fetchs(MUTABLE_HV(vs), "original", FALSE); if (svp) { - SV *pv; - pv = *svp; - if ( SvPOK(pv) + SV *pv; + pv = *svp; + if ( SvPOK(pv) #if PERL_VERSION_LT(5,17,2) - || SvPOKp(pv) + || SvPOKp(pv) #endif - ) - return newSVsv(pv); - else - return &PL_sv_undef; + ) + return newSVsv(pv); + else + return &PL_sv_undef; } else { - if ( hv_exists(MUTABLE_HV(vs), "qv", 2) ) - return VNORMAL(vs); - else - return VNUMIFY(vs); + if ( hv_exists(MUTABLE_HV(vs), "qv", 2) ) + return VNORMAL(vs); + else + return VNUMIFY(vs); } } /* =for apidoc vcmp -Version object aware cmp. Both operands must already have been +Version object aware cmp. Both operands must already have been converted into version objects. =cut @@ -1086,7 +1083,7 @@ Perl_vcmp(pTHX_ SV *lhv, SV *rhv) lhv = VVERIFY(lhv); rhv = VVERIFY(rhv); if ( ! ( lhv && rhv ) ) - Perl_croak(aTHX_ "Invalid version object"); + Perl_croak(aTHX_ "Invalid version object"); /* get the left hand term */ lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(lhv), "version", FALSE))); @@ -1101,40 +1098,40 @@ Perl_vcmp(pTHX_ SV *lhv, SV *rhv) i = 0; while ( i <= m && retval == 0 ) { - SV * const lsv = *av_fetch(lav,i,0); - SV * rsv; - left = SvIV(lsv); - rsv = *av_fetch(rav,i,0); - right = SvIV(rsv); - if ( left < right ) - retval = -1; - if ( left > right ) - retval = +1; - i++; + SV * const lsv = *av_fetch(lav,i,0); + SV * rsv; + left = SvIV(lsv); + rsv = *av_fetch(rav,i,0); + right = SvIV(rsv); + if ( left < right ) + retval = -1; + if ( left > right ) + retval = +1; + i++; } if ( l != r && retval == 0 ) /* possible match except for trailing 0's */ { - if ( l < r ) - { - while ( i <= r && retval == 0 ) - { - SV * const rsv = *av_fetch(rav,i,0); - if ( SvIV(rsv) != 0 ) - retval = -1; /* not a match after all */ - i++; - } - } - else - { - while ( i <= l && retval == 0 ) - { - SV * const lsv = *av_fetch(lav,i,0); - if ( SvIV(lsv) != 0 ) - retval = +1; /* not a match after all */ - i++; - } - } + if ( l < r ) + { + while ( i <= r && retval == 0 ) + { + SV * const rsv = *av_fetch(rav,i,0); + if ( SvIV(rsv) != 0 ) + retval = -1; /* not a match after all */ + i++; + } + } + else + { + while ( i <= l && retval == 0 ) + { + SV * const lsv = *av_fetch(lav,i,0); + if ( SvIV(lsv) != 0 ) + retval = +1; /* not a match after all */ + i++; + } + } } return retval; }