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;