Reputation: 31
I'm looking for a solution to bind a C variable (integer, double, normal C string or similar) to Lua. Lua should be able to modify this variable (in C context). I'm not looking for a solution to call a C function at all (from Lua to get the reference to that variable). I also do not want to use any external library for this (Lua API will do fine). I have seen that LuaBridge solve this (existing project using this: https://github.com/Malaxiz/Third/blob/network/Fifth/CGame.cpp#L240), but as I said, no external libraries and definitely not C++.
Example of use:
C code
typedef struct Instance {
int test; /* The variable I want to link to Lua (and be able to modify it)*/
} Instance;
int main() {
lua_State* L = lua_open();
Instance instance;
instance.test = 5;
/* ... */
}
And in Lua:
instance.test = instance.test + 5
print(instance.test) -- Should be 10
Back to C:
int main() {
...
printf("%i\n", instance.test); /* Should be 10 here too */
}
Is there a workaround for this?
Upvotes: 1
Views: 1685
Reputation: 3000
It is the "homework" for Lua/C programmer, but for google sake:
#include <stdio.h>
#include <stdlib.h>
#include <lauxlib.h>
#include <lualib.h>
typedef struct Instance Instance;
struct Instance {
int test1;
double test2;
};
// linstance.c {
static const char *const tname = "Instance";
enum { f_test1, f_test2 };
static const char *const fmap[] = { "test1", "test2" };
static int
l_get(lua_State *L) // (t, k) -> v
{
Instance *inst = *(Instance **)luaL_checkudata(L, 1, tname);
switch (luaL_checkoption(L, 2, NULL, fmap)) {
case f_test1: lua_pushinteger(L, inst->test1); break;
case f_test2: lua_pushnumber(L, inst->test2); break;
}
return 1;
}
static int
l_set(lua_State *L) // (t, k, v)
{
Instance *inst = *(Instance **)luaL_checkudata(L, 1, tname);
switch (luaL_checkoption(L, 2, NULL, fmap)) {
case f_test1: inst->test1 = luaL_checkinteger(L, 3); break;
case f_test2: inst->test2 = luaL_checknumber(L, 3); break;
}
return 0;
}
void
pushInstance(lua_State *L, Instance *instance)
{
Instance **ud = lua_newuserdata(L, sizeof(*ud));
*ud = instance;
if (luaL_newmetatable(L, tname)) {
lua_pushcfunction(L, l_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, l_get);
lua_setfield(L, -2, "__index");
lua_pushstring(L, tname);
lua_setfield(L, -2, "__metatable");
}
lua_setmetatable(L, -2);
}
// }
int
main(int argc, char *argv[])
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
Instance instance = { -1, -1.0 };
pushInstance(L, &instance);
lua_setglobal(L, "instance");
luaL_dostring(L, "print(instance.test1, instance.test2)");
luaL_dostring(L, "instance.test1 = 3.14; instance.test2 = 3.14");
luaL_dostring(L, "print(instance.test1, instance.test2)");
printf("%d\t%g\n", instance.test1, instance.test2);
if (luaL_dostring(L, "print(instance.UNKNOWN)")) {
printf("%s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
lua_close(L);
return 0;
}
-1 -1
3 3.14
3 3.14
[string "print(instance.UNKNOWN)"]:1: bad argument #2 to '__index' (invalid option 'UNKNOWN')
Upvotes: 1
Reputation: 5847
I'm not looking for a solution to call a C function at all.
You'll have to. There will be a call to C function, always. Even if it might be not explicit on Lua side, it will be there.
Typically you will set metatable on instance
object that lives in Lua. It will catch reads and writes to that object, and redirect those actions to C side by calling C functions.
Upvotes: 1