1 /* This file is part of the "version" CPAN distribution. Please avoid
2 editing it in the perl core. */
8 #define VERSION_MAX 0x7FFFFFFF
11 # define STRLENs(s) (sizeof("" s "") - 1)
13 #ifndef POSIX_SETLOCALE_LOCK
15 # define POSIX_SETLOCALE_LOCK gwLOCALE_LOCK
16 # define POSIX_SETLOCALE_UNLOCK gwLOCALE_UNLOCK
18 # define POSIX_SETLOCALE_LOCK NOOP
19 # define POSIX_SETLOCALE_UNLOCK NOOP
22 #ifndef DISABLE_LC_NUMERIC_CHANGES
23 # ifdef LOCK_LC_NUMERIC_STANDARD
24 # define DISABLE_LC_NUMERIC_CHANGES() LOCK_LC_NUMERIC_STANDARD()
25 # define REENABLE_LC_NUMERIC_CHANGES() UNLOCK_LC_NUMERIC_STANDARD()
27 # define DISABLE_LC_NUMERIC_CHANGES() NOOP
28 # define REENABLE_LC_NUMERIC_CHANGES() NOOP
33 =for apidoc prescan_version
35 Validate that a given string can be parsed as a version object, but doesn't
36 actually perform the parsing. Can use either strict or lax validation rules.
37 Can optionally set a number of hint variables to save the parsing code
38 some time when tokenizing.
43 #ifdef VUTIL_REPLACE_CORE
44 Perl_prescan_version2(pTHX_ const char *s, bool strict,
46 Perl_prescan_version(pTHX_ const char *s, bool strict,
49 bool *sqv, int *ssaw_decimal, int *swidth, bool *salpha) {
50 bool qv = (sqv ? *sqv : FALSE);
56 PERL_ARGS_ASSERT_PRESCAN_VERSION;
59 if (qv && isDIGIT(*d))
60 goto dotted_decimal_version;
62 if (*d == 'v') { /* explicit v-string */
67 else { /* degenerate v-string */
69 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
72 dotted_decimal_version:
73 if (strict && d[0] == '0' && isDIGIT(d[1])) {
74 /* no leading zeros allowed */
75 BADVERSION(s,errstr,"Invalid version format (no leading zeros)");
78 while (isDIGIT(*d)) /* integer part */
84 d++; /* decimal point */
90 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
93 goto version_prescan_finish;
100 while (isDIGIT(*d)) { /* just keep reading */
102 while (isDIGIT(*d)) {
104 /* maximum 3 digits between decimal */
105 if (strict && j > 3) {
106 BADVERSION(s,errstr,"Invalid version format (maximum 3 digits between decimals)");
111 BADVERSION(s,errstr,"Invalid version format (no underscores)");
114 BADVERSION(s,errstr,"Invalid version format (multiple underscores)");
119 else if (*d == '.') {
121 BADVERSION(s,errstr,"Invalid version format (underscores before decimal)");
126 else if (!isDIGIT(*d)) {
132 if (strict && i < 2) {
133 /* requires v1.2.3 */
134 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
137 } /* end if dotted-decimal */
139 { /* decimal versions */
140 int j = 0; /* may need this later */
141 /* special strict case for leading '.' or '0' */
144 BADVERSION(s,errstr,"Invalid version format (0 before decimal required)");
146 if (*d == '0' && isDIGIT(d[1])) {
147 BADVERSION(s,errstr,"Invalid version format (no leading zeros)");
151 /* and we never support negative versions */
153 BADVERSION(s,errstr,"Invalid version format (negative version number)");
156 /* consume all of the integer part */
160 /* look for a fractional part */
162 /* we found it, so consume it */
166 else if (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') {
169 BADVERSION(s,errstr,"Invalid version format (version required)");
171 /* found just an integer */
172 goto version_prescan_finish;
175 /* didn't find either integer or period */
176 BADVERSION(s,errstr,"Invalid version format (non-numeric data)");
178 else if (*d == '_') {
179 /* underscore can't come after integer part */
181 BADVERSION(s,errstr,"Invalid version format (no underscores)");
183 else if (isDIGIT(d[1])) {
184 BADVERSION(s,errstr,"Invalid version format (alpha without decimal)");
187 BADVERSION(s,errstr,"Invalid version format (misplaced underscore)");
191 /* anything else after integer part is just invalid data */
192 BADVERSION(s,errstr,"Invalid version format (non-numeric data)");
195 /* scan the fractional part after the decimal point*/
197 if (!isDIGIT(*d) && (strict || ! (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') )) {
198 /* strict or lax-but-not-the-end */
199 BADVERSION(s,errstr,"Invalid version format (fractional part required)");
202 while (isDIGIT(*d)) {
204 if (*d == '.' && isDIGIT(d[-1])) {
206 BADVERSION(s,errstr,"Invalid version format (underscores before decimal)");
209 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions must begin with 'v')");
211 d = (char *)s; /* start all over again */
213 goto dotted_decimal_version;
217 BADVERSION(s,errstr,"Invalid version format (no underscores)");
220 BADVERSION(s,errstr,"Invalid version format (multiple underscores)");
222 if ( ! isDIGIT(d[1]) ) {
223 BADVERSION(s,errstr,"Invalid version format (misplaced underscore)");
232 version_prescan_finish:
236 if (!isDIGIT(*d) && (! (!*d || *d == ';' || *d == ':' || *d == '{' || *d == '}') )) {
237 /* trailing non-numeric data */
238 BADVERSION(s,errstr,"Invalid version format (non-numeric data)");
240 if (saw_decimal > 1 && d[-1] == '.') {
241 /* no trailing period allowed */
242 BADVERSION(s,errstr,"Invalid version format (trailing decimal)");
251 *ssaw_decimal = saw_decimal;
258 =for apidoc scan_version
260 Returns a pointer to the next character after the parsed
261 version string, as well as upgrading the passed in SV to
264 Function must be called with an already existing SV like
267 s = scan_version(s, SV *sv, bool qv);
269 Performs some preprocessing to the string to ensure that
270 it has the correct characteristics of a version. Flags the
271 object if it contains an underscore (which denotes this
272 is an alpha version). The boolean qv denotes that the version
273 should be interpreted as if it had multiple decimals, even if
280 #ifdef VUTIL_REPLACE_CORE
281 Perl_scan_version2(pTHX_ const char *s, SV *rv, bool qv)
283 Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
286 const char *start = s;
289 const char *errstr = NULL;
297 PERL_ARGS_ASSERT_SCAN_VERSION;
299 while (isSPACE(*s)) /* leading whitespace is OK */
302 last = PRESCAN_VERSION(s, FALSE, &errstr, &qv, &saw_decimal, &width, &alpha);
304 /* "undef" is a special case and not an error */
305 if ( ! ( *s == 'u' && strEQ(s+1,"ndef")) ) {
306 Perl_croak(aTHX_ "%s", errstr);
315 /* Now that we are through the prescan, start creating the object */
317 hv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
318 (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */
320 #ifndef NODEFAULT_SHAREKEYS
321 HvSHAREKEYS_on(hv); /* key-sharing on by default */
325 (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(qv));
327 (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(alpha));
328 if ( !qv && width < 3 )
329 (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width));
331 while (isDIGIT(*pos) || *pos == '_')
333 if (!isALPHA(*pos)) {
339 /* this is atoi() that delimits on underscores */
340 const char *end = pos;
344 /* the following if() will only be true after the decimal
345 * point of a version originally created with a bare
346 * floating point number, i.e. not quoted in any way
348 if ( !qv && s > start && saw_decimal == 1 ) {
354 rev += (*s - '0') * mult;
356 if ( (PERL_ABS(orev) > PERL_ABS(rev))
357 || (PERL_ABS(rev) > VERSION_MAX )) {
358 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
359 "Integer overflow in version %d",VERSION_MAX);
375 if ( (mult == VERSION_MAX)
376 || (i > VERSION_MAX / mult)
377 || (i * mult > VERSION_MAX - rev))
379 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
380 "Integer overflow in version");
388 if (mult > VERSION_MAX / 10)
396 /* Append revision */
397 av_push(av, newSViv(rev));
402 else if ( *pos == '.' ) {
410 else if ( *pos == '_' && isDIGIT(pos[1]) )
412 else if ( *pos == ',' && isDIGIT(pos[1]) )
414 else if ( isDIGIT(*pos) )
421 while ( isDIGIT(*pos) || *pos == '_')
426 while ( ( isDIGIT(*pos) || *pos == '_' ) && digits < 3 ) {
434 if ( qv ) { /* quoted versions always get at least three terms*/
435 SSize_t len = AvFILLp(av);
436 /* This for loop appears to trigger a compiler bug on OS X, as it
437 loops infinitely. Yes, len is negative. No, it makes no sense.
438 Compiler in question is:
439 gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
440 for ( len = 2 - len; len > 0; len-- )
441 av_push(MUTABLE_AV(sv), newSViv(0));
445 av_push(av, newSViv(0));
448 /* need to save off the current version string for later */
450 SV * orig = newSVpvn("v.Inf", sizeof("v.Inf")-1);
451 (void)hv_stores(MUTABLE_HV(hv), "original", orig);
452 (void)hv_stores(MUTABLE_HV(hv), "vinf", newSViv(1));
454 else if ( s > start ) {
455 SV * orig = newSVpvn(start,s-start);
456 if ( qv && saw_decimal == 1 && *start != 'v' ) {
457 /* need to insert a v to be consistent */
458 sv_insert(orig, 0, 0, "v", 1);
460 (void)hv_stores(MUTABLE_HV(hv), "original", orig);
463 (void)hv_stores(MUTABLE_HV(hv), "original", newSVpvs("0"));
464 av_push(av, newSViv(0));
467 /* And finally, store the AV in the hash */
468 (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av)));
470 /* fix RT#19517 - special case 'undef' as string */
471 if ( *s == 'u' && strEQ(s+1,"ndef") ) {
479 =for apidoc new_version
481 Returns a new version object based on the passed in SV:
483 SV *sv = new_version(SV *ver);
485 Does not alter the passed in ver SV. See "upg_version" if you
486 want to upgrade the SV.
492 #ifdef VUTIL_REPLACE_CORE
493 Perl_new_version2(pTHX_ SV *ver)
495 Perl_new_version(pTHX_ SV *ver)
498 SV * const rv = newSV(0);
499 PERL_ARGS_ASSERT_NEW_VERSION;
500 if ( ISA_VERSION_OBJ(ver) ) /* can just copy directly */
503 AV * const av = newAV();
505 /* This will get reblessed later if a derived class*/
506 SV * const hv = newSVrv(rv, "version");
507 (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */
508 #ifndef NODEFAULT_SHAREKEYS
509 HvSHAREKEYS_on(hv); /* key-sharing on by default */
515 /* Begin copying all of the elements */
516 if ( hv_exists(MUTABLE_HV(ver), "qv", 2) )
517 (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(1));
519 if ( hv_exists(MUTABLE_HV(ver), "alpha", 5) )
520 (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(1));
522 SV ** svp = hv_fetchs(MUTABLE_HV(ver), "width", FALSE);
524 const I32 width = SvIV(*svp);
525 (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width));
529 SV ** svp = hv_fetchs(MUTABLE_HV(ver), "original", FALSE);
531 (void)hv_stores(MUTABLE_HV(hv), "original", newSVsv(*svp));
533 sav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(ver), "version", FALSE)));
534 /* This will get reblessed later if a derived class*/
535 for ( key = 0; key <= av_len(sav); key++ )
537 SV * const sv = *av_fetch(sav, key, FALSE);
538 const I32 rev = SvIV(sv);
539 av_push(av, newSViv(rev));
542 (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av)));
547 const MAGIC* const mg = SvVSTRING_mg(ver);
548 if ( mg ) { /* already a v-string */
549 const STRLEN len = mg->mg_len;
550 const char * const version = (const char*)mg->mg_ptr;
552 static const char underscore[] = "_";
553 sv_setpvn(rv,version,len);
554 raw = SvPV_nolen(rv);
555 under = ninstr(raw, raw+len, underscore, underscore + 1);
557 Move(under + 1, under, raw + len - under - 1, char);
558 SvCUR_set(rv, SvCUR(rv) - 1);
561 /* this is for consistency with the pure Perl class */
562 if ( isDIGIT(*version) )
563 sv_insert(rv, 0, 0, "v", 1);
567 SvSetSV_nosteal(rv, ver); /* make a duplicate */
572 sv_2mortal(rv); /* in case upg_version croaks before it returns */
573 return SvREFCNT_inc_NN(UPG_VERSION(rv, FALSE));
577 =for apidoc upg_version
579 In-place upgrade of the supplied SV to a version object.
581 SV *sv = upg_version(SV *sv, bool qv);
583 Returns a pointer to the upgraded SV. Set the boolean qv if you want
584 to force this SV to be interpreted as an "extended" version.
589 /* Macro to do the meat of getting the PV of an NV version number. This is
590 * macroized because can be called from several places */
591 #define GET_NUMERIC_VERSION(ver, sv, tbuf, buf, len) \
594 /* Prevent callees from trying to change the locale */ \
595 DISABLE_LC_NUMERIC_CHANGES(); \
597 /* We earlier created 'sv' for very large version numbers, to rely \
598 * on the specialized algorithms SV code has built-in for such \
601 Perl_sv_setpvf(aTHX_ sv, "%.9" NVff, SvNVX(ver)); \
606 len = my_snprintf(tbuf, sizeof(tbuf), "%.9" NVff, SvNVX(ver)); \
610 REENABLE_LC_NUMERIC_CHANGES(); \
614 #ifdef VUTIL_REPLACE_CORE
615 Perl_upg_version2(pTHX_ SV *ver, bool qv)
617 Perl_upg_version(pTHX_ SV *ver, bool qv)
620 const char *version, *s;
625 #if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS)
628 PERL_ARGS_ASSERT_UPG_VERSION;
630 if ( (SvUOK(ver) && SvUVX(ver) > VERSION_MAX)
631 || (SvIOK(ver) && SvIVX(ver) > VERSION_MAX) )
633 /* out of bounds [unsigned] integer */
636 len = my_snprintf(tbuf, sizeof(tbuf), "%d", VERSION_MAX);
637 version = savepvn(tbuf, len);
639 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
640 "Integer overflow in version %d",VERSION_MAX);
642 else if ( SvUOK(ver) || SvIOK(ver))
643 #if PERL_VERSION_LT(5,17,2)
647 version = savesvpv(ver);
650 else if (SvNOK(ver) && !( SvPOK(ver) && SvCUR(ver) == 3 ) )
651 #if PERL_VERSION_LT(5,17,2)
657 /* may get too much accuracy */
659 SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0;
662 #if PERL_VERSION_GE(5,19,0)
671 #ifdef USE_POSIX_2008_LOCALE
673 /* With POSIX 2008, all we have to do is toggle to the C locale
674 * just long enough to get the value (which should have a dot). */
675 const locale_t locale_obj_on_entry = uselocale(PL_C_locale_obj);
676 GET_NUMERIC_VERSION(ver, sv, tbuf, buf, len);
677 uselocale(locale_obj_on_entry);
679 /* Without POSIX 2008, it could be that toggling will zap another
680 * thread's locale. Avoid that if possible by looking at the NV and
681 * changing a non-dot radix into a dot */
684 unsigned int radix_len = 0;
686 GET_NUMERIC_VERSION(ver, sv, tbuf, buf, len);
688 # ifndef ARABIC_DECIMAL_SEPARATOR_UTF8
690 /* This becomes feasible since there are only very few possible
691 * radix characters in the world. khw knows of just 3 possible
692 * ones. If we are being compiled on a perl without the very rare
693 * third one, ARABIC DECIMAL SEPARATOR, just scan for the other
694 * two: FULL STOP (dot) and COMMA */
695 radix = strpbrk(buf, ".,");
700 /* Here, we have information about the third one; since it is
701 * multi-byte, it becomes a little more work. Scan for the dot,
702 * comma, or first byte of the arabic one */
705 ARABIC_DECIMAL_SEPARATOR_UTF8_FIRST_BYTE_s);
708 if (LIKELY( (* (U8 *) radix)
709 != ARABIC_DECIMAL_SEPARATOR_UTF8_FIRST_BYTE))
711 radix_len = 1; /* Dot and comma are length 1 */
715 /* Make sure that the rest of the bytes are what we expect
716 * for the remainder of the arabic radix. If not, we
717 * didn't find the radix. */
718 radix_len = STRLENs(ARABIC_DECIMAL_SEPARATOR_UTF8);
719 if ( radix + radix_len >= buf + len
721 STRLENs(ARABIC_DECIMAL_SEPARATOR_UTF8_TAIL),
722 ARABIC_DECIMAL_SEPARATOR_UTF8_TAIL))
732 /* Now convert any found radix into a dot (if not already). This
733 * effectively does: ver =~ s/radix/dot/ */
739 Move(radix + radix_len, /* from what follows the radix
741 radix + 1, /* to just after the new dot */
743 /* the number of bytes remaining, plus the NUL
745 len - (radix - buf) - radix_len + 1,
747 len -= radix_len - 1;
751 /* Guard against the very unlikely case that the radix is more
752 * than a single character, like ".."; that is, make sure the
753 * radix string we found above is the whole radix, and not just
754 * the prefix of a longer one. Success is indicated by it
755 * being at the end of the string, or the next byte should be a
757 if (radix < buf + len && ! inRANGE(radix[1], '0', '9')) {
765 /* If we couldn't find what the radix is, or didn't find it in
766 * the PV, resort to toggling the locale to one known to have a
767 * dot radix. This may or may not be called from code that has
768 * switched locales without letting perl know, therefore we
769 * have to find it from first principals. See [perl #121930].
772 # if ! defined(LC_NUMERIC) || ! defined(USE_LOCALE_NUMERIC)
774 Perl_croak(aTHX_ "panic: Unexpectedly didn't find a dot radix"
775 " character in '%s'", buf);
777 const char * locale_name_on_entry = NULL;
779 /* In windows, or not threaded, or not thread-safe, if it isn't
782 POSIX_SETLOCALE_LOCK; /* Start critical section */
784 locale_name_on_entry = setlocale(LC_NUMERIC, NULL);
785 if ( strEQ(locale_name_on_entry, "C")
786 || strEQ(locale_name_on_entry, "C.UTF-8")
787 || strEQ(locale_name_on_entry, "POSIX"))
789 /* No need to change the locale, since these all are known
790 * to have a dot radix. Change the variable to indicate to
791 * the restore code that nothing needs to be done */
792 locale_name_on_entry = NULL;
795 /* The setlocale() call might free or overwrite the name */
796 locale_name_on_entry = savepv(locale_name_on_entry);
797 setlocale(LC_NUMERIC, "C");
800 GET_NUMERIC_VERSION(ver, sv, tbuf, buf, len);
802 if (locale_name_on_entry) {
803 setlocale(LC_NUMERIC, locale_name_on_entry);
804 Safefree(locale_name_on_entry);
807 POSIX_SETLOCALE_UNLOCK; /* End critical section */
813 /* Strip trailing zero's from the version number */
814 while (buf[len-1] == '0' && len > 0) len--;
816 if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */
818 version = savepvn(buf, len);
823 else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */
824 version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
829 else if ( SvPOK(ver))/* must be a string or something like a string */
833 version = savepvn(SvPV(ver,len), SvCUR(ver));
836 /* This will only be executed for 5.6.0 - 5.8.0 inclusive */
837 if ( len >= 3 && !instr(version,".") && !instr(version,"_")) {
838 /* may be a v-string */
839 char *testv = (char *)version;
841 for (tlen=0; tlen < len; tlen++, testv++) {
842 /* if one of the characters is non-text assume v-string */
843 if (testv[0] < ' ') {
844 SV * const nsv = sv_newmortal();
848 sv_setpvf(nsv,"v%vd",ver);
849 pos = nver = savepv(SvPV_nolen(nsv));
852 /* scan the resulting formatted string */
853 pos++; /* skip the leading 'v' */
854 while ( *pos == '.' || isDIGIT(*pos) ) {
860 /* is definitely a v-string */
861 if ( saw_decimal >= 2 ) {
870 #if PERL_VERSION_LT(5,17,2)
871 else if (SvIOKp(ver)) {
874 else if (SvNOKp(ver)) {
877 else if (SvPOKp(ver)) {
883 /* no idea what this is */
884 Perl_croak(aTHX_ "Invalid version format (non-numeric data)");
887 s = SCAN_VERSION(version, ver, qv);
889 Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
890 "Version string '%s' contains invalid data; "
891 "ignoring: '%s'", version, s);
893 #if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS)
903 Validates that the SV contains valid internal structure for a version object.
904 It may be passed either the version object (RV) or the hash itself (HV). If
905 the structure is valid, it returns the HV. If the structure is invalid,
908 SV *hv = vverify(sv);
910 Note that it only confirms the bare minimum structure (so as not to get
911 confused by derived classes which may contain additional hash entries):
915 =item * The SV is an HV or a reference to an HV
917 =item * The hash contains a "version" key
919 =item * The "version" key has a reference to an AV as its value
927 #ifdef VUTIL_REPLACE_CORE
928 Perl_vverify2(pTHX_ SV *vs)
930 Perl_vverify(pTHX_ SV *vs)
936 PERL_ARGS_ASSERT_VVERIFY;
941 /* see if the appropriate elements exist */
942 if ( SvTYPE(vs) == SVt_PVHV
943 && (svp = hv_fetchs(MUTABLE_HV(vs), "version", FALSE))
945 && SvTYPE(sv) == SVt_PVAV )
954 Accepts a version object and returns the normalized floating
955 point representation. Call like:
959 NOTE: you can pass either the object directly or the SV
960 contained within the RV.
962 The SV returned has a refcount of 1.
968 #ifdef VUTIL_REPLACE_CORE
969 Perl_vnumify2(pTHX_ SV *vs)
971 Perl_vnumify(pTHX_ SV *vs)
980 PERL_ARGS_ASSERT_VNUMIFY;
982 /* extract the HV from the object */
985 Perl_croak(aTHX_ "Invalid version object");
987 /* see if various flags exist */
988 if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) )
992 Perl_ck_warner(aTHX_ packWARN(WARN_NUMERIC),
993 "alpha->numify() is lossy");
996 /* attempt to retrieve the version array */
997 if ( !(av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))) ) ) {
998 return newSVpvs("0");
1004 return newSVpvs("0");
1008 SV * tsv = *av_fetch(av, 0, 0);
1011 sv = Perl_newSVpvf(aTHX_ "%d.", (int)PERL_ABS(digit));
1012 for ( i = 1 ; i <= len ; i++ )
1014 SV * tsv = *av_fetch(av, i, 0);
1016 sv_catpvf(sv, "%03d", (int)digit);
1020 sv_catpvs(sv, "000");
1028 Accepts a version object and returns the normalized string
1029 representation. Call like:
1033 NOTE: you can pass either the object directly or the SV
1034 contained within the RV.
1036 The SV returned has a refcount of 1.
1042 #ifdef VUTIL_REPLACE_CORE
1043 Perl_vnormal2(pTHX_ SV *vs)
1045 Perl_vnormal(pTHX_ SV *vs)
1052 PERL_ARGS_ASSERT_VNORMAL;
1054 /* extract the HV from the object */
1057 Perl_croak(aTHX_ "Invalid version object");
1059 av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE)));
1064 return newSVpvs("");
1067 SV * tsv = *av_fetch(av, 0, 0);
1070 sv = Perl_newSVpvf(aTHX_ "v%" IVdf, (IV)digit);
1071 for ( i = 1 ; i <= len ; i++ ) {
1072 SV * tsv = *av_fetch(av, i, 0);
1074 sv_catpvf(sv, ".%" IVdf, (IV)digit);
1077 if ( len <= 2 ) { /* short version, must be at least three */
1078 for ( len = 2 - len; len != 0; len-- )
1085 =for apidoc vstringify
1087 In order to maintain maximum compatibility with earlier versions
1088 of Perl, this function will return either the floating point
1089 notation or the multiple dotted notation, depending on whether
1090 the original version contained 1 or more dots, respectively.
1092 The SV returned has a refcount of 1.
1098 #ifdef VUTIL_REPLACE_CORE
1099 Perl_vstringify2(pTHX_ SV *vs)
1101 Perl_vstringify(pTHX_ SV *vs)
1105 PERL_ARGS_ASSERT_VSTRINGIFY;
1107 /* extract the HV from the object */
1110 Perl_croak(aTHX_ "Invalid version object");
1112 svp = hv_fetchs(MUTABLE_HV(vs), "original", FALSE);
1117 #if PERL_VERSION_LT(5,17,2)
1123 return &PL_sv_undef;
1126 if ( hv_exists(MUTABLE_HV(vs), "qv", 2) )
1136 Version object aware cmp. Both operands must already have been
1137 converted into version objects.
1143 #ifdef VUTIL_REPLACE_CORE
1144 Perl_vcmp2(pTHX_ SV *lhv, SV *rhv)
1146 Perl_vcmp(pTHX_ SV *lhv, SV *rhv)
1155 PERL_ARGS_ASSERT_VCMP;
1157 /* extract the HVs from the objects */
1160 if ( ! ( lhv && rhv ) )
1161 Perl_croak(aTHX_ "Invalid version object");
1163 /* get the left hand term */
1164 lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(lhv), "version", FALSE)));
1166 /* and the right hand term */
1167 rav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(rhv), "version", FALSE)));
1174 while ( i <= m && retval == 0 )
1176 SV * const lsv = *av_fetch(lav,i,0);
1179 rsv = *av_fetch(rav,i,0);
1188 if ( l != r && retval == 0 ) /* possible match except for trailing 0's */
1192 while ( i <= r && retval == 0 )
1194 SV * const rsv = *av_fetch(rav,i,0);
1195 if ( SvIV(rsv) != 0 )
1196 retval = -1; /* not a match after all */
1202 while ( i <= l && retval == 0 )
1204 SV * const lsv = *av_fetch(lav,i,0);
1205 if ( SvIV(lsv) != 0 )
1206 retval = +1; /* not a match after all */