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