/* ** $Id: ldblib.c,v 1.7 1999/11/22 13:12:07 roberto Exp roberto $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ #include #include #define LUA_REENTRANT #include "lauxlib.h" #include "lua.h" #include "luadebug.h" #include "lualib.h" static void settabss (lua_State *L, lua_Object t, const char *i, const char *v) { lua_pushobject(L, t); lua_pushstring(L, i); lua_pushstring(L, v); lua_settable(L); } static void settabsi (lua_State *L, lua_Object t, const char *i, int v) { lua_pushobject(L, t); lua_pushstring(L, i); lua_pushnumber(L, v); lua_settable(L); } static lua_Object getfuncinfo (lua_State *L, lua_Object func) { lua_Object result = lua_createtable(L); const char *str; int line; lua_funcinfo(L, func, &str, &line); if (line == -1) /* C function? */ settabss(L, result, "kind", "C"); else if (line == 0) { /* "main"? */ settabss(L, result, "kind", "chunk"); settabss(L, result, "source", str); } else { /* Lua function */ settabss(L, result, "kind", "Lua"); settabsi(L, result, "def_line", line); settabss(L, result, "source", str); } if (line != 0) { /* is it not a "main"? */ const char *kind = lua_getobjname(L, func, &str); if (*kind) { settabss(L, result, "name", str); settabss(L, result, "where", kind); } } return result; } static void getstack (lua_State *L) { lua_Object func = lua_stackedfunction(L, luaL_check_int(L, 1)); if (func == LUA_NOOBJECT) /* level out of range? */ return; else { lua_Object result = getfuncinfo(L, func); int currline = lua_currentline(L, func); if (currline > 0) settabsi(L, result, "current", currline); lua_pushobject(L, result); lua_pushstring(L, "func"); lua_pushobject(L, func); lua_settable(L); /* result.func = func */ lua_pushobject(L, result); } } static void funcinfo (lua_State *L) { lua_pushobject(L, getfuncinfo(L, luaL_functionarg(L, 1))); } static int findlocal (lua_State *L, lua_Object func, int arg) { lua_Object v = lua_getparam(L, arg); if (lua_isnumber(L, v)) return (int)lua_getnumber(L, v); else { const char *name = luaL_check_string(L, arg); int i = 0; int result = -1; const char *vname; while (lua_getlocal(L, func, ++i, &vname) != LUA_NOOBJECT) { if (strcmp(name, vname) == 0) result = i; /* keep looping to get the last var with this name */ } if (result == -1) luaL_verror(L, "no local variable `%.50s' at given level", name); return result; } } static void getlocal (lua_State *L) { lua_Object func = lua_stackedfunction(L, luaL_check_int(L, 1)); lua_Object val; const char *name; if (func == LUA_NOOBJECT) /* level out of range? */ return; /* return nil */ else if (lua_getparam(L, 2) != LUA_NOOBJECT) { /* 2nd argument? */ if ((val = lua_getlocal(L, func, findlocal(L, func, 2), &name)) != LUA_NOOBJECT) { lua_pushobject(L, val); lua_pushstring(L, name); } /* else return nil */ } else { /* collect all locals in a table */ lua_Object result = lua_createtable(L); int i; for (i=1; ;i++) { if ((val = lua_getlocal(L, func, i, &name)) == LUA_NOOBJECT) break; lua_pushobject(L, result); lua_pushstring(L, name); lua_pushobject(L, val); lua_settable(L); /* result[name] = value */ } lua_pushobject(L, result); } } static void setlocal (lua_State *L) { lua_Object func = lua_stackedfunction(L, luaL_check_int(L, 1)); int numvar; luaL_arg_check(L, func != LUA_NOOBJECT, 1, "level out of range"); numvar = findlocal(L, func, 2); lua_pushobject(L, luaL_nonnullarg(L, 3)); if (!lua_setlocal(L, func, numvar)) lua_error(L, "no such local variable"); } static int linehook = -1; /* Lua reference to line hook function */ static int callhook = -1; /* Lua reference to call hook function */ static void dohook (lua_State *L, int ref) { lua_LHFunction oldlinehook = lua_setlinehook(L, NULL); lua_CHFunction oldcallhook = lua_setcallhook(L, NULL); lua_callfunction(L, lua_getref(L, ref)); lua_setlinehook(L, oldlinehook); lua_setcallhook(L, oldcallhook); } static void linef (lua_State *L, int line) { lua_pushnumber(L, line); dohook(L, linehook); } static void callf (lua_State *L, lua_Function func, const char *file, int line) { if (func != LUA_NOOBJECT) { lua_pushobject(L, func); lua_pushstring(L, file); lua_pushnumber(L, line); } dohook(L, callhook); } static void setcallhook (lua_State *L) { lua_Object f = lua_getparam(L, 1); lua_unref(L, callhook); if (f == LUA_NOOBJECT) { callhook = -1; lua_setcallhook(L, NULL); } else { lua_pushobject(L, f); callhook = lua_ref(L, 1); lua_setcallhook(L, callf); } } static void setlinehook (lua_State *L) { lua_Object f = lua_getparam(L, 1); lua_unref(L, linehook); if (f == LUA_NOOBJECT) { linehook = -1; lua_setlinehook(L, NULL); } else { lua_pushobject(L, f); linehook = lua_ref(L, 1); lua_setlinehook(L, linef); } } static const struct luaL_reg dblib[] = { {"funcinfo", funcinfo}, {"getlocal", getlocal}, {"getstack", getstack}, {"setcallhook", setcallhook}, {"setlinehook", setlinehook}, {"setlocal", setlocal} }; void lua_dblibopen (lua_State *L) { luaL_openl(L, dblib); }