ossp-pkg/js/src/perlconnect/JS.xs
/* -*- 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);