lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Forwarded with permission of the author:

--- Begin Message ---

> 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 ---