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 ################################################################################
29 __UNDEFINED__ SvGETMAGIC(x) ((void)(UNLIKELY(SvGMAGICAL(x)) && mg_get(x)))
31 /* That's the best we can do... */
32 __UNDEFINED__ sv_catpvn_nomg sv_catpvn
33 __UNDEFINED__ sv_catsv_nomg sv_catsv
34 __UNDEFINED__ sv_setsv_nomg sv_setsv
35 __UNDEFINED__ sv_pvn_nomg sv_pvn
38 #if defined(PERL_USE_GCC_BRACE_GROUPS)
39 __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; }))
40 __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; }))
42 __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)))
43 __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)))
46 __UNDEFINED__ SvIV_nomg(sv) (!SvGMAGICAL((sv)) ? SvIV((sv)) : SvIVx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
47 __UNDEFINED__ SvUV_nomg(sv) (!SvGMAGICAL((sv)) ? SvUV((sv)) : SvUVx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
50 __UNDEFINED__ SvNV_nomg(sv) (!SvGMAGICAL((sv)) ? SvNV((sv)) : SvNVx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
51 __UNDEFINED__ SvTRUE_nomg(sv) (!SvGMAGICAL((sv)) ? SvTRUE((sv)) : SvTRUEx(sv_mortalcopy_flags((sv), SV_NOSTEAL)))
54 # define sv_catpv_mg(sv, ptr) \
57 sv_catpv(TeMpSv,ptr); \
63 # define sv_catpvn_mg(sv, ptr, len) \
66 sv_catpvn(TeMpSv,ptr,len); \
72 # define sv_catsv_mg(dsv, ssv) \
75 sv_catsv(TeMpSv,ssv); \
81 # define sv_setiv_mg(sv, i) \
90 # define sv_setnv_mg(sv, num) \
93 sv_setnv(TeMpSv,num); \
99 # define sv_setpv_mg(sv, ptr) \
102 sv_setpv(TeMpSv,ptr); \
103 SvSETMAGIC(TeMpSv); \
108 # define sv_setpvn_mg(sv, ptr, len) \
111 sv_setpvn(TeMpSv,ptr,len); \
112 SvSETMAGIC(TeMpSv); \
117 # define sv_setsv_mg(dsv, ssv) \
120 sv_setsv(TeMpSv,ssv); \
121 SvSETMAGIC(TeMpSv); \
126 # define sv_setuv_mg(sv, i) \
129 sv_setuv(TeMpSv,i); \
130 SvSETMAGIC(TeMpSv); \
135 # define sv_usepvn_mg(sv, ptr, len) \
138 sv_usepvn(TeMpSv,ptr,len); \
139 SvSETMAGIC(TeMpSv); \
143 __UNDEFINED__ SvVSTRING_mg(sv) (SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_vstring) : NULL)
145 /* Hint: sv_magic_portable
146 * This is a compatibility function that is only available with
147 * Devel::PPPort. It is NOT in the perl core.
148 * Its purpose is to mimic the 5.8.0 behaviour of sv_magic() when
149 * it is being passed a name pointer with namlen == 0. In that
150 * case, perl 5.8.0 and later store the pointer, not a copy of it.
151 * The compatibility can be provided back to perl 5.004. With
152 * earlier versions, the code will not compile.
155 #if { VERSION < 5.004 }
157 /* code that uses sv_magic_portable will not compile */
159 #elif { VERSION < 5.8.0 }
161 # define sv_magic_portable(sv, obj, how, name, namlen) \
163 SV *SvMp_sv = (sv); \
164 char *SvMp_name = (char *) (name); \
165 I32 SvMp_namlen = (namlen); \
166 if (SvMp_name && SvMp_namlen == 0) \
169 sv_magic(SvMp_sv, obj, how, 0, 0); \
170 mg = SvMAGIC(SvMp_sv); \
171 mg->mg_len = -42; /* XXX: this is the tricky part */ \
172 mg->mg_ptr = SvMp_name; \
176 sv_magic(SvMp_sv, obj, how, SvMp_name, SvMp_namlen); \
182 # define sv_magic_portable(a, b, c, d, e) sv_magic(a, b, c, d, e)
186 #if !defined(mg_findext)
187 #if { NEED mg_findext }
190 mg_findext(const SV * sv, int type, const MGVTBL *vtbl) {
194 #ifdef AvPAD_NAMELIST
195 assert(!(SvTYPE(sv) == SVt_PVAV && AvPAD_NAMELIST(sv)));
198 for (mg = SvMAGIC (sv); mg; mg = mg->mg_moremagic) {
199 if (mg->mg_type == type && mg->mg_virtual == vtbl)
210 #if !defined(sv_unmagicext)
211 #if { NEED sv_unmagicext }
214 sv_unmagicext(pTHX_ SV *const sv, const int type, const MGVTBL *vtbl)
219 if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
221 mgp = &(SvMAGIC(sv));
222 for (mg = *mgp; mg; mg = *mgp) {
223 const MGVTBL* const virt = mg->mg_virtual;
224 if (mg->mg_type == type && virt == vtbl) {
225 *mgp = mg->mg_moremagic;
226 if (virt && virt->svt_free)
227 virt->svt_free(aTHX_ sv, mg);
228 if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
230 Safefree(mg->mg_ptr);
231 else if (mg->mg_len == HEf_SVKEY) /* Questionable on older perls... */
232 SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
233 else if (mg->mg_type == PERL_MAGIC_utf8)
234 Safefree(mg->mg_ptr);
236 if (mg->mg_flags & MGf_REFCOUNTED)
237 SvREFCNT_dec(mg->mg_obj);
241 mgp = &mg->mg_moremagic;
244 if (SvMAGICAL(sv)) /* if we're under save_magic, wait for restore_magic; */
245 mg_magical(sv); /* else fix the flags now */
249 SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
259 #define NEED_mg_findext
260 #define NEED_sv_unmagicext
263 #define STATIC static
266 STATIC MGVTBL null_mg_vtbl = {
274 #endif /* MGf_COPY */
280 #endif /* MGf_LOCAL */
283 STATIC MGVTBL other_mg_vtbl = {
291 #endif /* MGf_COPY */
297 #endif /* MGf_LOCAL */
303 new_with_other_mg(package, ...)
309 const char *data = "hello\0";
313 stash = gv_stashpv(SvPV_nolen(package), 0);
315 self_ref = newRV_noinc((SV*)self);
317 sv_magic((SV*)self, NULL, PERL_MAGIC_ext, data, strlen(data));
318 mg = mg_find((SV*)self, PERL_MAGIC_ext);
320 mg->mg_virtual = &other_mg_vtbl;
324 RETVAL = sv_bless(self_ref, stash);
329 new_with_mg(package, ...)
335 const char *data = "hello\0";
339 stash = gv_stashpv(SvPV_nolen(package), 0);
341 self_ref = newRV_noinc((SV*)self);
343 sv_magic((SV*)self, NULL, PERL_MAGIC_ext, data, strlen(data));
344 mg = mg_find((SV*)self, PERL_MAGIC_ext);
346 mg->mg_virtual = &null_mg_vtbl;
350 RETVAL = sv_bless(self_ref, stash);
355 remove_null_magic(self)
360 obj = (HV*) SvRV(self);
362 sv_unmagicext((SV*)obj, PERL_MAGIC_ext, &null_mg_vtbl);
365 remove_other_magic(self)
370 obj = (HV*) SvRV(self);
372 sv_unmagicext((SV*)obj, PERL_MAGIC_ext, &other_mg_vtbl);
381 obj = (HV*) SvRV(self);
383 if ((mg = mg_findext((SV*)obj, PERL_MAGIC_ext, &null_mg_vtbl))) {
384 XPUSHs(sv_2mortal(newSVpv(mg->mg_ptr, strlen(mg->mg_ptr))));
386 XPUSHs(sv_2mortal(newSVpvs("Sorry, your princess is in another castle.")));
390 sv_catpv_mg(sv, string)
394 sv_catpv_mg(sv, string);
397 sv_catpvn_mg(sv, sv2)
404 str = SvPV(sv2, len);
405 sv_catpvn_mg(sv, str, len);
412 sv_catsv_mg(sv, sv2);
436 sv_setpvn_mg(sv, sv2)
443 str = SvPV(sv2, len);
444 sv_setpvn_mg(sv, str, len);
451 sv_setsv_mg(sv, sv2);
461 sv_usepvn_mg(sv, sv2)
468 str = SvPV(sv2, len);
469 New(42, copy, len+1, char);
470 Copy(str, copy, len+1, char);
471 sv_usepvn_mg(sv, copy, len);
477 RETVAL = SvVSTRING_mg(sv) != NULL;
482 sv_magic_portable(sv)
486 const char *foo = "foo";
488 #if { VERSION >= 5.004 }
489 sv_magic_portable(sv, 0, '~', foo, 0);
490 mg = mg_find(sv, '~');
494 RETVAL = mg->mg_ptr == foo;
496 sv_magic(sv, 0, '~', (char *) foo, strlen(foo));
497 mg = mg_find(sv, '~');
498 RETVAL = strEQ(mg->mg_ptr, foo);
507 RETVAL = (UV)IV_MAX+100;
517 RETVAL = (SvFLAGS(sv) & SVf_IVisUV);
529 RETVAL = SvIV_nomg(sv);
541 RETVAL = SvUV_nomg(sv);
553 RETVAL = SvNV_nomg(sv);
562 magic_SvTRUE_nomg(sv)
565 RETVAL = SvTRUE_nomg(sv);
571 #ifdef SvPV_nomg_nolen
574 magic_SvPV_nomg_nolen(sv)
577 RETVAL = SvPV_nomg_nolen(sv);
586 ok(my $obj1 = Devel::PPPort->new_with_mg());
587 is(Devel::PPPort::as_string($obj1), 'hello');
590 my $obj = bless {}, 'Fake::Class';
591 is(Devel::PPPort::as_string($obj), "Sorry, your princess is in another castle.");
593 # Find with other magic (not the magic we are looking for)
594 ok($obj = Devel::PPPort->new_with_other_mg());
595 is(Devel::PPPort::as_string($obj), "Sorry, your princess is in another castle.");
597 # Okay, attempt to remove magic that isn't there
598 Devel::PPPort::remove_other_magic($obj1);
599 is(Devel::PPPort::as_string($obj1), 'hello');
601 # Remove magic that IS there
602 Devel::PPPort::remove_null_magic($obj1);
603 is(Devel::PPPort::as_string($obj1), "Sorry, your princess is in another castle.");
605 # Removing when no magic present
606 Devel::PPPort::remove_null_magic($obj1);
607 is(Devel::PPPort::as_string($obj1), "Sorry, your princess is in another castle.");
611 tie %h, 'Tie::StdHash';
615 &Devel::PPPort::sv_catpv_mg($h{foo}, 'bar');
616 is($h{foo}, 'foobar');
618 &Devel::PPPort::sv_catpvn_mg($h{bar}, 'baz');
621 &Devel::PPPort::sv_catsv_mg($h{foo}, '42');
622 is($h{foo}, 'foobar42');
624 &Devel::PPPort::sv_setiv_mg($h{bar}, 42);
627 &Devel::PPPort::sv_setnv_mg($h{PI}, 3.14159);
628 ok(abs($h{PI} - 3.14159) < 0.01);
630 &Devel::PPPort::sv_setpv_mg($h{mhx}, 'mhx');
633 &Devel::PPPort::sv_setpvn_mg($h{mhx}, 'Marcus');
634 is($h{mhx}, 'Marcus');
636 &Devel::PPPort::sv_setsv_mg($h{sv}, 'SV');
639 &Devel::PPPort::sv_setuv_mg($h{sv}, 4711);
642 &Devel::PPPort::sv_usepvn_mg($h{sv}, 'Perl');
645 # v1 is treated as a bareword in older perls...
646 my $ver = do { local $SIG{'__WARN__'} = sub {}; eval qq[v1.2.0] };
647 ok(ivers($]) < ivers("5.009") || $@ eq '');
648 ok(ivers($]) < ivers("5.009") || Devel::PPPort::SvVSTRING_mg($ver));
649 ok(!Devel::PPPort::SvVSTRING_mg(4711));
652 ok(Devel::PPPort::sv_magic_portable($foo));
655 tie my $scalar, 'TieScalarCounter', 10;
658 is tied($scalar)->{fetch}, 1;
659 is tied($scalar)->{store}, 0;
660 is Devel::PPPort::magic_SvIV_nomg($scalar), 10;
661 is tied($scalar)->{fetch}, 1;
662 is tied($scalar)->{store}, 0;
663 is Devel::PPPort::magic_SvUV_nomg($scalar), 10;
664 is tied($scalar)->{fetch}, 1;
665 is tied($scalar)->{store}, 0;
666 is Devel::PPPort::magic_SvNV_nomg($scalar), 10;
667 is tied($scalar)->{fetch}, 1;
668 is tied($scalar)->{store}, 0;
669 is Devel::PPPort::magic_SvPV_nomg_nolen($scalar), 10;
670 is tied($scalar)->{fetch}, 1;
671 is tied($scalar)->{store}, 0;
672 ok Devel::PPPort::magic_SvTRUE_nomg($scalar);
673 is tied($scalar)->{fetch}, 1;
674 is tied($scalar)->{store}, 0;
676 my $object = OverloadedObject->new('string', 5.5, 0);
678 is Devel::PPPort::magic_SvIV_nomg($object), 5;
679 is Devel::PPPort::magic_SvUV_nomg($object), 5;
680 is Devel::PPPort::magic_SvNV_nomg($object), 5.5;
681 is Devel::PPPort::magic_SvPV_nomg_nolen($object), 'string';
682 ok !Devel::PPPort::magic_SvTRUE_nomg($object);
684 tie my $negative, 'TieScalarCounter', -1;
687 is tied($negative)->{fetch}, 1;
688 is tied($negative)->{store}, 0;
689 is Devel::PPPort::magic_SvIV_nomg($negative), -1;
690 if (ivers($]) >= ivers("5.6")) {
691 ok !Devel::PPPort::SVf_IVisUV($negative);
693 skip 'SVf_IVisUV is unsupported', 1;
695 is tied($negative)->{fetch}, 1;
696 is tied($negative)->{store}, 0;
697 Devel::PPPort::magic_SvUV_nomg($negative);
698 if (ivers($]) >= ivers("5.6")) {
699 ok !Devel::PPPort::SVf_IVisUV($negative);
701 skip 'SVf_IVisUV is unsupported', 1;
703 is tied($negative)->{fetch}, 1;
704 is tied($negative)->{store}, 0;
706 tie my $big, 'TieScalarCounter', Devel::PPPort::above_IV_MAX();
709 is tied($big)->{fetch}, 1;
710 is tied($big)->{store}, 0;
711 Devel::PPPort::magic_SvIV_nomg($big);
712 if (ivers($]) >= ivers("5.6")) {
713 ok Devel::PPPort::SVf_IVisUV($big);
715 skip 'SVf_IVisUV is unsupported', 1;
717 is tied($big)->{fetch}, 1;
718 is tied($big)->{store}, 0;
719 is Devel::PPPort::magic_SvUV_nomg($big), Devel::PPPort::above_IV_MAX();
720 if (ivers($]) >= ivers("5.6")) {
721 ok Devel::PPPort::SVf_IVisUV($big);
723 skip 'SVf_IVisUV is unsupported', 1;
725 is tied($big)->{fetch}, 1;
726 is tied($big)->{store}, 0;
728 package TieScalarCounter;
731 my ($class, $value) = @_;
732 return bless { fetch => 0, store => 0, value => $value }, $class;
738 return $self->{value};
742 my ($self, $value) = @_;
744 $self->{value} = $value;
747 package OverloadedObject;
750 my ($class, $str, $num, $bool) = @_;
751 return bless { str => $str, num => $num, bool => $bool }, $class;
755 '""' => sub { $_[0]->{str} },
756 '0+' => sub { $_[0]->{num} },
757 'bool' => sub { $_[0]->{bool} },