/* ** $Id: ldblib.c,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ ** Interface from Lua to its debug API ** See Copyright Notice in lua.h */ #include #include #include #include "lua.h" #include "lauxlib.h" #include "luadebug.h" #include "lualib.h" static void settabss (lua_State *L, const char *i, const char *v) { lua_pushstring(L, v); lua_setstr(L, -2, i); } static void settabsi (lua_State *L, const char *i, int v) { lua_pushnumber(L, v); lua_setstr(L, -2, i); } static int getinfo (lua_State *L) { lua_Debug ar; const char *options = luaL_opt_string(L, 2, "flnSu"); char buff[20]; if (lua_isnumber(L, 1)) { 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_pushvalue(L, 1); sprintf(buff, ">%.10s", options); options = buff; } else luaL_argerror(L, 1, "function or level expected"); if (!lua_getinfo(L, options, &ar)) 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); settabsi(L, "linedefined", ar.linedefined); settabss(L, "what", ar.what); break; case 'l': settabsi(L, "currentline", ar.currentline); break; case 'u': settabsi(L, "nups", ar.nups); break; case 'n': settabss(L, "name", ar.name); settabss(L, "namewhat", ar.namewhat); break; case 'f': lua_pushvalue(L, -2); lua_setstr(L, -2, "func"); break; } } return 1; /* return table */ } 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 (name) { lua_pushstring(L, name); lua_pushvalue(L, -2); return 2; } else { lua_pushnil(L); return 1; } } 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"); luaL_check_any(L, 3); lua_pushstring(L, lua_setlocal(L, &ar, luaL_check_int(L, 2))); return 1; } #define KEY_CALLHOOK "luadblibCallhook" #define KEY_LINEHOOK "luadblibLinehook" static void hookf (lua_State *L, const char *key) { lua_getstr(L, LUA_REGISTRYINDEX, key); if (lua_isfunction(L, -1)) { lua_pushvalue(L, -2); /* original argument (below function) */ lua_rawcall(L, 1, 0); } else lua_pop(L, 1); /* pop result from gettable */ } static void callf (lua_State *L, lua_Debug *ar) { lua_pushstring(L, ar->event); hookf(L, KEY_CALLHOOK); } static void linef (lua_State *L, lua_Debug *ar) { lua_pushnumber(L, ar->currentline); hookf(L, KEY_LINEHOOK); } static void sethook (lua_State *L, const char *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_getstr(L, LUA_REGISTRYINDEX, key); /* get old value */ lua_pushvalue(L, 1); lua_setstr(L, LUA_REGISTRYINDEX, key); /* set new value */ } static int setcallhook (lua_State *L) { sethook(L, KEY_CALLHOOK, callf, lua_setcallhook); return 1; } static int setlinehook (lua_State *L) { sethook(L, KEY_LINEHOOK, linef, lua_setlinehook); return 1; } static const luaL_reg dblib[] = { {"getlocal", getlocal}, {"getinfo", getinfo}, {"setcallhook", setcallhook}, {"setlinehook", setlinehook}, {"setlocal", setlocal} }; LUALIB_API int lua_dblibopen (lua_State *L) { luaL_openl(L, dblib); return 0; }