Perl関数フックの実現

  1. EB::Hooksetのmagic_extにhookset_obj構造体を入れる。
  2. 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*)で渡さないとうまくいかない。