summaryrefslogtreecommitdiff
path: root/plugins/MirLua/src/mlua_function_loader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/MirLua/src/mlua_function_loader.cpp')
-rw-r--r--plugins/MirLua/src/mlua_function_loader.cpp194
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