Perl関数フックの実現
- EB::Hooksetのmagic_extにhookset_obj構造体を入れる。
- Perl関数でフックするときにフック関数 eb_text_hookを呼び出し、その中でPerl関数を実行して、返り値を書き込む。
EB.XSの一部
typedef struct hookset_obj_struct { EB_Hookset *hookset; AV *functions; // perl関数(のリファレンス)を保存 } hookset_obj; EB_Error_Code eb_text_hook(EB_Book *book, EB_Appendix *appendix, void *container, EB_Hook_Code hook_code, int argc, const unsigned int *argv) { if(!SvOK((SV *)container) || !SvROK((SV *)container)) return EB_SUCCESS; SV *sv = SvRV((SV *)container); hookset_obj *obj = (hookset_obj *)mg_find(sv, PERL_MAGIC_ext)->mg_obj; SV *func = *av_fetch(obj->functions, (int)hook_code, 0); int n = 0; dSP; int count; ENTER; SAVETMPS; PUSHMARK(SP); for(n = 0; n < argc; n++) XPUSHs(sv_2mortal(newSViv(argv[n]))); PUTBACK; count = perl_call_sv(func, G_SCALAR); if (count > 0){ eb_write_text_string(book, POPp); } FREETMPS; LEAVE; return EB_SUCCESS; } MODULE = EB PACKAGE = EB::Hookset PREFIX=eb_ void eb_set_sub(obj, code, func) hookset_obj* obj; EB_Hook_Code code; CV* func; PREINIT: EB_Hook *hook; CODE: av_store(obj->functions, code, newRV_noinc((SV *)func)); // functions内にperlの関数のリファレンスを登録 Newx(hook, sizeof(hook), EB_Hook); hook->code = code; hook->function = eb_text_hook; eb_set_hook(obj->hookset, hook);
perlの関数はリファレンス(RV*)で渡さないとうまくいかない。