js.xs
来自「一个基于alice开发的机器人」· XS 代码 · 共 1,046 行 · 第 1/2 页
XS
1,046 行
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
/*
* 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"
#include <malloc.h>
/* __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;
//JSObject *jsStub;
JSObject *jsObject;
JSClass *jsClass;
struct PerlCallbackItem* vector;
struct PerlObjectItem *next;
};
typedef struct PerlObjectItem PerlObjectItem;
/* error reporter */
//struct JSContextItem;
//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;
//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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?