|
#ifdef __cplusplus |
|
extern "C" { |
|
#endif |
|
|
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include "stackdumper.h" |
|
#include <stdbool.h> |
|
#include <inttypes.h> |
|
|
|
bool _enable = true; |
|
|
|
void callLuaPrint(lua_State *L, const char *str) |
|
{ |
|
if (!_enable) |
|
{ |
|
return; |
|
} |
|
|
|
lua_getglobal(L, "print"); |
|
lua_pushfstring(L, str); |
|
|
|
int result = lua_pcall(L, 1, 0, 0); |
|
if (result != 0) |
|
{ |
|
int stackSize = lua_gettop(L); |
|
const char *errMsg = lua_tostring(L, -1); |
|
char finalErrMsg[8192]; |
|
snprintf(finalErrMsg, sizeof(finalErrMsg), "callLuaPrint result: %d, stackSize: %d, error: %s\n", result, stackSize, errMsg); |
|
luaL_error(L, finalErrMsg); |
|
} |
|
} |
|
|
|
void callLuaPrintFmt(lua_State *L, const char *fmt, ...) |
|
{ |
|
lua_getglobal(L, "print"); |
|
|
|
va_list argp; |
|
va_start(argp, fmt); |
|
lua_pushvfstring(L, fmt, argp); |
|
va_end(argp); |
|
|
|
int result = lua_pcall(L, 1, 0, 0); |
|
if (result != 0) |
|
{ |
|
int stackSize = lua_gettop(L); |
|
const char *errMsg = lua_tostring(L, -1); |
|
char finalErrMsg[8192]; |
|
snprintf(finalErrMsg, sizeof(finalErrMsg), "callLuaPrintFmt result: %d, stackSize: %d, error: %s\n", result, stackSize, errMsg); |
|
luaL_error(L, finalErrMsg); |
|
} |
|
} |
|
|
|
const char *callLuaTostring(lua_State *L, int idx) |
|
{ |
|
lua_pushvalue(L, idx); |
|
lua_getglobal(L, "tostring"); |
|
lua_insert(L, -2); |
|
|
|
int result = lua_pcall(L, 1, 1, 0); |
|
if (result != 0) |
|
{ |
|
int stackSize = lua_gettop(L); |
|
const char *errMsg = lua_tostring(L, -1); |
|
char finalErrMsg[8192]; |
|
snprintf(finalErrMsg, sizeof(finalErrMsg), "callLuaTostring result: %d, stackSize: %d, error: %s\n", result, stackSize, errMsg); |
|
luaL_error(L, finalErrMsg); |
|
return ""; |
|
} |
|
const char *msg = lua_tostring(L, -1); /* get result */ |
|
lua_pop(L, 1); /* pop result */ |
|
return msg; |
|
} |
|
|
|
void stackDump(lua_State *L) |
|
{ |
|
if (!_enable) |
|
{ |
|
return; |
|
} |
|
|
|
int top = lua_gettop(L); |
|
callLuaPrintFmt(L, "<<<stackDump start, count %d", top); |
|
int i; |
|
for (i = 1; i <= top; i++) |
|
{ /* repeat for each level */ |
|
int t = lua_type(L, i); |
|
switch (t) |
|
{ |
|
case LUA_TNIL: /* nil */ |
|
callLuaPrintFmt(L, "LUA_TNIL: nil"); |
|
break; |
|
case LUA_TBOOLEAN: /* boolean */ |
|
callLuaPrintFmt(L, "LUA_TBOOLEAN: `%s`", lua_toboolean(L, i) ? "true" : "false"); |
|
break; |
|
case LUA_TLIGHTUSERDATA: /* light userdata */ |
|
callLuaPrintFmt(L, "LUA_TLIGHTUSERDATA: @%p, tostring: %s", lua_touserdata(L, i), callLuaTostring(L, i)); |
|
break; |
|
case LUA_TNUMBER: /* number */ |
|
callLuaPrintFmt(L, "LUA_TNUMBER: %g", lua_tonumber(L, i)); |
|
break; |
|
case LUA_TSTRING: /* string */ |
|
callLuaPrintFmt(L, "LUA_TSTRING: \"%s\"", lua_tostring(L, i)); |
|
break; |
|
case LUA_TTABLE: /* number */ |
|
{ |
|
char *dumpedTableStr = mallocDumpedTableStr(L, i); |
|
callLuaPrintFmt(L, "LUA_TTABLE: tostring: %s\n%s", callLuaTostring(L, i), dumpedTableStr); |
|
free(dumpedTableStr); |
|
break; |
|
} |
|
case LUA_TFUNCTION: /* function */ |
|
callLuaPrintFmt(L, "LUA_TFUNCTION: @%p, tostring: %s", lua_touserdata(L, i), callLuaTostring(L, i)); |
|
break; |
|
case LUA_TUSERDATA: /* userdata */ |
|
callLuaPrintFmt(L, "LUA_TUSERDATA: @%p, tostring: %s", lua_touserdata(L, i), callLuaTostring(L, i)); |
|
break; |
|
case LUA_TTHREAD: /* thread */ |
|
callLuaPrintFmt(L, "LUA_TTHREAD: @%p, tostring: %s", lua_touserdata(L, i), callLuaTostring(L, i)); |
|
break; |
|
|
|
default: /* other values */ |
|
// callLuaPrintFmt(L, "LUA_other_values(type): type: %s, tostring: %s", lua_typename(L, t), lua_tostring(L, i)); |
|
callLuaPrintFmt(L, "LUA_other_values(type): type: %s, tostring: %s", lua_typename(L, t), callLuaTostring(L, i)); |
|
break; |
|
} |
|
} |
|
callLuaPrintFmt(L, "stackDump end>>>"); |
|
} |
|
|
|
char *_malloc_dump_lua_table_internal(lua_State *L, int index, int indent); |
|
|
|
char *_malloc_concatenate_strings_free_first(char *str1, const char *str2) |
|
{ |
|
size_t len1 = strlen(str1); |
|
size_t len2 = strlen(str2); |
|
char *result = (char *)malloc(len1 + len2 + 1); |
|
strcpy(result, str1); |
|
strcat(result, str2); |
|
free(str1); |
|
return result; |
|
} |
|
|
|
char *_malloc_concatenate_spaced_strings_free_first(char *str1, const char *str2) |
|
{ |
|
char *spacedStr1 = _malloc_concatenate_strings_free_first(str1, " "); |
|
char *result = _malloc_concatenate_strings_free_first(spacedStr1, str2); |
|
return result; |
|
} |
|
|
|
char *mallocDumpedTableStr(lua_State *L, int index) |
|
{ |
|
lua_pushvalue(L, index); |
|
if (lua_istable(L, -1)) |
|
{ |
|
char *result = _malloc_dump_lua_table_internal(L, lua_gettop(L), 0); |
|
result = _malloc_concatenate_strings_free_first(result, "\n"); |
|
lua_pop(L, 1); |
|
return result; |
|
} |
|
else |
|
{ |
|
int t = lua_type(L, -1); |
|
char *result = (char *)malloc(8192); |
|
snprintf(result, sizeof(result), "getDumpedTableStr is not table, type: %s, tostring: %s\n", lua_typename(L, t), callLuaTostring(L, -1)); |
|
lua_pop(L, 1); |
|
return result; |
|
} |
|
} |
|
|
|
void dumpTable(lua_State *L, int index) |
|
{ |
|
if (!_enable) |
|
{ |
|
return; |
|
} |
|
|
|
lua_pushvalue(L, index); |
|
if (lua_istable(L, -1)) |
|
{ |
|
char *result = _malloc_dump_lua_table_internal(L, lua_gettop(L), 0); |
|
callLuaPrintFmt(L, "<<<dumpTable start \n%s\ndumpTable end>>>", result); |
|
free(result); |
|
} |
|
else |
|
{ |
|
int t = lua_type(L, -1); |
|
callLuaPrintFmt(L, "<<<dumpTable start \ndump_lua_table is not table, type: %s, tostring: %s\ndumpTable end>>>", lua_typename(L, t), callLuaTostring(L, -1)); |
|
} |
|
lua_pop(L, 1); |
|
} |
|
|
|
char *_malloc_dump_lua_table_internal(lua_State *L, int index, int indent) |
|
{ |
|
if (indent > 6) |
|
{ |
|
char *result = strdup("...\n"); |
|
return result; |
|
} |
|
|
|
char *result = strdup("{\n"); |
|
|
|
lua_pushnil(L); // Push a nil value to start the iteration |
|
|
|
while (lua_next(L, index) != 0) |
|
{ |
|
// Print indentation |
|
for (int i = 0; i < indent + 1; i++) |
|
{ |
|
result = _malloc_concatenate_strings_free_first(result, " "); |
|
} |
|
|
|
if (lua_isnumber(L, -2)) |
|
{ |
|
char key[8192]; |
|
snprintf(key, sizeof(key), "[%" PRId64 "] = ", lua_tointeger(L, -2)); |
|
result = _malloc_concatenate_spaced_strings_free_first(result, key); |
|
} |
|
else |
|
{ |
|
const char *key = lua_tostring(L, -2); |
|
result = _malloc_concatenate_spaced_strings_free_first(result, key ? key : "nil"); |
|
result = _malloc_concatenate_strings_free_first(result, " = "); |
|
} |
|
|
|
// Print the value |
|
if (lua_istable(L, -1)) |
|
{ |
|
char *nestedTable = _malloc_dump_lua_table_internal(L, lua_gettop(L), indent + 1); // Recursively dump nested tables |
|
result = _malloc_concatenate_strings_free_first(result, nestedTable); |
|
free(nestedTable); |
|
|
|
for (int i = 0; i < indent + 1; i++) |
|
{ |
|
result = _malloc_concatenate_strings_free_first(result, " "); |
|
} |
|
result = _malloc_concatenate_strings_free_first(result, "\n"); |
|
} |
|
else if (lua_isstring(L, -1)) |
|
{ |
|
const char *value = lua_tostring(L, -1); |
|
result = _malloc_concatenate_spaced_strings_free_first(result, value ? value : "nil"); |
|
result = _malloc_concatenate_strings_free_first(result, "\n"); |
|
} |
|
else if (lua_isboolean(L, -1)) |
|
{ |
|
result = _malloc_concatenate_strings_free_first(result, lua_toboolean(L, -1) ? "true\n" : "false\n"); |
|
} |
|
else if (lua_isnumber(L, -1)) |
|
{ |
|
char value[8192]; |
|
snprintf(value, sizeof(value), "%g\n", lua_tonumber(L, -1)); |
|
result = _malloc_concatenate_strings_free_first(result, value); |
|
} |
|
else |
|
{ |
|
const char *typeName = lua_typename(L, lua_type(L, -1)); |
|
result = _malloc_concatenate_spaced_strings_free_first(result, typeName ? typeName : "nil"); |
|
result = _malloc_concatenate_strings_free_first(result, "\n"); |
|
} |
|
|
|
// Pop the value, but keep the key for the next iteration |
|
lua_pop(L, 1); |
|
} |
|
|
|
for (int i = 0; i < indent; i++) |
|
{ |
|
result = _malloc_concatenate_strings_free_first(result, " "); |
|
} |
|
result = _malloc_concatenate_strings_free_first(result, "}"); |
|
|
|
return result; |
|
} |
|
|
|
#ifdef __cplusplus |
|
} |
|
#endif |