mirror of
https://github.com/vxcontrol/golua.git
synced 2026-07-01 22:14:01 -04:00
802 lines
18 KiB
C
802 lines
18 KiB
C
#include "golua.h"
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
|
|
//lint:ignore C/C++(1696)
|
|
#include "_cgo_export.h"
|
|
|
|
#define MT_GOFUNCTION "GoLua.GoFunction"
|
|
#define MT_GOINTERFACE "GoLua.GoInterface"
|
|
|
|
#define GOLUA_DEFAULT_MSGHANDLER "golua_default_msghandler"
|
|
|
|
// golua registry key, main states only, non non-main coroutines.
|
|
// The address of this constant is used as a unique
|
|
// lightuserdata key.
|
|
static const char GoMainStatesKey = 'k';
|
|
|
|
// Within one main state, store the main state (at 1),
|
|
// plus all other coroutines at uniqArray[pos > 1].
|
|
// Stored in the per state Lua registry.
|
|
// The address of this constant is used as a unique
|
|
// lightuserdata key.
|
|
static const char GoWithinStateUniqArrayKey = 'u'; //golua registry key, uniq array.
|
|
|
|
// Within one main state's
|
|
// the reverseUniqMap maps *lua_State -> uPos
|
|
// Stored in the per state Lua registry.
|
|
// The address of this constant is used as a unique
|
|
// lightuserdata key.
|
|
static const char GoWithinStateRevUniqMap = 'r'; //in golua registry, reverse uniq map
|
|
|
|
static const char PanicFIDRegistryKey = 'k';
|
|
|
|
/* makes sure we compile in atoll/_atoi64 if available.*/
|
|
long long int wrapAtoll(const char *nptr)
|
|
{
|
|
#if _WIN32 || _WIN64
|
|
return _atoi64(nptr);
|
|
#else
|
|
return atoll(nptr);
|
|
#endif
|
|
}
|
|
|
|
/* taken from lua5.2 source */
|
|
void *testudata(lua_State *L, int ud, const char *tname)
|
|
{
|
|
void *p = lua_touserdata(L, ud);
|
|
if (p != NULL)
|
|
{ /* value is a userdata? */
|
|
if (lua_getmetatable(L, ud))
|
|
{ /* does it have a metatable? */
|
|
luaL_getmetatable(L, tname); /* get correct metatable */
|
|
if (!lua_rawequal(L, -1, -2)) /* not the same? */
|
|
p = NULL; /* value is a userdata with wrong metatable */
|
|
lua_pop(L, 2); /* remove both metatables */
|
|
return p;
|
|
}
|
|
}
|
|
return NULL; /* value is not a userdata with a metatable */
|
|
}
|
|
|
|
int clua_isgofunction(lua_State *L, int n)
|
|
{
|
|
return testudata(L, n, MT_GOFUNCTION) != NULL;
|
|
}
|
|
|
|
int clua_isgostruct(lua_State *L, int n)
|
|
{
|
|
return testudata(L, n, MT_GOINTERFACE) != NULL;
|
|
}
|
|
|
|
unsigned int* clua_checkgosomething(lua_State* L, int index, const char *desired_metatable)
|
|
{
|
|
if (desired_metatable != NULL)
|
|
{
|
|
return testudata(L, index, desired_metatable);
|
|
}
|
|
else
|
|
{
|
|
unsigned int *sid = testudata(L, index, MT_GOFUNCTION);
|
|
if (sid != NULL) return sid;
|
|
return testudata(L, index, MT_GOINTERFACE);
|
|
}
|
|
}
|
|
|
|
static lua_State* clua_get_main_thread(lua_State* L) {
|
|
// experiment: can we get main from uniqArray[1]; it should be there.
|
|
int top = lua_gettop(L);
|
|
lua_pushlightuserdata(L, (void*)&GoWithinStateUniqArrayKey);
|
|
lua_gettable(L, LUA_REGISTRYINDEX); // pushes value onto top of stack
|
|
// stack: uniqArray
|
|
|
|
if (lua_isnil(L,-1)) {
|
|
printf("\n debug: arg. nil back for UniqKey lookup.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
lua_pushnumber(L, 1);
|
|
// stack: 1, uniqArray
|
|
lua_gettable(L, -2);
|
|
// stack: main *lua_State, uniqArray
|
|
|
|
int ty = lua_type(L, -1);
|
|
|
|
lua_State* mainThread = lua_tothread(L, -1);
|
|
|
|
lua_settop(L, top);
|
|
|
|
return mainThread;
|
|
}
|
|
|
|
size_t clua_getgostate(lua_State* L)
|
|
{
|
|
size_t gostateindex;
|
|
|
|
//get gostate from registry entry
|
|
lua_pushlightuserdata(L,(void*)&GoMainStatesKey);
|
|
lua_gettable(L, LUA_REGISTRYINDEX); // pushes value onto top of stack
|
|
|
|
// 'k' is now a map from lua_State* to index
|
|
// push key
|
|
lua_pushthread(L);
|
|
// stack is now:
|
|
// key
|
|
// map
|
|
lua_gettable(L, -2);
|
|
// stack is now
|
|
// index value
|
|
// map
|
|
|
|
// if nil, enter it, so it is recorded.
|
|
if (lua_isnil(L, -1)) {
|
|
gostateindex = (size_t)(0);
|
|
} else {
|
|
gostateindex = (size_t)lua_tonumber(L, -1);
|
|
}
|
|
lua_pop(L, 2);
|
|
return gostateindex;
|
|
}
|
|
|
|
//wrapper for callgofunction
|
|
int callback_function(lua_State* coro)
|
|
{
|
|
int r;
|
|
unsigned int *fid = clua_checkgosomething(coro, 1, MT_GOFUNCTION);
|
|
size_t coro_index = clua_getgostate(coro);
|
|
lua_State* mainThread = clua_get_main_thread(coro);
|
|
size_t mainIndex = clua_getgostate(mainThread);
|
|
|
|
// jea: the metatable is on the stack.
|
|
//remove the userdata metatable (go function??) from the stack (to present same behavior as lua_CFunctions)
|
|
lua_remove(coro, 1);
|
|
|
|
return golua_callgofunction(coro, coro_index, mainIndex, mainThread, fid!=NULL ? *fid : -1);
|
|
}
|
|
|
|
//wrapper for gchook
|
|
int gchook_wrapper(lua_State* L)
|
|
{
|
|
unsigned int* fid = clua_checkgosomething(L, -1, NULL);
|
|
if (fid != NULL) {
|
|
lua_State* mainThread = clua_get_main_thread(L);
|
|
size_t main_index = clua_getgostate(mainThread);
|
|
return golua_gchook(main_index, *fid);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int clua_togofunction(lua_State* L, int index)
|
|
{
|
|
unsigned int *r = clua_checkgosomething(L, index, MT_GOFUNCTION);
|
|
return (r != NULL) ? *r : -1;
|
|
}
|
|
|
|
int clua_togostruct(lua_State *L, int index)
|
|
{
|
|
unsigned int *r = clua_checkgosomething(L, index, MT_GOINTERFACE);
|
|
return (r != NULL) ? *r : -1;
|
|
}
|
|
|
|
void clua_pushgofunction(lua_State* L, unsigned int fid)
|
|
{
|
|
unsigned int* fidptr = (unsigned int *)lua_newuserdata(L, sizeof(unsigned int));
|
|
*fidptr = fid;
|
|
luaL_getmetatable(L, MT_GOFUNCTION);
|
|
lua_setmetatable(L, -2);
|
|
}
|
|
|
|
static int callback_c(lua_State* coro)
|
|
{
|
|
int fid = clua_togofunction(coro, lua_upvalueindex(1));
|
|
size_t coro_index = clua_getgostate(coro);
|
|
lua_State* mainThread = clua_get_main_thread(coro);
|
|
size_t main_index = clua_getgostate(mainThread);
|
|
|
|
return golua_callgofunction(coro, coro_index, main_index, mainThread, fid);
|
|
}
|
|
|
|
void clua_pushcallback(lua_State* L)
|
|
{
|
|
lua_pushcclosure(L,callback_c,1);
|
|
}
|
|
|
|
void clua_pushgostruct(lua_State* L, unsigned int iid)
|
|
{
|
|
unsigned int* iidptr = (unsigned int *)lua_newuserdata(L, sizeof(unsigned int));
|
|
*iidptr = iid;
|
|
luaL_getmetatable(L, MT_GOINTERFACE);
|
|
lua_setmetatable(L,-2);
|
|
}
|
|
|
|
int default_panicf(lua_State *L)
|
|
{
|
|
char *s = (char *)lua_tostring(L, -1);
|
|
lua_State* mainThread = clua_get_main_thread(L);
|
|
size_t main_index = clua_getgostate(mainThread);
|
|
|
|
go_default_panic_msghandler(L, main_index, s);
|
|
|
|
printf("Lua unprotected panic: %s\n", s);
|
|
abort();
|
|
return 0;
|
|
}
|
|
|
|
int panic_msghandler(lua_State *L)
|
|
{
|
|
char *s = (char *)lua_tolstring(L, -1, NULL);
|
|
lua_State* mainThread = clua_get_main_thread(L);
|
|
size_t main_index = clua_getgostate(mainThread);
|
|
|
|
go_panic_msghandler(L, main_index, s);
|
|
return 1;
|
|
}
|
|
|
|
void create_uniqArray(lua_State* L) {
|
|
// stack: ...
|
|
|
|
lua_newtable(L);
|
|
// stack: newtable, ...
|
|
|
|
lua_pushlightuserdata(L,(void*)&GoWithinStateUniqArrayKey);
|
|
// stack: ukey, newtable, ...
|
|
|
|
lua_insert(L, -2);
|
|
// stack: newtable, ukey, ...
|
|
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
// stack: ...
|
|
|
|
// and create the reverse uniq map: *lua_State -> uPos
|
|
lua_newtable(L);
|
|
// stack: newtable, ...
|
|
|
|
lua_pushlightuserdata(L,(void*)&GoWithinStateRevUniqMap);
|
|
// stack: urevkey, newtable, ...
|
|
|
|
lua_insert(L, -2);
|
|
// stack: newtable, urevkey, ...
|
|
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
// stack: ...
|
|
}
|
|
|
|
// return 1 if created, 0 if already existed.
|
|
int clua_create_uniq_array_if_not_exists(lua_State* L) {
|
|
// stack: ...
|
|
|
|
lua_pushlightuserdata(L,(void*)&GoWithinStateUniqArrayKey);
|
|
// stack: ukey, ...
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
// stack: (uniqArray or nil), ...
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
lua_pop(L, 1);
|
|
// stack: ...
|
|
create_uniqArray(L);
|
|
// stack: ...
|
|
return 1;
|
|
}
|
|
lua_pop(L, 1);
|
|
// stack: ...
|
|
return 0;
|
|
}
|
|
|
|
int clua_add_thread_to_uniq_array_and_rev_uniq(lua_State* L);
|
|
|
|
// clua_known_coro returns the index
|
|
// of L in uniqArray, adding L to
|
|
// uniqArray and revUniqMap if it
|
|
// is not already present in revUniqMap.
|
|
//
|
|
// POST INVAR:
|
|
// On return of value uPos, uniqArray[uPos] == L
|
|
// and revUniqMap[L] == uPos.
|
|
//
|
|
// The returned value will be >= 1.
|
|
//
|
|
int clua_dedup_coro(lua_State* L)
|
|
{
|
|
if (1 == clua_create_uniq_array_if_not_exists(L)) {
|
|
return clua_add_thread_to_uniq_array_and_rev_uniq(L);
|
|
}
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
// use revUniqMap, for O(1) lookup.
|
|
|
|
// store pos into revUniqMap too, for O(1) coroutine lookup.
|
|
lua_pushlightuserdata(L, (void*)&GoWithinStateRevUniqMap);
|
|
// stack: revkey
|
|
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
// stack: revUniqMap
|
|
|
|
int isMain = lua_pushthread(L);
|
|
// stack: thread, revUniqMap
|
|
|
|
lua_gettable(L, -2);
|
|
// stack: (pos or nil), revUniqMap
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
// stack: nil, revUniqMap
|
|
|
|
// not previously known
|
|
lua_settop(L, top);
|
|
// stack clean
|
|
|
|
// add it
|
|
return clua_add_thread_to_uniq_array_and_rev_uniq(L);
|
|
}
|
|
|
|
// stack: pos, revUniqMap
|
|
int res = (int)lua_tonumber(L, -1);
|
|
|
|
lua_settop(L, top);
|
|
// stack clean
|
|
return res;
|
|
}
|
|
|
|
int clua_add_thread_to_uniq_array_and_rev_uniq(lua_State* L) {
|
|
//
|
|
// Do the equivalent of: table.insert(uniqueArray, L)
|
|
// and then revUniq[L] = #uniqArray (==uPos)
|
|
|
|
// stack: ...
|
|
int top = lua_gettop(L);
|
|
|
|
lua_pushlightuserdata(L,(void*)&GoWithinStateUniqArrayKey);
|
|
// stack: ukey, ...
|
|
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
// stack: uniqArray, ...
|
|
|
|
// jea: now store the actual thread in uniqArray
|
|
//
|
|
lua_pushthread(L);
|
|
// stack: thread, uniqArray, ...
|
|
|
|
// append to array at -2
|
|
int pos = lua_objlen(L, -2) + 1; /* first empty element */
|
|
|
|
lua_rawseti(L, -2, pos); /* t[pos] = v; and pops v from the top of the stack*/
|
|
// stack: uniqArray, ...
|
|
|
|
lua_pop(L, 1);
|
|
// stack: ...
|
|
|
|
// Phase 2:
|
|
//
|
|
// store pos into revUniqMap too, for O(1) coroutine lookup.
|
|
lua_pushlightuserdata(L, (void*)&GoWithinStateRevUniqMap);
|
|
// stack: revkey, ...
|
|
|
|
lua_gettable(L, LUA_REGISTRYINDEX);
|
|
// stack: revUniqMap, ...
|
|
|
|
lua_pushthread(L);
|
|
// stack: thread, revUniqMap, ...
|
|
|
|
lua_pushnumber(L, (double)pos);
|
|
// stack: pos, thread, revUniqMap, ...
|
|
|
|
lua_settable(L, -3);
|
|
// stack: revUniqMap, ...
|
|
|
|
lua_settop(L, top);
|
|
// stack clean
|
|
|
|
return pos;
|
|
}
|
|
|
|
int clua_setgostate(lua_State* L, size_t gostateindex)
|
|
{
|
|
int ret = 0;
|
|
int top = lua_gettop(L);
|
|
|
|
lua_atpanic(L, default_panicf);
|
|
lua_pushlightuserdata(L,(void*)&GoMainStatesKey);
|
|
|
|
//
|
|
// store L into a table that maps lua_State* -> gostateindex.
|
|
// Call the table the Lmap. It maps L to an index.
|
|
//
|
|
lua_gettable(L, LUA_REGISTRYINDEX); // pops the key
|
|
// does it already exist, or did we get nil back?
|
|
if (lua_isnil(L, -1)) {
|
|
// doesn't exist yet, need to create it the first time.
|
|
lua_pop(L, 1); // get rid of the nil
|
|
lua_newtable(L);
|
|
|
|
// save Lmap into lua registry under GoMainStatesKey.
|
|
|
|
// stack:
|
|
// Lmap
|
|
lua_pushvalue(L, -1);
|
|
// stack:
|
|
// Lmap
|
|
// Lmap
|
|
|
|
// get the key
|
|
lua_pushlightuserdata(L,(void*)&GoMainStatesKey);
|
|
// stack is now:
|
|
// key
|
|
// Lmap
|
|
// Lmap
|
|
|
|
lua_insert(L, -2);
|
|
// stack should now be ready for lua_settable:
|
|
// Lmap
|
|
// key
|
|
// Lmap
|
|
|
|
//set into registry table
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
// stack:
|
|
// Lmap
|
|
|
|
// and create the uniq array too, at the same time.
|
|
clua_create_uniq_array_if_not_exists(L);
|
|
|
|
// stack: Lmap
|
|
}
|
|
// INVAR: our Lmap is at top of stack, -1 position.
|
|
// stack: Lmap
|
|
|
|
// does our key already exist in the Lmap?
|
|
// If not, then append to the uniqArray.
|
|
// key
|
|
lua_pushthread(L);
|
|
// stack: key, Lmap
|
|
|
|
lua_gettable(L, -2);
|
|
// stack: nil, Lmap OR priorValue, Lmap
|
|
|
|
if (!lua_isnil(L, -1)) {
|
|
// stack: priorValue, Lmap
|
|
// no duplicate insert into Lmap needed
|
|
lua_settop(L, top);
|
|
// stack clean.
|
|
|
|
// should be returning 1 always, indicating
|
|
// a main coroutine.
|
|
return clua_dedup_coro(L);
|
|
}
|
|
|
|
// stack: thread, Lmap
|
|
lua_pop(L, 1);
|
|
// stack: Lmap
|
|
|
|
// This thread, L, is not known to Lmap.
|
|
ret = clua_add_thread_to_uniq_array_and_rev_uniq(L);
|
|
|
|
// stack: Lmap
|
|
|
|
// Finally, populate the Lmap
|
|
|
|
// key
|
|
lua_pushthread(L);
|
|
// stack: key, Lmap
|
|
|
|
// value
|
|
lua_pushnumber(L, gostateindex);
|
|
// stack: value, key, Lmap
|
|
|
|
// store key:value in map
|
|
lua_settable(L, -3);
|
|
// stack: Lmap
|
|
|
|
// cleanup stack, remove Lmap
|
|
lua_settop(L, top);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* called when lua code attempts to access a field of a published go object */
|
|
int interface_index_callback(lua_State *L)
|
|
{
|
|
unsigned int *iid = clua_checkgosomething(L, 1, MT_GOINTERFACE);
|
|
if (iid == NULL)
|
|
{
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
char *field_name = (char *)lua_tostring(L, 2);
|
|
if (field_name == NULL)
|
|
{
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
lua_State* mainThread = clua_get_main_thread(L);
|
|
size_t main_index = clua_getgostate(mainThread);
|
|
|
|
int r = golua_interface_index_callback(L, main_index, *iid, field_name);
|
|
|
|
if (r < 0)
|
|
{
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return r;
|
|
}
|
|
}
|
|
|
|
/* called when lua code attempts to set a field of a published go object */
|
|
int interface_newindex_callback(lua_State *L)
|
|
{
|
|
unsigned int *iid = clua_checkgosomething(L, 1, MT_GOINTERFACE);
|
|
if (iid == NULL)
|
|
{
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
char *field_name = (char *)lua_tostring(L, 2);
|
|
if (field_name == NULL)
|
|
{
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
lua_State* mainThread = clua_get_main_thread(L);
|
|
size_t main_index = clua_getgostate(mainThread);
|
|
|
|
int r = golua_interface_newindex_callback(L, main_index, *iid, field_name);
|
|
|
|
if (r < 0)
|
|
{
|
|
lua_error(L);
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return r;
|
|
}
|
|
}
|
|
|
|
void clua_hide_pcall(lua_State *L)
|
|
{
|
|
lua_getglobal(L, "pcall");
|
|
lua_setglobal(L, "unsafe_pcall");
|
|
lua_pushnil(L);
|
|
lua_setglobal(L, "pcall");
|
|
|
|
lua_getglobal(L, "xpcall");
|
|
lua_setglobal(L, "unsafe_xpcall");
|
|
lua_pushnil(L);
|
|
lua_setglobal(L, "xpcall");
|
|
}
|
|
|
|
void clua_initstate(lua_State* L)
|
|
{
|
|
/* create the GoLua.GoFunction metatable */
|
|
luaL_newmetatable(L, MT_GOFUNCTION);
|
|
|
|
// gofunction_metatable[__call] = &callback_function
|
|
lua_pushliteral(L,"__call");
|
|
lua_pushcfunction(L,&callback_function);
|
|
lua_settable(L,-3);
|
|
|
|
// gofunction_metatable[__gc] = &gchook_wrapper
|
|
lua_pushliteral(L,"__gc");
|
|
lua_pushcfunction(L,&gchook_wrapper);
|
|
lua_settable(L,-3);
|
|
lua_pop(L,1);
|
|
|
|
luaL_newmetatable(L, MT_GOINTERFACE);
|
|
|
|
// gointerface_metatable[__gc] = &gchook_wrapper
|
|
lua_pushliteral(L, "__gc");
|
|
lua_pushcfunction(L, &gchook_wrapper);
|
|
lua_settable(L, -3);
|
|
|
|
// gointerface_metatable[__index] = &interface_index_callback
|
|
lua_pushliteral(L, "__index");
|
|
lua_pushcfunction(L, &interface_index_callback);
|
|
lua_settable(L, -3);
|
|
|
|
// gointerface_metatable[__newindex] = &interface_newindex_callback
|
|
lua_pushliteral(L, "__newindex");
|
|
lua_pushcfunction(L, &interface_newindex_callback);
|
|
lua_settable(L, -3);
|
|
|
|
lua_register(L, GOLUA_DEFAULT_MSGHANDLER, &panic_msghandler);
|
|
lua_pop(L, 1);
|
|
}
|
|
|
|
int callback_panicf(lua_State* L)
|
|
{
|
|
lua_pushlightuserdata(L,(void*)&PanicFIDRegistryKey);
|
|
lua_gettable(L,LUA_REGISTRYINDEX);
|
|
unsigned int fid = lua_tointeger(L,-1);
|
|
lua_pop(L,1);
|
|
size_t gostateindex = clua_getgostate(L);
|
|
return golua_callpanicfunction(gostateindex,fid);
|
|
}
|
|
|
|
//TODO: currently setting garbage when panicf set to null
|
|
GoValue clua_atpanic(lua_State* L, unsigned int panicf_id)
|
|
{
|
|
//get old panicfid
|
|
unsigned int old_id;
|
|
lua_pushlightuserdata(L, (void*)&PanicFIDRegistryKey);
|
|
lua_gettable(L,LUA_REGISTRYINDEX);
|
|
if(lua_isnil(L, -1) == 0)
|
|
old_id = lua_tointeger(L,-1);
|
|
lua_pop(L, 1);
|
|
|
|
//set registry key for function id of go panic function
|
|
lua_pushlightuserdata(L, (void*)&PanicFIDRegistryKey);
|
|
//push id value
|
|
lua_pushinteger(L, panicf_id);
|
|
//set into registry table
|
|
lua_settable(L, LUA_REGISTRYINDEX);
|
|
|
|
//now set the panic function
|
|
lua_CFunction pf = lua_atpanic(L,&callback_panicf);
|
|
//make a GoInterface with a wrapped C panicf or the original go panicf
|
|
if(pf == &callback_panicf)
|
|
return (GoValue){1, &old_id};
|
|
else
|
|
return (GoValue){2, pf};
|
|
}
|
|
|
|
int clua_callluacfunc(lua_State* L, lua_CFunction f)
|
|
{
|
|
return f(L);
|
|
}
|
|
|
|
void* allocwrapper(void* ud, void *ptr, size_t osize, size_t nsize)
|
|
{
|
|
return (void*)golua_callallocf((GoUintptr)ud,(GoUintptr)ptr,osize,nsize);
|
|
}
|
|
|
|
lua_State* clua_newstate(void* goallocf)
|
|
{
|
|
return lua_newstate(&allocwrapper,goallocf);
|
|
}
|
|
|
|
void clua_setallocf(lua_State* L, void* goallocf)
|
|
{
|
|
lua_setallocf(L,&allocwrapper,goallocf);
|
|
}
|
|
|
|
void clua_openbase(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_base);
|
|
lua_pushstring(L,"");
|
|
lua_call(L, 1, 0);
|
|
clua_hide_pcall(L);
|
|
}
|
|
|
|
void clua_openio(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_io);
|
|
lua_pushstring(L,"io");
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
void clua_openmath(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_math);
|
|
lua_pushstring(L,"math");
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
void clua_openpackage(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_package);
|
|
lua_pushstring(L,"package");
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
void clua_openstring(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_string);
|
|
lua_pushstring(L,"string");
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
void clua_opentable(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_table);
|
|
lua_pushstring(L,"table");
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
void clua_openos(lua_State* L)
|
|
{
|
|
lua_pushcfunction(L,&luaopen_os);
|
|
lua_pushstring(L,"os");
|
|
lua_call(L, 1, 0);
|
|
}
|
|
|
|
void clua_hook_function(lua_State *L, lua_Debug *ar)
|
|
{
|
|
lua_checkstack(L, 2);
|
|
size_t gostateindex = clua_getgostate(L);
|
|
golua_callgohook(gostateindex);
|
|
}
|
|
|
|
void clua_sethook(lua_State* L, int n)
|
|
{
|
|
lua_sethook(L, &clua_hook_function, LUA_MASKCOUNT, n);
|
|
}
|
|
|
|
/*return the ctype of the cdata at the top of the stack*/
|
|
uint32_t clua_luajit_ctypeid(lua_State *L, int idx)
|
|
{
|
|
return luajit_ctypeid(L, idx);
|
|
}
|
|
|
|
void clua_luajit_push_cdata_int64(lua_State *L, int64_t n)
|
|
{
|
|
return luajit_push_cdata_int64(L, n);
|
|
}
|
|
|
|
void clua_luajit_push_cdata_uint64(lua_State *L, uint64_t u)
|
|
{
|
|
return luajit_push_cdata_uint64(L, u);
|
|
}
|
|
|
|
typedef struct _chunk {
|
|
int size; // chunk size
|
|
char *buffer; // chunk data
|
|
char* toread; // chunk to read
|
|
} chunk;
|
|
|
|
static const char * reader(lua_State *L, void *ud, size_t *sz) {
|
|
chunk *ck = (chunk *)ud;
|
|
if (ck->size > LUAL_BUFFERSIZE) {
|
|
ck->size -= LUAL_BUFFERSIZE;
|
|
*sz = LUAL_BUFFERSIZE;
|
|
ck->toread = ck->buffer;
|
|
ck->buffer += LUAL_BUFFERSIZE;
|
|
}else{
|
|
*sz = ck->size;
|
|
ck->toread = ck->buffer;
|
|
ck->size = 0;
|
|
}
|
|
return ck->toread;
|
|
}
|
|
|
|
static int writer(lua_State *L, const void* b, size_t size, void* B) {
|
|
static int count=0;
|
|
(void)L;
|
|
luaL_addlstring((luaL_Buffer*) B, (const char *)b, size);
|
|
return 0;
|
|
}
|
|
|
|
// load function chunk dumped from dump_chunk
|
|
int load_chunk(lua_State *L, char *b, int size, const char* chunk_name) {
|
|
chunk ck;
|
|
ck.buffer = b;
|
|
ck.size = size;
|
|
int err;
|
|
err = lua_load(L, reader, &ck, chunk_name);
|
|
if (err != 0) {
|
|
return luaL_error(L, "unable to load chunk, err: %d", err);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// dump function chunk from luaL_loadstring
|
|
int dump_chunk(lua_State *L) {
|
|
luaL_Buffer b;
|
|
luaL_checktype(L, -1, LUA_TFUNCTION);
|
|
lua_settop(L, -1);
|
|
luaL_buffinit(L,&b);
|
|
int err;
|
|
err = lua_dump(L, writer, &b);
|
|
if (err != 0){
|
|
return luaL_error(L, "unable to dump given function, err:%d", err);
|
|
}
|
|
luaL_pushresult(&b);
|
|
return 0;
|
|
}
|