From 2258b1b2cf951347d167d01201f0dc4bbf9a4428 Mon Sep 17 00:00:00 2001 From: aunsane Date: Tue, 26 Sep 2017 23:32:12 +0300 Subject: MirLua: refactoring - respect metatables in print function - srmm module functions now return metatable - version bump --- plugins/MirLua/src/m_database.cpp | 154 ++++++++++-------------- plugins/MirLua/src/m_protocols.cpp | 20 ++-- plugins/MirLua/src/m_srmm.cpp | 141 +++++++++++++++++----- plugins/MirLua/src/main.cpp | 1 + plugins/MirLua/src/mlua.cpp | 15 +++ plugins/MirLua/src/mlua_metatable.h | 232 +++++++++++++++++++----------------- plugins/MirLua/src/version.h | 2 +- 7 files changed, 327 insertions(+), 238 deletions(-) (limited to 'plugins/MirLua/src') diff --git a/plugins/MirLua/src/m_database.cpp b/plugins/MirLua/src/m_database.cpp index bdb5822fcf..7519caa8c8 100644 --- a/plugins/MirLua/src/m_database.cpp +++ b/plugins/MirLua/src/m_database.cpp @@ -1,5 +1,44 @@ #include "stdafx.h" +void luaM_pushdbvt(lua_State *L, const DBVARIANT &value) +{ + switch (value.type) + { + case DBVT_BYTE: + lua_pushinteger(L, value.bVal); + break; + case DBVT_WORD: + lua_pushinteger(L,value.wVal); + break; + case DBVT_DWORD: + lua_pushnumber(L, value.dVal); + break; + case DBVT_ASCIIZ: + lua_pushstring(L, ptrA(mir_utf8encode(value.pszVal))); + break; + case DBVT_UTF8: + lua_pushstring(L, value.pszVal); + break; + case DBVT_WCHAR: + lua_pushstring(L, ptrA(mir_utf8encodeW(value.pwszVal))); + break; + case DBVT_BLOB: + { + lua_createtable(L, value.cpbVal, 0); + for (int i = 0; i < value.cpbVal; i++) + { + lua_pushinteger(L, value.pbVal[i]); + lua_rawseti(L, -2, i + 1); + } + } + break; + default: + lua_pushnil(L); + } +} + +/***********************************************/ + static int db_FindFirstContact(lua_State *L) { ObsoleteMethod(L, "Use Contacts method"); @@ -328,7 +367,7 @@ static int db_AddEvent(lua_State *L) { MCONTACT hContact = luaL_checkinteger(L, 1); - DBEVENTINFO dbei = {}; + DBEVENTINFO dbei; MakeDbEvent(L, dbei); MEVENT hDbEvent = db_event_add(hContact, &dbei); @@ -398,6 +437,17 @@ static int db_Modules(lua_State *L) return 1; } +static int db_DeleteModule(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, 1); + const char *szModule = luaL_checkstring(L, 2); + + INT_PTR res = db_delete_module(hContact, szModule); + lua_pushboolean(L, !res); + + return 1; +} + static int SettingsEnumProc(const char* szSetting, LPARAM lParam) { if (szSetting) @@ -429,17 +479,6 @@ static int db_SettingIterator(lua_State *L) return 1; } -static int db_DeleteModule(lua_State *L) -{ - MCONTACT hContact = lua_tointeger(L, 1); - LPCSTR szModule = luaL_checkstring(L, 2); - - INT_PTR res = db_delete_module(hContact, szModule); - lua_pushboolean(L, !res); - - return 1; -} - static int db_Settings(lua_State *L) { MCONTACT hContact = lua_tointeger(L, 1); @@ -458,8 +497,8 @@ static int db_Settings(lua_State *L) static int db_GetSetting(lua_State *L) { MCONTACT hContact = lua_tointeger(L, 1); - LPCSTR szModule = luaL_checkstring(L, 2); - LPCSTR szSetting = luaL_checkstring(L, 3); + const char *szModule = luaL_checkstring(L, 2); + const char *szSetting = luaL_checkstring(L, 3); DBVARIANT dbv; if (db_get(hContact, szModule, szSetting, &dbv)) @@ -468,55 +507,26 @@ static int db_GetSetting(lua_State *L) return 1; } - switch (dbv.type) - { - case DBVT_BYTE: - lua_pushinteger(L, dbv.bVal); - break; - case DBVT_WORD: - lua_pushinteger(L, dbv.wVal); - break; - case DBVT_DWORD: - lua_pushnumber(L, dbv.dVal); - break; - case DBVT_ASCIIZ: - lua_pushstring(L, ptrA(mir_utf8encode(dbv.pszVal))); - break; - case DBVT_UTF8: - lua_pushstring(L, dbv.pszVal); - break; - case DBVT_WCHAR: - lua_pushstring(L, ptrA(mir_utf8encodeW(dbv.pwszVal))); - break; - case DBVT_BLOB: + luaM_pushdbvt(L, dbv); + db_free(&dbv); + + if (lua_isnil(L, -1) && !lua_isnoneornil(L, 4)) { - lua_createtable(L, dbv.cpbVal, 0); - for (int i = 0; i < dbv.cpbVal; i++) - { - lua_pushinteger(L, dbv.pbVal[i]); - lua_rawseti(L, -2, i + 1); - } - } - break; - default: - db_free(&dbv); + lua_pop(L, 1); lua_pushvalue(L, 4); - return 1; } - lua_pushinteger(L, dbv.type); - db_free(&dbv); - return 2; + return 1; } static int db_WriteSetting(lua_State *L) { MCONTACT hContact = lua_tointeger(L, 1); - LPCSTR szModule = luaL_checkstring(L, 2); - LPCSTR szSetting = luaL_checkstring(L, 3); + const char *szModule = luaL_checkstring(L, 2); + const char *szSetting = luaL_checkstring(L, 3); luaL_checkany(L, 4); - DBVARIANT dbv = { 0 }; + DBVARIANT dbv; if (lua_isnoneornil(L, 5)) { int type = lua_type(L, 4); @@ -646,46 +656,12 @@ static luaL_Reg databaseApi[] = #define MT_DBCONTACTWRITESETTING "DBCONTACTWRITESETTING" template <> -int MT::Index(lua_State *L, DBCONTACTWRITESETTING *dbcw) +int MT::Get(lua_State *L, DBCONTACTWRITESETTING *dbcw) { const char *key = luaL_checkstring(L, 2); if (mir_strcmpi(key, "Value") == 0) - { - switch (dbcw->value.type) - { - case DBVT_BYTE: - lua_pushinteger(L, dbcw->value.bVal); - break; - case DBVT_WORD: - lua_pushinteger(L, dbcw->value.wVal); - break; - case DBVT_DWORD: - lua_pushnumber(L, dbcw->value.dVal); - break; - case DBVT_ASCIIZ: - lua_pushstring(L, ptrA(mir_utf8encode(dbcw->value.pszVal))); - break; - case DBVT_UTF8: - lua_pushstring(L, dbcw->value.pszVal); - break; - case DBVT_WCHAR: - lua_pushstring(L, ptrA(mir_utf8encodeW(dbcw->value.pwszVal))); - break; - case DBVT_BLOB: - { - lua_createtable(L, dbcw->value.cpbVal, 0); - for (int i = 0; i < dbcw->value.cpbVal; i++) - { - lua_pushinteger(L, dbcw->value.pbVal[i]); - lua_rawseti(L, -2, i + 1); - } - } - break; - default: - lua_pushnil(L); - } - } + luaM_pushdbvt(L, dbcw->value); else lua_pushnil(L); @@ -710,7 +686,7 @@ DBEVENTINFO* MT::Init(lua_State *L) } template <> -int MT::Index(lua_State *L, DBEVENTINFO *dbei) +int MT::Get(lua_State *L, DBEVENTINFO *dbei) { const char *key = luaL_checkstring(L, 2); diff --git a/plugins/MirLua/src/m_protocols.cpp b/plugins/MirLua/src/m_protocols.cpp index 979388eed6..42b24c4936 100644 --- a/plugins/MirLua/src/m_protocols.cpp +++ b/plugins/MirLua/src/m_protocols.cpp @@ -25,7 +25,7 @@ static int lua_GetProtocol(lua_State *L) PROTOCOLDESCRIPTOR *pd = Proto_IsProtocolLoaded(szProto); if (pd) - MT::Set(L, pd); + MT::Apply(L, pd); else lua_pushnil(L); @@ -42,7 +42,7 @@ static int lua_ProtocolIterator(lua_State *L) { lua_pushinteger(L, (i + 1)); lua_replace(L, lua_upvalueindex(1)); - MT::Set(L, protos[i]); + MT::Apply(L, protos[i]); } else lua_pushnil(L); @@ -110,7 +110,7 @@ static int lua_GetAccount(lua_State *L) PROTOACCOUNT *pa = Proto_GetAccount(name); if (pa) - MT::Set(L, pa); + MT::Apply(L, pa); else lua_pushnil(L); @@ -132,7 +132,7 @@ static int lua_AccountIterator(lua_State *L) { lua_pushinteger(L, (i + 1)); lua_replace(L, lua_upvalueindex(1)); - MT::Set(L, accounts[i]); + MT::Apply(L, accounts[i]); } else lua_pushnil(L); @@ -153,8 +153,8 @@ static int lua_Accounts(lua_State *L) break; case LUA_TUSERDATA: { - PROTOCOLDESCRIPTOR **pd = (PROTOCOLDESCRIPTOR**)luaL_checkudata(L, 1, MT_PROTOCOLDESCRIPTOR); - szProto = (*pd)->szName; + PROTOCOLDESCRIPTOR *pd = *(PROTOCOLDESCRIPTOR**)luaL_checkudata(L, 1, MT_PROTOCOLDESCRIPTOR); + szProto = pd->szName; break; } default: @@ -188,8 +188,8 @@ static int lua_CallService(lua_State *L) break; case LUA_TUSERDATA: { - PROTOACCOUNT **pa = (PROTOACCOUNT**)luaL_checkudata(L, 1, MT_PROTOACCOUNT); - szModule = (*pa)->szModuleName; + PROTOACCOUNT *pa = *(PROTOACCOUNT**)luaL_checkudata(L, 1, MT_PROTOACCOUNT); + szModule = pa->szModuleName; break; } default: @@ -266,8 +266,8 @@ LUAMOD_API int luaopen_m_protocols(lua_State *L) MT(L, "CCSDATA") .Field(&CCSDATA::hContact, "hContact", LUA_TINTEGER) .Field(&CCSDATA::szProtoService, "Service", LUA_TSTRINGA) - .Field([](CCSDATA *ccd) -> MTFieldVal { MTFieldVal tmp; tmp.userdata = (void*)ccd->wParam; return tmp; }, "wParam", LUA_TLIGHTUSERDATA) - .Field([](CCSDATA *ccd) -> MTFieldVal { MTFieldVal tmp; tmp.userdata = (void*)ccd->lParam; return tmp; }, "lParam", LUA_TLIGHTUSERDATA); + .Field(&CCSDATA::wParam, "wParam", LUA_TLIGHTUSERDATA) + .Field(&CCSDATA::lParam, "lParam", LUA_TLIGHTUSERDATA); MT(L, "PROTORECVEVENT") .Field(&PROTORECVEVENT::timestamp, "Timestamp", LUA_TINTEGER) diff --git a/plugins/MirLua/src/m_srmm.cpp b/plugins/MirLua/src/m_srmm.cpp index a1b7240cec..c28f2de4ce 100644 --- a/plugins/MirLua/src/m_srmm.cpp +++ b/plugins/MirLua/src/m_srmm.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" +#define MT_BBBUTTON "BBButton" + static void MakeBBButton(lua_State *L, BBButton &bbb) { bbb.dwDefPos = 100; @@ -29,56 +31,114 @@ static void MakeBBButton(lua_State *L, BBButton &bbb) lua_pop(L, 1); } +/***********************************************/ + static int lua_AddButton(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); - BBButton bbb; - MakeBBButton(L, bbb); + BBButton *bbb = (BBButton*)mir_calloc(sizeof(BBButton)); + MakeBBButton(L, *bbb); int hScriptLangpack = CMLuaScript::GetScriptIdFromEnviroment(L); - - INT_PTR res = Srmm_AddButton(&bbb, hScriptLangpack); - lua_pushboolean(L, res == 0); - - mir_free((void*)bbb.pszModuleName); - mir_free((void*)bbb.pwszText); - mir_free((void*)bbb.pwszTooltip); + if (Srmm_AddButton(bbb, hScriptLangpack)) + { + lua_pushnil(L); + return 1; + } + + MT::Apply(L, bbb); return 1; } static int lua_ModifyButton(lua_State *L) { - if (lua_type(L, 1) != LUA_TTABLE) + switch (lua_type(L, 1)) { - lua_pushlightuserdata(L, 0); - return 1; + case LUA_TTABLE: + { + BBButton bbb; + MakeBBButton(L, bbb); + INT_PTR res = Srmm_ModifyButton(&bbb); + mir_free((void*)bbb.pszModuleName); + mir_free((void*)bbb.pwszText); + mir_free((void*)bbb.pwszTooltip); + lua_pushboolean(L, !res); + break; + } + case LUA_TUSERDATA: + { + BBButton *bbb = *(BBButton**)luaL_checkudata(L, 1, MT_BBBUTTON); + luaL_checktype(L, 2, LUA_TTABLE); + { + if (lua_getfield(L, -1, "Text")) + { + mir_free((void*)bbb->pwszText); + bbb->pwszText = mir_utf8decodeW(lua_tostring(L, -1)); + } + lua_pop(L, 1); + + if (lua_getfield(L, -1, "Tooltip")) + { + mir_free((void*)bbb->pwszTooltip); + bbb->pwszTooltip = mir_utf8decodeW(lua_tostring(L, -1)); + } + lua_pop(L, 1); + + if (lua_getfield(L, -1, "Flags")) + bbb->bbbFlags = luaL_optinteger(L, -1, BBBF_ISIMBUTTON); + lua_pop(L, 1); + + if (lua_getfield(L, -1, "Icon")) + bbb->hIcon = (HANDLE)lua_touserdata(L, -1); + lua_pop(L, 1); + } + INT_PTR res = Srmm_ModifyButton(bbb); + lua_pushvalue(L, 1); + break; + } + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); } - - BBButton bbb; - MakeBBButton(L, bbb); - - INT_PTR res = Srmm_ModifyButton(&bbb); - lua_pushinteger(L, res); - - mir_free((void*)bbb.pszModuleName); - mir_free((void*)bbb.pwszText); - mir_free((void*)bbb.pwszTooltip); return 1; } static int lua_RemoveButton(lua_State *L) { - ptrA szModuleName(mir_utf8decodeA(luaL_checkstring(L, 1))); - - BBButton mbb = {}; - mbb.pszModuleName = szModuleName; - mbb.dwButtonID = luaL_checkinteger(L, 2); - - INT_PTR res = Srmm_RemoveButton(&mbb); - lua_pushinteger(L, res); + switch (lua_type(L, 1)) + { + case LUA_TSTRING: + { + BBButton bbb; + bbb.pszModuleName = mir_utf8decodeA(lua_tostring(L, 1)); + bbb.dwButtonID = luaL_checkinteger(L, 2); + INT_PTR res = Srmm_RemoveButton(&bbb); + mir_free((void*)bbb.pszModuleName); + lua_pushboolean(L, !res); + break; + } + case LUA_TTABLE: + { + BBButton bbb; + bbb.pszModuleName = mir_utf8decodeA(luaL_checkstring(L, 1)); + bbb.dwButtonID = luaL_checkinteger(L, 2); + INT_PTR res = Srmm_RemoveButton(&bbb); + mir_free((void*)bbb.pszModuleName); + lua_pushboolean(L, !res); + break; + } + case LUA_TUSERDATA: + { + BBButton *bbb = *(BBButton**)luaL_checkudata(L, 1, MT_BBBUTTON); + INT_PTR res = Srmm_RemoveButton(bbb); + lua_pushboolean(L, !res); + break; + } + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); + } return 1; } @@ -94,10 +154,31 @@ static luaL_Reg srmmApi[] = /***********************************************/ +template <> +void MT::Free(lua_State*, BBButton **bbb) +{ + mir_free((void*)(*bbb)->pszModuleName); + mir_free((void*)(*bbb)->pwszText); + mir_free((void*)(*bbb)->pwszTooltip); + mir_free(*bbb); +} + +/***********************************************/ + LUAMOD_API int luaopen_m_srmm(lua_State *L) { luaL_newlib(L, srmmApi); + MT(L, MT_BBBUTTON) + .Field(&BBButton::pszModuleName, "Module", LUA_TSTRINGA) + .Field(&BBButton::dwButtonID, "ButtonId", LUA_TINTEGER) + .Field(&BBButton::pwszText, "Text", LUA_TSTRINGW) + .Field(&BBButton::pwszTooltip, "Tooltip", LUA_TSTRINGW) + .Field(&BBButton::bbbFlags, "Flags", LUA_TINTEGER) + .Field(&BBButton::hIcon, "Icon", LUA_TLIGHTUSERDATA) + .Field(lua_ModifyButton, "Modify") + .Field(lua_RemoveButton, "Remove"); + MT(L, "CustomButtonClickData") .Field(&CustomButtonClickData::pszModule, "Module", LUA_TSTRINGA) .Field(&CustomButtonClickData::dwButtonId, "ButtonId", LUA_TINTEGER) diff --git a/plugins/MirLua/src/main.cpp b/plugins/MirLua/src/main.cpp index 7648ecf930..0da7a5d157 100644 --- a/plugins/MirLua/src/main.cpp +++ b/plugins/MirLua/src/main.cpp @@ -74,6 +74,7 @@ extern "C" int __declspec(dllexport) Load(void) hRecvMessage = CreateHookableEvent(MODULE PSR_MESSAGE); CreateProtoServiceFunction(MODULE, PSR_MESSAGE, FilterRecvMessage); + return 0; } diff --git a/plugins/MirLua/src/mlua.cpp b/plugins/MirLua/src/mlua.cpp index d3c835ee7d..5229196f64 100644 --- a/plugins/MirLua/src/mlua.cpp +++ b/plugins/MirLua/src/mlua.cpp @@ -42,6 +42,21 @@ static int mlua_print(lua_State *L) data.AppendFormat("%s", lua_tostring(L, i)); break; default: + if (lua_getmetatable(L, 1)) + { + if (lua_getfield(L, -1, "__tostring") == LUA_TFUNCTION) + { + lua_pushvalue(L, 1); + if (luaM_pcall(L, 1, 1) == LUA_OK) + { + data.AppendFormat("%s", lua_tostring(L, -1)); + lua_pop(L, 2); + break; + } + lua_pop(L, 2); + } + lua_pop(L, 1); + } data.AppendFormat("%s(0x%p)", luaL_typename(L, i), lua_topointer(L, i)); break; } diff --git a/plugins/MirLua/src/mlua_metatable.h b/plugins/MirLua/src/mlua_metatable.h index 58dfede077..04173a2a56 100644 --- a/plugins/MirLua/src/mlua_metatable.h +++ b/plugins/MirLua/src/mlua_metatable.h @@ -9,7 +9,7 @@ #define LUA_TSTRINGA LUA_NUMTAGS + 2 #define LUA_TSTRINGW LUA_NUMTAGS + 3 -union MTFieldVal +union MTValue { void *userdata; int boolean; @@ -21,88 +21,76 @@ union MTFieldVal lua_CFunction function; }; -struct MTField -{ - int lua_type; - MTFieldVal val; -}; - class CMTField { - ptrA pszName; + ptrA name; + int type; public: - CMTField(const char *name) : - pszName(mir_strdup(name)) - {} + CMTField(const char *name, int type) : + name(mir_strdup(name)), type(type) {} - const char* GetName() const { return pszName; } + virtual ~CMTField() {}; - static int Compare(const CMTField *p1, const CMTField *p2) - { return mir_strcmp(p1->pszName, p2->pszName); + const char* GetName() const { return name; } + int GetType() const { return type; } + + static int Compare(const CMTField *p1, const CMTField *p2) { + return mir_strcmp(p1->name, p2->name); } - virtual MTField GetValue(void *obj) = 0; - virtual ~CMTField(){}; + virtual MTValue GetValue(void *obj) = 0; }; -template +template class CMTFieldOffset : public CMTField { - int lua_type; ptrdiff_t offset; size_t size; public: - CMTFieldOffset(const char *name, ptrdiff_t off, size_t s, int type) - : CMTField(name), - offset(off), lua_type(type), size(s) - {} + CMTFieldOffset(const char *name, int type, ptrdiff_t offset, size_t size) + : CMTField(name, type), offset(offset), size(size) {} - virtual MTField GetValue(void *obj) + virtual MTValue GetValue(void *obj) { - MTField fd = { lua_type }; - //fd.val = *(Ret*)((char*)obj + offset); - memcpy(&fd.val, ((char*)obj + offset), sizeof(Ret)); - return fd; + MTValue value; + memcpy(&value, ((char*)obj + offset), sizeof(R)); + return value; } }; class CMTFieldFunction : public CMTField { - lua_CFunction func; + lua_CFunction function; public: - CMTFieldFunction(const char *name, lua_CFunction f) : - CMTField(name), - func(f) - {} + CMTFieldFunction(const char *name, lua_CFunction function) : + CMTField(name, LUA_TFUNCTION), function(function) {} - virtual MTField GetValue(void*) + virtual MTValue GetValue(void*) { - MTField tmp = { LUA_TFUNCTION }; - tmp.val.function = func; - return tmp; + MTValue value; + value.function = function; + return value; } }; -template +template class CMTFieldLambda : public CMTField { - int lua_type; - std::function lambda; + int type; + std::function lambda; public: - CMTFieldLambda(const char *name, decltype(lambda) f, int type) - : CMTField(name), - lambda(f), lua_type(type) - {} + CMTFieldLambda(const char *name, int type, decltype(lambda) lambda) + : CMTField(name, type), lambda(lambda), type(type) {} - virtual MTField GetValue(void *obj) + virtual MTValue GetValue(void *obj) { - MTField tmp = { lua_type }; - tmp.val = lambda((Obj*)obj); - return tmp; + CMTValue result = { type }; + result.Value = lambda((Obj*)obj); + return result; } }; @@ -113,7 +101,8 @@ private: lua_State *L; static const char *name; - static OBJLIST arFields; + static const luaL_Reg events[]; + static OBJLIST fields; static T* Init(lua_State *L) { @@ -121,12 +110,17 @@ private: return (T*)lua_touserdata(L, 1); } - static int Index(lua_State *L, T* /*obj*/) + static int Get(lua_State *L, T* /*obj*/) { lua_pushnil(L); return 1; } + static bool Set(lua_State *L, T* /*obj*/) + { + return false; + } + static void Free(lua_State* /*L*/, T **obj) { *obj = NULL; @@ -135,17 +129,27 @@ private: static int lua__new(lua_State *L) { T **udata = (T**)lua_newuserdata(L, sizeof(T*)); + *udata = Init(L); if (*udata == NULL) { lua_pushnil(L); return 1; } + luaL_setmetatable(L, MT::name); return 1; } + static int lua__gc(lua_State *L) + { + T **obj = (T**)luaL_checkudata(L, 1, MT::name); + MT::Free(L, obj); + + return 0; + } + static int lua__bnot(lua_State *L) { T *obj = *(T**)luaL_checkudata(L, 1, MT::name); @@ -159,36 +163,37 @@ private: T *obj = *(T**)luaL_checkudata(L, 1, MT::name); const char *key = lua_tostring(L, 2); - LPCVOID arTmp[2] = { nullptr, key }; - CMTField *pField = arFields.find((CMTField*)&arTmp); - if (pField == nullptr) - return Index(L, obj); + const void *tmp[2] = { nullptr, key }; + CMTField *field = fields.find((CMTField*)&tmp); + if (field == nullptr) + return Get(L, obj); - MTField fieldVal = pField->GetValue(obj); - switch (fieldVal.lua_type) { + MTValue value = field->GetValue(obj); + int type = field->GetType(); + switch (type) { case LUA_TBOOLEAN: - lua_pushboolean(L, fieldVal.val.boolean); + lua_pushboolean(L, value.boolean); break; case LUA_TINTEGER: - lua_pushinteger(L, fieldVal.val.integer); + lua_pushinteger(L, value.integer); break; case LUA_TNUMBER: - lua_pushnumber(L, fieldVal.val.number); + lua_pushnumber(L, value.number); break; case LUA_TSTRING: - lua_pushstring(L, fieldVal.val.string); + lua_pushstring(L, value.string); break; case LUA_TSTRINGA: - lua_pushstring(L, ptrA(mir_utf8encode(fieldVal.val.stringA))); + lua_pushstring(L, ptrA(mir_utf8encode(value.stringA))); break; case LUA_TSTRINGW: - lua_pushstring(L, T2Utf(fieldVal.val.stringW)); + lua_pushstring(L, T2Utf(value.stringW)); break; case LUA_TLIGHTUSERDATA: - lua_pushlightuserdata(L, fieldVal.val.userdata); + lua_pushlightuserdata(L, value.userdata); break; case LUA_TFUNCTION: - lua_pushcfunction(L, fieldVal.val.function); + lua_pushcfunction(L, value.function); break; default: lua_pushnil(L); @@ -197,45 +202,57 @@ private: return 1; } + static int lua__newindex(lua_State *L) + { + T *obj = *(T**)luaL_checkudata(L, 1, MT::name); + + if (!Set(L, obj)) { + const char *key = lua_tostring(L, 2); + luaL_error(L, "attempt to index a %s value (%s is readonly)", MT::name, key); + } + + return 0; + } + static int lua__tostring(lua_State *L) { T *obj = *(T**)luaL_checkudata(L, 1, MT::name); CMStringA data(MT::name); data += "("; - for (int i = 0; i < arFields.getCount(); i++) - { - CMTField &F = arFields[i]; + for (int i = 0; i < fields.getCount(); i++) { + CMTField &field = fields[i]; - data += F.GetName(); + data += field.GetName(); data += "="; - MTField fieldVal = F.GetValue(obj); - switch (fieldVal.lua_type) - { + MTValue value = field.GetValue(obj); + int type = field.GetType(); + switch (type) { + case LUA_TNIL: + data.Append("nil"); + break; case LUA_TBOOLEAN: - data.Append(fieldVal.val.boolean == 0 ? "false" : "true"); + data.Append(value.boolean == 0 ? "false" : "true"); break; case LUA_TINTEGER: - data.AppendFormat("%d", fieldVal.val.integer); + data.AppendFormat("%d", value.integer); break; case LUA_TNUMBER: - data.AppendFormat("%f", fieldVal.val.number); + data.AppendFormat("%f", value.number); break; case LUA_TSTRING: - data.Append(fieldVal.val.string); + data.Append(value.string); break; case LUA_TSTRINGA: - data.Append(ptrA(mir_utf8encode(fieldVal.val.stringA))); + data.Append(ptrA(mir_utf8encode(value.stringA))); break; case LUA_TSTRINGW: - data.Append(T2Utf(fieldVal.val.stringW)); - break; - case LUA_TLIGHTUSERDATA: - data.AppendFormat("(0x%p)", fieldVal.val.userdata); + data.Append(T2Utf(value.stringW)); break; default: - data.Append("nil"); + data.AppendFormat("%s(0x%p)", lua_typename(L, type), value.userdata); + break; } data += ", "; } @@ -244,40 +261,29 @@ private: return 1; } - static int lua__gc(lua_State *L) - { - T **obj = (T**)luaL_checkudata(L, 1, MT::name); - MT::Free(L, obj); - - return 0; - } - static int lua__call(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); luaL_checkany(L, 2); + int nres = lua_gettop(L) - 1; + lua_getfield(L, 1, "new"); - lua_pushvalue(L, 2); - luaM_pcall(L, 1, 1); + for (int i = 1; i <= nres; i++) + lua_pushvalue(L, i + 1); + luaM_pcall(L, nres, 1); return 1; } public: - MT(lua_State *L, const char *tname) : L(L) + MT(lua_State *L, const char *tname) + : L(L) { MT::name = tname; luaL_newmetatable(L, MT::name); - lua_pushcfunction(L, lua__index); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, lua__bnot); - lua_setfield(L, -2, "__bnot"); - lua_pushcfunction(L, lua__tostring); - lua_setfield(L, -2, "__tostring"); - lua_pushcfunction(L, lua__gc); - lua_setfield(L, -2, "__gc"); + luaL_setfuncs(L, events, 0); lua_pop(L, 1); lua_createtable(L, 0, 1); @@ -298,28 +304,27 @@ public: size = sizeof(M); size_t offset = (size_t)(&(((T*)0)->*M)); if (type != LUA_TNONE) - arFields.insert(new CMTFieldOffset(name, offset, size, type)); + fields.insert(new CMTFieldOffset(name, type, offset, size)); return *this; } template - MT& Field(const L &f, const char *name, int type) + MT& Field(const L &lambda, const char *name, int type) { if (type != LUA_TNONE) - arFields.insert(new CMTFieldLambda(name, f, type)); + fields.insert(new CMTFieldLambda(name, type, lambda)); return *this; } - MT& Field(const lua_CFunction f, const char *name) + MT& Field(const lua_CFunction function, const char *name) { - arFields.insert(new CMTFieldFunction(name, f)); + fields.insert(new CMTFieldFunction(name, function)); return *this; } - static void Set(lua_State *L, T *obj) + static void Apply(lua_State *L, T *obj) { - if (obj == NULL) - { + if (obj == NULL) { lua_pushnil(L); return; } @@ -334,6 +339,17 @@ template const char *MT::name; template -OBJLIST MT::arFields(5, &CMTField::Compare); +const luaL_Reg MT::events[] = { + { "__index", lua__index }, + { "__newindex", lua__newindex }, + { "__bnot", lua__bnot }, + { "__tostring", lua__tostring }, + { "__gc", lua__gc }, + + { NULL, NULL }, +}; + +template +OBJLIST MT::fields(5, &CMTField::Compare); #endif //_LUA_METATABLE_H_ diff --git a/plugins/MirLua/src/version.h b/plugins/MirLua/src/version.h index 89028c524c..6b783b7c7b 100644 --- a/plugins/MirLua/src/version.h +++ b/plugins/MirLua/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 11 #define __RELEASE_NUM 8 -#define __BUILD_NUM 2 +#define __BUILD_NUM 3 #include -- cgit v1.2.3