This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
IO::getline(): use CALLRUNOPS
[perl5.git] / vutil.c
CommitLineData
abc6d738
FC
1/* This file is part of the "version" CPAN distribution. Please avoid
2 editing it in the perl core. */
3
14f3031b
JP
4#ifdef PERL_CORE
5# include "vutil.h"
d4e59e62 6#endif
d4e59e62 7
abc6d738
FC
8#define VERSION_MAX 0x7FFFFFFF
9
cd622ffb
PE
10#ifndef STRLENs
11# define STRLENs(s) (sizeof("" s "") - 1)
12#endif
13#ifndef POSIX_SETLOCALE_LOCK
14# ifdef gwLOCALE_LOCK
15# define POSIX_SETLOCALE_LOCK gwLOCALE_LOCK
16# define POSIX_SETLOCALE_UNLOCK gwLOCALE_UNLOCK
17# else
18# define POSIX_SETLOCALE_LOCK NOOP
19# define POSIX_SETLOCALE_UNLOCK NOOP
20# endif
21#endif
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()
26# else
27# define DISABLE_LC_NUMERIC_CHANGES() NOOP
28# define REENABLE_LC_NUMERIC_CHANGES() NOOP
29# endif
30#endif
31
abc6d738
FC
32/*
33=for apidoc prescan_version
34
35Validate that a given string can be parsed as a version object, but doesn't
36actually perform the parsing. Can use either strict or lax validation rules.
37Can optionally set a number of hint variables to save the parsing code
38some time when tokenizing.
39
40=cut
41*/
42const char *
24120986 43#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
44Perl_prescan_version2(pTHX_ const char *s, bool strict,
45#else
abc6d738 46Perl_prescan_version(pTHX_ const char *s, bool strict,
d4e59e62 47#endif
cd622ffb
PE
48 const char **errstr,
49 bool *sqv, int *ssaw_decimal, int *swidth, bool *salpha) {
abc6d738
FC
50 bool qv = (sqv ? *sqv : FALSE);
51 int width = 3;
52 int saw_decimal = 0;
53 bool alpha = FALSE;
54 const char *d = s;
55
130cad93
LT
56 PERL_ARGS_ASSERT_PRESCAN_VERSION;
57 PERL_UNUSED_CONTEXT;
abc6d738
FC
58
59 if (qv && isDIGIT(*d))
cd622ffb 60 goto dotted_decimal_version;
abc6d738
FC
61
62 if (*d == 'v') { /* explicit v-string */
cd622ffb
PE
63 d++;
64 if (isDIGIT(*d)) {
65 qv = TRUE;
66 }
67 else { /* degenerate v-string */
68 /* requires v1.2.3 */
69 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
70 }
abc6d738
FC
71
72dotted_decimal_version:
cd622ffb
PE
73 if (strict && d[0] == '0' && isDIGIT(d[1])) {
74 /* no leading zeros allowed */
75 BADVERSION(s,errstr,"Invalid version format (no leading zeros)");
76 }
77
78 while (isDIGIT(*d)) /* integer part */
79 d++;
80
81 if (*d == '.')
82 {
83 saw_decimal++;
84 d++; /* decimal point */
85 }
86 else
87 {
88 if (strict) {
89 /* require v1.2.3 */
90 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions require at least three parts)");
91 }
92 else {
93 goto version_prescan_finish;
94 }
95 }
96
97 {
98 int i = 0;
99 int j = 0;
100 while (isDIGIT(*d)) { /* just keep reading */
101 i++;
102 while (isDIGIT(*d)) {
103 d++; j++;
104 /* maximum 3 digits between decimal */
105 if (strict && j > 3) {
106 BADVERSION(s,errstr,"Invalid version format (maximum 3 digits between decimals)");
107 }
108 }
109 if (*d == '_') {
110 if (strict) {
111 BADVERSION(s,errstr,"Invalid version format (no underscores)");
112 }
113 if ( alpha ) {
114 BADVERSION(s,errstr,"Invalid version format (multiple underscores)");
115 }
116 d++;
117 alpha = TRUE;
118 }
119 else if (*d == '.') {
120 if (alpha) {
121 BADVERSION(s,errstr,"Invalid version format (underscores before decimal)");
122 }
123 saw_decimal++;
124 d++;
125 }
126 else if (!isDIGIT(*d)) {
127 break;
128 }
129 j = 0;
130 }
131
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)");
135 }
136 }
137 } /* end if dotted-decimal */
abc6d738 138 else
cd622ffb
PE
139 { /* decimal versions */
140 int j = 0; /* may need this later */
141 /* special strict case for leading '.' or '0' */
142 if (strict) {
143 if (*d == '.') {
144 BADVERSION(s,errstr,"Invalid version format (0 before decimal required)");
145 }
146 if (*d == '0' && isDIGIT(d[1])) {
147 BADVERSION(s,errstr,"Invalid version format (no leading zeros)");
148 }
149 }
150
151 /* and we never support negative versions */
152 if ( *d == '-') {
153 BADVERSION(s,errstr,"Invalid version format (negative version number)");
154 }
155
156 /* consume all of the integer part */
157 while (isDIGIT(*d))
158 d++;
159
160 /* look for a fractional part */
161 if (*d == '.') {
162 /* we found it, so consume it */
163 saw_decimal++;
164 d++;
165 }
166 else if (!*d || *d == ';' || isSPACE(*d) || *d == '{' || *d == '}') {
167 if ( d == s ) {
168 /* found nothing */
169 BADVERSION(s,errstr,"Invalid version format (version required)");
170 }
171 /* found just an integer */
172 goto version_prescan_finish;
173 }
174 else if ( d == s ) {
175 /* didn't find either integer or period */
176 BADVERSION(s,errstr,"Invalid version format (non-numeric data)");
177 }
178 else if (*d == '_') {
179 /* underscore can't come after integer part */
180 if (strict) {
181 BADVERSION(s,errstr,"Invalid version format (no underscores)");
182 }
183 else if (isDIGIT(d[1])) {
184 BADVERSION(s,errstr,"Invalid version format (alpha without decimal)");
185 }
186 else {
187 BADVERSION(s,errstr,"Invalid version format (misplaced underscore)");
188 }
189 }
190 else {
191 /* anything else after integer part is just invalid data */
192 BADVERSION(s,errstr,"Invalid version format (non-numeric data)");
193 }
194
195 /* scan the fractional part after the decimal point*/
196
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)");
200 }
201
202 while (isDIGIT(*d)) {
203 d++; j++;
204 if (*d == '.' && isDIGIT(d[-1])) {
205 if (alpha) {
206 BADVERSION(s,errstr,"Invalid version format (underscores before decimal)");
207 }
208 if (strict) {
209 BADVERSION(s,errstr,"Invalid version format (dotted-decimal versions must begin with 'v')");
210 }
211 d = (char *)s; /* start all over again */
212 qv = TRUE;
213 goto dotted_decimal_version;
214 }
215 if (*d == '_') {
216 if (strict) {
217 BADVERSION(s,errstr,"Invalid version format (no underscores)");
218 }
219 if ( alpha ) {
220 BADVERSION(s,errstr,"Invalid version format (multiple underscores)");
221 }
222 if ( ! isDIGIT(d[1]) ) {
223 BADVERSION(s,errstr,"Invalid version format (misplaced underscore)");
224 }
225 width = j;
226 d++;
227 alpha = TRUE;
228 }
229 }
abc6d738
FC
230 }
231
232version_prescan_finish:
233 while (isSPACE(*d))
cd622ffb 234 d++;
abc6d738 235
cd622ffb
PE
236 if (!isDIGIT(*d) && (! (!*d || *d == ';' || *d == ':' || *d == '{' || *d == '}') )) {
237 /* trailing non-numeric data */
238 BADVERSION(s,errstr,"Invalid version format (non-numeric data)");
abc6d738 239 }
14f3031b 240 if (saw_decimal > 1 && d[-1] == '.') {
cd622ffb
PE
241 /* no trailing period allowed */
242 BADVERSION(s,errstr,"Invalid version format (trailing decimal)");
14f3031b
JP
243 }
244
abc6d738
FC
245
246 if (sqv)
cd622ffb 247 *sqv = qv;
abc6d738 248 if (swidth)
cd622ffb 249 *swidth = width;
abc6d738 250 if (ssaw_decimal)
cd622ffb 251 *ssaw_decimal = saw_decimal;
abc6d738 252 if (salpha)
cd622ffb 253 *salpha = alpha;
abc6d738
FC
254 return d;
255}
256
257/*
258=for apidoc scan_version
259
260Returns a pointer to the next character after the parsed
261version string, as well as upgrading the passed in SV to
262an RV.
263
264Function must be called with an already existing SV like
265
266 sv = newSV(0);
267 s = scan_version(s, SV *sv, bool qv);
268
269Performs some preprocessing to the string to ensure that
270it has the correct characteristics of a version. Flags the
271object if it contains an underscore (which denotes this
272is an alpha version). The boolean qv denotes that the version
273should be interpreted as if it had multiple decimals, even if
274it doesn't.
275
276=cut
277*/
278
279const char *
24120986 280#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
281Perl_scan_version2(pTHX_ const char *s, SV *rv, bool qv)
282#else
abc6d738 283Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv)
d4e59e62 284#endif
abc6d738
FC
285{
286 const char *start = s;
287 const char *pos;
288 const char *last;
289 const char *errstr = NULL;
290 int saw_decimal = 0;
291 int width = 3;
292 bool alpha = FALSE;
293 bool vinf = FALSE;
294 AV * av;
295 SV * hv;
296
297 PERL_ARGS_ASSERT_SCAN_VERSION;
298
299 while (isSPACE(*s)) /* leading whitespace is OK */
cd622ffb 300 s++;
abc6d738 301
d4e59e62 302 last = PRESCAN_VERSION(s, FALSE, &errstr, &qv, &saw_decimal, &width, &alpha);
abc6d738 303 if (errstr) {
cd622ffb
PE
304 /* "undef" is a special case and not an error */
305 if ( ! ( *s == 'u' && strEQ(s+1,"ndef")) ) {
306 Perl_croak(aTHX_ "%s", errstr);
307 }
abc6d738
FC
308 }
309
310 start = s;
311 if (*s == 'v')
cd622ffb 312 s++;
abc6d738
FC
313 pos = s;
314
315 /* Now that we are through the prescan, start creating the object */
316 av = newAV();
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 */
319
320#ifndef NODEFAULT_SHAREKEYS
321 HvSHAREKEYS_on(hv); /* key-sharing on by default */
322#endif
323
324 if ( qv )
cd622ffb 325 (void)hv_stores(MUTABLE_HV(hv), "qv", newSViv(qv));
abc6d738 326 if ( alpha )
cd622ffb 327 (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(alpha));
abc6d738 328 if ( !qv && width < 3 )
cd622ffb 329 (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width));
abc6d738 330
14f3031b 331 while (isDIGIT(*pos) || *pos == '_')
cd622ffb 332 pos++;
abc6d738 333 if (!isALPHA(*pos)) {
cd622ffb
PE
334 I32 rev;
335
336 for (;;) {
337 rev = 0;
338 {
339 /* this is atoi() that delimits on underscores */
340 const char *end = pos;
341 I32 mult = 1;
342 I32 orev;
343
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
347 */
348 if ( !qv && s > start && saw_decimal == 1 ) {
349 mult *= 100;
350 while ( s < end ) {
351 if (*s == '_')
352 continue;
353 orev = rev;
354 rev += (*s - '0') * mult;
355 mult /= 10;
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);
360 s = end - 1;
361 rev = VERSION_MAX;
362 vinf = 1;
363 }
364 s++;
365 if ( *s == '_' )
366 s++;
367 }
368 }
369 else {
370 while (--end >= s) {
371 int i;
372 if (*end == '_')
373 continue;
374 i = (*end - '0');
14f3031b
JP
375 if ( (mult == VERSION_MAX)
376 || (i > VERSION_MAX / mult)
377 || (i * mult > VERSION_MAX - rev))
378 {
cd622ffb
PE
379 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
380 "Integer overflow in version");
381 end = s - 1;
382 rev = VERSION_MAX;
383 vinf = 1;
384 }
14f3031b
JP
385 else
386 rev += i * mult;
387
388 if (mult > VERSION_MAX / 10)
389 mult = VERSION_MAX;
390 else
391 mult *= 10;
cd622ffb
PE
392 }
393 }
394 }
395
396 /* Append revision */
397 av_push(av, newSViv(rev));
398 if ( vinf ) {
399 s = last;
400 break;
401 }
402 else if ( *pos == '.' ) {
403 pos++;
404 if (qv) {
405 while (*pos == '0')
406 ++pos;
407 }
408 s = pos;
409 }
410 else if ( *pos == '_' && isDIGIT(pos[1]) )
411 s = ++pos;
412 else if ( *pos == ',' && isDIGIT(pos[1]) )
413 s = ++pos;
414 else if ( isDIGIT(*pos) )
415 s = pos;
416 else {
417 s = pos;
418 break;
419 }
420 if ( qv ) {
421 while ( isDIGIT(*pos) || *pos == '_')
422 pos++;
423 }
424 else {
425 int digits = 0;
426 while ( ( isDIGIT(*pos) || *pos == '_' ) && digits < 3 ) {
427 if ( *pos != '_' )
428 digits++;
429 pos++;
430 }
431 }
432 }
abc6d738
FC
433 }
434 if ( qv ) { /* quoted versions always get at least three terms*/
cd622ffb
PE
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));
442 */
443 len = 2 - len;
444 while (len-- > 0)
445 av_push(av, newSViv(0));
abc6d738
FC
446 }
447
448 /* need to save off the current version string for later */
449 if ( vinf ) {
cd622ffb
PE
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));
abc6d738
FC
453 }
454 else if ( s > start ) {
cd622ffb
PE
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);
459 }
460 (void)hv_stores(MUTABLE_HV(hv), "original", orig);
abc6d738
FC
461 }
462 else {
cd622ffb
PE
463 (void)hv_stores(MUTABLE_HV(hv), "original", newSVpvs("0"));
464 av_push(av, newSViv(0));
abc6d738
FC
465 }
466
467 /* And finally, store the AV in the hash */
468 (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av)));
469
470 /* fix RT#19517 - special case 'undef' as string */
05402f6b 471 if ( *s == 'u' && strEQ(s+1,"ndef") ) {
cd622ffb 472 s += 5;
abc6d738
FC
473 }
474
475 return s;
476}
477
478/*
479=for apidoc new_version
480
481Returns a new version object based on the passed in SV:
482
483 SV *sv = new_version(SV *ver);
484
485Does not alter the passed in ver SV. See "upg_version" if you
486want to upgrade the SV.
487
488=cut
489*/
490
491SV *
24120986 492#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
493Perl_new_version2(pTHX_ SV *ver)
494#else
abc6d738 495Perl_new_version(pTHX_ SV *ver)
d4e59e62 496#endif
abc6d738 497{
abc6d738
FC
498 SV * const rv = newSV(0);
499 PERL_ARGS_ASSERT_NEW_VERSION;
05402f6b 500 if ( ISA_VERSION_OBJ(ver) ) /* can just copy directly */
abc6d738 501 {
cd622ffb
PE
502 SSize_t key;
503 AV * const av = newAV();
504 AV *sav;
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 */
abc6d738 508#ifndef NODEFAULT_SHAREKEYS
cd622ffb 509 HvSHAREKEYS_on(hv); /* key-sharing on by default */
abc6d738
FC
510#endif
511
cd622ffb
PE
512 if ( SvROK(ver) )
513 ver = SvRV(ver);
514
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));
518
519 if ( hv_exists(MUTABLE_HV(ver), "alpha", 5) )
520 (void)hv_stores(MUTABLE_HV(hv), "alpha", newSViv(1));
521 {
522 SV ** svp = hv_fetchs(MUTABLE_HV(ver), "width", FALSE);
523 if(svp) {
524 const I32 width = SvIV(*svp);
525 (void)hv_stores(MUTABLE_HV(hv), "width", newSViv(width));
526 }
527 }
528 {
529 SV ** svp = hv_fetchs(MUTABLE_HV(ver), "original", FALSE);
530 if(svp)
531 (void)hv_stores(MUTABLE_HV(hv), "original", newSVsv(*svp));
532 }
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++ )
536 {
537 SV * const sv = *av_fetch(sav, key, FALSE);
538 const I32 rev = SvIV(sv);
539 av_push(av, newSViv(rev));
540 }
541
542 (void)hv_stores(MUTABLE_HV(hv), "version", newRV_noinc(MUTABLE_SV(av)));
543 return rv;
abc6d738
FC
544 }
545#ifdef SvVOK
546 {
cd622ffb
PE
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;
551 char *raw, *under;
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);
556 if (under) {
557 Move(under + 1, under, raw + len - under - 1, char);
558 SvCUR_set(rv, SvCUR(rv) - 1);
559 *SvEND(rv) = '\0';
560 }
561 /* this is for consistency with the pure Perl class */
562 if ( isDIGIT(*version) )
563 sv_insert(rv, 0, 0, "v", 1);
564 }
565 else {
abc6d738 566#endif
cd622ffb 567 SvSetSV_nosteal(rv, ver); /* make a duplicate */
abc6d738 568#ifdef SvVOK
cd622ffb 569 }
abc6d738
FC
570 }
571#endif
9190f8ab
JP
572 sv_2mortal(rv); /* in case upg_version croaks before it returns */
573 return SvREFCNT_inc_NN(UPG_VERSION(rv, FALSE));
abc6d738
FC
574}
575
576/*
577=for apidoc upg_version
578
579In-place upgrade of the supplied SV to a version object.
580
581 SV *sv = upg_version(SV *sv, bool qv);
582
583Returns a pointer to the upgraded SV. Set the boolean qv if you want
584to force this SV to be interpreted as an "extended" version.
585
586=cut
587*/
588
cd622ffb
PE
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) \
592 STMT_START { \
593 \
594 /* Prevent callees from trying to change the locale */ \
595 DISABLE_LC_NUMERIC_CHANGES(); \
596 \
597 /* We earlier created 'sv' for very large version numbers, to rely \
598 * on the specialized algorithms SV code has built-in for such \
599 * values */ \
600 if (sv) { \
601 Perl_sv_setpvf(aTHX_ sv, "%.9" NVff, SvNVX(ver)); \
602 len = SvCUR(sv); \
603 buf = SvPVX(sv); \
604 } \
605 else { \
606 len = my_snprintf(tbuf, sizeof(tbuf), "%.9" NVff, SvNVX(ver)); \
607 buf = tbuf; \
608 } \
609 \
610 REENABLE_LC_NUMERIC_CHANGES(); \
611 } STMT_END
612
abc6d738 613SV *
24120986 614#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
615Perl_upg_version2(pTHX_ SV *ver, bool qv)
616#else
abc6d738 617Perl_upg_version(pTHX_ SV *ver, bool qv)
d4e59e62 618#endif
abc6d738
FC
619{
620 const char *version, *s;
621#ifdef SvVOK
622 const MAGIC *mg;
623#endif
624
d2b110e6 625#if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS)
e2ca569e 626 ENTER;
d2b110e6 627#endif
abc6d738
FC
628 PERL_ARGS_ASSERT_UPG_VERSION;
629
9190f8ab 630 if ( (SvUOK(ver) && SvUVX(ver) > VERSION_MAX)
cd622ffb
PE
631 || (SvIOK(ver) && SvIVX(ver) > VERSION_MAX) )
632 {
633 /* out of bounds [unsigned] integer */
634 STRLEN len;
635 char tbuf[64];
636 len = my_snprintf(tbuf, sizeof(tbuf), "%d", VERSION_MAX);
637 version = savepvn(tbuf, len);
638 SAVEFREEPV(version);
639 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
640 "Integer overflow in version %d",VERSION_MAX);
9190f8ab
JP
641 }
642 else if ( SvUOK(ver) || SvIOK(ver))
24120986 643#if PERL_VERSION_LT(5,17,2)
9190f8ab 644VER_IV:
24120986 645#endif
9190f8ab 646 {
cd622ffb
PE
647 version = savesvpv(ver);
648 SAVEFREEPV(version);
9190f8ab
JP
649 }
650 else if (SvNOK(ver) && !( SvPOK(ver) && SvCUR(ver) == 3 ) )
24120986 651#if PERL_VERSION_LT(5,17,2)
9190f8ab 652VER_NV:
24120986 653#endif
abc6d738 654 {
cd622ffb 655 STRLEN len;
abc6d738 656
cd622ffb
PE
657 /* may get too much accuracy */
658 char tbuf[64];
659 SV *sv = SvNVX(ver) > 10e50 ? newSV(64) : 0;
660 char *buf;
14f3031b
JP
661
662#if PERL_VERSION_GE(5,19,0)
cd622ffb
PE
663 if (SvPOK(ver)) {
664 /* dualvar? */
665 goto VER_PV;
666 }
14f3031b 667#endif
190ce35b 668
cd622ffb
PE
669 {
670
671#ifdef USE_POSIX_2008_LOCALE
190ce35b 672
cd622ffb
PE
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);
678#else
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 */
e9bc6d6b 682
cd622ffb
PE
683 char * radix = NULL;
684 unsigned int radix_len = 0;
e9bc6d6b 685
cd622ffb 686 GET_NUMERIC_VERSION(ver, sv, tbuf, buf, len);
190ce35b 687
cd622ffb 688# ifndef ARABIC_DECIMAL_SEPARATOR_UTF8
49d7d366 689
cd622ffb
PE
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, ".,");
696 if (LIKELY(radix)) {
697 radix_len = 1;
190ce35b 698 }
cd622ffb
PE
699# else
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 */
703 radix = strpbrk(buf,
704 ".,"
705 ARABIC_DECIMAL_SEPARATOR_UTF8_FIRST_BYTE_s);
706
707 if (LIKELY(radix)) {
708 if (LIKELY( (* (U8 *) radix)
709 != ARABIC_DECIMAL_SEPARATOR_UTF8_FIRST_BYTE))
710 {
711 radix_len = 1; /* Dot and comma are length 1 */
712 }
713 else {
714
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
720 || memNEs(radix + 1,
721 STRLENs(ARABIC_DECIMAL_SEPARATOR_UTF8_TAIL),
722 ARABIC_DECIMAL_SEPARATOR_UTF8_TAIL))
723 {
724 radix = NULL;
725 radix_len = 0;
726 }
727 }
190ce35b 728 }
49d7d366 729
cd622ffb 730# endif
e9bc6d6b 731
cd622ffb
PE
732 /* Now convert any found radix into a dot (if not already). This
733 * effectively does: ver =~ s/radix/dot/ */
734 if (radix) {
735 if (*radix != '.') {
736 *radix = '.';
737
738 if (radix_len > 1) {
739 Move(radix + radix_len, /* from what follows the radix
740 */
741 radix + 1, /* to just after the new dot */
742
743 /* the number of bytes remaining, plus the NUL
744 * */
745 len - (radix - buf) - radix_len + 1,
746 char);
747 len -= radix_len - 1;
748 }
749 }
e9bc6d6b 750
cd622ffb
PE
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
756 * digit */
757 if (radix < buf + len && ! inRANGE(radix[1], '0', '9')) {
758 radix = NULL;
759 radix_len = 0;
e9bc6d6b 760 }
e9bc6d6b
KW
761 }
762
cd622ffb 763 if (! radix) {
e9bc6d6b 764
cd622ffb
PE
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].
770 * */
190ce35b 771
cd622ffb 772# if ! defined(LC_NUMERIC) || ! defined(USE_LOCALE_NUMERIC)
190ce35b 773
cd622ffb
PE
774 Perl_croak(aTHX_ "panic: Unexpectedly didn't find a dot radix"
775 " character in '%s'", buf);
776# else
777 const char * locale_name_on_entry = NULL;
190ce35b 778
cd622ffb
PE
779 /* In windows, or not threaded, or not thread-safe, if it isn't
780 * C, set it to C. */
190ce35b 781
cd622ffb 782 POSIX_SETLOCALE_LOCK; /* Start critical section */
e9bc6d6b 783
cd622ffb
PE
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"))
788 {
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;
793 }
794 else {
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");
798 }
49d7d366 799
cd622ffb 800 GET_NUMERIC_VERSION(ver, sv, tbuf, buf, len);
49d7d366 801
cd622ffb
PE
802 if (locale_name_on_entry) {
803 setlocale(LC_NUMERIC, locale_name_on_entry);
804 Safefree(locale_name_on_entry);
805 }
e9bc6d6b 806
cd622ffb
PE
807 POSIX_SETLOCALE_UNLOCK; /* End critical section */
808# endif
e9bc6d6b 809 }
cd622ffb 810#endif
d3a5b29c 811 }
e9bc6d6b 812
cd622ffb
PE
813 /* Strip trailing zero's from the version number */
814 while (buf[len-1] == '0' && len > 0) len--;
190ce35b 815
cd622ffb 816 if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */
190ce35b 817
cd622ffb
PE
818 version = savepvn(buf, len);
819 SAVEFREEPV(version);
820 SvREFCNT_dec(sv);
abc6d738
FC
821 }
822#ifdef SvVOK
823 else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */
cd622ffb
PE
824 version = savepvn( (const char*)mg->mg_ptr,mg->mg_len );
825 SAVEFREEPV(version);
826 qv = TRUE;
abc6d738
FC
827 }
828#endif
9190f8ab
JP
829 else if ( SvPOK(ver))/* must be a string or something like a string */
830VER_PV:
abc6d738 831 {
cd622ffb
PE
832 STRLEN len;
833 version = savepvn(SvPV(ver,len), SvCUR(ver));
834 SAVEFREEPV(version);
abc6d738 835#ifndef SvVOK
cd622ffb
PE
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;
840 STRLEN tlen = len;
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();
845 const char *nver;
846 const char *pos;
847 int saw_decimal = 0;
848 sv_setpvf(nsv,"v%vd",ver);
849 pos = nver = savepv(SvPV_nolen(nsv));
05402f6b 850 SAVEFREEPV(pos);
abc6d738 851
cd622ffb
PE
852 /* scan the resulting formatted string */
853 pos++; /* skip the leading 'v' */
854 while ( *pos == '.' || isDIGIT(*pos) ) {
855 if ( *pos == '.' )
856 saw_decimal++ ;
857 pos++;
858 }
859
860 /* is definitely a v-string */
861 if ( saw_decimal >= 2 ) {
862 version = nver;
863 }
864 break;
865 }
866 }
867 }
abc6d738
FC
868#endif
869 }
9190f8ab
JP
870#if PERL_VERSION_LT(5,17,2)
871 else if (SvIOKp(ver)) {
cd622ffb 872 goto VER_IV;
9190f8ab
JP
873 }
874 else if (SvNOKp(ver)) {
cd622ffb 875 goto VER_NV;
9190f8ab
JP
876 }
877 else if (SvPOKp(ver)) {
cd622ffb 878 goto VER_PV;
9190f8ab
JP
879 }
880#endif
ab4e0d4b
JP
881 else
882 {
cd622ffb
PE
883 /* no idea what this is */
884 Perl_croak(aTHX_ "Invalid version format (non-numeric data)");
ab4e0d4b 885 }
abc6d738 886
d4e59e62 887 s = SCAN_VERSION(version, ver, qv);
cd622ffb
PE
888 if ( *s != '\0' )
889 Perl_ck_warner(aTHX_ packWARN(WARN_MISC),
890 "Version string '%s' contains invalid data; "
891 "ignoring: '%s'", version, s);
d2b110e6
JP
892
893#if PERL_VERSION_LT(5,19,8) && defined(USE_ITHREADS)
e2ca569e 894 LEAVE;
d2b110e6 895#endif
9190f8ab 896
abc6d738
FC
897 return ver;
898}
899
900/*
901=for apidoc vverify
902
903Validates that the SV contains valid internal structure for a version object.
904It may be passed either the version object (RV) or the hash itself (HV). If
905the structure is valid, it returns the HV. If the structure is invalid,
906it returns NULL.
907
908 SV *hv = vverify(sv);
909
910Note that it only confirms the bare minimum structure (so as not to get
911confused by derived classes which may contain additional hash entries):
912
913=over 4
914
915=item * The SV is an HV or a reference to an HV
916
917=item * The hash contains a "version" key
918
919=item * The "version" key has a reference to an AV as its value
920
921=back
922
923=cut
924*/
925
926SV *
24120986 927#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
928Perl_vverify2(pTHX_ SV *vs)
929#else
abc6d738 930Perl_vverify(pTHX_ SV *vs)
d4e59e62 931#endif
abc6d738
FC
932{
933 SV *sv;
05402f6b 934 SV **svp;
abc6d738
FC
935
936 PERL_ARGS_ASSERT_VVERIFY;
937
938 if ( SvROK(vs) )
cd622ffb 939 vs = SvRV(vs);
abc6d738
FC
940
941 /* see if the appropriate elements exist */
942 if ( SvTYPE(vs) == SVt_PVHV
cd622ffb
PE
943 && (svp = hv_fetchs(MUTABLE_HV(vs), "version", FALSE))
944 && (sv = SvRV(*svp))
945 && SvTYPE(sv) == SVt_PVAV )
946 return vs;
abc6d738 947 else
cd622ffb 948 return NULL;
abc6d738
FC
949}
950
951/*
952=for apidoc vnumify
953
954Accepts a version object and returns the normalized floating
955point representation. Call like:
956
957 sv = vnumify(rv);
958
959NOTE: you can pass either the object directly or the SV
960contained within the RV.
961
962The SV returned has a refcount of 1.
963
964=cut
965*/
966
967SV *
24120986 968#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
969Perl_vnumify2(pTHX_ SV *vs)
970#else
abc6d738 971Perl_vnumify(pTHX_ SV *vs)
d4e59e62 972#endif
abc6d738
FC
973{
974 SSize_t i, len;
975 I32 digit;
abc6d738
FC
976 bool alpha = FALSE;
977 SV *sv;
978 AV *av;
979
980 PERL_ARGS_ASSERT_VNUMIFY;
981
982 /* extract the HV from the object */
d4e59e62 983 vs = VVERIFY(vs);
abc6d738 984 if ( ! vs )
cd622ffb 985 Perl_croak(aTHX_ "Invalid version object");
abc6d738
FC
986
987 /* see if various flags exist */
817794ed 988 if ( hv_exists(MUTABLE_HV(vs), "alpha", 5 ) )
cd622ffb 989 alpha = TRUE;
abc6d738 990
14f3031b 991 if (alpha) {
cd622ffb
PE
992 Perl_ck_warner(aTHX_ packWARN(WARN_NUMERIC),
993 "alpha->numify() is lossy");
14f3031b 994 }
abc6d738
FC
995
996 /* attempt to retrieve the version array */
997 if ( !(av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE))) ) ) {
cd622ffb 998 return newSVpvs("0");
abc6d738
FC
999 }
1000
1001 len = av_len(av);
1002 if ( len == -1 )
1003 {
cd622ffb 1004 return newSVpvs("0");
abc6d738
FC
1005 }
1006
05402f6b 1007 {
cd622ffb
PE
1008 SV * tsv = *av_fetch(av, 0, 0);
1009 digit = SvIV(tsv);
05402f6b 1010 }
abc6d738 1011 sv = Perl_newSVpvf(aTHX_ "%d.", (int)PERL_ABS(digit));
14f3031b 1012 for ( i = 1 ; i <= len ; i++ )
abc6d738 1013 {
cd622ffb
PE
1014 SV * tsv = *av_fetch(av, i, 0);
1015 digit = SvIV(tsv);
1016 Perl_sv_catpvf(aTHX_ sv, "%03d", (int)digit);
abc6d738
FC
1017 }
1018
14f3031b 1019 if ( len == 0 ) {
cd622ffb 1020 sv_catpvs(sv, "000");
abc6d738
FC
1021 }
1022 return sv;
1023}
1024
1025/*
1026=for apidoc vnormal
1027
1028Accepts a version object and returns the normalized string
1029representation. Call like:
1030
1031 sv = vnormal(rv);
1032
1033NOTE: you can pass either the object directly or the SV
1034contained within the RV.
1035
1036The SV returned has a refcount of 1.
1037
1038=cut
1039*/
1040
1041SV *
24120986 1042#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
1043Perl_vnormal2(pTHX_ SV *vs)
1044#else
abc6d738 1045Perl_vnormal(pTHX_ SV *vs)
d4e59e62 1046#endif
abc6d738
FC
1047{
1048 I32 i, len, digit;
abc6d738
FC
1049 SV *sv;
1050 AV *av;
1051
1052 PERL_ARGS_ASSERT_VNORMAL;
1053
1054 /* extract the HV from the object */
d4e59e62 1055 vs = VVERIFY(vs);
abc6d738 1056 if ( ! vs )
cd622ffb 1057 Perl_croak(aTHX_ "Invalid version object");
abc6d738 1058
abc6d738
FC
1059 av = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(vs), "version", FALSE)));
1060
1061 len = av_len(av);
1062 if ( len == -1 )
1063 {
cd622ffb 1064 return newSVpvs("");
abc6d738 1065 }
05402f6b 1066 {
cd622ffb
PE
1067 SV * tsv = *av_fetch(av, 0, 0);
1068 digit = SvIV(tsv);
05402f6b 1069 }
a6842133 1070 sv = Perl_newSVpvf(aTHX_ "v%" IVdf, (IV)digit);
14f3031b 1071 for ( i = 1 ; i <= len ; i++ ) {
cd622ffb
PE
1072 SV * tsv = *av_fetch(av, i, 0);
1073 digit = SvIV(tsv);
1074 Perl_sv_catpvf(aTHX_ sv, ".%" IVdf, (IV)digit);
abc6d738
FC
1075 }
1076
abc6d738 1077 if ( len <= 2 ) { /* short version, must be at least three */
cd622ffb
PE
1078 for ( len = 2 - len; len != 0; len-- )
1079 sv_catpvs(sv,".0");
abc6d738
FC
1080 }
1081 return sv;
1082}
1083
1084/*
1085=for apidoc vstringify
1086
1087In order to maintain maximum compatibility with earlier versions
1088of Perl, this function will return either the floating point
1089notation or the multiple dotted notation, depending on whether
1090the original version contained 1 or more dots, respectively.
1091
1092The SV returned has a refcount of 1.
1093
1094=cut
1095*/
1096
1097SV *
24120986 1098#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
1099Perl_vstringify2(pTHX_ SV *vs)
1100#else
abc6d738 1101Perl_vstringify(pTHX_ SV *vs)
d4e59e62 1102#endif
abc6d738 1103{
05402f6b 1104 SV ** svp;
abc6d738
FC
1105 PERL_ARGS_ASSERT_VSTRINGIFY;
1106
1107 /* extract the HV from the object */
d4e59e62 1108 vs = VVERIFY(vs);
abc6d738 1109 if ( ! vs )
cd622ffb 1110 Perl_croak(aTHX_ "Invalid version object");
abc6d738 1111
05402f6b
JP
1112 svp = hv_fetchs(MUTABLE_HV(vs), "original", FALSE);
1113 if (svp) {
cd622ffb
PE
1114 SV *pv;
1115 pv = *svp;
1116 if ( SvPOK(pv)
dddb2275 1117#if PERL_VERSION_LT(5,17,2)
cd622ffb 1118 || SvPOKp(pv)
dddb2275 1119#endif
cd622ffb
PE
1120 )
1121 return newSVsv(pv);
1122 else
1123 return &PL_sv_undef;
abc6d738
FC
1124 }
1125 else {
cd622ffb
PE
1126 if ( hv_exists(MUTABLE_HV(vs), "qv", 2) )
1127 return VNORMAL(vs);
1128 else
1129 return VNUMIFY(vs);
abc6d738
FC
1130 }
1131}
1132
1133/*
1134=for apidoc vcmp
1135
cd622ffb 1136Version object aware cmp. Both operands must already have been
abc6d738
FC
1137converted into version objects.
1138
1139=cut
1140*/
1141
1142int
24120986 1143#ifdef VUTIL_REPLACE_CORE
d4e59e62
FC
1144Perl_vcmp2(pTHX_ SV *lhv, SV *rhv)
1145#else
abc6d738 1146Perl_vcmp(pTHX_ SV *lhv, SV *rhv)
d4e59e62 1147#endif
abc6d738
FC
1148{
1149 SSize_t i,l,m,r;
1150 I32 retval;
abc6d738
FC
1151 I32 left = 0;
1152 I32 right = 0;
1153 AV *lav, *rav;
1154
1155 PERL_ARGS_ASSERT_VCMP;
1156
1157 /* extract the HVs from the objects */
d4e59e62
FC
1158 lhv = VVERIFY(lhv);
1159 rhv = VVERIFY(rhv);
abc6d738 1160 if ( ! ( lhv && rhv ) )
cd622ffb 1161 Perl_croak(aTHX_ "Invalid version object");
abc6d738
FC
1162
1163 /* get the left hand term */
1164 lav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(lhv), "version", FALSE)));
abc6d738
FC
1165
1166 /* and the right hand term */
1167 rav = MUTABLE_AV(SvRV(*hv_fetchs(MUTABLE_HV(rhv), "version", FALSE)));
abc6d738
FC
1168
1169 l = av_len(lav);
1170 r = av_len(rav);
1171 m = l < r ? l : r;
1172 retval = 0;
1173 i = 0;
1174 while ( i <= m && retval == 0 )
1175 {
cd622ffb
PE
1176 SV * const lsv = *av_fetch(lav,i,0);
1177 SV * rsv;
1178 left = SvIV(lsv);
1179 rsv = *av_fetch(rav,i,0);
1180 right = SvIV(rsv);
1181 if ( left < right )
1182 retval = -1;
1183 if ( left > right )
1184 retval = +1;
1185 i++;
abc6d738
FC
1186 }
1187
abc6d738
FC
1188 if ( l != r && retval == 0 ) /* possible match except for trailing 0's */
1189 {
cd622ffb
PE
1190 if ( l < r )
1191 {
1192 while ( i <= r && retval == 0 )
1193 {
1194 SV * const rsv = *av_fetch(rav,i,0);
1195 if ( SvIV(rsv) != 0 )
1196 retval = -1; /* not a match after all */
1197 i++;
1198 }
1199 }
1200 else
1201 {
1202 while ( i <= l && retval == 0 )
1203 {
1204 SV * const lsv = *av_fetch(lav,i,0);
1205 if ( SvIV(lsv) != 0 )
1206 retval = +1; /* not a match after all */
1207 i++;
1208 }
1209 }
abc6d738
FC
1210 }
1211 return retval;
1212}
14f3031b
JP
1213
1214/* ex: set ro: */