#include #include #include "api.h" #include "../any_log.h" static lua_CFunction lua_log_stringformat = NULL; static int lua_log_format(lua_State *state, any_log_level_t level) { // Use string.format to print safely // int n_args = lua_gettop(state); lua_pushcfunction(state, lua_log_stringformat); for (int i = 1; i <= n_args; ++i) lua_pushvalue(state, i); lua_call(state, n_args, 1); const char *message = lua_tostring(state, -1); lua_getglobal(state, "debug"); lua_getfield(state, -1, "getinfo"); // Ignore the first frame (lua_log_format itself) lua_pushnumber(state, 2); // S: source, l: currentline, n: name lua_pushstring(state, "Sln"); const char *source = "?", *func = "?"; char buffer[4096]; if (lua_pcall(state, 2, 1, 0) == LUA_OK) { lua_getfield(state, -1, "short_src"); const char *shortsrc = lua_tostring(state, -1); lua_getfield(state, -2, "currentline"); int line = lua_tointeger(state, -1); if (!strncmp(shortsrc, "[string ", 8)) { int length = strlen(shortsrc); snprintf(buffer, sizeof(buffer), "lua %.*s", length - 9, shortsrc + 8); } else { snprintf(buffer, sizeof(buffer), "lua %s:%d", shortsrc, line); } lua_getfield(state, -3, "name"); const char *name = lua_tostring(state, -1); source = buffer; func = name ? name : "..."; } lua_pop(state, 3); any_log_format(level, source, func, "%s", message); return 0; } static int lua_log_log(lua_State *state) { const char *level = luaL_checkstring(state, 1); lua_pop(state, 1); any_log_level_t l = any_log_level_from_string(level); assert(l > ANY_LOG_ALL); return lua_log_format(state, l); } static int lua_log_panic(lua_State *state) { return lua_log_format(state, ANY_LOG_PANIC); } static int lua_log_error(lua_State *state) { return lua_log_format(state, ANY_LOG_ERROR); } static int lua_log_warn(lua_State *state) { return lua_log_format(state, ANY_LOG_WARN); } static int lua_log_info(lua_State *state) { return lua_log_format(state, ANY_LOG_INFO); } static int lua_log_debug(lua_State *state) { return lua_log_format(state, ANY_LOG_DEBUG); } static int lua_log_trace(lua_State *state) { return lua_log_format(state, ANY_LOG_TRACE); } int lua_log_library(lua_State *state) { static const luaL_Reg library[] = { { "log", lua_log_log }, { "panic", lua_log_panic }, { "error", lua_log_error }, { "warn", lua_log_warn }, { "info", lua_log_info }, { "debug", lua_log_debug }, { "trace", lua_log_trace }, { NULL, NULL }, }; lua_getglobal(state, "string"); lua_getfield(state, -1, "format"); lua_log_stringformat = lua_tocfunction(state, -1); lua_pop(state, 2); luaL_newlib(state, library); return 1; }