1 ################################################################################
3 ## Version 3.x, Copyright (C) 2004-2013, Marcus Holland-Moritz.
4 ## Version 2.x, Copyright (C) 2001, Paul Marquess.
5 ## Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
7 ## This program is free software; you can redistribute it and/or
8 ## modify it under the same terms as Perl itself.
10 ################################################################################
28 __UNDEFINED__ SvGETMAGIC(x) STMT_START { if (SvGMAGICAL(x)) mg_get(x); } STMT_END
30 /* That's the best we can do... */
31 __UNDEFINED__ sv_catpvn_nomg sv_catpvn
32 __UNDEFINED__ sv_catsv_nomg sv_catsv
33 __UNDEFINED__ sv_setsv_nomg sv_setsv
34 __UNDEFINED__ sv_pvn_nomg sv_pvn
37 #if defined(PERL_USE_GCC_BRACE_GROUPS)
38 __UNDEFINED__ SvIV_nomg(sv) (!SvGMAGICAL((sv)) ? SvIV((sv)) : ({ SV *_sviv = sv_mortalcopy_flags((sv), SV_NOSTEAL); IV _iv = SvIV(_sviv); SvFLAGS((sv)) = (SvFLAGS((sv)) & ~SVf_IVisUV) | (SvFLAGS(_sviv) & SVf_IVisUV); _iv; }))
39 __UNDEFINED__ SvUV_nomg(sv) (!SvGMAGICAL((sv)) ? SvUV((sv)) : ({ SV *_svuv = sv_mortalcopy_flags((sv), SV_NOSTEAL); UV _uv = SvUV(_svuv); SvFLAGS((sv)) = (SvFLAGS((sv)) & ~SVf_IVisUV) | (SvFLAGS(_svuv) & SVf_IVisUV); _uv; }))
41 __UNDEFINED__ SvIV_nomg(sv) (!SvGMAGICAL((sv)) ? SvIV((sv)) : ((PL_Sv = sv_mortalcopy_flags((sv), SV_NOSTEAL)), sv_upgrade(PL_Sv, SVt_PVIV), (SvIVX(PL_Sv) = SvIV(PL_Sv)), (SvFLAGS((sv)) = (SvFLAGS((sv)) & ~SVf_IVisUV) | (SvFLAGS(PL_Sv) & SVf_IVisUV)), SvIVX(PL_Sv)))
42 __UNDEFINED__ SvUV_nomg(sv) (!SvGMAGICAL((sv)) ? SvIV((sv)) : ((PL_Sv = sv_mortalcopy_flags((sv), SV_NOSTEAL)), sv_upgrade(PL_Sv, SVt_PVIV), (SvUVX(PL_Sv) = SvUV(PL_Sv)), (SvFLAGS((sv)) = (SvFLAGS((sv)) & ~SVf_IVisUV) | (SvFLAGS(PL_Sv) & SVf_IVisUV)), SvUVX(PL_Sv)))
45 __UNDEFINED__ SvIV_nomg(sv) (!SvGMAGICAL((sv)) ? SvIV((sv)) : SvIVx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
46 __UNDEFINED__ SvUV_nomg(sv) (!SvGMAGICAL((sv)) ? SvUV((sv)) : SvUVx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
49 __UNDEFINED__ SvNV_nomg(sv) (!SvGMAGICAL((sv)) ? SvNV((sv)) : SvNVx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
50 __UNDEFINED__ SvTRUE_nomg(sv) (!SvGMAGICAL((sv)) ? SvTRUE((sv)) : SvTRUEx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
53 # define sv_catpv_mg(sv, ptr) \
56 sv_catpv(TeMpSv,ptr); \
62 # define sv_catpvn_mg(sv, ptr, len) \
65 sv_catpvn(TeMpSv,ptr,len); \
71 # define sv_catsv_mg(dsv, ssv) \
74 sv_catsv(TeMpSv,ssv); \
80 # define sv_setiv_mg(sv, i) \
89 # define sv_setnv_mg(sv, num) \
92 sv_setnv(TeMpSv,num); \
98 # define sv_setpv_mg(sv, ptr) \
101 sv_setpv(TeMpSv,ptr); \
102 SvSETMAGIC(TeMpSv); \
107 # define sv_setpvn_mg(sv, ptr, len) \
110 sv_setpvn(TeMpSv,ptr,len); \
111 SvSETMAGIC(TeMpSv); \
116 # define sv_setsv_mg(dsv, ssv) \
119 sv_setsv(TeMpSv,ssv); \
120 SvSETMAGIC(TeMpSv); \
125 # define sv_setuv_mg(sv, i) \
128 sv_setuv(TeMpSv,i); \
129 SvSETMAGIC(TeMpSv); \
134 # define sv_usepvn_mg(sv, ptr, len) \
137 sv_usepvn(TeMpSv,ptr,len); \
138 SvSETMAGIC(TeMpSv); \
142 __UNDEFINED__ SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL)
144 /* Hint: sv_magic_portable
145 * This is a compatibility function that is only available with
146 * Devel::PPPort. It is NOT in the perl core.
147 * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when
148 * it is being passed a name pointer with namlen == 0. In that
149 * case, perl 5.8.0 and later store the pointer, not a copy of it.
150 * The compatibility can be provided back to perl 5.004. With
151 * earlier versions, the code will not compile.
154 #if { VERSION < 5.004 }
156 /* code that uses sv_magic_portable will not compile */
158 #elif { VERSION < 5.8.0 }
160 # define sv_magic_portable(sv, obj, how, name, namlen) \
162 SV *SvMp_sv = (sv); \
163 char *SvMp_name = (char *) (name); \
164 I32 SvMp_namlen = (namlen); \
165 if (SvMp_name && SvMp_namlen == 0) \
168 sv_magic(SvMp_sv, obj, how, 0, 0); \
169 mg = SvMAGIC(SvMp_sv); \
170 mg->mg_len = -42; /* XXX: this is the tricky part */ \
171 mg->mg_ptr = SvMp_name; \
175 sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \
181 # define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e)
185 #if !defined(mg_findext)
186 #if { NEED mg_findext }
189 mg_findext(const SV * sv, int type, const MGVTBL *vtbl) {
193 #ifdef AvPAD_NAMELIST
194 assert(!(SvTYPE(sv) == SVt_PVAV && AvPAD_NAMELIST(sv)));
197 for (mg = SvMAGIC (sv); mg; mg = mg->mg_moremagic) {
198 if (mg->mg_type == type && mg->mg_virtual == vtbl)
209 #if !defined(sv_unmagicext)
210 #if { NEED sv_unmagicext }
213 sv_unmagicext(pTHX_ SV *const sv, const int type, MGVTBL *vtbl)
218 if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
220 mgp = &(SvMAGIC(sv));
221 for (mg = *mgp; mg; mg = *mgp) {
222 const MGVTBL* const virt = mg->mg_virtual;
223 if (mg->mg_type == type && virt == vtbl) {
224 *mgp = mg->mg_moremagic;
225 if (virt && virt->svt_free)
226 virt->svt_free(aTHX_ sv, mg);
227 if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
229 Safefree(mg->mg_ptr);
230 else if (mg->mg_len == HEf_SVKEY) /* Questionable on older perls... */
231 SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
232 else if (mg->mg_type == PERL_MAGIC_utf8)
233 Safefree(mg->mg_ptr);
235 if (mg->mg_flags & MGf_REFCOUNTED)
236 SvREFCNT_dec(mg->mg_obj);
240 mgp = &mg->mg_moremagic;
243 if (SvMAGICAL(sv)) /* if we're under save_magic, wait for restore_magic; */
244 mg_magical(sv); /* else fix the flags now */
248 SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
258 #define NEED_mg_findext
259 #define NEED_sv_unmagicext
262 #define STATIC static
265 STATIC MGVTBL null_mg_vtbl = {
273 #endif /* MGf_COPY */
279 #endif /* MGf_LOCAL */
282 STATIC MGVTBL other_mg_vtbl = {
290 #endif /* MGf_COPY */
296 #endif /* MGf_LOCAL */
302 new_with_other_mg(package, ...)
308 const char *data = "hello\0";
312 stash = gv_stashpv(SvPV_nolen(package), 0);
314 self_ref = newRV_noinc((SV*)self);
316 sv_magic((SV*)self, NULL, PERL_MAGIC_ext, data, strlen(data));
317 mg = mg_find((SV*)self, PERL_MAGIC_ext);
319 mg->mg_virtual = &other_mg_vtbl;
323 RETVAL = sv_bless(self_ref, stash);
328 new_with_mg(package, ...)
334 const char *data = "hello\0";
338 stash = gv_stashpv(SvPV_nolen(package), 0);
340 self_ref = newRV_noinc((SV*)self);
342 sv_magic((SV*)self, NULL, PERL_MAGIC_ext, data, strlen(data));
343 mg = mg_find((SV*)self, PERL_MAGIC_ext);
345 mg->mg_virtual = &null_mg_vtbl;
349 RETVAL = sv_bless(self_ref, stash);
354 remove_null_magic(self)
359 obj = (HV*) SvRV(self);
361 sv_unmagicext((SV*)obj, PERL_MAGIC_ext, &null_mg_vtbl);
364 remove_other_magic(self)
369 obj = (HV*) SvRV(self);
371 sv_unmagicext((SV*)obj, PERL_MAGIC_ext, &other_mg_vtbl);
380 obj = (HV*) SvRV(self);
382 if ((mg = mg_findext((SV*)obj, PERL_MAGIC_ext, &null_mg_vtbl))) {
383 XPUSHs(sv_2mortal(newSVpv(mg->mg_ptr, strlen(mg->mg_ptr))));
385 XPUSHs(sv_2mortal(newSVpvs("Sorry, your princess is in another castle.")));
389 sv_catpv_mg(sv, string)
393 sv_catpv_mg(sv, string);
396 sv_catpvn_mg(sv, sv2)
403 str = SvPV(sv2, len);
404 sv_catpvn_mg(sv, str, len);
411 sv_catsv_mg(sv, sv2);
435 sv_setpvn_mg(sv, sv2)
442 str = SvPV(sv2, len);
443 sv_setpvn_mg(sv, str, len);
450 sv_setsv_mg(sv, sv2);
460 sv_usepvn_mg(sv, sv2)
467 str = SvPV(sv2, len);
468 New(42, copy, len+1, char);
469 Copy(str, copy, len+1, char);
470 sv_usepvn_mg(sv, copy, len);
476 RETVAL = SvVSTRING_mg(sv) != NULL;
481 sv_magic_portable(sv)
485 const char *foo = "foo";
487 #if { VERSION >= 5.004 }
488 sv_magic_portable(sv, 0, '~', foo, 0);
489 mg = mg_find(sv, '~');
493 RETVAL = mg->mg_ptr == foo;
495 sv_magic(sv, 0, '~', (char *) foo, strlen(foo));
496 mg = mg_find(sv, '~');
497 RETVAL = strEQ(mg->mg_ptr, foo);
506 RETVAL = (UV)IV_MAX+100;
516 RETVAL = (SvFLAGS(sv) & SVf_IVisUV);
528 RETVAL = SvIV_nomg(sv);
540 RETVAL = SvUV_nomg(sv);
552 RETVAL = SvNV_nomg(sv);
561 magic_SvTRUE_nomg(sv)
564 RETVAL = SvTRUE_nomg(sv);
570 #ifdef SvPV_nomg_nolen
573 magic_SvPV_nomg_nolen(sv)
576 RETVAL = SvPV_nomg_nolen(sv);
585 ok(my $obj1 = Devel::PPPort->new_with_mg());
586 is(Devel::PPPort::as_string($obj1), 'hello');
589 my $obj = bless {}, 'Fake::Class';
590 is(Devel::PPPort::as_string($obj), "Sorry, your princess is in another castle.");
592 # Find with other magic (not the magic we are looking for)
593 ok($obj = Devel::PPPort->new_with_other_mg());
594 is(Devel::PPPort::as_string($obj), "Sorry, your princess is in another castle.");
596 # Okay, attempt to remove magic that isn't there
597 Devel::PPPort::remove_other_magic($obj1);
598 is(Devel::PPPort::as_string($obj1), 'hello');
600 # Remove magic that IS there
601 Devel::PPPort::remove_null_magic($obj1);
602 is(Devel::PPPort::as_string($obj1), "Sorry, your princess is in another castle.");
604 # Removing when no magic present
605 Devel::PPPort::remove_null_magic($obj1);
606 is(Devel::PPPort::as_string($obj1), "Sorry, your princess is in another castle.");
610 tie %h, 'Tie::StdHash';
614 &Devel::PPPort::sv_catpv_mg($h{foo}, 'bar');
615 is($h{foo}, 'foobar');
617 &Devel::PPPort::sv_catpvn_mg($h{bar}, 'baz');
620 &Devel::PPPort::sv_catsv_mg($h{foo}, '42');
621 is($h{foo}, 'foobar42');
623 &Devel::PPPort::sv_setiv_mg($h{bar}, 42);
626 &Devel::PPPort::sv_setnv_mg($h{PI}, 3.14159);
627 ok(abs($h{PI} - 3.14159) < 0.01);
629 &Devel::PPPort::sv_setpv_mg($h{mhx}, 'mhx');
632 &Devel::PPPort::sv_setpvn_mg($h{mhx}, 'Marcus');
633 is($h{mhx}, 'Marcus');
635 &Devel::PPPort::sv_setsv_mg($h{sv}, 'SV');
638 &Devel::PPPort::sv_setuv_mg($h{sv}, 4711);
641 &Devel::PPPort::sv_usepvn_mg($h{sv}, 'Perl');
644 # v1 is treated as a bareword in older perls...
645 my $ver = do { local $SIG{'__WARN__'} = sub {}; eval qq[v1.2.0] };
646 ok(ivers($]) < ivers("5.009") || $@ eq '');
647 ok(ivers($]) < ivers("5.009") || Devel::PPPort::SvVSTRING_mg($ver));
648 ok(!Devel::PPPort::SvVSTRING_mg(4711));
651 ok(Devel::PPPort::sv_magic_portable($foo));
654 tie my $scalar, 'TieScalarCounter', 10;
657 is tied($scalar)->{fetch}, 1;
658 is tied($scalar)->{store}, 0;
659 is Devel::PPPort::magic_SvIV_nomg($scalar), 10;
660 is tied($scalar)->{fetch}, 1;
661 is tied($scalar)->{store}, 0;
662 is Devel::PPPort::magic_SvUV_nomg($scalar), 10;
663 is tied($scalar)->{fetch}, 1;
664 is tied($scalar)->{store}, 0;
665 is Devel::PPPort::magic_SvNV_nomg($scalar), 10;
666 is tied($scalar)->{fetch}, 1;
667 is tied($scalar)->{store}, 0;
668 is Devel::PPPort::magic_SvPV_nomg_nolen($scalar), 10;
669 is tied($scalar)->{fetch}, 1;
670 is tied($scalar)->{store}, 0;
671 ok Devel::PPPort::magic_SvTRUE_nomg($scalar);
672 is tied($scalar)->{fetch}, 1;
673 is tied($scalar)->{store}, 0;
675 my $object = OverloadedObject->new('string', 5.5, 0);
677 is Devel::PPPort::magic_SvIV_nomg($object), 5;
678 is Devel::PPPort::magic_SvUV_nomg($object), 5;
679 is Devel::PPPort::magic_SvNV_nomg($object), 5.5;
680 is Devel::PPPort::magic_SvPV_nomg_nolen($object), 'string';
681 ok !Devel::PPPort::magic_SvTRUE_nomg($object);
683 tie my $negative, 'TieScalarCounter', -1;
686 is tied($negative)->{fetch}, 1;
687 is tied($negative)->{store}, 0;
688 is Devel::PPPort::magic_SvIV_nomg($negative), -1;
689 if (ivers($]) >= ivers("5.6")) {
690 ok !Devel::PPPort::SVf_IVisUV($negative);
692 skip 'SVf_IVisUV is unsupported', 1;
694 is tied($negative)->{fetch}, 1;
695 is tied($negative)->{store}, 0;
696 Devel::PPPort::magic_SvUV_nomg($negative);
697 if (ivers($]) >= ivers("5.6")) {
698 ok !Devel::PPPort::SVf_IVisUV($negative);
700 skip 'SVf_IVisUV is unsupported', 1;
702 is tied($negative)->{fetch}, 1;
703 is tied($negative)->{store}, 0;
705 tie my $big, 'TieScalarCounter', Devel::PPPort::above_IV_MAX();
708 is tied($big)->{fetch}, 1;
709 is tied($big)->{store}, 0;
710 Devel::PPPort::magic_SvIV_nomg($big);
711 if (ivers($]) >= ivers("5.6")) {
712 ok Devel::PPPort::SVf_IVisUV($big);
714 skip 'SVf_IVisUV is unsupported', 1;
716 is tied($big)->{fetch}, 1;
717 is tied($big)->{store}, 0;
718 is Devel::PPPort::magic_SvUV_nomg($big), Devel::PPPort::above_IV_MAX();
719 if (ivers($]) >= ivers("5.6")) {
720 ok Devel::PPPort::SVf_IVisUV($big);
722 skip 'SVf_IVisUV is unsupported', 1;
724 is tied($big)->{fetch}, 1;
725 is tied($big)->{store}, 0;
727 package TieScalarCounter;
730 my ($class, $value) = @_;
731 return bless { fetch => 0, store => 0, value => $value }, $class;
737 return $self->{value};
741 my ($self, $value) = @_;
743 $self->{value} = $value;
746 package OverloadedObject;
749 my ($class, $str, $num, $bool) = @_;
750 return bless { str => $str, num => $num, bool => $bool }, $class;
754 '""' => sub { $_[0]->{str} },
755 '0+' => sub { $_[0]->{num} },
756 'bool' => sub { $_[0]->{bool} },