From 5e45bdeeda7d149b30a550733121b8e34876343f Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 1 Mar 2013 12:22:51 +0100 Subject: [PATCH] Add optional user_data to Nasal C functions. A user_data pointer and another pointer to an optional deleter function is stored in unused parts of the naPtr union. The previous behavior of extension functions does not change. Only one additional boolean comparison is required upon each function call to check whether user data is available. --- simgear/nasal/code.c | 5 ++++- simgear/nasal/data.h | 10 +++++++++- simgear/nasal/gc.c | 7 +++++++ simgear/nasal/misc.c | 18 ++++++++++++++++++ simgear/nasal/nasal.h | 18 +++++++++++++++++- 5 files changed, 55 insertions(+), 3 deletions(-) diff --git a/simgear/nasal/code.c b/simgear/nasal/code.c index 511f490f..5601b074 100644 --- a/simgear/nasal/code.c +++ b/simgear/nasal/code.c @@ -313,7 +313,10 @@ static struct Frame* setupFuncall(naContext ctx, int nargs, int mcall, int named ctx->opFrame = opf; if(IS_CCODE(code)) { - naRef result = (*PTR(code).ccode->fptr)(ctx, obj, nargs, args); + struct naCCode *ccode = PTR(code).ccode; + naRef result = ccode->fptru + ? (*ccode->fptru)(ctx, obj, nargs, args, ccode->user_data) + : (*ccode->fptr)(ctx, obj, nargs, args); if(named) ERR(ctx, "native functions have no named arguments"); ctx->opTop = ctx->opFrame; PUSH(result); diff --git a/simgear/nasal/data.h b/simgear/nasal/data.h index deb4fbdc..a2c023ef 100644 --- a/simgear/nasal/data.h +++ b/simgear/nasal/data.h @@ -160,7 +160,15 @@ struct naFunc { struct naCCode { GC_HEADER; - naCFunction fptr; + union { + naCFunction fptr; //constants); o->constants = 0; } +static void naCCode_gcclean(struct naCCode* c) +{ + if(c->fptru && c->user_data && c->destroy) c->destroy(c->user_data); + c->user_data = 0; +} + static void naGhost_gcclean(struct naGhost* g) { if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr); @@ -142,6 +148,7 @@ static void freeelem(struct naPool* p, struct naObj* o) case T_VEC: naVec_gcclean ((struct naVec*) o); break; case T_HASH: naiGCHashClean ((struct naHash*) o); break; case T_CODE: naCode_gcclean ((struct naCode*) o); break; + case T_CCODE: naCCode_gcclean((struct naCCode*)o); break; case T_GHOST: naGhost_gcclean((struct naGhost*)o); break; } p->free[p->nfree++] = o; // ...and add it to the free list diff --git a/simgear/nasal/misc.c b/simgear/nasal/misc.c index dae0bfe4..a249fce7 100644 --- a/simgear/nasal/misc.c +++ b/simgear/nasal/misc.c @@ -107,6 +107,24 @@ naRef naNewCCode(struct Context* c, naCFunction fptr) { naRef r = naNew(c, T_CCODE); PTR(r).ccode->fptr = fptr; + PTR(r).ccode->fptru = 0; + return r; +} + +naRef naNewCCodeU(struct Context* c, naCFunctionU fptr, void* user_data) +{ + return naNewCCodeUD(c, fptr, user_data, 0); +} + +naRef naNewCCodeUD( struct Context* c, + naCFunctionU fptr, + void* user_data, + void (*destroy)(void*) ) +{ + naRef r = naNew(c, T_CCODE); + PTR(r).ccode->fptru = fptr; + PTR(r).ccode->user_data = user_data; + PTR(r).ccode->destroy = destroy; return r; } diff --git a/simgear/nasal/nasal.h b/simgear/nasal/nasal.h index 7fc54203..d3cb9167 100644 --- a/simgear/nasal/nasal.h +++ b/simgear/nasal/nasal.h @@ -16,10 +16,14 @@ extern "C" { #endif typedef struct Context* naContext; - + // The function signature for an extension function: typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args); +// The function signature for an extension function with userdata passed back: +typedef naRef (*naCFunctionU) + (naContext ctx, naRef me, int argc, naRef* args, void* user_data); + // All Nasal code runs under the watch of a naContext: naContext naNewContext(); void naFreeContext(naContext c); @@ -146,7 +150,19 @@ naRef naNewString(naContext c); naRef naNewVector(naContext c); naRef naNewHash(naContext c); naRef naNewFunc(naContext c, naRef code); + +/** + * Register extension function + * + * @param fptr Pointer to C-function + * @param user_data Optional user data passed back on calling the function + * @param destroy Optional callback called if function gets freed by garbage + * collector to free user data if required. + */ naRef naNewCCode(naContext c, naCFunction fptr); +naRef naNewCCodeU(naContext c, naCFunctionU fptr, void* user_data); +naRef naNewCCodeUD(naContext c, naCFunctionU fptr, void* user_data, + void (*destroy)(void*)); // Some useful conversion/comparison routines int naEqual(naRef a, naRef b) GCC_PURE; -- 2.39.5