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 #ifdef __vax__ 591 SV *sv = SvNVX(ver) > 10e37 ? newSV(64) : 0; 592 #else 593 SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0; 594 #endif 595 char *buf; 596 #ifdef USE_LOCALE_NUMERIC 597 const char * const cur_numeric = setlocale(LC_NUMERIC, NULL); 598 assert(cur_numeric); 599 600 /* XS code can set the locale without us knowing. To protect the 601 * version number parsing, which requires the radix character to be a 602 * dot, update our records as to what the locale is, so that our 603 * existing macro mechanism can correctly change it to a dot and back 604 * if necessary. This code is extremely unlikely to be in a loop, so 605 * the extra work will have a negligible performance impact. See [perl 606 * #121930]. 607 * 608 * If the current locale is a standard one, but we are expecting it to 609 * be a different, underlying locale, update our records to make the 610 * underlying locale this (standard) one. If the current locale is not 611 * a standard one, we should be expecting a non-standard one, the same 612 * one that we have recorded as the underlying locale. If not, update 613 * our records. */ 614 if (strEQ(cur_numeric, "C") || strEQ(cur_numeric, "POSIX")) { 615 if (! PL_numeric_standard) { 616 new_numeric(cur_numeric); 617 } 618 } 619 else if (PL_numeric_standard 620 || ! PL_numeric_name 621 || strNE(PL_numeric_name, cur_numeric)) 622 { 623 new_numeric(cur_numeric); 624 } 625 #endif 626 { /* Braces needed because macro just below declares a variable */ 627 STORE_NUMERIC_LOCAL_SET_STANDARD(); 628 if (sv) { 629 Perl_sv_catpvf(aTHX_ sv, "%.9"NVff, SvNVX(ver)); 630 len = SvCUR(sv); 631 buf = SvPVX(sv); 632 } 633 else { 634 len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver)); 635 buf = tbuf; 636 } 637 RESTORE_NUMERIC_LOCAL(); 638 } 639 while (buf[len-1] == '0' && len > 0) len--; 640 if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */ 641 version = savepvn(buf, len); 642 SAVEFREEPV(version); 643 SvREFCNT_dec(sv); 644 } 645 #ifdef SvVOK 646 else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */ 647 version = savepvn( (const char*)mg->mg_ptr,mg->mg_len ); 648 SAVEFREEPV(version); 649 qv = TRUE; 650 } 651 #endif 652 else if ( SvPOK(ver))/* must be a string or something like a string */ 653 #if PERL_VERSION_LT(5,17,2) 654 VER_PV: 655 #endif 656 { 657 STRLEN len; 658 version = savepvn(SvPV(ver,len), SvCUR(ver)); 659 SAVEFREEPV(version); 660 #ifndef SvVOK 661 # if PERL_VERSION > 5 662 /* This will only be executed for 5.6.0 - 5.8.0 inclusive */ 663 if ( len >= 3 && !instr(version,".") && !instr(version,"_")) { 664 /* may be a v-string */ 665 char *testv = (char *)version; 666 STRLEN tlen = len; 667 for (tlen=0; tlen < len; tlen++, testv++) { 668 /* if one of the characters is non-text assume v-string */ 669 if (testv[0] < ' ') { 670 SV * const nsv = sv_newmortal(); 671 const char *nver; 672 const char *pos; 673 int saw_decimal = 0; 674 sv_setpvf(nsv,"v%vd",ver); 675 pos = nver = savepv(SvPV_nolen(nsv)); 676 SAVEFREEPV(pos); 677 678 /* scan the resulting formatted string */ 679 pos++; /* skip the leading 'v' */ 680 while ( *pos == '.' || isDIGIT(*pos) ) { 681 if ( *pos == '.' ) 682 saw_decimal++ ; 683 pos++; 684 } 685 686 /* is definitely a v-string */ 687 if ( saw_decimal >= 2 ) { 688 version = nver; 689 } 690 break; 691 } 692 } 693 } 694 # endif 695 #endif 696 } 697 #if PERL_VERSION_LT(5,17,2) 698 else if (SvIOKp(ver)) { 699 goto VER_IV; 700 } 701 else if (SvNOKp(ver)) { 702 goto VER_NV; 703 } 704 else if (SvPOKp(ver)) { 705 goto VER_PV; 706 } 707 #endif 708 else 709 { 710 /* no idea what this is */ 711 Perl_croak(aTHX_ "Invalid version format (non-numeric data)"); 712 } 713 714 s = SCAN_VERSION(version, ver, qv); 715 if ( *s != '\0' ) 716 Perl_ck_warner(aTHX_ packWARN(WARN_MISC), 717 "Version string '%s' contains invalid data; " 718 "ignoring: '%s'", version, s); 719 720 #if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS) 721 LEAVE; 722 #endif 723 724 return ver; 725 } 726 727 /* 728 =for apidoc vverify 729 730 Validates that the SV contains valid internal structure for a version object. 731 It may be passed either the version object (RV) or the hash itself (HV). If 732 the structure is valid, it returns the HV. If the structure is invalid, 733 it returns NULL. 734 735 SV *hv = vverify(sv); 736 737 Note that it only confirms the bare minimum structure (so as not to get 738 confused by derived classes which may contain additional hash entries): 739 740 =over 4 741 742 =item * The SV is an HV or a reference to an HV 743 744 =item * The hash contains a "version" key 745 746 =item * The "version" key has a reference to an AV as its value 747 748 =back 749 750 =cut 751 */ 752 753 SV * 754 #ifdef VUTIL_REPLACE_CORE 755 Perl_vverify2(pTHX_ SV *vs) 756 #else 757 Perl_vverify(pTHX_ SV *vs) 758 #endif 759 { 760 SV *sv; 761 SV **svp; 762 763 PERL_ARGS_ASSERT_VVERIFY; 764 765 if ( SvROK(vs) ) 766 vs = SvRV(vs); 767 768 /* see if the appropriate elements exist */ 769 if ( SvTYPE(vs) == SVt_PVHV 770 && (svp = hv_fetchs(MUTABLE_HV(vs), "version", FALSE)) 771 && (sv = SvRV(*svp)) 772 && SvTYPE(sv) == SVt_PVAV ) 773 return vs; 774 else 775 return NULL; 776 } 777 778 /* 779 =for apidoc vnumify 780 781 Accepts a version object and returns the normalized floating 782 point representation. Call like: 783 784 sv = vnumify(rv); 785 786 NOTE: you can pass either the object directly or the SV 787 contained within the RV. 788 789 The SV returned has a refcount of 1. 790 791 =cut 792 */ 793 794 SV * 795 #ifdef VUTIL_REPLACE_CORE 796 Perl_vnumify2(pTHX_ SV *vs) 797 #else 798 Perl_vnumify(pTHX_ SV *vs) 799 #endif 800 { 801 SSize_t i, len; 802 I32 digit; 803 int width; 804 bool alpha = FALSE; 805 SV *sv; 806 AV *av; 807 808 PERL_ARGS_ASSERT_VNUMIFY; 809 810 /* extract the HV from the object */ 811 vs = VVERIFY(vs); 812 if ( ! vs ) 813 Perl_croak(aTHX_ "Invalid version object"); 814 815 /* see if various flags exist */ 816 if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) ) 817 alpha = TRUE; 818 { 819 SV ** svp = hv_fetchs(MUTABLE_HV(vs), "width", FALSE); 820 if ( svp ) 821 width = SvIV(*svp); 822 else 823 width = 3; 824 } 825 826 827 /* attempt to retrieve the version array */ 828 if ( !(av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))) ) ) { 829 return newSVpvs("0"); 830 } 831 832 len = av_len(av); 833 if ( len == -1 ) 834 { 835 return newSVpvs("0"); 836 } 837 838 { 839 SV * tsv = *av_fetch(av, 0, 0); 840 digit = SvIV(tsv); 841 } 842 sv = Perl_newSVpvf(aTHX_ "%d.", (int)PERL_ABS(digit)); 843 for ( i = 1 ; i < len ; i++ ) 844 { 845 SV * tsv = *av_fetch(av, i, 0); 846 digit = SvIV(tsv); 847 if ( width < 3 ) { 848 const int denom = (width == 2 ? 10 : 100); 849 const div_t term = div((int)PERL_ABS(digit),denom); 850 Perl_sv_catpvf(aTHX_ sv, "%0*d_%d", width, term.quot, term.rem); 851 } 852 else { 853 Perl_sv_catpvf(aTHX_ sv, "%0*d", width, (int)digit); 854 } 855 } 856 857 if ( len > 0 ) 858 { 859 SV * tsv = *av_fetch(av, len, 0); 860 digit = SvIV(tsv); 861 if ( alpha && width == 3 ) /* alpha version */ 862 sv_catpvs(sv,"_"); 863 Perl_sv_catpvf(aTHX_ sv, "%0*d", width, (int)digit); 864 } 865 else /* len == 0 */ 866 { 867 sv_catpvs(sv, "000"); 868 } 869 return sv; 870 } 871 872 /* 873 =for apidoc vnormal 874 875 Accepts a version object and returns the normalized string 876 representation. Call like: 877 878 sv = vnormal(rv); 879 880 NOTE: you can pass either the object directly or the SV 881 contained within the RV. 882 883 The SV returned has a refcount of 1. 884 885 =cut 886 */ 887 888 SV * 889 #ifdef VUTIL_REPLACE_CORE 890 Perl_vnormal2(pTHX_ SV *vs) 891 #else 892 Perl_vnormal(pTHX_ SV *vs) 893 #endif 894 { 895 I32 i, len, digit; 896 bool alpha = FALSE; 897 SV *sv; 898 AV *av; 899 900 PERL_ARGS_ASSERT_VNORMAL; 901 902 /* extract the HV from the object */ 903 vs = VVERIFY(vs); 904 if ( ! vs ) 905 Perl_croak(aTHX_ "Invalid version object"); 906 907 if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) ) 908 alpha = TRUE; 909 av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))); 910 911 len = av_len(av); 912 if ( len == -1 ) 913 { 914 return newSVpvs(""); 915 } 916 { 917 SV * tsv = *av_fetch(av, 0, 0); 918 digit = SvIV(tsv); 919 } 920 sv = Perl_newSVpvf(aTHX_ "v%"IVdf, (IV)digit); 921 for ( i = 1 ; i < len ; i++ ) { 922 SV * tsv = *av_fetch(av, i, 0); 923 digit = SvIV(tsv); 924 Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit); 925 } 926 927 if ( len > 0 ) 928 { 929 /* handle last digit specially */ 930 SV * tsv = *av_fetch(av, len, 0); 931 digit = SvIV(tsv); 932 if ( alpha ) 933 Perl_sv_catpvf(aTHX_ sv, "_%"IVdf, (IV)digit); 934 else 935 Perl_sv_catpvf(aTHX_ sv, ".%"IVdf, (IV)digit); 936 } 937 938 if ( len <= 2 ) { /* short version, must be at least three */ 939 for ( len = 2 - len; len != 0; len-- ) 940 sv_catpvs(sv,".0"); 941 } 942 return sv; 943 } 944 945 /* 946 =for apidoc vstringify 947 948 In order to maintain maximum compatibility with earlier versions 949 of Perl, this function will return either the floating point 950 notation or the multiple dotted notation, depending on whether 951 the original version contained 1 or more dots, respectively. 952 953 The SV returned has a refcount of 1. 954 955 =cut 956 */ 957 958 SV * 959 #ifdef VUTIL_REPLACE_CORE 960 Perl_vstringify2(pTHX_ SV *vs) 961 #else 962 Perl_vstringify(pTHX_ SV *vs) 963 #endif 964 { 965 SV ** svp; 966 PERL_ARGS_ASSERT_VSTRINGIFY; 967 968 /* extract the HV from the object */ 969 vs = VVERIFY(vs); 970 if ( ! vs ) 971 Perl_croak(aTHX_ "Invalid version object"); 972 973 svp = hv_fetchs(MUTABLE_HV(vs), "original", FALSE); 974 if (svp) { 975 SV *pv; 976 pv = *svp; 977 if ( SvPOK(pv) ) 978 return newSVsv(pv); 979 else 980 return &PL_sv_undef; 981 } 982 else { 983 if ( hv_exists(MUTABLE_HV(vs), "qv", 2) ) 984 return VNORMAL(vs); 985 else 986 return VNUMIFY(vs); 987 } 988 } 989 990 /* 991 =for apidoc vcmp 992 993 Version object aware cmp. Both operands must already have been 994 converted into version objects. 995 996 =cut 997 */ 998 999 int 1000 #ifdef VUTIL_REPLACE_CORE 1001 Perl_vcmp2(pTHX_ SV *lhv, SV *rhv) 1002 #else 1003 Perl_vcmp(pTHX_ SV *lhv, SV *rhv) 1004 #endif 1005 { 1006 SSize_t i,l,m,r; 1007 I32 retval; 1008 bool lalpha = FALSE; 1009 bool ralpha = FALSE; 1010 I32 left = 0; 1011 I32 right = 0; 1012 AV *lav, *rav; 1013 1014 PERL_ARGS_ASSERT_VCMP; 1015 1016 /* extract the HVs from the objects */ 1017 lhv = VVERIFY(lhv); 1018 rhv = VVERIFY(rhv); 1019 if ( ! ( lhv && rhv ) ) 1020 Perl_croak(aTHX_ "Invalid version object"); 1021 1022 /* get the left hand term */ 1023 lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(lhv), "version", FALSE))); 1024 if ( hv_exists(MUTABLE_HV(lhv), "alpha", 5 ) ) 1025 lalpha = TRUE; 1026 1027 /* and the right hand term */ 1028 rav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(rhv), "version", FALSE))); 1029 if ( hv_exists(MUTABLE_HV(rhv), "alpha", 5 ) ) 1030 ralpha = TRUE; 1031 1032 l = av_len(lav); 1033 r = av_len(rav); 1034 m = l < r ? l : r; 1035 retval = 0; 1036 i = 0; 1037 while ( i <= m && retval == 0 ) 1038 { 1039 SV * const lsv = *av_fetch(lav,i,0); 1040 SV * rsv; 1041 left = SvIV(lsv); 1042 rsv = *av_fetch(rav,i,0); 1043 right = SvIV(rsv); 1044 if ( left < right ) 1045 retval = -1; 1046 if ( left > right ) 1047 retval = +1; 1048 i++; 1049 } 1050 1051 /* tiebreaker for alpha with identical terms */ 1052 if ( retval == 0 && l == r && left == right && ( lalpha || ralpha ) ) 1053 { 1054 if ( lalpha && !ralpha ) 1055 { 1056 retval = -1; 1057 } 1058 else if ( ralpha && !lalpha) 1059 { 1060 retval = +1; 1061 } 1062 } 1063 1064 if ( l != r && retval == 0 ) /* possible match except for trailing 0's */ 1065 { 1066 if ( l < r ) 1067 { 1068 while ( i <= r && retval == 0 ) 1069 { 1070 SV * const rsv = *av_fetch(rav,i,0); 1071 if ( SvIV(rsv) != 0 ) 1072 retval = -1; /* not a match after all */ 1073 i++; 1074 } 1075 } 1076 else 1077 { 1078 while ( i <= l && retval == 0 ) 1079 { 1080 SV * const lsv = *av_fetch(lav,i,0); 1081 if ( SvIV(lsv) != 0 ) 1082 retval = +1; /* not a match after all */ 1083 i++; 1084 } 1085 } 1086 } 1087 return retval; 1088 } 1089