diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c index 9ee3956cce5062efc38592d7cb2b0e916cc9974e..dc3c1e1fe24cbacbe4a7a2b7fe1a19477b2a26a8 100644 --- a/src/sbbs3/js_global.c +++ b/src/sbbs3/js_global.c @@ -5080,6 +5080,7 @@ BOOL DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* p->methods = methods; p->startup = startup; p->exit_func=NULL; + p->onexit = NULL; if((*glob = JS_NewCompartmentAndGlobalObject(cx, &js_global_class, NULL)) ==NULL) { free(p); diff --git a/src/sbbs3/js_internal.c b/src/sbbs3/js_internal.c index ebe7f8f58bb46f5d14c0ab33bae9a4d7e8c3bbbd..afa5cd907b8637de6daf64be2ee05edb6d6ceeb5 100644 --- a/src/sbbs3/js_internal.c +++ b/src/sbbs3/js_internal.c @@ -59,11 +59,6 @@ enum { ,PROP_GLOBAL }; -struct onexit_private { - char signature[7]; - str_list_t list; -}; - static JSBool js_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval idval; @@ -606,45 +601,41 @@ js_on_exit(JSContext *cx, uintN argc, jsval *arglist) JSObject *glob=JS_GetGlobalObject(cx); jsval *argv=JS_ARGV(cx, arglist); global_private_t* pd; - struct onexit_private *oep = NULL; + struct js_onexit_scope *oes = NULL; str_list_t oldlist; str_list_t list; char *p = NULL; JS_SET_RVAL(cx, arglist, JSVAL_VOID); + if((pd=(global_private_t*)JS_GetPrivate(cx,glob))==NULL) + return(JS_FALSE); if(glob==scope) { - if((pd=(global_private_t*)JS_GetPrivate(cx,glob))==NULL) - return(JS_FALSE); if(pd->exit_func==NULL) pd->exit_func=strListInit(); list=pd->exit_func; } else { - oep=(struct onexit_private *)JS_GetPrivate(cx,scope); - if(oep==NULL) { - oep = malloc(sizeof(*oep)); - if (oep == NULL) { - JS_ReportError(cx, "Unable to allocate memory for on_exit() list"); - return JS_FALSE; - } - memcpy(oep->signature, "onexit", 7); - oep->list=strListInit(); - JS_SetPrivate(cx,scope,oep); + /* First, look for an existing onexit scope for this scope */ + for (oes = pd->onexit; oes; oes = oes->next) { + if (oes->scope == scope) + break; } - else { - if (oep->signature[0] != 'o' - || oep->signature[1] != 'n' - || oep->signature[2] != 'e' - || oep->signature[3] != 'x' - || oep->signature[4] != 'i' - || oep->signature[5] != 't' - || oep->signature[6] != 0) { - JS_ReportError(cx, "on_exit not available in %s scopes", JS_GetClass(cx, scope)->name); + + /* If one isn't found, insert it */ + if (oes == NULL) { + oes = malloc(sizeof(*oes)); + if (oes == NULL) { + JS_ReportError(cx, "Unable to allocate memory for onexit scope"); return JS_FALSE; - } + } + oes->next = pd->onexit; + pd->onexit = oes; + oes->scope = scope; + oes->onexit = strListInit(); + JS_AddObjectRoot(cx, &oes->scope); } - list = oep->list; + list = oes->onexit; } JSVALUE_TO_MSTRING(cx, argv[0], p, NULL); @@ -658,7 +649,7 @@ js_on_exit(JSContext *cx, uintN argc, jsval *arglist) if(glob==scope) pd->exit_func=list; else - oep->list = list; + oes->onexit = list; } return(JS_TRUE); } @@ -800,25 +791,43 @@ void DLLCALL js_EvalOnExit(JSContext *cx, JSObject *obj, js_callback_t* cb) JSObject *glob=JS_GetGlobalObject(cx); global_private_t *pt; str_list_t list = NULL; + struct js_onexit_scope **prev_oes_next = NULL; + struct js_onexit_scope *oes = NULL; + pt=(global_private_t *)JS_GetPrivate(cx,JS_GetGlobalObject(cx)); if(glob==obj) { - pt=(global_private_t *)JS_GetPrivate(cx,JS_GetGlobalObject(cx)); + /* Yes, this is recursive to one level */ + while (pt->onexit) { + if (pt->onexit->scope == glob) { + // This shouldn't happen, but let's not go inifinite eh? + JS_ReportError(cx, "js_EvalOnExit() extra scope is global"); + return; + } + else { + oes = pt->onexit; + js_EvalOnExit(cx, pt->onexit->scope, cb); + if (oes == pt->onexit) { + // This *really* shouldn't happen... + JS_ReportError(cx, "js_EvalOnExit() did not pop on_exit stack"); + return; + } + } + } list=pt->exit_func; } else { - struct onexit_private *oep = JS_GetPrivate(cx,obj); - if (oep != NULL) { - if (oep->signature[0] == 'o' - || oep->signature[1] == 'n' - || oep->signature[2] == 'e' - || oep->signature[3] == 'x' - || oep->signature[4] == 'i' - || oep->signature[5] == 't' - || oep->signature[6] == 0) { - list = oep->list; - free(oep); + /* Find this scope in onexit list */ + for (prev_oes_next = &pt->onexit, oes = pt->onexit; oes; prev_oes_next = &(oes->next), oes = oes->next) { + if (oes->scope == obj) { + (*prev_oes_next) = oes->next; + list = oes->onexit; + JS_RemoveObjectRoot(cx, &oes->scope); + free(oes); + break; } } + if (oes == NULL) + return; } cb->auto_terminate=FALSE; @@ -831,9 +840,7 @@ void DLLCALL js_EvalOnExit(JSContext *cx, JSObject *obj, js_callback_t* cb) } strListFree(&list); - if(glob != obj) - JS_SetPrivate(cx,obj,NULL); - else + if(glob == obj) pt->exit_func=NULL; if(auto_terminate) diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h index 82385ab19992ab4c0b6d5a8287253336f53dafbe..46ff730d9f58dd663fcce7b5b819660b8341446e 100644 --- a/src/sbbs3/sbbs.h +++ b/src/sbbs3/sbbs.h @@ -1295,6 +1295,12 @@ extern "C" { ,js_server_props_t* props); /* js_global.c */ + struct js_onexit_scope { + JSObject *scope; + str_list_t onexit; + struct js_onexit_scope *next; + }; + typedef struct { scfg_t* cfg; jsSyncMethodSpec* methods; @@ -1302,6 +1308,7 @@ extern "C" { unsigned bg_count; sem_t bg_sem; str_list_t exit_func; + struct js_onexit_scope *onexit; } global_private_t; DLLEXPORT BOOL DLLCALL js_argc(JSContext *cx, unsigned argc, unsigned min); DLLEXPORT BOOL DLLCALL js_CreateGlobalObject(JSContext* cx, scfg_t* cfg, jsSyncMethodSpec* methods, js_startup_t*, JSObject**);