#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "JavaScript_Env.h" #include "PJS_Call.h" #include "PJS_Context.h" #include "PJS_TypeConversion.h" SV *PJS_call_perl_method(const char *method, ...) { dSP; va_list ap; SV *arg, *ret = sv_newmortal(); int rcount; ENTER; SAVETMPS; PUSHMARK(SP); va_start(ap, method); while ((arg = va_arg(ap, SV*)) != NULL) { XPUSHs(arg); } PUTBACK; rcount = perl_call_method(method, G_SCALAR); SPAGAIN; sv_setsv(ret, POPs); PUTBACK; FREETMPS; LEAVE; return ret; } I32 perl_call_sv_with_jsvals_rsv(JSContext *cx, JSObject *obj, SV *code, SV *caller, uintN argc, jsval *argv, SV **rsv) { dSP; I32 rcount = 0; int arg; if (SvROK(code) && SvTYPE(SvRV(code)) == SVt_PVCV) { ENTER ; SAVETMPS ; PUSHMARK(SP) ; if (caller) { XPUSHs(caller); } for (arg = 0; arg < argc; arg++) { SV *sv = sv_newmortal(); JSVALToSV(cx, NULL, argv[arg], &sv); XPUSHs(sv); } PUTBACK ; rcount = perl_call_sv(SvRV(code), G_SCALAR|G_EVAL); SPAGAIN ; if(rcount) { int i; /* XXX: this is wrong */ for (i = 0; i < rcount; ++i) { if (rsv) { *rsv = POPs; SvREFCNT_inc(*rsv); } } } else { } if (SvTRUE(ERRSV)) { jsval rval; SV* cp = sv_mortalcopy( ERRSV ); if (PJS_ConvertPerlToJSType(cx, NULL, obj, cp, &rval) != JS_FALSE) { JS_SetPendingException(cx, rval); rcount = -1; /* ERRSV is now converted into JS space. If it leaves again, we'll turn it into a perl exception, so we can drop the perl-space error here. */ sv_setsv(ERRSV, &PL_sv_undef); } else { croak("Can't convert perl error into JSVAL"); } } PUTBACK ; FREETMPS ; LEAVE ; } else { warn("not a coderef"); } return rcount; } I32 perl_call_sv_with_jsvals(JSContext *cx, JSObject *obj, SV *code, SV *caller, uintN argc, jsval *argv, jsval *rval) { SV *rsv; I32 rcount = perl_call_sv_with_jsvals_rsv(cx, obj, code, caller, argc, argv, rval ? &rsv : NULL); if (rval) { PJS_ConvertPerlToJSType(cx, NULL, obj, rsv, rval); } return rcount; } JSBool PJS_call_javascript_function(PJS_Context *pcx, jsval func, SV *args, jsval *rval) { jsval *arg_list; SV *val; AV *av; int arg_count, i; JSFunction *js_fun; /* Clear $@ */ sv_setsv(ERRSV, &PL_sv_undef); av = (AV *) SvRV(args); arg_count = av_len(av); Newz(1, arg_list, arg_count + 1, jsval); if (arg_list == NULL) { croak("Failed to allocate memory for argument list"); } for (i = 0; i <= arg_count; i++) { val = *av_fetch(av, i, 0); if (PJS_ConvertPerlToJSType(PJS_GetJSContext(pcx), NULL, JS_GetGlobalObject(PJS_GetJSContext(pcx)), val, &(arg_list[i])) == JS_FALSE) { Safefree(arg_list); croak("Can't convert argument number %d to jsval", i); } } js_fun = JS_ValueToFunction(PJS_GetJSContext(pcx), func); if (JS_CallFunction(PJS_GetJSContext(pcx), JS_GetGlobalObject(PJS_GetJSContext(pcx)), js_fun, arg_count + 1, (jsval *) arg_list, (jsval *) rval) == JS_FALSE) { PJS_report_exception(pcx); return JS_FALSE; } return JS_TRUE; } JSBool perl_call_jsfunc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { jsval tmp; SV *code; JSFunction *jsfun = PJS_FUNC_SELF; JSObject *funobj = JS_GetFunctionObject(jsfun); if (JS_GetProperty(cx, funobj, "_perl_func", &tmp) == JS_FALSE) { croak("Can't get coderef\n"); } code = JSVAL_TO_PRIVATE(tmp); if (perl_call_sv_with_jsvals(cx, obj, code, NULL, argc, argv, rval) < 0) { return JS_FALSE; } return JS_TRUE; }