- #include "EXTERN.h"
- #include "perl.h"
- #include "XSUB.h"
- #define SVt_PADNAME SVt_PVMG
- #ifndef COP_SEQ_RANGE_LOW_set
- # define COP_SEQ_RANGE_LOW_set(sv,val) \
- do { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xlow = val; } while(0)
- # define COP_SEQ_RANGE_HIGH_set(sv,val) \
- do { ((XPVNV*)SvANY(sv))->xnv_u.xpad_cop_seq.xhigh = val; } while(0)
- #endif
- #ifndef PAD_MAX
- # define PAD_MAX I32_MAX
- #endif
- static BHK my_blk_hooks;
- #define pad_add_my_scalar_pvn(namepv, namelen) \
- S_pad_add_my_scalar_pvn(aTHX_ namepv, namelen)
- static
- PADOFFSET S_pad_add_my_scalar_pvn(pTHX_ char const *namepv, STRLEN namelen)
- {
- PADOFFSET offset;
- SV *namesv, *myvar;
- myvar = *av_fetch(PL_comppad, AvFILLp(PL_comppad) + 1, 1);
- offset = AvFILLp(PL_comppad);
- SvPADMY_on(myvar);
- PL_curpad = AvARRAY(PL_comppad);
- namesv = newSV_type(SVt_PADNAME);
- sv_setpvn(namesv, namepv, namelen);
- COP_SEQ_RANGE_LOW_set(namesv, PL_cop_seqmax);
- COP_SEQ_RANGE_HIGH_set(namesv, PAD_MAX);
- PL_cop_seqmax++;
- av_store(PL_comppad_name, offset, namesv);
- return offset;
- }
- #define new_hook(cb) S_new_hook(aTHX_ cb)
- static SV *
- S_new_hook (pTHX_ SV *cb)
- {
- HV *obj = newHV();
- SV *self = newRV_noinc((SV *)obj);
- sv_bless(self, gv_stashpvs("Hook::EndOfRuntime::Hook", 0));
- hv_stores(obj, "cb", cb);
- return self;
- }
- #define runtime_hook(cb) S_runtime_hook(aTHX_ cb)
- static OP *
- S_runtime_hook (pTHX_ SV *cb)
- {
- OP *pvarop;
- pvarop = newOP(OP_PADSV, (OPpLVAL_INTRO<<8));
- pvarop->op_targ = pad_add_my_scalar_pvn("\0", 1);
- return newASSIGNOP(OPf_STACKED, pvarop, 0,
- newSVOP(OP_CONST, 0, new_hook(cb)));
- }
- #define call_cb(cb) S_call_cb(aTHX_ cb)
- static void
- S_call_cb (pTHX_ CV *cb)
- {
- dSP;
- ENTER;
- SAVETMPS;
- PUSHMARK(SP);
- PUTBACK;
- call_sv((SV *)cb, G_VOID | G_DISCARD);
- FREETMPS;
- LEAVE;
- }
- static SV *current_cb;
- void
- my_pre_block_end (pTHX_ OP **op_ptr)
- {
- if (!current_cb)
- return;
- OP *hook = runtime_hook(current_cb);
- current_cb = NULL;
- *op_ptr = op_append_elem(OP_LIST, hook, *op_ptr);
- }
- MODULE = Hook::EndOfRuntime PACKAGE = Hook::EndOfRuntime
- PROTOTYPES: DISABLE
- BOOT:
- BhkENTRY_set(&my_blk_hooks, bhk_pre_end, my_pre_block_end);
- Perl_blockhook_register(aTHX_ &my_blk_hooks);
- void
- after_runtime (UV level, SV *cb)
- CODE:
- if (current_cb)
- croak("override");
- current_cb = newSVsv(cb);
- MODULE = Hook::EndOfRuntime PACKAGE = Hook::EndOfRuntime::Hook
- void
- DESTROY (self)
- SV *self
- PREINIT:
- CV *cb;
- CODE:
- cb = (CV *)SvRV(*hv_fetchs((HV *)SvRV(self), "cb", 0));
- call_cb(cb);