1 /* This file is part of the "version" CPAN distribution. Please avoid 2 editing it in the perl core. */ 3 4 #ifndef PERL_CORE 5 # define PERL_NO_GET_CONTEXT 6 # include "EXTERN.h" 7 # include "perl.h" 8 # include "XSUB.h" 9 # define NEED_my_snprintf 10 # define NEED_newRV_noinc 11 # define NEED_vnewSVpvf 12 # define NEED_newSVpvn_flags_GLOBAL 13 # define NEED_warner 14 # include "ppport.h" 15 #endif 16 #include "vutil.h" 17 18 #define VERSION_MAX 0x7FFFFFFF 19 20 /* 21 =for apidoc prescan_version 22 23 Validate that a given string can be parsed as a version object, but doesn't 24 actually perform the parsing. Can use either strict or lax validation rules. 25 Can optionally set a number of hint variables to save the parsing code 26 some time when tokenizing. 27 28 =cut 29 */ 30 const char * 31 #ifdef VUTIL_REPLACE_CORE 32 Perl_prescan_version2(pTHX_ const char *s, bool strict, 33 #else 34 Perl_prescan_version(pTHX_ const char *s, bool strict, 35 #endif 36 const char **errstr, 37 bool *sqv, int *ssaw_decimal, int *swidth, bool *salpha) { 38 bool qv = (sqv ? *sqv : FALSE); 39 int width = 3; 40 int saw_decimal = 0; 41 bool alpha = FALSE; 42 const char *d = s; 43 44 PERL_ARGS_ASSERT_PRESCAN_VERSION; 45 46 if (qv && isDIGIT(*d)) 47 goto dotted_decimal_version; 48 49 if (*d == 'v') { /* explicit v-string */ 50 d++; 51 if (isDIGIT(*d)) { 52 qv = TRUE; 53 } 54 else { /* degenerate v-string */ 55 /* requires v1.2.3 */ 56 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); 57 } 58 59 dotted_decimal_version: 60 if (strict && d[0] == '0' && isDIGIT(d[1])) { 61 /* no leading zeros allowed */ 62 BADVERSION(s,errstr,"Invalid version format (no leading zeros)"); 63 } 64 65 while (isDIGIT(*d)) /* integer part */ 66 d++; 67 68 if (*d == '.') 69 { 70 saw_decimal++; 71 d++; /* decimal point */ 72 } 73 else 74 { 75 if (strict) { 76 /* require v1.2.3 */ 77 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); 78 } 79 else { 80 goto version_prescan_finish; 81 } 82 } 83 84 { 85 int i = 0; 86 int j = 0; 87 while (isDIGIT(*d)) { /* just keep reading */ 88 i++; 89 while (isDIGIT(*d)) { 90 d++; j++; 91 /* maximum 3 digits between decimal */ 92 if (strict && j > 3) { 93 BADVERSION(s,errstr,"Invalid version format (maximum 3 digits between decimals)"); 94 } 95 } 96 if (*d == '_') { 97 if (strict) { 98 BADVERSION(s,errstr,"Invalid version format (no underscores)"); 99 } 100 if ( alpha ) { 101 BADVERSION(s,errstr,"Invalid version format (multiple underscores)"); 102 } 103 d++; 104 alpha = TRUE; 105 } 106 else if (*d == '.') { 107 if (alpha) { 108 BADVERSION(s,errstr,"Invalid version format (underscores before decimal)"); 109 } 110 saw_decimal++; 111 d++; 112 } 113 else if (!isDIGIT(*d)) { 114 break; 115 } 116 j = 0; 117 } 118 119 if (strict && i < 2) { 120 /* requires v1.2.3 */ 121 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)"); 122 } 123 } 124 } /* end if dotted-decimal */ 125 else 126 { /* decimal versions */ 127 int j = 0; /* may need this later */ 128 /* special strict case for leading '.' or '0' */ 129 if (strict) { 130 if (*d == '.') { 131 BADVERSION(s,errstr,"Invalid version format (0 before decimal required)"); 132 } 133 if (*d == '0' && isDIGIT(d[1])) { 134 BADVERSION(s,errstr,"Invalid version format (no leading zeros)"); 135 } 136 } 137 138 /* and we never support negative versions */ 139 if ( *d == '-') { 140 BADVERSION(s,errstr,"Invalid version format (negative version number)"); 141 } 142 143 /* consume all of the integer part */ 144 while (isDIGIT(*d)) 145 d++; 146 147 /* look for a fractional part */ 148 if (*d == '.') { 149 /* we found it, so consume it */ 150 saw_decimal++; 151 d++; 152 } 153 else if (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') { 154 if ( d == s ) { 155 /* found nothing */ 156 BADVERSION(s,errstr,"Invalid version format (version required)"); 157 } 158 /* found just an integer */ 159 goto version_prescan_finish; 160 } 161 else if ( d == s ) { 162 /* didn't find either integer or period */ 163 BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); 164 } 165 else if (*d == '_') { 166 /* underscore can't come after integer part */ 167 if (strict) { 168 BADVERSION(s,errstr,"Invalid version format (no underscores)"); 169 } 170 else if (isDIGIT(d[1])) { 171 BADVERSION(s,errstr,"Invalid version format (alpha without decimal)"); 172 } 173 else { 174 BADVERSION(s,errstr,"Invalid version format (misplaced underscore)"); 175 } 176 } 177 else { 178 /* anything else after integer part is just invalid data */ 179 BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); 180 } 181 182 /* scan the fractional part after the decimal point*/ 183 184 if (!isDIGIT(*d) && (strict || ! (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') )) { 185 /* strict or lax-but-not-the-end */ 186 BADVERSION(s,errstr,"Invalid version format (fractional part required)"); 187 } 188 189 while (isDIGIT(*d)) { 190 d++; j++; 191 if (*d == '.' && isDIGIT(d[-1])) { 192 if (alpha) { 193 BADVERSION(s,errstr,"Invalid version format (underscores before decimal)"); 194 } 195 if (strict) { 196 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions must begin with 'v')"); 197 } 198 d = (char *)s; /* start all over again */ 199 qv = TRUE; 200 goto dotted_decimal_version; 201 } 202 if (*d == '_') { 203 if (strict) { 204 BADVERSION(s,errstr,"Invalid version format (no underscores)"); 205 } 206 if ( alpha ) { 207 BADVERSION(s,errstr,"Invalid version format (multiple underscores)"); 208 } 209 if ( ! isDIGIT(d[1]) ) { 210 BADVERSION(s,errstr,"Invalid version format (misplaced underscore)"); 211 } 212 width = j; 213 d++; 214 alpha = TRUE; 215 } 216 } 217 } 218 219 version_prescan_finish: 220 while (isSPACE(*d)) 221 d++; 222 223 if (!isDIGIT(*d) && (! (!*d || *d == ';' || *d == '{' || *d == '}') )) { 224 /* trailing non-numeric data */ 225 BADVERSION(s,errstr,"Invalid version format (non-numeric data)"); 226 } 227 228 if (sqv) 229 *sqv = qv; 230 if (swidth) 231 *swidth = width; 232 if (ssaw_decimal) 233 *ssaw_decimal = saw_decimal; 234 if (salpha) 235 *salpha = alpha; 236 return d; 237 } 238 239 /* 240 =for apidoc scan_version 241 242 Returns a pointer to the next character after the parsed 243 version string, as well as upgrading the passed in SV to 244 an RV. 245 246 Function must be called with an already existing SV like 247 248 sv = newSV(0); 249 s = scan_version(s, SV *sv, bool qv); 250 251 Performs some preprocessing to the string to ensure that 252 it has the correct characteristics of a version. Flags the 253 object if it contains an underscore (which denotes this 254 is an alpha version). The boolean qv denotes that the version 255 should be interpreted as if it had multiple decimals, even if 256 it doesn't. 257 258 =cut 259 */ 260 261 const char * 262 #ifdef VUTIL_REPLACE_CORE 263 Perl_scan_version2(pTHX_ const char *s, SV *rv, bool qv) 264 #else 265 Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) 266 #endif 267 { 268 const char *start = s; 269 const char *pos; 270 const char *last; 271 const char *errstr = NULL; 272 int saw_decimal = 0; 273 int width = 3; 274 bool alpha = FALSE; 275 bool vinf = FALSE; 276 AV * av; 277 SV * hv; 278 279 PERL_ARGS_ASSERT_SCAN_VERSION; 280 281 while (isSPACE(*s)) /* leading whitespace is OK */ 282 s++; 283 284 last = PRESCAN_VERSION(s, FALSE, &errstr, &qv, &saw_decimal, &width, &alpha); 285 if (errstr) { 286 /* "undef" is a special case and not an error */ 287 if ( ! ( *s == 'u' && strEQ(s+1,"ndef")) ) { 288 Perl_croak(aTHX_ "%s", errstr); 289 } 290 } 291 292 start = s; 293 if (*s == 'v') 294 s++; 295 pos = s; 296 297 /* Now that we are through the prescan, start creating the object */ 298 av = newAV(); 299 hv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */ 300 (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */ 301 302 #ifndef NODEFAULT_SHAREKEYS 303 HvSHAREKEYS_on(hv); /* key-sharing on by default */ 304 #endif 305 306 if ( qv ) 307 (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(qv)); 308 if ( alpha ) 309 (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(alpha)); 310 if ( !qv && width < 3 ) 311 (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width)); 312 313 while (isDIGIT(*pos)) 314 pos++; 315 if (!isALPHA(*pos)) { 316 I32 rev; 317 318 for (;;) { 319 rev = 0; 320 { 321 /* this is atoi() that delimits on underscores */ 322 const char *end = pos; 323 I32 mult = 1; 324 I32 orev; 325 326 /* the following if() will only be true after the decimal 327 * point of a version originally created with a bare 328 * floating point number, i.e. not quoted in any way 329 */ 330 if ( !qv && s > start && saw_decimal == 1 ) { 331 mult *= 100; 332 while ( s < end ) { 333 orev = rev; 334 rev += (*s - '0') * mult; 335 mult /= 10; 336 if ( (PERL_ABS(orev) > PERL_ABS(rev)) 337 || (PERL_ABS(rev) > VERSION_MAX )) { 338 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), 339 "Integer overflow in version %d",VERSION_MAX); 340 s = end - 1; 341 rev = VERSION_MAX; 342 vinf = 1; 343 } 344 s++; 345 if ( *s == '_' ) 346 s++; 347 } 348 } 349 else { 350 while (--end >= s) { 351 orev = rev; 352 rev += (*end - '0') * mult; 353 mult *= 10; 354 if ( (PERL_ABS(orev) > PERL_ABS(rev)) 355 || (PERL_ABS(rev) > VERSION_MAX )) { 356 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), 357 "Integer overflow in version"); 358 end = s - 1; 359 rev = VERSION_MAX; 360 vinf = 1; 361 } 362 } 363 } 364 } 365 366 /* Append revision */ 367 av_push(av, newSViv(rev)); 368 if ( vinf ) { 369 s = last; 370 break; 371 } 372 else if ( *pos == '.' ) 373 s = ++pos; 374 else if ( *pos == '_' && isDIGIT(pos[1]) ) 375 s = ++pos; 376 else if ( *pos == ',' && isDIGIT(pos[1]) ) 377 s = ++pos; 378 else if ( isDIGIT(*pos) ) 379 s = pos; 380 else { 381 s = pos; 382 break; 383 } 384 if ( qv ) { 385 while ( isDIGIT(*pos) ) 386 pos++; 387 } 388 else { 389 int digits = 0; 390 while ( ( isDIGIT(*pos) || *pos == '_' ) && digits < 3 ) { 391 if ( *pos != '_' ) 392 digits++; 393 pos++; 394 } 395 } 396 } 397 } 398 if ( qv ) { /* quoted versions always get at least three terms*/ 399 SSize_t len = AvFILLp(av); 400 /* This for loop appears to trigger a compiler bug on OS X, as it 401 loops infinitely. Yes, len is negative. No, it makes no sense. 402 Compiler in question is: 403 gcc version 3.3 20030304 (Apple Computer, Inc. build 1640) 404 for ( len = 2 - len; len > 0; len-- ) 405 av_push(MUTABLE_AV(sv), newSViv(0)); 406 */ 407 len = 2 - len; 408 while (len-- > 0) 409 av_push(av, newSViv(0)); 410 } 411 412 /* need to save off the current version string for later */ 413 if ( vinf ) { 414 SV * orig = newSVpvn("v.Inf", sizeof("v.Inf")-1); 415 (void)hv_stores(MUTABLE_HV(hv), "original", orig); 416 (void)hv_stores(MUTABLE_HV(hv), "vinf", newSViv(1)); 417 } 418 else if ( s > start ) { 419 SV * orig = newSVpvn(start,s-start); 420 if ( qv && saw_decimal == 1 && *start != 'v' ) { 421 /* need to insert a v to be consistent */ 422 sv_insert(orig, 0, 0, "v", 1); 423 } 424 (void)hv_stores(MUTABLE_HV(hv), "original", orig); 425 } 426 else { 427 (void)hv_stores(MUTABLE_HV(hv), "original", newSVpvs("0")); 428 av_push(av, newSViv(0)); 429 } 430 431 /* And finally, store the AV in the hash */ 432 (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av))); 433 434 /* fix RT#19517 - special case 'undef' as string */ 435 if ( *s == 'u' && strEQ(s+1,"ndef") ) { 436 s += 5; 437 } 438 439 return s; 440 } 441 442 /* 443 =for apidoc new_version 444 445 Returns a new version object based on the passed in SV: 446 447 SV *sv = new_version(SV *ver); 448 449 Does not alter the passed in ver SV. See "upg_version" if you 450 want to upgrade the SV. 451 452 =cut 453 */ 454 455 SV * 456 #ifdef VUTIL_REPLACE_CORE 457 Perl_new_version2(pTHX_ SV *ver) 458 #else 459 Perl_new_version(pTHX_ SV *ver) 460 #endif 461 { 462 dVAR; 463 SV * const rv = newSV(0); 464 PERL_ARGS_ASSERT_NEW_VERSION; 465 if ( ISA_VERSION_OBJ(ver) ) /* can just copy directly */ 466 { 467 SSize_t key; 468 AV * const av = newAV(); 469 AV *sav; 470 /* This will get reblessed later if a derived class*/ 471 SV * const hv = newSVrv(rv, "version"); 472 (void)sv_upgrade(hv, SVt_PVHV); /* needs to be an HV type */ 473 #ifndef NODEFAULT_SHAREKEYS 474 HvSHAREKEYS_on(hv); /* key-sharing on by default */ 475 #endif 476 477 if ( SvROK(ver) ) 478 ver = SvRV(ver); 479 480 /* Begin copying all of the elements */ 481 if ( hv_exists(MUTABLE_HV(ver), "qv", 2) ) 482 (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(1)); 483 484 if ( hv_exists(MUTABLE_HV(ver), "alpha", 5) ) 485 (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(1)); 486 { 487 SV ** svp = hv_fetchs(MUTABLE_HV(ver), "width", FALSE); 488 if(svp) { 489 const I32 width = SvIV(*svp); 490 (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width)); 491 } 492 } 493 { 494 SV ** svp = hv_fetchs(MUTABLE_HV(ver), "original", FALSE); 495 if(svp) 496 (void)hv_stores(MUTABLE_HV(hv), "original", newSVsv(*svp)); 497 } 498 sav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(ver), "version", FALSE))); 499 /* This will get reblessed later if a derived class*/ 500 for ( key = 0; key <= av_len(sav); key++ ) 501 { 502 SV * const sv = *av_fetch(sav, key, FALSE); 503 const I32 rev = SvIV(sv); 504 av_push(av, newSViv(rev)); 505 } 506 507 (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av))); 508 return rv; 509 } 510 #ifdef SvVOK 511 { 512 const MAGIC* const mg = SvVSTRING_mg(ver); 513 if ( mg ) { /* already a v-string */ 514 const STRLEN len = mg->mg_len; 515 const char * const version = (const char*)mg->mg_ptr; 516 sv_setpvn(rv,version,len); 517 /* this is for consistency with the pure Perl class */ 518 if ( isDIGIT(*version) ) 519 sv_insert(rv, 0, 0, "v", 1); 520 } 521 else { 522 #endif 523 SvSetSV_nosteal(rv, ver); /* make a duplicate */ 524 #ifdef SvVOK 525 } 526 } 527 #endif 528 sv_2mortal(rv); /* in case upg_version croaks before it returns */ 529 return SvREFCNT_inc_NN(UPG_VERSION(rv, FALSE)); 530 } 531 532 /* 533 =for apidoc upg_version 534 535 In-place upgrade of the supplied SV to a version object. 536 537 SV *sv = upg_version(SV *sv, bool qv); 538 539 Returns a pointer to the upgraded SV. Set the boolean qv if you want 540 to force this SV to be interpreted as an "extended" version. 541 542 =cut 543 */ 544 545 SV * 546 #ifdef VUTIL_REPLACE_CORE 547 Perl_upg_version2(pTHX_ SV *ver, bool qv) 548 #else 549 Perl_upg_version(pTHX_ SV *ver, bool qv) 550 #endif 551 { 552 const char *version, *s; 553 #ifdef SvVOK 554 const MAGIC *mg; 555 #endif 556 557 #if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS) 558 ENTER; 559 #endif 560 PERL_ARGS_ASSERT_UPG_VERSION; 561 562 if ( (SvUOK(ver) && SvUVX(ver) > VERSION_MAX) 563 || (SvIOK(ver) && SvIVX(ver) > VERSION_MAX) ) { 564 /* out of bounds [unsigned] integer */ 565 STRLEN len; 566 char tbuf[64]; 567 len = my_snprintf(tbuf, sizeof(tbuf), "%d", VERSION_MAX); 568 version = savepvn(tbuf, len); 569 SAVEFREEPV(version); 570 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW), 571 "Integer overflow in version %d",VERSION_MAX); 572 } 573 else if ( SvUOK(ver) || SvIOK(ver)) 574 #if PERL_VERSION_LT(5,17,2) 575 VER_IV: 576 #endif 577 { 578 version = savesvpv(ver); 579 SAVEFREEPV(version); 580 } 581 else if (SvNOK(ver) && !( SvPOK(ver) && SvCUR(ver) == 3 ) ) 582 #if PERL_VERSION_LT(5,17,2) 583 VER_NV: 584 #endif 585 { 586 STRLEN len; 587 588 /* may get too much accuracy */ 589 char tbuf[64]; 590 SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0; 591 char *buf; 592 #ifdef USE_LOCALE_NUMERIC 593 const char * const cur_numeric = setlocale(LC_NUMERIC, NULL); 594 assert(cur_numeric); 595 596 /* XS code can set the locale without us knowing. To protect the 597 * version number parsing, which requires the radix character to be a 598 * dot, update our records as to what the locale is, so that our 599 * existing macro mechanism can correctly change it to a dot and back 600 * if necessary. This code is extremely unlikely to be in a loop, so 601 * the extra work will have a negligible performance impact. See [perl 602 * #121930]. 603 * 604 * If the current locale is a standard one, but we are expecting it to 605 * be a different, underlying locale, update our records to make the 606 * underlying locale this (standard) one. If the current locale is not 607 * a standard one, we should be expecting a non-standard one, the same 608 * one that we have recorded as the underlying locale. If not, update 609 * our records. */ 610 if (strEQ(cur_numeric, "C") || strEQ(cur_numeric, "POSIX")) { 611 if (! PL_numeric_standard) { 612 new_numeric(cur_numeric); 613 } 614 } 615 else if (PL_numeric_standard 616 || ! PL_numeric_name 617 || strNE(PL_numeric_name, cur_numeric)) 618 { 619 new_numeric(cur_numeric); 620 } 621 #endif 622 { /* Braces needed because macro just below declares a variable */ 623 STORE_NUMERIC_LOCAL_SET_STANDARD(); 624 if (sv) { 625 Perl_sv_catpvf(aTHX_ sv, "%.9"NVff, SvNVX(ver)); 626 len = SvCUR(sv); 627 buf = SvPVX(sv); 628 } 629 else { 630 len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver)); 631 buf = tbuf; 632 } 633 RESTORE_NUMERIC_LOCAL(); 634 } 635 while (buf[len-1] == '0' && len > 0) len--; 636 if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */ 637 version = savepvn(buf, len); 638 SAVEFREEPV(version); 639 SvREFCNT_dec(sv); 640 } 641 #ifdef SvVOK 642 else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */ 643 version = savepvn( (const char*)mg->mg_ptr,mg->mg_len ); 644 SAVEFREEPV(version); 645 qv = TRUE; 646 } 647 #endif 648 else if ( SvPOK(ver))/* must be a string or something like a string */ 649 #if PERL_VERSION_LT(5,17,2) 650 VER_PV: 651 #endif 652 { 653 STRLEN len; 654 version = savepvn(SvPV(ver,len), SvCUR(ver)); 655 SAVEFREEPV(version); 656 #ifndef SvVOK 657 # if PERL_VERSION > 5 658 /* This will only be executed for 5.6.0 - 5.8.0 inclusive */ 659 if ( len >= 3 && !instr(version,".") && !instr(version,"_")) { 660 /* may be a v-string */ 661 char *testv = (char *)version; 662 STRLEN tlen = len; 663 for (tlen=0; tlen < len; tlen++, testv++) { 664 /* if one of the characters is non-text assume v-string */ 665 if (testv[0] < ' ') { 666 SV * const nsv = sv_newmortal(); 667 const char *nver; 668 const char *pos; 669 int saw_decimal = 0; 670 sv_setpvf(nsv,"v%vd",ver); 671 pos = nver = savepv(SvPV_nolen(nsv)); 672 SAVEFREEPV(pos); 673 674 /* scan the resulting formatted string */ 675 pos++; /* skip the leading 'v' */ 676 while ( *pos == '.' || isDIGIT(*pos) ) { 677 if ( *pos == '.' ) 678 saw_decimal++ ; 679 pos++; 680 } 681 682 /* is definitely a v-string */ 683 if ( saw_decimal >= 2 ) { 684 version = nver; 685 } 686 break; 687 } 688 } 689 } 690 # endif 691 #endif 692 } 693 #if PERL_VERSION_LT(5,17,2) 694 else if (SvIOKp(ver)) { 695 goto VER_IV; 696 } 697 else if (SvNOKp(ver)) { 698 goto VER_NV; 699 } 700 else if (SvPOKp(ver)) { 701 goto VER_PV; 702 } 703 #endif 704 else 705 { 706 /* no idea what this is */ 707 Perl_croak(aTHX_ "Invalid version format (non-numeric data)"); 708 } 709 710 s = SCAN_VERSION(version, ver, qv); 711 if ( *s != '\0' ) 712 Perl_ck_warner(aTHX_ packWARN(WARN_MISC), 713 "Version string '%s' contains invalid data; " 714 "ignoring: '%s'", version, s); 715 716 #if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS) 717 LEAVE; 718 #endif 719 720 return ver; 721 } 722 723 /* 724 =for apidoc vverify 725 726 Validates that the SV contains valid internal structure for a version object. 727 It may be passed either the version object (RV) or the hash itself (HV). If 728 the structure is valid, it returns the HV. If the structure is invalid, 729 it returns NULL. 730 731 SV *hv = vverify(sv); 732 733 Note that it only confirms the bare minimum structure (so as not to get 734 confused by derived classes which may contain additional hash entries): 735 736 =over 4 737 738 =item * The SV is an HV or a reference to an HV 739 740 =item * The hash contains a "version" key 741 742 =item * The "version" key has a reference to an AV as its value 743 744 =back 745 746 =cut 747 */ 748 749 SV * 750 #ifdef VUTIL_REPLACE_CORE 751 Perl_vverify2(pTHX_ SV *vs) 752 #else 753 Perl_vverify(pTHX_ SV *vs) 754 #endif 755 { 756 SV *sv; 757 SV **svp; 758 759 PERL_ARGS_ASSERT_VVERIFY; 760 761 if ( SvROK(vs) ) 762 vs = SvRV(vs); 763 764 /* see if the appropriate elements exist */ 765 if ( SvTYPE(vs) == SVt_PVHV 766 && (svp = hv_fetchs(MUTABLE_HV(vs), "version", FALSE)) 767 && (sv = SvRV(*svp)) 768 && SvTYPE(sv) == SVt_PVAV ) 769 return vs; 770 else 771 return NULL; 772 } 773 774 /* 775 =for apidoc vnumify 776 777 Accepts a version object and returns the normalized floating 778 point representation. Call like: 779 780 sv = vnumify(rv); 781 782 NOTE: you can pass either the object directly or the SV 783 contained within the RV. 784 785 The SV returned has a refcount of 1. 786 787 =cut 788 */ 789 790 SV * 791 #ifdef VUTIL_REPLACE_CORE 792 Perl_vnumify2(pTHX_ SV *vs) 793 #else 794 Perl_vnumify(pTHX_ SV *vs) 795 #endif 796 { 797 SSize_t i, len; 798 I32 digit; 799 int width; 800 bool alpha = FALSE; 801 SV *sv; 802 AV *av; 803 804 PERL_ARGS_ASSERT_VNUMIFY; 805 806 /* extract the HV from the object */ 807 vs = VVERIFY(vs); 808 if ( ! vs ) 809 Perl_croak(aTHX_ "Invalid version object"); 810 811 /* see if various flags exist */ 812 if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) ) 813 alpha = TRUE; 814 { 815 SV ** svp = hv_fetchs(MUTABLE_HV(vs), "width", FALSE); 816 if ( svp ) 817 width = SvIV(*svp); 818 else 819 width = 3; 820 } 821 822 823 /* attempt to retrieve the version array */ 824 if ( !(av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))) ) ) { 825 return newSVpvs("0"); 826 } 827 828 len = av_len(av); 829 if ( len == -1 ) 830 { 831 return newSVpvs("0"); 832 } 833 834 { 835 SV * tsv = *av_fetch(av, 0, 0); 836 digit = SvIV(tsv); 837 } 838 sv = Perl_newSVpvf(aTHX_ "%d.", (int)PERL_ABS(digit)); 839 for ( i = 1 ; i < len ; i++ ) 840 { 841 SV * tsv = *av_fetch(av, i, 0); 842 digit = SvIV(tsv); 843 if ( width < 3 ) { 844 const int denom = (width == 2 ? 10 : 100); 845 const div_t term = div((int)PERL_ABS(digit),denom); 846 Perl_sv_catpvf(aTHX_ sv, "%0*d_%d", width, term.quot, term.rem); 847 } 848 else { 849 Perl_sv_catpvf(aTHX_ sv, "%0*d", width, (int)digit); 850 } 851 } 852 853 if ( len > 0 ) 854 { 855 SV * tsv = *av_fetch(av, len, 0); 856 digit = SvIV(tsv); 857 if ( alpha && width == 3 ) /* alpha version */ 858 sv_catpvs(sv,"_"); 859 Perl_sv_catpvf(aTHX_ sv, "%0*d", width, (int)digit); 860 } 861 else /* len == 0 */ 862 { 863 sv_catpvs(sv, "000"); 864 } 865 return sv; 866 } 867 868 /* 869 =for apidoc vnormal 870 871 Accepts a version object and returns the normalized string 872 representation. Call like: 873 874 sv = vnormal(rv); 875 876 NOTE: you can pass either the object directly or the SV 877 contained within the RV. 878 879 The SV returned has a refcount of 1. 880 881 =cut 882 */ 883 884 SV * 885 #ifdef VUTIL_REPLACE_CORE 886 Perl_vnormal2(pTHX_ SV *vs) 887 #else 888 Perl_vnormal(pTHX_ SV *vs) 889 #endif 890 { 891 I32 i, len, digit; 892 bool alpha = FALSE; 893 SV *sv; 894 AV *av; 895 896 PERL_ARGS_ASSERT_VNORMAL; 897 898 /* extract the HV from the object */ 899 vs = VVERIFY(vs); 900 if ( ! vs ) 901 Perl_croak(aTHX_ "Invalid version object"); 902 903 if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) ) 904 alpha = TRUE; 905 av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))); 906 907 len = av_len(av); 908 if ( len == -1 ) 909 { 910 return newSVpvs(""); 911 } 912 { 913 SV * tsv = *av_fetch(av, 0, 0); 914 digit = SvIV(tsv); 915 } 916 sv = Perl_newSVpvf(aTHX_ "v%"IVdf, (IV)digit); 917 for ( i = 1 ; i < len ; i++ ) { 918 SV * tsv = *av_fetch(av, i, 0); 919 digit = SvIV(tsv); 920 Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit); 921 } 922 923 if ( len > 0 ) 924 { 925 /* handle last digit specially */ 926 SV * tsv = *av_fetch(av, len, 0); 927 digit = SvIV(tsv); 928 if ( alpha ) 929 Perl_sv_catpvf(aTHX_ sv, "_%"IVdf, (IV)digit); 930 else 931 Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit); 932 } 933 934 if ( len <= 2 ) { /* short version, must be at least three */ 935 for ( len = 2 - len; len != 0; len-- ) 936 sv_catpvs(sv,".0"); 937 } 938 return sv; 939 } 940 941 /* 942 =for apidoc vstringify 943 944 In order to maintain maximum compatibility with earlier versions 945 of Perl, this function will return either the floating point 946 notation or the multiple dotted notation, depending on whether 947 the original version contained 1 or more dots, respectively. 948 949 The SV returned has a refcount of 1. 950 951 =cut 952 */ 953 954 SV * 955 #ifdef VUTIL_REPLACE_CORE 956 Perl_vstringify2(pTHX_ SV *vs) 957 #else 958 Perl_vstringify(pTHX_ SV *vs) 959 #endif 960 { 961 SV ** svp; 962 PERL_ARGS_ASSERT_VSTRINGIFY; 963 964 /* extract the HV from the object */ 965 vs = VVERIFY(vs); 966 if ( ! vs ) 967 Perl_croak(aTHX_ "Invalid version object"); 968 969 svp = hv_fetchs(MUTABLE_HV(vs), "original", FALSE); 970 if (svp) { 971 SV *pv; 972 pv = *svp; 973 if ( SvPOK(pv) ) 974 return newSVsv(pv); 975 else 976 return &PL_sv_undef; 977 } 978 else { 979 if ( hv_exists(MUTABLE_HV(vs), "qv", 2) ) 980 return VNORMAL(vs); 981 else 982 return VNUMIFY(vs); 983 } 984 } 985 986 /* 987 =for apidoc vcmp 988 989 Version object aware cmp. Both operands must already have been 990 converted into version objects. 991 992 =cut 993 */ 994 995 int 996 #ifdef VUTIL_REPLACE_CORE 997 Perl_vcmp2(pTHX_ SV *lhv, SV *rhv) 998 #else 999 Perl_vcmp(pTHX_ SV *lhv, SV *rhv) 1000 #endif 1001 { 1002 SSize_t i,l,m,r; 1003 I32 retval; 1004 bool lalpha = FALSE; 1005 bool ralpha = FALSE; 1006 I32 left = 0; 1007 I32 right = 0; 1008 AV *lav, *rav; 1009 1010 PERL_ARGS_ASSERT_VCMP; 1011 1012 /* extract the HVs from the objects */ 1013 lhv = VVERIFY(lhv); 1014 rhv = VVERIFY(rhv); 1015 if ( ! ( lhv && rhv ) ) 1016 Perl_croak(aTHX_ "Invalid version object"); 1017 1018 /* get the left hand term */ 1019 lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(lhv), "version", FALSE))); 1020 if ( hv_exists(MUTABLE_HV(lhv), "alpha", 5 ) ) 1021 lalpha = TRUE; 1022 1023 /* and the right hand term */ 1024 rav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(rhv), "version", FALSE))); 1025 if ( hv_exists(MUTABLE_HV(rhv), "alpha", 5 ) ) 1026 ralpha = TRUE; 1027 1028 l = av_len(lav); 1029 r = av_len(rav); 1030 m = l < r ? l : r; 1031 retval = 0; 1032 i = 0; 1033 while ( i <= m && retval == 0 ) 1034 { 1035 SV * const lsv = *av_fetch(lav,i,0); 1036 SV * rsv; 1037 left = SvIV(lsv); 1038 rsv = *av_fetch(rav,i,0); 1039 right = SvIV(rsv); 1040 if ( left < right ) 1041 retval = -1; 1042 if ( left > right ) 1043 retval = +1; 1044 i++; 1045 } 1046 1047 /* tiebreaker for alpha with identical terms */ 1048 if ( retval == 0 && l == r && left == right && ( lalpha || ralpha ) ) 1049 { 1050 if ( lalpha && !ralpha ) 1051 { 1052 retval = -1; 1053 } 1054 else if ( ralpha && !lalpha) 1055 { 1056 retval = +1; 1057 } 1058 } 1059 1060 if ( l != r && retval == 0 ) /* possible match except for trailing 0's */ 1061 { 1062 if ( l < r ) 1063 { 1064 while ( i <= r && retval == 0 ) 1065 { 1066 SV * const rsv = *av_fetch(rav,i,0); 1067 if ( SvIV(rsv) != 0 ) 1068 retval = -1; /* not a match after all */ 1069 i++; 1070 } 1071 } 1072 else 1073 { 1074 while ( i <= l && retval == 0 ) 1075 { 1076 SV * const lsv = *av_fetch(lav,i,0); 1077 if ( SvIV(lsv) != 0 ) 1078 retval = +1; /* not a match after all */ 1079 i++; 1080 } 1081 } 1082 } 1083 return retval; 1084 } 1085