--- sbbs/src/sbbs3/js_internal.c 2018/04/24 16:41:23 1.1 +++ sbbs/src/sbbs3/js_internal.c 2018/04/24 16:43:35 1.1.1.2 @@ -2,13 +2,13 @@ /* Synchronet "js" object, for internal JavaScript branch and GC control */ -/* $Id: js_internal.c,v 1.1 2018/04/24 16:41:23 root Exp $ */ +/* $Id: js_internal.c,v 1.1.1.2 2018/04/24 16:43:35 root Exp $ */ /**************************************************************************** * @format.tab-size 4 (Plain Text/Source Code File Header) * * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * * * - * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * + * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of the GNU General Public License * @@ -36,8 +36,11 @@ ****************************************************************************/ #include "sbbs.h" +#include "js_request.h" -#include /* Needed for Context-private data structure */ +#ifdef _DEBUG + #include /* Needed for Context-private data structure */ +#endif enum { PROP_VERSION @@ -108,14 +111,10 @@ static JSBool js_get(JSContext *cx, JSOb case PROP_MAXBYTES: JS_NewNumberValue(cx,cx->runtime->gcMaxBytes,vp); break; +#endif case PROP_GLOBAL: - *vp = OBJECT_TO_JSVAL(cx->globalObject); - break; -#else - case PROP_GLOBAL: - *vp = OBJECT_TO_JSVAL(JS_GetParent(cx,obj)); + *vp = OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)); break; -#endif } return(JS_TRUE); @@ -134,7 +133,7 @@ static JSBool js_set(JSContext *cx, JSOb switch(tiny) { case PROP_TERMINATED: if(branch->terminated!=NULL) - JS_ValueToBoolean(cx, *vp, branch->terminated); + JS_ValueToBoolean(cx, *vp, (int *)branch->terminated); break; case PROP_AUTO_TERMINATE: JS_ValueToBoolean(cx,*vp,&branch->auto_terminate); @@ -213,7 +212,7 @@ js_CommonBranchCallback(JSContext *cx, j /* Terminated? */ if(branch->auto_terminate && (branch->terminated!=NULL && *branch->terminated)) { - JS_ReportError(cx,"Terminated"); + JS_ReportWarning(cx,"Terminated"); branch->counter=0; return(JS_FALSE); } @@ -225,13 +224,20 @@ js_CommonBranchCallback(JSContext *cx, j return(JS_FALSE); } +#ifndef USE_JS_OPERATION_CALLBACK /* Give up timeslices every once in a while */ - if(branch->yield_interval && (branch->counter%branch->yield_interval)==0) + if(branch->yield_interval && (branch->counter%branch->yield_interval)==0) { + jsrefcount rc; + + rc=JS_SUSPENDREQUEST(cx); YIELD(); + JS_RESUMEREQUEST(cx, rc); + } /* Periodic Garbage Collection */ if(branch->gc_interval && (branch->counter%branch->gc_interval)==0) JS_MaybeGC(cx), branch->gc_attempts++; +#endif return(JS_TRUE); } @@ -248,8 +254,10 @@ js_eval(JSContext *parent_cx, JSObject * JSObject* obj; JSErrorReporter reporter; #ifndef EVAL_BRANCH_CALLBACK +#ifndef USE_JS_OPERATION_CALLBACK JSBranchCallback callback; #endif +#endif if(argc<1) return(JS_TRUE); @@ -270,13 +278,21 @@ js_eval(JSContext *parent_cx, JSObject * #ifdef EVAL_BRANCH_CALLBACK JS_SetContextPrivate(cx, JS_GetPrivate(parent_cx, parent_obj)); +#ifdef USE_JS_OPERATION_CALLBACK + JS_SetOperationCallback(cx, js_OperationCallback); +#else JS_SetBranchCallback(cx, js_BranchCallback); +#endif #else /* Use the branch callback from the parent context */ JS_SetContextPrivate(cx, JS_GetContextPrivate(parent_cx)); +#ifdef USE_JS_OPERATION_CALLBACK + JS_SetOperationCallback(cx, JS_GetOperationCallback(parent_cx)); +#else callback=JS_SetBranchCallback(parent_cx,NULL); JS_SetBranchCallback(parent_cx, callback); JS_SetBranchCallback(cx, callback); #endif +#endif if((obj=JS_NewObject(cx, NULL, NULL, NULL))==NULL || !JS_InitStandardClasses(cx,obj)) { @@ -357,19 +373,6 @@ js_get_parent(JSContext *cx, JSObject *o return(JS_TRUE); } -static JSClass js_internal_class = { - "JsInternal" /* name */ - ,JSCLASS_HAS_PRIVATE /* flags */ - ,JS_PropertyStub /* addProperty */ - ,JS_PropertyStub /* delProperty */ - ,js_get /* getProperty */ - ,js_set /* setProperty */ - ,JS_EnumerateStub /* enumerate */ - ,JS_ResolveStub /* resolve */ - ,JS_ConvertStub /* convert */ - ,JS_FinalizeStub /* finalize */ -}; - static jsSyncMethodSpec js_functions[] = { {"eval", js_eval, 0, JSTYPE_UNDEF, JSDOCSTR("script") ,JSDOCSTR("evaluate a JavaScript string in its own (secure) context, returning the result") @@ -398,23 +401,58 @@ static jsSyncMethodSpec js_functions[] = {0} }; +static JSBool js_internal_resolve(JSContext *cx, JSObject *obj, jsval id) +{ + char* name=NULL; + + if(id != JSVAL_NULL) + name=JS_GetStringBytes(JSVAL_TO_STRING(id)); + + return(js_SyncResolve(cx, obj, name, js_properties, js_functions, NULL, 0)); +} + +static JSBool js_internal_enumerate(JSContext *cx, JSObject *obj) +{ + return(js_internal_resolve(cx, obj, JSVAL_NULL)); +} + +static JSClass js_internal_class = { + "JsInternal" /* name */ + ,JSCLASS_HAS_PRIVATE /* flags */ + ,JS_PropertyStub /* addProperty */ + ,JS_PropertyStub /* delProperty */ + ,js_get /* getProperty */ + ,js_set /* setProperty */ + ,js_internal_enumerate /* enumerate */ + ,js_internal_resolve /* resolve */ + ,JS_ConvertStub /* convert */ + ,JS_FinalizeStub /* finalize */ +}; + void DLLCALL js_EvalOnExit(JSContext *cx, JSObject *obj, js_branch_t* branch) { char* p; jsval rval; JSScript* script; + BOOL auto_terminate=branch->auto_terminate; + + branch->auto_terminate=FALSE; while((p=strListPop(&branch->exit_func))!=NULL) { if((script=JS_CompileScript(cx, obj, p, strlen(p), NULL, 0))!=NULL) { JS_ExecuteScript(cx, obj, script, &rval); JS_DestroyScript(cx, script); } + free(p); } strListFree(&branch->exit_func); + + if(auto_terminate) + branch->auto_terminate = TRUE; } -JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_branch_t* branch) +JSObject* DLLCALL js_CreateInternalJsObject(JSContext* cx, JSObject* parent, js_branch_t* branch, js_startup_t* startup) { JSObject* obj; @@ -425,11 +463,31 @@ JSObject* DLLCALL js_CreateInternalJsObj if(!JS_SetPrivate(cx, obj, branch)) /* Store a pointer to js_branch_t */ return(NULL); - if(!js_DefineSyncProperties(cx, obj, js_properties)) /* expose them */ - return(NULL); - - if(!js_DefineSyncMethods(cx, obj, js_functions, /* append? */ FALSE)) - return(NULL); + if(startup!=NULL) { + JSObject* load_path_list; + jsval val; + str_list_t load_path; + + if((load_path_list=JS_NewArrayObject(cx, 0, NULL))==NULL) + return(NULL); + val=OBJECT_TO_JSVAL(load_path_list); + if(!JS_SetProperty(cx, obj, JAVASCRIPT_LOAD_PATH_LIST, &val)) + return(NULL); + + if((load_path=strListSplitCopy(NULL, startup->load_path, ",")) != NULL) { + JSString* js_str; + unsigned i; + + for(i=0; load_path[i]!=NULL; i++) { + if((js_str=JS_NewStringCopyZ(cx, load_path[i]))==NULL) + break; + val=STRING_TO_JSVAL(js_str); + if(!JS_SetElement(cx, load_path_list, i, &val)) + break; + } + strListFree(&load_path); + } + } #ifdef BUILD_JSDOCS js_DescribeSyncObject(cx,obj,"JavaScript execution and garbage collection control object",311); @@ -438,3 +496,36 @@ JSObject* DLLCALL js_CreateInternalJsObj return(obj); } + +void DLLCALL js_PrepareToExecute(JSContext *cx, JSObject *obj, const char *filename, const char* startup_dir) +{ + JSString* str; + jsval val; + + if(JS_GetProperty(cx, obj, "js", &val) && JSVAL_IS_OBJECT(val)) { + JSObject* js = JSVAL_TO_OBJECT(val); + char dir[MAX_PATH+1]; + + if(filename!=NULL) { + char* p; + + if((str=JS_NewStringCopyZ(cx, filename)) != NULL) + JS_DefineProperty(cx, js, "exec_path", STRING_TO_JSVAL(str) + ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY); + if((str=JS_NewStringCopyZ(cx, getfname(filename))) != NULL) + JS_DefineProperty(cx, js, "exec_file", STRING_TO_JSVAL(str) + ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY); + SAFECOPY(dir,filename); + p=getfname(dir); + *p=0; + if((str=JS_NewStringCopyZ(cx, dir)) != NULL) + JS_DefineProperty(cx, js, "exec_dir", STRING_TO_JSVAL(str) + ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY); + } + if(startup_dir==NULL) + startup_dir=""; + if((str=JS_NewStringCopyZ(cx, startup_dir)) != NULL) + JS_DefineProperty(cx, js, "startup_dir", STRING_TO_JSVAL(str) + ,NULL,NULL,JSPROP_ENUMERATE|JSPROP_READONLY); + } +}