summaryrefslogtreecommitdiff
path: root/mg.c
diff options
context:
space:
mode:
authorZefram <zefram@fysh.org>2010-10-03 14:53:16 +0100
committerFather Chrysostomos <sprout@cpan.org>2010-10-10 17:25:15 -0700
commitd908838680ec40ea0e85f59ee66f5f56a225f9b4 (patch)
treebe5eafa5cf981949a4e4bc308be6797443882229 /mg.c
parentb98b62bccdcb420ec5430eb831023e3d91ab2fa0 (diff)
downloadperl-d908838680ec40ea0e85f59ee66f5f56a225f9b4.tar.gz
plugin mechanism to rewrite calls to a subroutine
New magic type PERL_MAGIC_checkcall attaches a function to a CV, which will be called as the second half of the op checker for an entersub op calling that CV. Default state, in the absence of this magic, is to process the CV's prototype if it has one, or apply list context to all the arguments if not. New API functions cv_get_call_checker() and cv_set_call_checker() provide a clean interface to this facility, hiding the internal use of magic. Expose in the API the new functions rv2cv_op_cv(), ck_entersub_args_list(), ck_entersub_args_proto(), and ck_entersub_args_proto_or_list(), which are meaningful segments of standard entersub op checking and are likely to be useful in plugged-in call checker functions. Expose new API function op_contextualize(), which is a public interface to the internal scalar()/list()/scalarvoid() functions. This API is likely to be required in most plugged-in call checker functions. Incidentally add new function mg_free_type(), in the API, which will remove magic of one type from an SV. (mg_free() removes all magic, and there isn't anything else more selective.)
Diffstat (limited to 'mg.c')
-rw-r--r--mg.c65
1 files changed, 53 insertions, 12 deletions
diff --git a/mg.c b/mg.c
index 8b283d993e..b96a1c1262 100644
--- a/mg.c
+++ b/mg.c
@@ -179,6 +179,7 @@ S_is_container_magic(const MAGIC *mg)
case PERL_MAGIC_rhash:
case PERL_MAGIC_symtab:
case PERL_MAGIC_tied: /* treat as value, so 'local @tied' isn't tied */
+ case PERL_MAGIC_checkcall:
return 0;
default:
return 1;
@@ -522,6 +523,24 @@ Perl_mg_localize(pTHX_ SV *sv, SV *nsv, bool setmagic)
}
}
+#define mg_free_struct(sv, mg) S_mg_free_struct(aTHX_ sv, mg)
+static void
+S_mg_free_struct(pTHX_ SV *sv, MAGIC *mg)
+{
+ const MGVTBL* const vtbl = mg->mg_virtual;
+ if (vtbl && vtbl->svt_free)
+ vtbl->svt_free(aTHX_ sv, mg);
+ if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
+ if (mg->mg_len > 0 || mg->mg_type == PERL_MAGIC_utf8)
+ Safefree(mg->mg_ptr);
+ else if (mg->mg_len == HEf_SVKEY)
+ SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
+ }
+ if (mg->mg_flags & MGf_REFCOUNTED)
+ SvREFCNT_dec(mg->mg_obj);
+ Safefree(mg);
+}
+
/*
=for apidoc mg_free
@@ -539,19 +558,8 @@ Perl_mg_free(pTHX_ SV *sv)
PERL_ARGS_ASSERT_MG_FREE;
for (mg = SvMAGIC(sv); mg; mg = moremagic) {
- const MGVTBL* const vtbl = mg->mg_virtual;
moremagic = mg->mg_moremagic;
- if (vtbl && vtbl->svt_free)
- vtbl->svt_free(aTHX_ sv, mg);
- if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
- if (mg->mg_len > 0 || mg->mg_type == PERL_MAGIC_utf8)
- Safefree(mg->mg_ptr);
- else if (mg->mg_len == HEf_SVKEY)
- SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
- }
- if (mg->mg_flags & MGf_REFCOUNTED)
- SvREFCNT_dec(mg->mg_obj);
- Safefree(mg);
+ mg_free_struct(sv, mg);
SvMAGIC_set(sv, moremagic);
}
SvMAGIC_set(sv, NULL);
@@ -559,6 +567,39 @@ Perl_mg_free(pTHX_ SV *sv)
return 0;
}
+/*
+=for apidoc Am|void|mg_free_type|SV *sv|int how
+
+Remove any magic of type I<how> from the SV I<sv>. See L</sv_magic>.
+
+=cut
+*/
+
+void
+Perl_mg_free_type(pTHX_ SV *sv, int how)
+{
+ MAGIC *mg, *prevmg, *moremg;
+ PERL_ARGS_ASSERT_MG_FREE_TYPE;
+ for (prevmg = NULL, mg = SvMAGIC(sv); mg; prevmg = mg, mg = moremg) {
+ MAGIC *newhead;
+ moremg = mg->mg_moremagic;
+ if (mg->mg_type == how) {
+ /* temporarily move to the head of the magic chain, in case
+ custom free code relies on this historical aspect of mg_free */
+ if (prevmg) {
+ prevmg->mg_moremagic = moremg;
+ mg->mg_moremagic = SvMAGIC(sv);
+ SvMAGIC_set(sv, mg);
+ }
+ newhead = mg->mg_moremagic;
+ mg_free_struct(sv, mg);
+ SvMAGIC_set(sv, newhead);
+ mg = prevmg;
+ }
+ }
+ mg_magical(sv);
+}
+
#include <signal.h>
U32