B-Hooks-OP-Check/Check.xs
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"
#if PERL_BCDVERSION < 0x5010001
typedef unsigned Optype;
#endif /* <5.10.1 */
#ifndef wrap_op_checker
# define wrap_op_checker(c,n,o) THX_wrap_op_checker(aTHX_ c,n,o)
static void THX_wrap_op_checker(pTHX_ Optype opcode,
Perl_check_t new_checker, Perl_check_t *old_checker_p)
{
if(*old_checker_p) return;
OP_REFCNT_LOCK;
if(!*old_checker_p) {
*old_checker_p = PL_check[opcode];
PL_check[opcode] = new_checker;
}
OP_REFCNT_UNLOCK;
}
#endif /* !wrap_op_checker */
#include "hook_op_check.h"
STATIC Perl_check_t orig_PL_check[OP_max];
STATIC AV *check_cbs[OP_max];
#define run_orig_check(type, op) (CALL_FPTR (orig_PL_check[(type)])(aTHX_ op))
STATIC void *
get_mg_ptr (SV *sv) {
MAGIC *mg;
if ((mg = mg_find (sv, PERL_MAGIC_ext))) {
return mg->mg_ptr;
}
return NULL;
}
STATIC OP *
check_cb (pTHX_ OP *op) {
I32 i;
AV *hooks = check_cbs[op->op_type];
OP *ret = run_orig_check (op->op_type, op);
if (!hooks) {
return ret;
}
for (i = 0; i <= av_len (hooks); i++) {
hook_op_check_cb cb;
void *user_data;
SV **hook = av_fetch (hooks, i, 0);
if (!hook || !*hook) {
continue;
}
user_data = get_mg_ptr (*hook);
cb = INT2PTR (hook_op_check_cb, SvUV (*hook));
ret = CALL_FPTR (cb)(aTHX_ ret, user_data);
}
return ret;
}
hook_op_check_id
hook_op_check (opcode type, hook_op_check_cb cb, void *user_data) {
AV *hooks;
SV *hook;
hooks = check_cbs[type];
if (!hooks) {
hooks = newAV ();
check_cbs[type] = hooks;
wrap_op_checker(type, check_cb, &orig_PL_check[type]);
}
hook = newSVuv (PTR2UV (cb));
sv_magic (hook, NULL, PERL_MAGIC_ext, (const char *)user_data, 0);
av_push (hooks, hook);
return (hook_op_check_id)PTR2UV (hook);
}
void *
hook_op_check_remove (opcode type, hook_op_check_id id) {
AV *hooks;
I32 i;
void *ret = NULL;
hooks = check_cbs[type];
if (!hooks) {
return NULL;
}
for (i = 0; i <= av_len (hooks); i++) {
SV **hook = av_fetch (hooks, i, 0);
if (!hook || !*hook) {
continue;
}
if ((hook_op_check_id)PTR2UV (*hook) == id) {
ret = get_mg_ptr (*hook);
av_delete (hooks, i, G_DISCARD);
}
}
return ret;
}
MODULE = B::Hooks::OP::Check PACKAGE = B::Hooks::OP::Check
PROTOTYPES: DISABLE