📄 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"#include <malloc.h>/* __REMOVE__ *//* #include <stdio.h> *//************************************************************//* utils */static JSBoolcheckError(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 voidclearException(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;staticJSClass 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 voidPCB_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 JSBoolPCB_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 JSBoolPCB_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_ */voidPCB_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 JSBoolPCB_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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -