diff options
| author | Lua Team <team@lua.org> | 2003-04-11 12:00:00 +0000 |
|---|---|---|
| committer | repogen <> | 2003-04-11 12:00:00 +0000 |
| commit | f0e4e22f5c119865eb5a8d3844a40df2d5980b3b (patch) | |
| tree | c4df063a747e9c99f8aba1678588a030993780a9 /src/lib/ldblib.c | |
| parent | 1981b7c90eb09e956e969cda5c473be4560af573 (diff) | |
| download | lua-github-5.0.tar.gz | |
Lua 5.05.0
Diffstat (limited to 'src/lib/ldblib.c')
| -rw-r--r-- | src/lib/ldblib.c | 241 |
1 files changed, 176 insertions, 65 deletions
diff --git a/src/lib/ldblib.c b/src/lib/ldblib.c index 636dbe05..6dc9b64c 100644 --- a/src/lib/ldblib.c +++ b/src/lib/ldblib.c @@ -1,5 +1,5 @@ /* -** $Id: ldblib.c,v 1.29 2000/11/06 17:58:38 roberto Exp $ +** $Id: ldblib.c,v 1.80 2003/04/03 13:35:34 roberto Exp $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ @@ -9,10 +9,11 @@ #include <stdlib.h> #include <string.h> +#define ldblib_c + #include "lua.h" #include "lauxlib.h" -#include "luadebug.h" #include "lualib.h" @@ -20,43 +21,41 @@ static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, i); lua_pushstring(L, v); - lua_settable(L, -3); + lua_rawset(L, -3); } static void settabsi (lua_State *L, const char *i, int v) { lua_pushstring(L, i); - lua_pushnumber(L, v); - lua_settable(L, -3); + lua_pushnumber(L, (lua_Number)v); + lua_rawset(L, -3); } static int getinfo (lua_State *L) { lua_Debug ar; - const char *options = luaL_opt_string(L, 2, "flnSu"); - char buff[20]; + const char *options = luaL_optstring(L, 2, "flnSu"); if (lua_isnumber(L, 1)) { - if (!lua_getstack(L, (int)lua_tonumber(L, 1), &ar)) { + if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { lua_pushnil(L); /* level out of range */ return 1; } } else if (lua_isfunction(L, 1)) { + lua_pushfstring(L, ">%s", options); + options = lua_tostring(L, -1); lua_pushvalue(L, 1); - sprintf(buff, ">%.10s", options); - options = buff; } else - luaL_argerror(L, 1, "function or level expected"); + return luaL_argerror(L, 1, "function or level expected"); if (!lua_getinfo(L, options, &ar)) - luaL_argerror(L, 2, "invalid option"); + return luaL_argerror(L, 2, "invalid option"); lua_newtable(L); for (; *options; options++) { switch (*options) { case 'S': settabss(L, "source", ar.source); - if (ar.source) - settabss(L, "short_src", ar.short_src); + settabss(L, "short_src", ar.short_src); settabsi(L, "linedefined", ar.linedefined); settabss(L, "what", ar.what); break; @@ -71,9 +70,9 @@ static int getinfo (lua_State *L) { settabss(L, "namewhat", ar.namewhat); break; case 'f': - lua_pushstring(L, "func"); + lua_pushliteral(L, "func"); lua_pushvalue(L, -3); - lua_settable(L, -3); + lua_rawset(L, -3); break; } } @@ -84,9 +83,9 @@ static int getinfo (lua_State *L) { static int getlocal (lua_State *L) { lua_Debug ar; const char *name; - if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ - luaL_argerror(L, 1, "level out of range"); - name = lua_getlocal(L, &ar, luaL_check_int(L, 2)); + if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ + return luaL_argerror(L, 1, "level out of range"); + name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); if (name) { lua_pushstring(L, name); lua_pushvalue(L, -2); @@ -101,88 +100,200 @@ static int getlocal (lua_State *L) { static int setlocal (lua_State *L) { lua_Debug ar; - if (!lua_getstack(L, luaL_check_int(L, 1), &ar)) /* level out of range? */ - luaL_argerror(L, 1, "level out of range"); + if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ + return luaL_argerror(L, 1, "level out of range"); luaL_checkany(L, 3); - lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2))); + lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); return 1; } +static int auxupvalue (lua_State *L, int get) { + const char *name; + int n = luaL_checkint(L, 2); + luaL_checktype(L, 1, LUA_TFUNCTION); + if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */ + name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); + if (name == NULL) return 0; + lua_pushstring(L, name); + lua_insert(L, -(get+1)); + return get + 1; +} + + +static int getupvalue (lua_State *L) { + return auxupvalue(L, 1); +} + + +static int setupvalue (lua_State *L) { + luaL_checkany(L, 3); + return auxupvalue(L, 0); +} + + -/* dummy variables (to define unique addresses) */ -static char key1, key2; -#define KEY_CALLHOOK (&key1) -#define KEY_LINEHOOK (&key2) +static const char KEY_HOOK = 'h'; -static void hookf (lua_State *L, void *key) { - lua_getregistry(L); - lua_pushuserdata(L, key); - lua_gettable(L, -2); +static void hookf (lua_State *L, lua_Debug *ar) { + static const char *const hooknames[] = + {"call", "return", "line", "count", "tail return"}; + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); if (lua_isfunction(L, -1)) { - lua_pushvalue(L, 1); - lua_rawcall(L, 1, 0); + lua_pushstring(L, hooknames[(int)ar->event]); + if (ar->currentline >= 0) + lua_pushnumber(L, (lua_Number)ar->currentline); + else lua_pushnil(L); + lua_assert(lua_getinfo(L, "lS", ar)); + lua_call(L, 2, 0); } else lua_pop(L, 1); /* pop result from gettable */ - lua_pop(L, 1); /* pop table */ } -static void callf (lua_State *L, lua_Debug *ar) { - lua_pushstring(L, ar->event); - hookf(L, KEY_CALLHOOK); +static int makemask (const char *smask, int count) { + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + return mask; } -static void linef (lua_State *L, lua_Debug *ar) { - lua_pushnumber(L, ar->currentline); - hookf(L, KEY_LINEHOOK); +static char *unmakemask (int mask, char *smask) { + int i = 0; + if (mask & LUA_MASKCALL) smask[i++] = 'c'; + if (mask & LUA_MASKRET) smask[i++] = 'r'; + if (mask & LUA_MASKLINE) smask[i++] = 'l'; + smask[i] = '\0'; + return smask; } -static void sethook (lua_State *L, void *key, lua_Hook hook, - lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) { - lua_settop(L, 1); - if (lua_isnil(L, 1)) - (*sethookf)(L, NULL); - else if (lua_isfunction(L, 1)) - (*sethookf)(L, hook); - else - luaL_argerror(L, 1, "function expected"); - lua_getregistry(L); - lua_pushuserdata(L, key); - lua_pushvalue(L, -1); /* dup key */ - lua_gettable(L, -3); /* get old value */ - lua_pushvalue(L, -2); /* key (again) */ +static int sethook (lua_State *L) { + if (lua_isnoneornil(L, 1)) { + lua_settop(L, 1); + lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + } + else { + const char *smask = luaL_checkstring(L, 2); + int count = luaL_optint(L, 3, 0); + luaL_checktype(L, 1, LUA_TFUNCTION); + lua_sethook(L, hookf, makemask(smask, count), count); + } + lua_pushlightuserdata(L, (void *)&KEY_HOOK); lua_pushvalue(L, 1); - lua_settable(L, -5); /* set new value */ + lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ + return 0; } -static int setcallhook (lua_State *L) { - sethook(L, KEY_CALLHOOK, callf, lua_setcallhook); - return 1; +static int gethook (lua_State *L) { + char buff[5]; + int mask = lua_gethookmask(L); + lua_Hook hook = lua_gethook(L); + if (hook != NULL && hook != hookf) /* external hook? */ + lua_pushliteral(L, "external hook"); + else { + lua_pushlightuserdata(L, (void *)&KEY_HOOK); + lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ + } + lua_pushstring(L, unmakemask(mask, buff)); + lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); + return 3; +} + + +static int debug (lua_State *L) { + for (;;) { + char buffer[250]; + fputs("lua_debug> ", stderr); + if (fgets(buffer, sizeof(buffer), stdin) == 0 || + strcmp(buffer, "cont\n") == 0) + return 0; + lua_dostring(L, buffer); + lua_settop(L, 0); /* remove eventual returns */ + } } -static int setlinehook (lua_State *L) { - sethook(L, KEY_LINEHOOK, linef, lua_setlinehook); +#define LEVELS1 12 /* size of the first part of the stack */ +#define LEVELS2 10 /* size of the second part of the stack */ + +static int errorfb (lua_State *L) { + int level = 1; /* skip level 0 (it's this function) */ + int firstpart = 1; /* still before eventual `...' */ + lua_Debug ar; + if (lua_gettop(L) == 0) + lua_pushliteral(L, ""); + else if (!lua_isstring(L, 1)) return 1; /* no string message */ + else lua_pushliteral(L, "\n"); + lua_pushliteral(L, "stack traceback:"); + while (lua_getstack(L, level++, &ar)) { + if (level > LEVELS1 && firstpart) { + /* no more than `LEVELS2' more levels? */ + if (!lua_getstack(L, level+LEVELS2, &ar)) + level--; /* keep going */ + else { + lua_pushliteral(L, "\n\t..."); /* too many levels */ + while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ + level++; + } + firstpart = 0; + continue; + } + lua_pushliteral(L, "\n\t"); + lua_getinfo(L, "Snl", &ar); + lua_pushfstring(L, "%s:", ar.short_src); + if (ar.currentline > 0) + lua_pushfstring(L, "%d:", ar.currentline); + switch (*ar.namewhat) { + case 'g': /* global */ + case 'l': /* local */ + case 'f': /* field */ + case 'm': /* method */ + lua_pushfstring(L, " in function `%s'", ar.name); + break; + default: { + 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); + } + } + lua_concat(L, lua_gettop(L)); + } + lua_concat(L, lua_gettop(L)); return 1; } -static const struct luaL_reg dblib[] = { +static const luaL_reg dblib[] = { {"getlocal", getlocal}, {"getinfo", getinfo}, - {"setcallhook", setcallhook}, - {"setlinehook", setlinehook}, - {"setlocal", setlocal} + {"gethook", gethook}, + {"getupvalue", getupvalue}, + {"sethook", sethook}, + {"setlocal", setlocal}, + {"setupvalue", setupvalue}, + {"debug", debug}, + {"traceback", errorfb}, + {NULL, NULL} }; -LUALIB_API void lua_dblibopen (lua_State *L) { - luaL_openl(L, dblib); +LUALIB_API int luaopen_debug (lua_State *L) { + luaL_openlib(L, LUA_DBLIBNAME, dblib, 0); + lua_pushliteral(L, "_TRACEBACK"); + lua_pushcfunction(L, errorfb); + lua_settable(L, LUA_GLOBALSINDEX); + return 1; } |
