#include "traceback.hpp" #define TRACEBACK_LEVELS1 12 #define TRACEBACK_LEVELS2 10 // Call this with the error message on top of the stack. static void traceback_general(lua_State *L, lua_State *L1, int baselevel) { int top = lua_gettop(L); // Convert message to a string if (!lua_tostring(L, top)) { luaL_callmeta(L, top, "__tostring"); // If callmeta didn't produce exactly one string, clear the stack // and push "unknown error" if ((lua_gettop(L) == top + 1) && (lua_tostring(L, -1))) { lua_remove(L, top); } else { lua_settop(L, top - 1); lua_pushstring(L, "unknown error"); } } // Append the traceback. lua_Debug ar; int level = baselevel; int firstpart = 1; while (lua_getstack(L1, level++, &ar)) { if (level > TRACEBACK_LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\n\t..."); /* too many levels */ while (lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } lua_getinfo(L1, "Snl", &ar); if ((ar.currentline > 0) || (*ar.namewhat != 0) || (*ar.what != 'C')) { lua_pushliteral(L, "\n\t"); lua_pushfstring(L, "%s:", ar.short_src); if (ar.currentline > 0) lua_pushfstring(L, "%d:", ar.currentline); if (*ar.namewhat != '\0') /* is there a name? */ lua_pushfstring(L, " in function " LUA_QS, ar.name); else { if (*ar.what == 'm') /* main? */ lua_pushfstring(L, " in main chunk"); else if (*ar.what == 'C' || *ar.what == 't') lua_pushliteral(L, " ?"); /* C function or tail call */ else lua_pushfstring(L, " in function <%s:%d>", ar.short_src, ar.linedefined); } if (1 + lua_gettop(L) - top > 5) { lua_concat(L, 1 + lua_gettop(L) - top); } } } lua_pushstring(L, "\n"); if (1 + lua_gettop(L) - top > 1) { lua_concat(L, 1 + lua_gettop(L) - top); } } int traceback_handler(lua_State *L) { traceback_general(L, L, 1); return 1; } void traceback_coroutine(lua_State *L, lua_State *CO) { lua_xmove(CO, L, 1); traceback_general(L, CO, 0); } int traceback_pcall(lua_State *L, int narg, int nret) { int status; int base = lua_gettop(L) - narg; /* function index */ lua_pushcfunction(L, traceback_handler); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ status = lua_pcall(L, narg, nret, base); lua_remove(L, base); /* remove traceback function */ return status; }