397 lines
10 KiB
C
397 lines
10 KiB
C
#include "lua_glib.h"
|
|
|
|
#define GLIB_DATABASE_GUID "{cf75e032-00c8-4887-b15f-87b755784ad3}"
|
|
#define GLIB_DATABASE_GETTERS "getters" /* Table of getter functions. */
|
|
#define GLIB_DATABASE_SETTERS "setters" /* Table of setter functions. */
|
|
#define GLIB_DATABASE_ENUMS "enums" /* Table of enum fallback functions. */
|
|
#define GLIB_DATABASE_CACHE "cache" /* Table of cached enum values. */
|
|
#define GLIB_DATABASE_MTABLE "metatable" /* Metatable.*/
|
|
#define GLIB_DATABASE_PROXY "proxy" /* Proxy table for the library that isn't the global table. */
|
|
|
|
static inline void lua_glib_push_db(lua_State *L)
|
|
{
|
|
lua_pushliteral(L, GLIB_DATABASE_GUID);
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
}
|
|
|
|
void lua_glib_get_proxy(lua_State *L)
|
|
{
|
|
lua_pushliteral(L, GLIB_DATABASE_GUID);
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
lua_pushliteral(L, GLIB_DATABASE_PROXY);
|
|
lua_gettable(L, -2);
|
|
lua_remove(L, -2);
|
|
}
|
|
|
|
/**
|
|
* Copy table contents to another.
|
|
* @param L[1] Destination table.
|
|
* @param L[2] Source table.
|
|
*/
|
|
static int lua_glib_copy_table(lua_State *L)
|
|
{
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
|
luaL_checktype(L, 2, LUA_TTABLE);
|
|
|
|
lua_pushnil(L);
|
|
while (lua_next(L, 2))
|
|
{
|
|
lua_pushvalue(L, -2); /* Push key. */
|
|
lua_pushvalue(L, -2); /* Push value. */
|
|
lua_settable(L, 1); /* Store at dst. */
|
|
|
|
lua_pop(L, 1); /* Pop the value. */
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int lua_glib___index(lua_State *L)
|
|
{
|
|
/* function mt:__index(key) */
|
|
|
|
const int CACHE = lua_upvalueindex(1); /* Enum cache. */
|
|
const int GETTERS = lua_upvalueindex(2); /* Storage for getters. */
|
|
const int ENUMS = lua_upvalueindex(3); /* Enum fallback cache. */
|
|
|
|
if (!lua_isstring(L, 2))
|
|
{
|
|
/* A non string key should not happen. But somebody might really want it. */
|
|
return 0;
|
|
}
|
|
|
|
/* Attempt cache lookup. */
|
|
|
|
lua_pushvalue(L, 2);
|
|
lua_gettable(L, CACHE);
|
|
if (!lua_isnil(L, -1))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
lua_pop(L, 1);
|
|
|
|
/* Attempt a get property. */
|
|
|
|
lua_pushvalue(L, 2);
|
|
lua_gettable(L, GETTERS);
|
|
if (lua_isfunction(L, -1))
|
|
{
|
|
lua_call(L, 0, 1);
|
|
return 1;
|
|
}
|
|
|
|
/* Try finding a the relevant enum fallback function. */
|
|
const char *str = lua_tostring(L, 2);
|
|
int sz = lua_strlen(L, 2);
|
|
for (int i = 1; i < sz; i++)
|
|
{
|
|
lua_pushlstring(L, str, i);
|
|
lua_gettable(L, ENUMS);
|
|
|
|
if (lua_isfunction(L, -1))
|
|
{
|
|
lua_pushvalue(L, 2);
|
|
lua_call(L, 1, 1);
|
|
|
|
/* Store value in cache. */
|
|
lua_pushvalue(L, 2);
|
|
lua_pushvalue(L, -2);
|
|
lua_settable(L, CACHE);
|
|
|
|
/* Return it. */
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
lua_pop(L, 1);
|
|
}
|
|
}
|
|
|
|
/* This really does not exist. Returns nil. */
|
|
return 0;
|
|
}
|
|
|
|
static int lua_glib___newindex(lua_State *L)
|
|
{
|
|
/* function mt:__newindex(key, value) */
|
|
|
|
const int SETTERS = lua_upvalueindex(1);
|
|
|
|
lua_pushvalue(L, 2);
|
|
lua_gettable(L, SETTERS);
|
|
if (!lua_isfunction(L, -1))
|
|
{
|
|
return luaL_error(L, "You cannot set the global table except known writeable properties. If this isn't a mistake use `rawset(_G, k, v)`.");
|
|
}
|
|
|
|
/* Set the property. */
|
|
lua_pushvalue(L, 3);
|
|
lua_call(L, 1, 0);
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_append_cache(lua_State *L)
|
|
{
|
|
luaL_checktype(L, 1, LUA_TTABLE);
|
|
|
|
lua_glib_push_db(L);
|
|
|
|
lua_pushcfunction(L, lua_glib_copy_table);
|
|
lua_pushliteral(L, GLIB_DATABASE_CACHE);
|
|
lua_gettable(L, -3);
|
|
lua_pushvalue(L, 1);
|
|
lua_call(L, 2, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_require(lua_State *L)
|
|
{
|
|
if (!lua_isboolean(L, 1))
|
|
{
|
|
/* Request loading the metatable by default. */
|
|
lua_pushboolean(L, 1);
|
|
}
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_GUID);
|
|
lua_newtable(L);
|
|
/* Standard functions. */
|
|
lua_pushliteral(L, GLIB_DATABASE_GETTERS);
|
|
lua_newtable(L);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_SETTERS);
|
|
lua_newtable(L);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_ENUMS);
|
|
lua_newtable(L);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_CACHE);
|
|
lua_newtable(L);
|
|
lua_settable(L, -3);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_MTABLE);
|
|
lua_newtable(L);
|
|
lua_pushliteral(L, "__index");
|
|
lua_pushliteral(L, GLIB_DATABASE_CACHE);
|
|
lua_gettable(L, -5);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_GETTERS);
|
|
lua_gettable(L, -6);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_ENUMS);
|
|
lua_gettable(L, -7);
|
|
|
|
lua_pushcclosure(L, lua_glib___index, 3);
|
|
lua_settable(L, -3); /* __index */
|
|
|
|
lua_pushliteral(L, "__newindex");
|
|
lua_pushliteral(L, GLIB_DATABASE_SETTERS);
|
|
lua_gettable(L, -5);
|
|
|
|
lua_pushcclosure(L, lua_glib___newindex, 1);
|
|
lua_settable(L, -3); /* __newindex */
|
|
lua_settable(L, -3); /* GLIB_DATABASE_MTABLE. */
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_PROXY);
|
|
lua_newtable(L);
|
|
lua_pushliteral(L, GLIB_DATABASE_MTABLE);
|
|
lua_gettable(L, -4);
|
|
lua_setmetatable(L, -2); /* get GLIB_DATABASE_MTABLE. */
|
|
lua_settable(L, -3); /* GLIB_DATABASE_PROXY. */
|
|
|
|
lua_settable(L, LUA_REGISTRYINDEX); /* GLIB_DATABASE_GUID. */
|
|
|
|
/* Set global metatable. */
|
|
if (lua_toboolean(L, 1))
|
|
{
|
|
lua_glib_push_db(L);
|
|
lua_pushliteral(L, GLIB_DATABASE_MTABLE);
|
|
lua_gettable(L, -2);
|
|
lua_setmetatable(L, LUA_GLOBALSINDEX);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_new_enum(lua_State *L)
|
|
{
|
|
lua_glib_push_db(L);
|
|
|
|
if (lua_istable(L, 1))
|
|
{
|
|
/* copy_table(dst, src) */
|
|
|
|
lua_pushcfunction(L, lua_glib_copy_table);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_CACHE);
|
|
lua_gettable(L, -3); /* dst */
|
|
|
|
lua_pushvalue(L, 1); /* src */
|
|
lua_call(L, 2, 0);
|
|
}
|
|
|
|
if (lua_isstring(L, 2) && lua_isfunction(L, 3))
|
|
{
|
|
lua_pushliteral(L, GLIB_DATABASE_ENUMS);
|
|
lua_gettable(L, -2);
|
|
|
|
lua_pushvalue(L, 2); /* prefix */
|
|
lua_pushvalue(L, 3); /* fallback */
|
|
lua_settable(L, -3);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_invalidate_cache(lua_State *L)
|
|
{
|
|
luaL_checktype(L, 1, LUA_TSTRING);
|
|
|
|
lua_glib_push_db(L);
|
|
|
|
lua_pushliteral(L, GLIB_DATABASE_CACHE);
|
|
lua_gettable(L, -2);
|
|
|
|
lua_pushvalue(L, 1);
|
|
lua_pushnil(L);
|
|
|
|
lua_settable(L, -3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_new_getter(lua_State *L)
|
|
{
|
|
luaL_checktype(L, 1, LUA_TSTRING);
|
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
|
|
|
lua_glib_push_db(L);
|
|
lua_pushliteral(L, GLIB_DATABASE_GETTERS);
|
|
lua_gettable(L, -2);
|
|
|
|
lua_pushvalue(L, 1);
|
|
lua_pushvalue(L, 2);
|
|
lua_settable(L, -3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_new_setter(lua_State *L)
|
|
{
|
|
luaL_checktype(L, 1, LUA_TSTRING);
|
|
luaL_checktype(L, 2, LUA_TFUNCTION);
|
|
|
|
lua_glib_push_db(L);
|
|
lua_pushliteral(L, GLIB_DATABASE_SETTERS);
|
|
lua_gettable(L, -2);
|
|
|
|
lua_pushvalue(L, 1);
|
|
lua_pushvalue(L, 2);
|
|
lua_settable(L, -3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define _GLIB_DECL_INT_GETTER(T, name) \
|
|
int lua_glib_getter_##name(lua_State *L) { \
|
|
const T* ptr = (const T*)lua_touserdata(L, lua_upvalueindex(1)); \
|
|
lua_pushinteger(L, (lua_Integer)*ptr); \
|
|
return 1; \
|
|
}
|
|
|
|
#define _GLIB_DECL_INT_SETTER(T, name) \
|
|
int lua_glib_setter_##name(lua_State *L) { \
|
|
luaL_checktype(L, 1, LUA_TNUMBER); \
|
|
T* ptr = (T*)lua_touserdata(L, lua_upvalueindex(1)); \
|
|
*ptr = (T)lua_tointeger(L, 1); \
|
|
return 0; \
|
|
}
|
|
|
|
#define _GLIB_DECL_BOOL_GETTER(T, name) \
|
|
int lua_glib_getter_##name(lua_State *L) { \
|
|
const T* ptr = (const T*)lua_touserdata(L, lua_upvalueindex(1)); \
|
|
lua_pushboolean(L, *ptr != 0); \
|
|
return 1; \
|
|
}
|
|
|
|
#define _GLIB_DECL_FLOAT_GETTER(T, name) \
|
|
int lua_glib_getter_##name(lua_State *L) { \
|
|
const T* ptr = (const T*)lua_touserdata(L, lua_upvalueindex(1)); \
|
|
lua_pushnumber(L, (lua_Number)*ptr); \
|
|
return 1; \
|
|
}
|
|
|
|
#define _GLIB_DECL_FLOAT_SETTER(T, name) \
|
|
int lua_glib_setter_##name(lua_State *L) { \
|
|
luaL_checktype(L, 1, LUA_TNUMBER); \
|
|
T* ptr = (T*)lua_touserdata(L, lua_upvalueindex(1)); \
|
|
*ptr = (T)lua_tonumber(L, 1); \
|
|
return 0; \
|
|
}
|
|
|
|
#define _GLIB_DECL_BOOL_SETTER(T, name) \
|
|
int lua_glib_setter_##name(lua_State *L) { \
|
|
T* ptr = (T*)lua_touserdata(L, lua_upvalueindex(1)); \
|
|
*ptr = lua_toboolean(L, 1) ? true : false; \
|
|
return 0; \
|
|
}
|
|
|
|
_GLIB_DECL_INT_GETTER(int8_t, i8);
|
|
_GLIB_DECL_INT_GETTER(int16_t, i16);
|
|
_GLIB_DECL_INT_GETTER(int32_t, i32);
|
|
_GLIB_DECL_INT_GETTER(int64_t, i64);
|
|
_GLIB_DECL_INT_GETTER(uint8_t, u8);
|
|
_GLIB_DECL_INT_GETTER(uint16_t, u16);
|
|
_GLIB_DECL_INT_GETTER(uint32_t, u32);
|
|
_GLIB_DECL_INT_GETTER(uint64_t, u64);
|
|
_GLIB_DECL_BOOL_GETTER(uint8_t, b8);
|
|
_GLIB_DECL_BOOL_GETTER(uint16_t, b16);
|
|
_GLIB_DECL_BOOL_GETTER(uint32_t, b32);
|
|
_GLIB_DECL_BOOL_GETTER(uint64_t, b64);
|
|
_GLIB_DECL_BOOL_GETTER(boolean, bool);
|
|
|
|
_GLIB_DECL_INT_SETTER(int8_t, i8);
|
|
_GLIB_DECL_INT_SETTER(int16_t, i16);
|
|
_GLIB_DECL_INT_SETTER(int32_t, i32);
|
|
_GLIB_DECL_INT_SETTER(int64_t, i64);
|
|
_GLIB_DECL_INT_SETTER(uint8_t, u8);
|
|
_GLIB_DECL_INT_SETTER(uint16_t, u16);
|
|
_GLIB_DECL_INT_SETTER(uint32_t, u32);
|
|
_GLIB_DECL_INT_SETTER(uint64_t, u64);
|
|
_GLIB_DECL_BOOL_SETTER(uint8_t, b8);
|
|
_GLIB_DECL_BOOL_SETTER(uint16_t, b16);
|
|
_GLIB_DECL_BOOL_SETTER(uint32_t, b32);
|
|
_GLIB_DECL_BOOL_SETTER(uint64_t, b64);
|
|
_GLIB_DECL_BOOL_SETTER(boolean, bool);
|
|
|
|
int lua_glib_setter_fxp(lua_State *L)
|
|
{
|
|
fixed_t *fxp = (fixed_t*)lua_touserdata(L, lua_upvalueindex(1));
|
|
*fxp = lua_tointeger(L, 1);
|
|
return 0;
|
|
}
|
|
|
|
int lua_glib_getter_fxp(lua_State *L)
|
|
{
|
|
const fixed_t *fxp = (const fixed_t*)lua_touserdata(L, lua_upvalueindex(1));
|
|
lua_pushfixed(L, *fxp);
|
|
return 1;
|
|
}
|
|
|
|
int lua_glib_getter_str(lua_State *L)
|
|
{
|
|
const char *str = (const char*)lua_touserdata(L, lua_upvalueindex(1));
|
|
lua_pushstring(L, str);
|
|
return 1;
|
|
}
|
|
|
|
int lua_glib_getter_ptr(lua_State *L)
|
|
{
|
|
lua_pushvalue(L, lua_upvalueindex(1));
|
|
return 1;
|
|
}
|