views:

379

answers:

2

How to register a C function in Lua, but not in a global context, but as a table field?

+2  A: 
void register_c_function(char const * const tableName, char const * const funcName, CFunctionSignature funcPointer)
{
    lua_getfield(lstate, LUA_GLOBALSINDEX, tableName);  // push table onto stack
    if (!lua_istable(lstate, -1))                       // not a table, create it
    {
        lua_createtable(lstate, 0, 1);      // create new table
        lua_setfield(lstate, LUA_GLOBALSINDEX, tableName);  // add it to global context

        // reset table on stack
        lua_pop(lstate, 1);                 // pop table (nil value) from stack
        lua_getfield(lstate, LUA_GLOBALSINDEX, tableName);  // push table onto stack
    }

    lua_pushstring(lstate, funcName);       // push key onto stack
    lua_pushcfunction(lstate, funcPointer); // push value onto stack
    lua_settable(lstate, -3);               // add key-value pair to table

    lua_pop(lstate, 1);                     // pop table from stack
}
topright
Why not just use luaL_register?
uroc
+6  A: 

This is what luaL_register() is intended to do, for one or more functions. The canonical usage is as part of the setup for a module written in C:

/* actual definitions of modA() and modB() are left as an exercise. */

/* list of functions in the module */
static const luaL_reg modfuncs[] =
{
    { "a", modA},
    { "b", modB},
    { NULL, NULL }
};

/* module loader function called eventually by require"mod" */  
int luaopen_mod(lua_State *L) {
    luaL_register(L, "mod", modfuncs);
    return 1;
}

where this creates a module named "mod" that has two functions named mod.a and mod.b.

Quoting the manual for luaL_register(L,libname,l):

When called with libname equal to NULL, it simply registers all functions in the list l (see luaL_Reg) into the table on the top of the stack.

When called with a non-null libname, luaL_register creates a new table t, sets it as the value of the global variable libname, sets it as the value of package.loaded[libname], and registers on it all functions in the list l. If there is a table in package.loaded[libname] or in variable libname, reuses this table instead of creating a new one.

In any case the function leaves the table on the top of the stack.

luaL_register() can be used to put C functions in any table by passing NULL for its second parameter as long as the table is on the top of the stack.

RBerteig
If there is already mod table with other fields, will it be extended or replaced with new one after luaL_register() call?
topright
it will reuse and update a previous table, according to the 5.1 manual.
kaizer.se
Whether applied to a named global table or the table at the top of stack, it only sets those fields named in the list of functions to register and leaves any other fields untouched. The difference is that given a global name, it also creates the table if needed and adds a reference to `package.loaded`.
RBerteig
I do not like that a client code knows luaL_reg type. I prefer to incapsulate such things. See my solution.
topright