diff options
Diffstat (limited to 'plugins/MirLua/src/mlua_function_loader.cpp')
-rw-r--r-- | plugins/MirLua/src/mlua_function_loader.cpp | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/plugins/MirLua/src/mlua_function_loader.cpp b/plugins/MirLua/src/mlua_function_loader.cpp new file mode 100644 index 0000000000..6e82086d29 --- /dev/null +++ b/plugins/MirLua/src/mlua_function_loader.cpp @@ -0,0 +1,194 @@ +#include "stdafx.h" + +CMLuaFunctionLoader::CMLuaFunctionLoader(lua_State *L) : L(L) +{ +} + +/***********************************************/ + +static int mlua_print(lua_State *L) +{ + CMStringA data; + int nargs = lua_gettop(L); + for (int i = 1; i <= nargs; i++) { + switch (lua_type(L, i)) { + case LUA_TNIL: + data.Append("nil"); + break; + case LUA_TBOOLEAN: + data.AppendFormat("%s", lua_toboolean(L, i) ? "true" : "false"); + break; + case LUA_TNUMBER: + data.AppendFormat("%s", lua_tostring(L, i)); + break; + case LUA_TSTRING: + data.AppendFormat("'%s'", lua_tostring(L, i)); + break; + default: + if (luaL_callmeta(L, i, "__tostring")) { + data.AppendFormat("'%s'", lua_tostring(L, -1)); + break; + } + data.AppendFormat("%s(0x%p)", luaL_typename(L, i), lua_topointer(L, i)); + break; + } + data.Append(", "); + } + if (data.GetLength() >= 1) + data.Delete(data.GetLength() - 2, 2); + + Log(data.GetBuffer()); + + return 0; +} + +static int mlua_toansi(lua_State *L) +{ + const char *value = luaL_checkstring(L, 1); + int codepage = luaL_optinteger(L, 2, Langpack_GetDefaultCodePage()); + + ptrA string(mir_strdup(value)); + lua_pushstring(L, mir_utf8decodecp(string, codepage, nullptr)); + + return 1; +} + +static int mlua_toucs2(lua_State *L) +{ + const char *value = luaL_checkstring(L, 1); + + ptrW unicode(mir_utf8decodeW(value)); + size_t length = mir_wstrlen(unicode) * sizeof(wchar_t); + + ptrA string((char*)mir_calloc(length + 1)); + memcpy(string, unicode, length); + + lua_pushlstring(L, string, length + 1); + + return 1; +} + +static int mlua_topointer(lua_State *L) +{ + switch (lua_type(L, 1)) { + case LUA_TBOOLEAN: + lua_pushlightuserdata(L, (void*)lua_toboolean(L, 1)); + break; + case LUA_TNUMBER: + if (lua_isinteger(L, 1)) { + lua_Integer value = lua_tointeger(L, 1); + if (value > INTPTR_MAX) { + const char *msg = lua_pushfstring(L, "%f is larger than %d", value, INTPTR_MAX); + return luaL_argerror(L, 1, msg); + } + lua_pushlightuserdata(L, (void*)value); + } + break; + case LUA_TSTRING: + lua_pushlightuserdata(L, (void*)lua_tostring(L, 1)); + break; + case LUA_TLIGHTUSERDATA: + lua_pushvalue(L, 1); + default: + return luaL_argerror(L, 1, luaL_typename(L, 1)); + } + + return 1; +} + +static int mlua_tonumber(lua_State *L) +{ + if (lua_islightuserdata(L, 1)) { + lua_Integer value = (lua_Integer)lua_touserdata(L, 1); + lua_pushinteger(L, value); + return 1; + } + + int n = lua_gettop(L); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pushvalue(L, 1); + if (n == 2) + lua_pushvalue(L, 2); + luaM_pcall(L, n, 1); + + return 1; +} + +static int mlua_interpolate(lua_State *L) +{ + const char *string = luaL_checkstring(L, 1); + + char pattern[128]; + + if (lua_istable(L, 2)) { + for (lua_pushnil(L); lua_next(L, 2); lua_pop(L, 3)) { + lua_pushvalue(L, -2); + const char *key = lua_tostring(L, -1); + const char *val = lua_tostring(L, -2); + + mir_snprintf(pattern, "{%s}", key); + string = luaL_gsub(L, string, pattern, val ? val : ""); + } + } + else { + int nargs = lua_gettop(L); + for (int i = 2; i <= nargs; i++) { + const char *val = lua_tostring(L, i); + + mir_snprintf(pattern, "{%d}", i - 1); + string = luaL_gsub(L, string, pattern, val ? val : ""); + lua_pop(L, 1); + } + } + + lua_Debug ar; + int level = 1; + while (lua_getstack(L, level++, &ar)) { + int i = 1; + while (const char *name = lua_getlocal(L, &ar, i++)) { + const char *val = lua_tostring(L, -1); + mir_snprintf(pattern, "{%s}", name); + string = luaL_gsub(L, string, pattern, val ? val : ""); + lua_pop(L, 1); + } + } + + lua_pushstring(L, string); + + return 1; +} + +/***********************************************/ + +void CMLuaFunctionLoader::LoadFunctions() +{ + Log("Loading additional functions"); + + lua_register(L, "print", mlua_print); + lua_register(L, "a", mlua_toansi); + lua_register(L, "toansi", mlua_toansi); + lua_register(L, "u", mlua_toucs2); + lua_register(L, "toucs2", mlua_toucs2); + lua_register(L, "topointer", mlua_topointer); + + lua_getglobal(L, "tonumber"); + lua_pushcclosure(L, mlua_tonumber, 1); + lua_setglobal(L, "tonumber"); + + lua_pushstring(L, ""); + lua_getmetatable(L, -1); + lua_pushstring(L, "__mod"); + lua_pushcfunction(L, mlua_interpolate); + lua_rawset(L, -3); + lua_pushstring(L, "__index"); + lua_rawget(L, -2); + lua_pushcfunction(L, mlua_interpolate); + lua_setfield(L, -2, "interpolate"); + lua_pop(L, 3); +} + +void CMLuaFunctionLoader::Load(lua_State *L) +{ + CMLuaFunctionLoader loader(L); + loader.LoadFunctions(); +}
\ No newline at end of file |