--- Begin Message ---
- Subject: Re: Callbacks using a 3rd party library in C
- From: Edgar Toernig <froese@...>
- Date: Sun, 1 Aug 2004 23:54:45 +0200
> static int callback_wrapper(void *userdata)
> {
> lua_State * L = (lua_State * userdata);
> /* PROBLEM: how to find the the function to call ???
> lua_call(L, 0, 0);
> return 0;
> }
>
> int l_foo_reg_cb(lua_State * L)
> {
> foo * f = (foo *)lua_touserdata(L, 1);
> char * name = lua_tostring(L, 2);
> /* PROBLEM: What todo with the 3rd arg, the lua callback function? */
> foo_reg_cb(f, name, L, callback_wrapper);
> return 0;
> }
>
>
> How should I deal with this problem? I don't like the idea of a global
> lua_State and pass the function itself or some reference to the wrapper,
> because then it won't be possible to use this binding with two or more
> different lua-States in the same host.
Malloc a struct, store the lua_State in the struct and pass that to the
callback function. Use the registry to store associated Lua data.
Example code without any error checking or garbage collection:
struct foo_cbdata
{
lua_State *L;
// The addresses of the next fields are used as keys
// into the registry where the actual data is stored.
char func;
char arg1;
char arg2;
// Normally, you only need func (args are not needed
// in Lua - it has closures with upvalues). In that
// case, &foo_cbdata->L can be used and these fields
// are unnecessary.
};
static void *
callback_wrapper(void *_cbd)
{
struct foo_cbdata *cbd = _cbd;
lua_State *L = cbd->L;
lua_pushlightuserdata(L, &cbd->func);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, &cbd->arg1);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, &cbd->arg2);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_call(L, 2, 0);
return NULL;
}
static int
l_foo_reg_cb(lua_State *L)
{
foo *f = lua_touserdata(L, 1);
const char *name = lua_tostring(L, 2);
struct foo_cbdata *cbd = malloc(sizeof(*cbd));
cbd->L = L;
lua_pushlightuserdata(L, &cbd->func);
lua_pushvalue(L, 3);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, &cbd->arg1);
lua_pushvalue(L, 4);
lua_rawset(L, LUA_REGISTRYINDEX);
lua_pushlightuserdata(L, &cbd->arg2);
lua_pushvalue(L, 5);
lua_rawset(L, LUA_REGISTRYINDEX);
foo_reg_cb(L, name, cbd, callback_wrapper);
return 0;
}
Ciao, ET.
PS: Be *very* careful when exposing lightuserdata to scripts...
--- End Message ---