#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "RPM.h" static CV* err_callback; /* This was static, but it needs to be accessible from other modules, as well. */ SV* rpm_errSV; /* This is a callback routine that the bootstrapper will register with the RPM lib so as to catch any errors. (I hope) */ static void rpm_catch_errors(void) { /* Because rpmErrorSetCallback expects (void)fn(void), we have to declare our thread context here */ dTHX; int error_code; const char* error_string; error_code = rpmErrorCode(); error_string = rpmErrorString(); /* Set the string part, first */ sv_setpv(rpm_errSV, error_string); /* Set the IV part */ sv_setiv(rpm_errSV, error_code); /* Doing that didn't erase the PV part, but it cleared the flag: */ SvPOK_on(rpm_errSV); /* If there is a current callback, invoke it: */ if (err_callback != Nullcv) { /* This is just standard boilerplate for calling perl from C */ dSP; ENTER; SAVETMPS; PUSHMARK(sp); XPUSHs(sv_2mortal(newSViv(error_code))); XPUSHs(sv_2mortal(newSVpv((char*)error_string, strlen(error_string)))); PUTBACK; /* The actual call */ call_sv((SV *)err_callback, G_DISCARD); /* More boilerplate */ SPAGAIN; PUTBACK; FREETMPS; LEAVE; } return; } static SV* set_error_callback(pTHX_ SV* newcb) { SV* oldcb; oldcb = (err_callback) ? newRV((SV *)err_callback) : newSVsv(&PL_sv_undef); if (SvROK(newcb)) newcb = SvRV(newcb); if (SvTYPE(newcb) == SVt_PVCV) err_callback = (CV *)newcb; else if (SvPOK(newcb)) { STRLEN len; const char *name = SvPV(newcb, len); if (strstr(name, "::")) err_callback = get_cv(name, FALSE); else { SV *sv = sv_2mortal(newSVpvn("main::", 6)); sv_catpvn(sv, name, len); err_callback = get_cv(SvPV_nolen(sv), FALSE); } } else { err_callback = Nullcv; } return oldcb; } MODULE = RPM::Error PACKAGE = RPM::Error SV* set_error_callback(newcb) SV* newcb; PROTOTYPE: $ CODE: RETVAL = set_error_callback(aTHX_ newcb); OUTPUT: RETVAL void clear_errors() PROTOTYPE: CODE: /* This is just to offer an easy way to clear both sides of $RPM::err */ sv_setpv(rpm_errSV, ""); sv_setiv(rpm_errSV, 0); SvPOK_on(rpm_errSV); void rpm_error(code, message) int code; char* message; PROTOTYPE: $$ CODE: rpmError(code, "%s", message); BOOT: { rpm_errSV = get_sv("RPM::err", GV_ADD|GV_ADDMULTI); rpmErrorSetCallback(rpm_catch_errors); err_callback = Nullcv; }