#include #include "BLua.h" #ifndef BUFFERSIZE #define BUFFERSIZE 2048 #endif typedef GeneralException LuaException; class LuaStatics : public Base { public: static const char * getF(lua_State *, void *, size_t *); static int putF(lua_State *, const void *, size_t, void *); static int luapanic(lua_State *) throw(GeneralException); static int destructor(lua_State *); static int andB(lua_State *); static int orB(lua_State *); static int xorB(lua_State *); static int notB(lua_State *); static int hex(lua_State *); }; std::map Lua::lualist; int LuaStatics::luapanic(lua_State * L) throw (GeneralException) { Lua::find(L)->showerror(); throw LuaException("Error running Lua code, bailing out."); } int LuaStatics::andB(lua_State * _L) { Lua * L = Lua::find(_L); int n = L->gettop(); int a, b; if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { L->error("Incorrect arguments to function `andB'"); } a = L->tonumber(1); b = L->tonumber(2); L->push((lua_Number) (a & b)); return 1; } int LuaStatics::orB(lua_State * _L) { Lua * L = Lua::find(_L); int n = L->gettop(); int a, b; if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { L->error("Incorrect arguments to function `orB'"); } a = L->tonumber(1); b = L->tonumber(2); L->push((lua_Number) (a | b)); return 1; } int LuaStatics::xorB(lua_State * _L) { Lua * L = Lua::find(_L); int n = L->gettop(); int a, b; if ((n != 2) && !L->isnumber(1) && !L->isnumber(2)) { L->error("Incorrect arguments to function `xorB'"); } a = L->tonumber(1); b = L->tonumber(2); L->push((lua_Number) (a ^ b)); return 1; } int LuaStatics::notB(lua_State * _L) { Lua * L = Lua::find(_L); int n = L->gettop(); int x; if ((n != 1) && !L->isnumber()) { L->error("Incorrect arguments to function `notB'"); } x = L->tonumber(); L->push((lua_Number) (~x)); return 1; } int LuaStatics::hex(lua_State * _L) { Lua * L = Lua::find(_L); int n = L->gettop(); int x; String r; if (((n != 1) || (n != 2)) && !L->isnumber(1) && ((n == 2) && !L->isstring(2))) { L->error("Incorrect arguments to function `hex'"); } x = L->tonumber(1); String fmt = n == 2 ? L->tostring() : "%x"; r.set(fmt.to_charp(), x); L->push(r); return 1; } Lua::Lua() : L(lua_open()) { lua_atpanic(L, LuaStatics::luapanic); lualist[L] = this; declarefunc("andB", LuaStatics::andB); declarefunc("orB", LuaStatics::orB); declarefunc("xorB", LuaStatics::xorB); declarefunc("notB", LuaStatics::notB); declarefunc("hex", LuaStatics::hex); } Lua::Lua(lua_State * _L) : L(_L) { lua_atpanic(L, LuaStatics::luapanic); lualist[L] = this; } Lua::~Lua() { lua_setgcthreshold(L, 0); lua_close(L); } Lua::Lua(const Lua & l) throw (GeneralException) { throw GeneralException("Error: can't duplicate a Lua object."); } void Lua::open_base() { luaopen_base(L); lua_pop(L, 1); } void Lua::open_table() { luaopen_table(L); lua_pop(L, 1); } void Lua::open_io() { luaopen_io(L); lua_pop(L, 1); } void Lua::open_string() { luaopen_string(L); lua_pop(L, 1); } void Lua::open_math() { luaopen_math(L); lua_pop(L, 1); } void Lua::open_debug() { luaopen_debug(L); lua_pop(L, 1); } void Lua::declarefunc(const String & name, lua_CFunction f, int i) { lua_pushstring(L, name.to_charp()); lua_pushcfunction(L, f); lua_settable(L, i); } void Lua::call(const String & f, int i, int nargs, int nresults) { lua_pushstring(L, f.to_charp()); lua_gettable(L, i); lua_insert(L, -1 - nargs - nresults); lua_call(L, nargs, nresults); } void Lua::call(int nargs, int nresults) { lua_call(L, nargs, nresults); } void Lua::push() { lua_pushnil(L); } void Lua::push(lua_Number n) { lua_pushnumber(L, n); } void Lua::push(const String & s) { lua_pushlstring(L, s.to_charp(), s.strlen()); } void Lua::push(bool b) { lua_pushboolean(L, b); } void Lua::push(void * p) { lua_pushlightuserdata(L, p); } void Lua::push(lua_CFunction f, int n) { lua_pushcclosure(L, f, n); } void Lua::pop(int n) { lua_pop(L, n); } void Lua::newtable() { lua_newtable(L); } void Lua::settable(int i) { lua_settable(L, i); } void Lua::gettable(int i) { lua_gettable(L, i); } int Lua::gettop() { return lua_gettop(L); } void Lua::error(const String & msg) { push(msg); lua_error(L); } int Lua::type(int i) { return lua_type(L, i); } bool Lua::isnil(int i) { return lua_isnil(L, i); } bool Lua::isboolean(int i) { return lua_isboolean(L, i); } bool Lua::isnumber(int i) { return lua_isnumber(L, i); } bool Lua::isstring(int i) { return lua_isstring(L, i); } bool Lua::istable(int i) { return lua_istable(L, i); } bool Lua::isfunction(int i) { return lua_isfunction(L, i); } bool Lua::iscfunction(int i) { return lua_iscfunction(L, i); } bool Lua::isuserdata(int i) { return lua_isuserdata(L, i); } bool Lua::islightuserdata(int i) { return lua_islightuserdata(L, i); } bool toboolean(int = -1); lua_Number tonumber(int = -1); String tostring(int = -1); lua_CFunction tocfunction(int = -1); void * touserdata(int = -1); Lua * tothread(int = -1); bool Lua::toboolean(int i) { return lua_toboolean(L, i); } lua_Number Lua::tonumber(int i) { return lua_tonumber(L, i); } String Lua::tostring(int i) { return String(lua_tostring(L, i)); } lua_CFunction Lua::tocfunction(int i) { return lua_tocfunction(L, i); } void * Lua::touserdata(int i) { return lua_touserdata(L, i); } Lua * Lua::tothread(int i) { return find(lua_tothread(L, i)); } struct LoadF { Handle * f; char buff[BUFFERSIZE]; }; const char * LuaStatics::getF(lua_State * L, void * ud, size_t * size) { LoadF *lf = (LoadF *)ud; (void)L; *size = lf->f->read(lf->buff, BUFFERSIZE); return (*size > 0) ? lf->buff : NULL; } struct DumpF { Handle * f; }; int LuaStatics::putF(lua_State * L, const void * p, size_t size, void * ud) { DumpF *lf = (DumpF *)ud; (void)L; return lf->f->write(p, size) == size; } void Lua::load(Handle * h, bool docall) throw (GeneralException) { LoadF lf; int status; lf.f = h; status = lua_load(L, LuaStatics::getF, &lf, h->GetName().to_charp()); if (status) { showerror(); throw LuaException("Error loading lua chunk from Handle `" + h->GetName() + "'"); } if (docall) call(); } extern "C" void luacmain(lua_State * L, int stripping, lua_Chunkwriter w, void * uD); void Lua::dump(Handle * h, bool strip) { DumpF lf; lf.f = h; luacmain(L, strip, LuaStatics::putF, &lf); } Lua * Lua::thread() { return new Lua(lua_newthread(L)); } Lua * Lua::find(lua_State * _L) throw (GeneralException) { std::map::iterator i; if ((i = lualist.find(_L)) == lualist.end()) { throw GeneralException("Unable to find the Lua object for this context"); } return i->second; } void Lua::showerror() { int n = lua_gettop(L); int i; String t; printm(M_ERROR, "Lua object: Got an LUA error\n"); printm(M_ERROR, "Inspecting LUA stack\n"); if (n == 0) { printm(M_ERROR, "Stack empty\n"); return; } for (i = 1; i <= n; i++) { switch(lua_type(L, i)) { case LUA_TNONE: t = "Invalid"; break; case LUA_TNIL: t = "(Nil)"; break; case LUA_TNUMBER: t.set("(Number) %f", lua_tonumber(L, i)); break; case LUA_TBOOLEAN: t.set("(Bool) %s", lua_toboolean(L, i) ? "true" : "false"); break; case LUA_TSTRING: t.set("(String) %s", lua_tostring(L, i)); break; case LUA_TTABLE: t = "(Table)"; break; case LUA_TFUNCTION: t = "(Function)"; break; default: t = "Unknown"; } printm(M_ERROR, String(i) + ": " + t + "\n"); } } int Lua::getmetatable(int i) { return lua_getmetatable(L, i); } int Lua::setmetatable(int i) { return lua_setmetatable(L, i); } void LuaObject::push(Lua * L) throw (GeneralException) { if (pushed && wantdestruct) { throw GeneralException("Error: object is owned by the LUA script and can not be pushed."); } L->newtable(); pushmembers(L); pushed = true; } void LuaObject::pushme(Lua * L, void * o) { L->push("__obj"); L->push(o); L->settable(); } void * LuaObject::getme(Lua * L, int i) throw (GeneralException) { void * r; L->push("__obj"); L->gettable(i); if (!(r = L->touserdata())) { throw GeneralException("Lua object already destroyed"); } L->pop(); return r; } void LuaObject::pushit(Lua * L, const String & s, lua_CFunction f) { L->push(s); L->push(f); L->settable(); } int LuaStatics::destructor(lua_State * _L) { Lua * L = Lua::find(_L); Base * b = (Base *) LuaObject::getme(L); delete b; L->push("__obj"); L->push((void *) 0); L->settable(); printm(M_INFO, "Destructing an object from LUA\n"); return 0; } void LuaObject::pushdestruct(Lua * L) throw (GeneralException) { if (pushed) { throw GeneralException("Error: can't push destructor, object already pushed"); } push(L); if (!L->getmetatable(1)) { L->newtable(); } L->push("__gc"); L->push(LuaStatics::destructor); L->settable(); L->setmetatable(1); pushit(L, "destroy", LuaStatics::destructor); wantdestruct = true; }