1056 lines
26 KiB
Plaintext
1056 lines
26 KiB
Plaintext
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is Mozilla Communicator client code, released
|
|
* March 31, 1998.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
/*
|
|
* PerlConnect. Provides means for OO Perl <==> JS communications
|
|
*/
|
|
|
|
/* This is an program written in XSUB. You need to compile it using xsubpp */
|
|
/* usually found in your perl\bin directory. On my machine I do it like this:*/
|
|
/* perl c:\perl\lib\ExtUtils\xsubpp -typemap \ */
|
|
/* c:\perl\lib\extutils\typemap -typemap typemap JS.xs > JS.c */
|
|
/* See perlxs man page for details. */
|
|
/* Don't edit the resulting C file directly. See README.html for more info */
|
|
/* on PerlConnect in general */
|
|
|
|
#ifdef __cplusplus
|
|
extern "C"; {
|
|
#endif
|
|
#include "EXTERN.h"
|
|
#include "perl.h"
|
|
#include "XSUB.h"
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#include <jsapi.h>
|
|
#include "jsperlpvt.h"
|
|
#ifdef OSSP
|
|
#include <stdlib.h>
|
|
#else
|
|
#include <malloc.h>
|
|
#endif
|
|
|
|
/* __REMOVE__ */
|
|
/* #include <stdio.h> */
|
|
|
|
/************************************************************/
|
|
/* utils */
|
|
|
|
static JSBool
|
|
checkError(JSContext *cx)
|
|
{
|
|
if(SvTRUE(GvSV(PL_errgv))){
|
|
JS_ReportError(cx, "perl eval failed: %s",
|
|
SvPV(GvSV(PL_errgv), PL_na));
|
|
/* clear error status. there should be a way to do this faster */
|
|
perl_eval_sv(newSVpv("undef $@;", 0), G_KEEPERR);
|
|
return JS_FALSE;
|
|
}
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static void
|
|
clearException(JSContext *cx)
|
|
{
|
|
if (JS_IsExceptionPending(cx)) {
|
|
JS_ClearPendingException(cx);
|
|
}
|
|
}
|
|
|
|
/************************************************************/
|
|
/* calback stub */
|
|
|
|
/* this is internal js structure needed in errorFromPrivate */
|
|
typedef struct JSExnPrivate {
|
|
JSErrorReport *errorReport;
|
|
} JSExnPrivate;
|
|
|
|
static
|
|
JSClass global_class = {
|
|
"Global", 0,
|
|
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
|
};
|
|
|
|
/* __PH__BEGIN */
|
|
/* perl callback structure */
|
|
/* prefix PCB means Perl CallBack */
|
|
|
|
struct PerlCallbackItem{
|
|
char* name;
|
|
SV* perl_proc;
|
|
int param_num;
|
|
struct PerlCallbackItem *next;
|
|
};
|
|
|
|
typedef struct PerlCallbackItem PerlCallbackItem;
|
|
|
|
|
|
struct PerlObjectItem {
|
|
char * name;
|
|
SV* pObject;
|
|
/* OSSP BUGFIX *//*JSObject *jsStub;*/
|
|
JSObject *jsObject;
|
|
JSClass *jsClass;
|
|
struct PerlCallbackItem* vector;
|
|
struct PerlObjectItem *next;
|
|
};
|
|
|
|
typedef struct PerlObjectItem PerlObjectItem;
|
|
|
|
/* error reporter */
|
|
/* OSSP BUGFIX *//*struct JSContextItem;*/
|
|
/* OSSP BUGFIX *//*struct JSContextItem;*/
|
|
struct JSContextItem {
|
|
JSContext *cx;
|
|
SV *errorReporter;
|
|
PerlObjectItem *objects;
|
|
int dieFromErrors;
|
|
struct JSContextItem* next;
|
|
};
|
|
|
|
typedef struct JSContextItem JSContextItem;
|
|
|
|
static JSContextItem *context_list = NULL;
|
|
|
|
static JSContextItem*
|
|
PCB_NewContextItem() {
|
|
JSContextItem *ret;
|
|
ret = (JSContextItem*)calloc(1, sizeof(JSContextItem));
|
|
return ret;
|
|
}
|
|
|
|
static JSContextItem*
|
|
PCB_FindContextItem (JSContext *cx) {
|
|
JSContextItem *cxitem = context_list;
|
|
while ( cxitem ) {
|
|
if (cxitem->cx == cx ) return cxitem;
|
|
cxitem = cxitem->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static SV*
|
|
PCB_FindErrorReporter (JSContext *cx) {
|
|
JSContextItem *cxitem;
|
|
if (cxitem = PCB_FindContextItem(cx)) {
|
|
return cxitem->errorReporter;
|
|
} else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
PCB_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
|
{
|
|
SV *report_proc;
|
|
if ( report_proc = PCB_FindErrorReporter(cx) ) {
|
|
dSP;
|
|
PUSHMARK(SP);
|
|
XPUSHs(sv_2mortal(newSVpv((char*)message, 0)));
|
|
if ( report ) {
|
|
if ( report->filename ) {
|
|
XPUSHs(sv_2mortal(newSVpv((char*)report->filename, 0)));
|
|
}
|
|
XPUSHs(sv_2mortal(newSViv(report->lineno)));
|
|
if (report->linebuf) {
|
|
XPUSHs(sv_2mortal(newSVpv((char*)report->linebuf, 0)));
|
|
XPUSHs(sv_2mortal(newSVpv((char*)report->tokenptr, 0)));
|
|
}
|
|
}
|
|
PUTBACK;
|
|
perl_call_sv(report_proc, G_VOID | G_DISCARD);
|
|
} else {
|
|
warn(message);
|
|
}
|
|
}
|
|
|
|
/* perl object stuff */
|
|
|
|
|
|
/* functions for callback list handling */
|
|
static PerlCallbackItem*
|
|
PCB_AddCallback(PerlObjectItem* object, char *name,
|
|
SV* perl_proc, int param_num) {
|
|
PerlCallbackItem *cbk;
|
|
|
|
cbk = (PerlCallbackItem*)calloc(1, sizeof(PerlCallbackItem));
|
|
cbk->name = (char*) malloc(strlen(name) + 1);
|
|
strcpy(cbk->name, name);
|
|
SvREFCNT_inc(perl_proc);
|
|
cbk->perl_proc = perl_proc;
|
|
cbk->param_num = param_num;
|
|
|
|
cbk->next = object->vector;
|
|
object->vector = cbk;
|
|
|
|
return cbk;
|
|
}
|
|
|
|
/* functions for perl object list handling */
|
|
|
|
static PerlObjectItem*
|
|
PCB_AddObject(char *name, SV *pobj, JSContext *cx, JSObject *jso, JSClass *class) {
|
|
JSContextItem *cxitem;
|
|
PerlObjectItem *object;
|
|
|
|
/* we should always find the item */
|
|
cxitem = PCB_FindContextItem(cx);
|
|
object = (PerlObjectItem*) calloc(1, sizeof(PerlObjectItem));
|
|
object->name = (char*) malloc(strlen(name) + 1);
|
|
strcpy(object->name, name);
|
|
SvREFCNT_inc(pobj);
|
|
object->pObject = pobj;
|
|
object->jsObject = jso;
|
|
object->jsClass = class;
|
|
object->next = cxitem->objects;
|
|
cxitem->objects = object;
|
|
|
|
return object;
|
|
}
|
|
|
|
static PerlObjectItem*
|
|
PCB_FindObject(JSContext *cx, JSObject *jso) {
|
|
JSContextItem *cxitem;
|
|
PerlObjectItem *objitem;
|
|
|
|
cxitem = PCB_FindContextItem(cx);
|
|
objitem = cxitem->objects;
|
|
|
|
while ( objitem ) {
|
|
if ( objitem->jsObject == jso ) return objitem;
|
|
objitem = objitem->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static PerlCallbackItem*
|
|
PCB_FindCallback(PerlObjectItem *obj, const char *name) {
|
|
PerlCallbackItem *cbkitem;
|
|
|
|
cbkitem = obj->vector;
|
|
while ( cbkitem ) {
|
|
if ( strcmp(name, cbkitem->name) == 0 ) return cbkitem;
|
|
cbkitem = cbkitem->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* deletion functions */
|
|
|
|
static void
|
|
PCB_FreeCallbackItem(PerlCallbackItem *callback) {
|
|
free(callback->name);
|
|
/* we have to decrease ref. count to proc */
|
|
SvREFCNT_dec(callback->perl_proc);
|
|
free(callback);
|
|
}
|
|
|
|
static void
|
|
PCB_FreeObjectItem(PerlObjectItem *object) {
|
|
PerlCallbackItem *cbkitem, *next;
|
|
JSClass *class;
|
|
|
|
free(object->name);
|
|
free(object->jsClass);
|
|
|
|
SvREFCNT_dec(object->pObject);
|
|
cbkitem = object->vector;
|
|
while ( cbkitem ) {
|
|
next = cbkitem->next;
|
|
PCB_FreeCallbackItem(cbkitem);
|
|
cbkitem = next;
|
|
}
|
|
free(object);
|
|
}
|
|
|
|
static void
|
|
PCB_FreeContextItem(JSContext *cx) {
|
|
JSContextItem *cxitem, *aux;
|
|
PerlObjectItem *objitem, *next;
|
|
|
|
cxitem = PCB_FindContextItem(cx);
|
|
objitem = cxitem->objects;
|
|
|
|
while ( objitem ) {
|
|
next = objitem->next;
|
|
PCB_FreeObjectItem(objitem);
|
|
objitem = next;
|
|
}
|
|
|
|
if (cxitem->errorReporter) {
|
|
SvREFCNT_dec(cxitem->errorReporter);
|
|
}
|
|
|
|
if ( context_list == cxitem ) {
|
|
context_list = cxitem->next;
|
|
} else {
|
|
aux = context_list;
|
|
while ( aux->next != cxitem ) aux = aux->next;
|
|
aux->next = cxitem->next;
|
|
}
|
|
free(cxitem);
|
|
}
|
|
|
|
/* later the object list should be bind to JS Context
|
|
in this case is needed to update destructor PerlFreeObjectList
|
|
*/
|
|
|
|
/* property getter and setter - cooperate with AUTOLOAD */
|
|
|
|
static JSBool
|
|
PCB_GetProperty(JSContext *cx, JSObject *obj, jsval name, jsval *rval) {
|
|
PerlObjectItem *po;
|
|
int i, cnt, len;
|
|
I32 ax;
|
|
SV *proc_sv;
|
|
HV *stash;
|
|
char prop_name[256];
|
|
char full_name[256];
|
|
char *foo;
|
|
GV *gv;
|
|
dSP;
|
|
|
|
/* property name */
|
|
strcpy(prop_name, JS_GetStringBytes(JSVAL_TO_STRING(name)));
|
|
|
|
if (! (po = PCB_FindObject(cx, obj)))
|
|
croak("Couldn't find stub for object");
|
|
if ( (PCB_FindCallback(po, prop_name)))
|
|
return(JS_TRUE);
|
|
|
|
stash = SvSTASH(SvRV(po->pObject));
|
|
/* strcpy(full_name, HvNAME(stash));
|
|
strcat(full_name, "::");
|
|
strcat(full_name, prop_name);
|
|
|
|
proc_sv = sv_newmortal();
|
|
sv_setpv(proc_sv, full_name); */
|
|
/* start of perl call stuff */
|
|
|
|
gv = gv_fetchmeth(stash, prop_name, strlen(prop_name), -1);
|
|
/* better check and error report should be done here */
|
|
if (!gv) return JS_FALSE;
|
|
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
XPUSHs(po->pObject); /* self for perl AUTOLOAD */
|
|
PUTBACK;
|
|
|
|
/* cnt = perl_call_sv(proc_sv, 0); */
|
|
cnt = perl_call_sv((SV*)GvCV(gv), G_ARRAY);
|
|
|
|
SPAGAIN;
|
|
/* adjust stack for use of ST macro (see perlcall) */
|
|
SP -= cnt;
|
|
ax = (SP - PL_stack_base) + 1;
|
|
|
|
/* read value(s) */
|
|
if (cnt == 1) {
|
|
SVToJSVAL(cx, obj, ST(0), rval);
|
|
} else {
|
|
JSObject *jsarr;
|
|
jsval val;
|
|
int i;
|
|
jsarr = JS_NewArrayObject(cx, 0, NULL);
|
|
for (i = 0; i < cnt; i++) {
|
|
SVToJSVAL(cx, JS_GetGlobalObject(cx), ST(i), &val);
|
|
JS_DefineElement(cx, jsarr, i, val, NULL, NULL, 0);
|
|
}
|
|
*rval = OBJECT_TO_JSVAL(jsarr);
|
|
}
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
return(JS_TRUE);
|
|
}
|
|
|
|
static JSBool
|
|
PCB_SetProperty(JSContext *cx, JSObject *obj, jsval name, jsval *rval) {
|
|
PerlObjectItem *po;
|
|
int i, cnt, len;
|
|
I32 ax;
|
|
SV *proc_sv, *value_sv;
|
|
HV *stash;
|
|
char prop_name[256];
|
|
char full_name[256];
|
|
char *foo;
|
|
dSP;
|
|
|
|
/* property name */
|
|
strcpy(prop_name, JS_GetStringBytes(JSVAL_TO_STRING(name)));
|
|
|
|
if (! (po = PCB_FindObject(cx, obj)))
|
|
croak("Couldn't find stub for object");
|
|
if ( (PCB_FindCallback(po, prop_name)))
|
|
return(JS_TRUE);
|
|
|
|
stash = SvSTASH(SvRV(po->pObject));
|
|
strcpy(full_name, HvNAME(stash));
|
|
strcat(full_name, "::");
|
|
strcat(full_name, prop_name);
|
|
|
|
proc_sv = sv_newmortal();
|
|
sv_setpv(proc_sv, full_name);
|
|
JSVALToSV(cx, obj, *rval, &value_sv);
|
|
/* start of perl call stuff */
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
XPUSHs(po->pObject); /* self for perl AUTOLOAD */
|
|
XPUSHs(value_sv);
|
|
PUTBACK;
|
|
|
|
cnt = perl_call_sv(proc_sv, G_ARRAY);
|
|
|
|
SPAGAIN;
|
|
/* adjust stack for use of ST macro (see perlcall) */
|
|
SP -= cnt;
|
|
ax = (SP - PL_stack_base) + 1;
|
|
|
|
/* read value(s) */
|
|
if (cnt == 1) {
|
|
SVToJSVAL(cx, obj, ST(0), rval);
|
|
} else {
|
|
JSObject *jsarr;
|
|
jsval val;
|
|
int i;
|
|
jsarr = JS_NewArrayObject(cx, 0, NULL);
|
|
for (i = 0; i < cnt; i++) {
|
|
SVToJSVAL(cx, JS_GetGlobalObject(cx), ST(i), &val);
|
|
JS_DefineElement(cx, jsarr, i, val, NULL, NULL, 0);
|
|
}
|
|
*rval = OBJECT_TO_JSVAL(jsarr);
|
|
}
|
|
PUTBACK;
|
|
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
return(JS_TRUE);
|
|
}
|
|
|
|
/* helper functions */
|
|
/* JSClass pointer is disposed by
|
|
JS engine during context cleanup _PH_
|
|
*/
|
|
void
|
|
PCB_FinalizeStub(JSContext *cx, JSObject *obj) {
|
|
}
|
|
|
|
static JSClass*
|
|
PCB_NewStdJSClass(char *name) {
|
|
JSClass *class;
|
|
|
|
class = (JSClass*)calloc(1, sizeof(JSClass));
|
|
class->name = name;
|
|
class->flags = JSCLASS_HAS_PRIVATE;
|
|
class->addProperty = JS_PropertyStub;
|
|
class->delProperty = JS_PropertyStub;
|
|
class->getProperty = PCB_GetProperty;
|
|
class->setProperty = PCB_SetProperty;
|
|
class->enumerate = JS_EnumerateStub;
|
|
class->resolve = JS_ResolveStub;
|
|
class->convert = JS_ConvertStub;
|
|
/* OSSP BUGFIX */
|
|
/*class->finalize = JS_FinalizeStub;*/
|
|
class->finalize = PCB_FinalizeStub;
|
|
return(class);
|
|
}
|
|
|
|
static JSBool
|
|
PCB_UniversalStub (JSContext *cx, JSObject *obj, uintN argc,
|
|
jsval *argv, jsval *rval) {
|
|
JSFunction *fun;
|
|
PerlObjectItem *po;
|
|
PerlCallbackItem *cbk;
|
|
int i, cnt;
|
|
I32 ax;
|
|
SV* sv;
|
|
dSP;
|
|
|
|
fun = JS_ValueToFunction(cx, argv[-2]);
|
|
if (! (po = PCB_FindObject(cx, obj)))
|
|
croak("Couldn't find stub for object");
|
|
if (! (cbk = PCB_FindCallback(po, JS_GetFunctionName(fun))))
|
|
croak("Couldn't find perl callback");
|
|
/* start of perl call stuff */
|
|
ENTER;
|
|
SAVETMPS;
|
|
PUSHMARK(SP);
|
|
XPUSHs(po->pObject); /* self for perl object method */
|
|
for (i = 0; i < argc; i++) {
|
|
JSVALToSV(cx, obj, argv[i], &sv);
|
|
XPUSHs(sv);
|
|
}
|
|
PUTBACK;
|
|
cnt = perl_call_sv(SvRV(cbk->perl_proc), G_ARRAY | G_KEEPERR | G_EVAL);
|
|
|
|
SPAGAIN;
|
|
/* adjust stack for use of ST macro (see perlcall) */
|
|
SP -= cnt;
|
|
ax = (SP - PL_stack_base) + 1;
|
|
|
|
/* read value(s) */
|
|
if (cnt == 1) {
|
|
SVToJSVAL(cx, obj, ST(0), rval);
|
|
} else {
|
|
JSObject *jsarr;
|
|
jsval val;
|
|
int i;
|
|
jsarr = JS_NewArrayObject(cx, 0, NULL);
|
|
for (i = 0; i < cnt; i++) {
|
|
SVToJSVAL(cx, JS_GetGlobalObject(cx), ST(i), &val);
|
|
JS_DefineElement(cx, jsarr, i, val, NULL, NULL, 0);
|
|
}
|
|
*rval = OBJECT_TO_JSVAL(jsarr);
|
|
}
|
|
|
|
PUTBACK;
|
|
FREETMPS;
|
|
LEAVE;
|
|
|
|
/* this solution is not perfect, but usefull when nested call happens */
|
|
return(checkError(cx) && !JS_IsExceptionPending(cx));
|
|
};
|
|
|
|
/* __PH__END */
|
|
|
|
|
|
/* Helper functions needed for most JS API routines */
|
|
/*
|
|
static JSRuntime *
|
|
getRuntime()
|
|
{
|
|
return (JSRuntime *)SvIV((SV*)SvRV(perl_get_sv("JS::Runtime::rt", FALSE)));
|
|
}
|
|
|
|
static JSContext *
|
|
getContext()
|
|
{
|
|
return (JSContext *)SvIV((SV*)SvRV(perl_get_sv("JS::Context::this", FALSE)));
|
|
}
|
|
*/ /* commented as obsolete by __PH__ */
|
|
|
|
/*
|
|
The following packages are defined below:
|
|
JS -- main container for all JS functionality
|
|
JS::Runtime -- wrapper around JSRuntime *
|
|
JS::Context -- wrapper around JSContext *
|
|
JS::Object -- wrapper around JSObject *
|
|
*/
|
|
|
|
MODULE = JS PACKAGE = JS PREFIX = JS_
|
|
PROTOTYPES: DISABLE
|
|
# package JS
|
|
|
|
# Most of the functions below have names coinsiding with those of the
|
|
# corresponding JS API functions. Thus, they are not commented.
|
|
JSRuntime *
|
|
JS_NewRuntime(maxbytes)
|
|
int maxbytes
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
JS_DestroyRuntime(rt)
|
|
JSRuntime *rt
|
|
CODE:
|
|
/*
|
|
Make sure that the reference count to the runtime is zero.
|
|
O.w. this sequence of commands will cause double-deallocation:
|
|
$rt = new JS::Runtime(10_000);
|
|
$rt1 = $rt;
|
|
[exit here]
|
|
So both $rt->DESTROY and $rt1->DESTROY will cause runtime destruction.
|
|
|
|
_PH_ That's not true, I guess. At least for Perl 5.
|
|
*/
|
|
/* warn("===> before runtime check\n"); */
|
|
if(SvREFCNT(ST(0)) == 1){
|
|
/* warn("===> really runtime destroing"); */
|
|
/* __PH__ */
|
|
/*__PH__END */
|
|
JS_DestroyRuntime(rt);
|
|
}
|
|
|
|
|
|
# package JS::Runtime
|
|
MODULE = JS PACKAGE = JS::Runtime PREFIX = JS_
|
|
|
|
int
|
|
JS_NewContext(rt, stacksize)
|
|
JSRuntime *rt
|
|
int stacksize
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
CODE:
|
|
{
|
|
JSObject *obj;
|
|
/* jsval v; comment out unused var __PH__*/
|
|
JSContext *cx;
|
|
cx = JS_NewContext(rt, stacksize);
|
|
cxitem = PCB_NewContextItem();
|
|
cxitem->cx = cx;
|
|
cxitem->next = context_list;
|
|
context_list = cxitem;
|
|
/* __PH__ set the error reporter */
|
|
JS_SetErrorReporter(cx, PCB_ErrorReporter);
|
|
obj = JS_NewObject(cx, &global_class, NULL, NULL);
|
|
JS_SetGlobalObject(cx, obj);
|
|
JS_InitStandardClasses(cx, obj);
|
|
RETVAL = (int)cx;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
JS_DestroyContext(cx)
|
|
JSContext *cx
|
|
CODE:
|
|
/* See the comment about ref. count above */
|
|
/* warn("===> before context check\n"); */
|
|
if(SvREFCNT(ST(0)) == 1){
|
|
/* warn("===> really destroing context"); */
|
|
if (JS_IsExceptionPending(cx)) {
|
|
JS_ClearPendingException(cx);
|
|
}
|
|
JS_SetErrorReporter(cx, NULL);
|
|
JS_GC(cx); /* OSSP BUGFIX */ /*important*/
|
|
JS_DestroyContext(cx);
|
|
PCB_FreeContextItem(cx);
|
|
}
|
|
|
|
|
|
# package JS::Context
|
|
MODULE = JS PACKAGE = JS::Context PREFIX = JS_
|
|
|
|
jsval
|
|
JS_eval(cx, bytes, ...)
|
|
JSContext *cx
|
|
char *bytes
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
char *filename = NULL;
|
|
CODE:
|
|
{
|
|
jsval rval;
|
|
if (items > 2) { filename = SvPV(ST(2), PL_na); };
|
|
/* Call on the global object */
|
|
if(!JS_EvaluateScript(cx, JS_GetGlobalObject(cx),
|
|
bytes, strlen(bytes),
|
|
filename ? filename : "Perl",
|
|
0, &rval)){
|
|
cxitem = PCB_FindContextItem(cx);
|
|
if (!cxitem || cxitem->dieFromErrors)
|
|
croak("JS script evaluation failed");
|
|
|
|
clearException(cx);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
RETVAL = rval;
|
|
}
|
|
clearException(cx);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
|
|
jsval
|
|
JS_exec_(cx, script)
|
|
JSContext *cx
|
|
SV *script
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
JSScript *handle;
|
|
CODE:
|
|
{
|
|
jsval rval;
|
|
handle = (JSScript*)SvIV(*hv_fetch((HV*)SvRV(script), "_script", 7, 0));
|
|
/* Call on the global object */
|
|
if(!JS_ExecuteScript(cx, JS_GetGlobalObject(cx),
|
|
handle, &rval)) {
|
|
cxitem = PCB_FindContextItem(cx);
|
|
if (!cxitem || cxitem->dieFromErrors)
|
|
croak("JS script evaluation failed");
|
|
|
|
clearException(cx);
|
|
XSRETURN_UNDEF;
|
|
}
|
|
clearException(cx);
|
|
RETVAL = rval;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#void
|
|
#JS_destroyScript(cx, script)
|
|
# JSContext *cx
|
|
# JSScript *script
|
|
# CODE:
|
|
# JS_DestroyScript(cx, script);
|
|
|
|
# __PH__
|
|
void
|
|
JS_setErrorReporter(cx, reporter)
|
|
JSContext *cx
|
|
SV* reporter
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
CODE:
|
|
cxitem = PCB_FindContextItem(cx);
|
|
SvREFCNT_inc(reporter);
|
|
if ( cxitem ) cxitem->errorReporter = reporter;
|
|
|
|
void
|
|
JS_unsetErrorReporter(cx)
|
|
JSContext *cx
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
CODE:
|
|
cxitem = PCB_FindContextItem(cx);
|
|
if ( cxitem ) {
|
|
if ( cxitem->errorReporter )
|
|
SvREFCNT_dec(cxitem->errorReporter);
|
|
cxitem->errorReporter = NULL;
|
|
}
|
|
|
|
int
|
|
JS_hasException(cx)
|
|
JSContext *cx
|
|
CODE:
|
|
RETVAL = ! JS_IsExceptionPending(cx);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
JS_reportError(cx, msg)
|
|
JSContext *cx
|
|
char *msg
|
|
CODE:
|
|
JS_ReportError(cx, msg);
|
|
|
|
void
|
|
JS_errorFromPrivate(cx, msg, ex)
|
|
JSContext *cx
|
|
char *msg
|
|
JSObject *ex
|
|
PREINIT:
|
|
JSErrorReport *rep;
|
|
CODE:
|
|
rep = (JSErrorReport*) JS_GetPrivate(cx, ex);
|
|
if (rep)
|
|
PCB_ErrorReporter(cx, msg, ((JSExnPrivate*)rep)->errorReport);
|
|
|
|
void
|
|
JS_setDieFromErrors(cx, value)
|
|
JSContext *cx
|
|
int value
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
CODE:
|
|
cxitem = PCB_FindContextItem(cx);
|
|
if ( cxitem ) cxitem->dieFromErrors = value;
|
|
|
|
void
|
|
JS_createObject(cx, object, name, methods)
|
|
JSContext *cx
|
|
SV *object
|
|
char *name
|
|
SV *methods
|
|
PREINIT:
|
|
JSObject *jso;
|
|
HV *m_hash;
|
|
I32 len;
|
|
HE *he;
|
|
int i;
|
|
PerlObjectItem *po;
|
|
JSClass *object_class;
|
|
PerlCallbackItem *pcbitem;
|
|
CODE:
|
|
if (SvTYPE(SvRV(methods)) != SVt_PVHV) {
|
|
croak("Second parameter has to be HASHREF");
|
|
}
|
|
/* create js object in given context */
|
|
object_class = PCB_NewStdJSClass(name);
|
|
/* OSSP BUGFIX */ /* jso = JS_NewObject(cx, object_class, NULL, 0); */
|
|
|
|
jso = JS_DefineObject(cx, JS_GetGlobalObject(cx), name,
|
|
object_class, NULL,
|
|
JSPROP_ENUMERATE | JSPROP_READONLY |
|
|
JSPROP_PERMANENT);
|
|
|
|
|
|
if (!jso) croak("Unable create JS object");
|
|
/* create callback info */
|
|
po = PCB_AddObject(name, object, cx, jso, object_class);
|
|
m_hash = (HV*)SvRV(methods);
|
|
hv_iterinit(m_hash);
|
|
while ((he = hv_iternext(m_hash))) {
|
|
PCB_AddCallback(po, hv_iterkey(he, &len), hv_iterval(m_hash, he), 0);
|
|
}
|
|
/* set js object methods */
|
|
/* HERE _PH_ */
|
|
pcbitem = po->vector;
|
|
while ( pcbitem ) {
|
|
if (! JS_DefineFunction(cx, jso, pcbitem->name,
|
|
PCB_UniversalStub, 0, 0))
|
|
croak("Unable create JS function");
|
|
pcbitem = pcbitem->next;
|
|
}
|
|
|
|
# __PH__END
|
|
|
|
|
|
# package JS::Object
|
|
MODULE = JS PACKAGE = JS::Object PREFIX = JS_
|
|
|
|
#
|
|
# The methods below get used when hash is tied.
|
|
#
|
|
SV *
|
|
JS_TIEHASH(class, obj)
|
|
char *class
|
|
SV *obj
|
|
PREINIT:
|
|
JSContext* cx;
|
|
CODE:
|
|
RETVAL = SvREFCNT_inc(obj);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
SV *
|
|
JS_TIEARRAY(class, obj)
|
|
char *class
|
|
SV *obj
|
|
PREINIT:
|
|
JSContext* cx;
|
|
CODE:
|
|
RETVAL = SvREFCNT_inc(obj);
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
jsval
|
|
JS_FETCH(obj, key)
|
|
JSObject *obj
|
|
char *key
|
|
PREINIT:
|
|
JSContext* cx;
|
|
jsval rval;
|
|
MAGIC *magic;
|
|
CODE:
|
|
{
|
|
/* printf("+++++++++> FETCH\n"); */
|
|
magic = mg_find(SvRV(ST(0)), '~');
|
|
if (magic) {
|
|
cx = (JSContext *)SvIV(magic->mg_obj);
|
|
} else {
|
|
warn("Tied object has no magic\n");
|
|
}
|
|
JS_GetProperty(cx, obj, key, &rval);
|
|
RETVAL = rval;
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
JS_FETCHSIZE(obj)
|
|
JSObject *obj
|
|
PREINIT:
|
|
JSContext* cx;
|
|
MAGIC *magic;
|
|
CODE:
|
|
{
|
|
/* printf("+++++++++> FETCHSIZE: %d\n", ST(0)); */
|
|
magic = mg_find(SvRV(ST(0)), '~');
|
|
if (magic) {
|
|
cx = (JSContext *)SvIV(magic->mg_obj);
|
|
} else {
|
|
warn("Tied object has no magic\n");
|
|
}
|
|
JS_IsArrayObject(cx, obj);
|
|
JS_GetArrayLength(cx, obj, &RETVAL);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
JS_STORE(obj, key, value)
|
|
JSObject *obj
|
|
char *key
|
|
jsval value
|
|
PREINIT:
|
|
JSContext* cx;
|
|
MAGIC *magic;
|
|
{
|
|
/* printf("+++++++++> STORE\n"); */
|
|
magic = mg_find(SvRV(ST(0)), '~');
|
|
if (magic) {
|
|
cx = (JSContext *)SvIV(magic->mg_obj);
|
|
} else {
|
|
warn("Tied object has no magic\n");
|
|
}
|
|
}
|
|
CODE:
|
|
{
|
|
JS_SetProperty(cx, obj, key, &value);
|
|
}
|
|
|
|
void
|
|
JS_DELETE(obj, key)
|
|
JSObject *obj
|
|
char *key
|
|
PREINIT:
|
|
JSContext* cx;
|
|
MAGIC *magic;
|
|
CODE:
|
|
{
|
|
/* printf("+++++++++> DELETE\n"); */
|
|
magic = mg_find(SvRV(ST(0)), '~');
|
|
if (magic) {
|
|
cx = (JSContext *)SvIV(magic->mg_obj);
|
|
} else {
|
|
warn("Tied object has no magic\n");
|
|
}
|
|
JS_DeleteProperty(cx, obj, key);
|
|
}
|
|
|
|
void
|
|
JS_CLEAR(obj)
|
|
JSObject *obj
|
|
PREINIT:
|
|
JSContext* cx;
|
|
MAGIC *magic;
|
|
CODE:
|
|
{
|
|
/* printf("+++++++++> CLEAR\n"); */
|
|
magic = mg_find(SvRV(ST(0)), '~');
|
|
if (magic) {
|
|
cx = (JSContext *)SvIV(magic->mg_obj);
|
|
} else {
|
|
warn("Tied object has no magic\n");
|
|
}
|
|
JS_ClearScope(cx, obj);
|
|
}
|
|
|
|
int
|
|
JS_EXISTS(obj, key)
|
|
JSObject *obj
|
|
char *key
|
|
PREINIT:
|
|
JSContext* cx;
|
|
MAGIC *magic;
|
|
CODE:
|
|
{
|
|
jsval v;
|
|
/* printf("+++++++++> EXISTS\n"); */
|
|
magic = mg_find(SvRV(ST(0)), '~');
|
|
if (magic) {
|
|
cx = (JSContext *)SvIV(magic->mg_obj);
|
|
} else {
|
|
warn("Tied object has no magic\n");
|
|
}
|
|
JS_LookupProperty(cx, obj, key, &v);
|
|
RETVAL = !JSVAL_IS_VOID(v);
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
#script
|
|
MODULE = JS PACKAGE = JS::Script PREFIX = JS_
|
|
|
|
int
|
|
JS_compileScript(object, cx, bytes, ...)
|
|
SV *object
|
|
JSContext *cx
|
|
char *bytes
|
|
PREINIT:
|
|
JSContextItem *cxitem;
|
|
char *filename = NULL;
|
|
CODE:
|
|
{
|
|
if (items > 2) { filename = SvPV(ST(2), PL_na); };
|
|
/* Call on the global object */
|
|
if(!(RETVAL = (int)JS_CompileScript(cx, JS_GetGlobalObject(cx),
|
|
bytes, strlen(bytes),
|
|
filename ? filename : "Perl",
|
|
0)))
|
|
{
|
|
cxitem = PCB_FindContextItem(cx);
|
|
if (!cxitem || cxitem->dieFromErrors)
|
|
croak("JS script compilation failed");
|
|
XSRETURN_UNDEF;
|
|
}
|
|
}
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
int
|
|
JS_rootScript(object, cx, name)
|
|
SV *object
|
|
JSContext *cx
|
|
char *name
|
|
PREINIT:
|
|
JSObject **scrobj;
|
|
JSScript *handle;
|
|
CODE:
|
|
handle = (JSScript*)SvIV(*hv_fetch((HV*)SvRV(object), "_script", 7, 0));
|
|
scrobj = malloc(sizeof(JSObject*));
|
|
*scrobj = JS_NewScriptObject(cx, handle);
|
|
JS_AddNamedRoot(cx, scrobj, name);
|
|
RETVAL = (int)scrobj;
|
|
OUTPUT:
|
|
RETVAL
|
|
|
|
void
|
|
JS_destroyScript(object, cx)
|
|
SV *object
|
|
JSContext *cx
|
|
PREINIT:
|
|
JSObject **scrobj;
|
|
JSScript *handle;
|
|
CODE:
|
|
handle = (JSScript*)SvIV(*hv_fetch((HV*)SvRV(object), "_script", 7, 0));
|
|
scrobj = (JSObject**)SvIV(*hv_fetch((HV*)SvRV(object), "_root", 5, 0));
|
|
JS_RemoveRoot(cx, scrobj);
|
|
|