Lua c API change library after creation

295 Views Asked by At

I am trying to wrap ncurses in Lua using the C API. I am working with the stdscr pointer: This is NULL before initscr is called, and initscr is called from Lua by design of my bindings. So in the driver function I do this:

// Driver function
LUALIB_API int luaopen_liblncurses(lua_State* L){
    luaL_newlib(L, lncurseslib);

    // This will start off as NULL
    lua_pushlightuserdata(L, stdscr);
    lua_setfield(L, -2, "stdscr");

    lua_pushstring(L, VERSION);
    lua_setglobal(L, "_LNCURSES_VERSION");
    return 1;
}

This works as intended. The trouble comes when I need to modify stdscr. initscr is bound like this:

/*
** Put the terminal in curses mode
*/
static int lncurses_initscr(lua_State* L){
    initscr();
    return 0;
}

I need to moify the stdscr in the library to no longer be null. Example code from Lua side:

lncurses = require("liblncurses");
lncurses.initscr();
lncurses.keypad(lncurses.stdscr, true);
lncurses.getch();
lncurses.endwin();

But, lncurses.stdscr is NULL, so the it's essentially running the c equivalent of keypad(NULL, true);

My question being, how do I modify library values in Lua after the library is created?

1

There are 1 best solutions below

3
On BEST ANSWER

You can use the registry.

Lua provides a registry, a predefined table that can be used by any C code to store whatever Lua values it needs to store. The registry table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table, but it must take care to choose keys that are different from those used by other libraries, to avoid collisions. Typically, you should use as key a string containing your library name, or a light userdata with the address of a C object in your code, or any Lua object created by your code. As with variable names, string keys starting with an underscore followed by uppercase letters are reserved for Lua.

Store a reference to the module table in the registry on creation.

LUALIB_API int luaopen_liblncurses(lua_State* L) {
    luaL_newlib(L, lncurseslib);

    // This will start off as NULL
    lua_pushlightuserdata(L, stdscr);
    lua_setfield(L, -2, "stdscr");

    lua_pushstring(L, VERSION);
    lua_setglobal(L, "_LNCURSES_VERSION");

    // Create a reference to the module table in the registry
    lua_pushvalue(L, -1);
    lua_setfield(L, LUA_REGISTRYINDEX, "lncurses");
    return 1;
}

Then when you initscr, update the field.

static int lncurses_initscr(lua_State* L) {
    initscr();

    // Update "stdscr" in the module table
    lua_getfield(L, LUA_REGISTRYINDEX, "lncurses");
    lua_pushlightuserdata(L, stdscr);
    lua_setfield(L, -2, "stdscr");
    return 0;
}