2 ** $Id: ldblib.c,v 1.1 2005/04/12 17:17:26 tlopatic Exp $
3 ** Interface from Lua to its debug API
4 ** See Copyright Notice in lua.h
21 static void settabss (lua_State *L, const char *i, const char *v) {
28 static void settabsi (lua_State *L, const char *i, int v) {
30 lua_pushnumber(L, (lua_Number)v);
35 static int getinfo (lua_State *L) {
37 const char *options = luaL_optstring(L, 2, "flnSu");
38 if (lua_isnumber(L, 1)) {
39 if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) {
40 lua_pushnil(L); /* level out of range */
44 else if (lua_isfunction(L, 1)) {
45 lua_pushfstring(L, ">%s", options);
46 options = lua_tostring(L, -1);
50 return luaL_argerror(L, 1, "function or level expected");
51 if (!lua_getinfo(L, options, &ar))
52 return luaL_argerror(L, 2, "invalid option");
54 for (; *options; options++) {
57 settabss(L, "source", ar.source);
58 settabss(L, "short_src", ar.short_src);
59 settabsi(L, "linedefined", ar.linedefined);
60 settabss(L, "what", ar.what);
63 settabsi(L, "currentline", ar.currentline);
66 settabsi(L, "nups", ar.nups);
69 settabss(L, "name", ar.name);
70 settabss(L, "namewhat", ar.namewhat);
73 lua_pushliteral(L, "func");
79 return 1; /* return table */
83 static int getlocal (lua_State *L) {
86 if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */
87 return luaL_argerror(L, 1, "level out of range");
88 name = lua_getlocal(L, &ar, luaL_checkint(L, 2));
90 lua_pushstring(L, name);
101 static int setlocal (lua_State *L) {
103 if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */
104 return luaL_argerror(L, 1, "level out of range");
106 lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2)));
111 static int auxupvalue (lua_State *L, int get) {
113 int n = luaL_checkint(L, 2);
114 luaL_checktype(L, 1, LUA_TFUNCTION);
115 if (lua_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from Lua */
116 name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
117 if (name == NULL) return 0;
118 lua_pushstring(L, name);
119 lua_insert(L, -(get+1));
124 static int getupvalue (lua_State *L) {
125 return auxupvalue(L, 1);
129 static int setupvalue (lua_State *L) {
131 return auxupvalue(L, 0);
136 static const char KEY_HOOK = 'h';
139 static void hookf (lua_State *L, lua_Debug *ar) {
140 static const char *const hooknames[] =
141 {"call", "return", "line", "count", "tail return"};
142 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
143 lua_rawget(L, LUA_REGISTRYINDEX);
144 if (lua_isfunction(L, -1)) {
145 lua_pushstring(L, hooknames[(int)ar->event]);
146 if (ar->currentline >= 0)
147 lua_pushnumber(L, (lua_Number)ar->currentline);
149 lua_assert(lua_getinfo(L, "lS", ar));
153 lua_pop(L, 1); /* pop result from gettable */
157 static int makemask (const char *smask, int count) {
159 if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
160 if (strchr(smask, 'r')) mask |= LUA_MASKRET;
161 if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
162 if (count > 0) mask |= LUA_MASKCOUNT;
167 static char *unmakemask (int mask, char *smask) {
169 if (mask & LUA_MASKCALL) smask[i++] = 'c';
170 if (mask & LUA_MASKRET) smask[i++] = 'r';
171 if (mask & LUA_MASKLINE) smask[i++] = 'l';
177 static int sethook (lua_State *L) {
178 if (lua_isnoneornil(L, 1)) {
180 lua_sethook(L, NULL, 0, 0); /* turn off hooks */
183 const char *smask = luaL_checkstring(L, 2);
184 int count = luaL_optint(L, 3, 0);
185 luaL_checktype(L, 1, LUA_TFUNCTION);
186 lua_sethook(L, hookf, makemask(smask, count), count);
188 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
190 lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */
195 static int gethook (lua_State *L) {
197 int mask = lua_gethookmask(L);
198 lua_Hook hook = lua_gethook(L);
199 if (hook != NULL && hook != hookf) /* external hook? */
200 lua_pushliteral(L, "external hook");
202 lua_pushlightuserdata(L, (void *)&KEY_HOOK);
203 lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
205 lua_pushstring(L, unmakemask(mask, buff));
206 lua_pushnumber(L, (lua_Number)lua_gethookcount(L));
211 static int debug (lua_State *L) {
214 fputs("lua_debug> ", stderr);
215 if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
216 strcmp(buffer, "cont\n") == 0)
218 lua_dostring(L, buffer);
219 lua_settop(L, 0); /* remove eventual returns */
224 #define LEVELS1 12 /* size of the first part of the stack */
225 #define LEVELS2 10 /* size of the second part of the stack */
227 static int errorfb (lua_State *L) {
228 int level = 1; /* skip level 0 (it's this function) */
229 int firstpart = 1; /* still before eventual `...' */
231 if (lua_gettop(L) == 0)
232 lua_pushliteral(L, "");
233 else if (!lua_isstring(L, 1)) return 1; /* no string message */
234 else lua_pushliteral(L, "\n");
235 lua_pushliteral(L, "stack traceback:");
236 while (lua_getstack(L, level++, &ar)) {
237 if (level > LEVELS1 && firstpart) {
238 /* no more than `LEVELS2' more levels? */
239 if (!lua_getstack(L, level+LEVELS2, &ar))
240 level--; /* keep going */
242 lua_pushliteral(L, "\n\t..."); /* too many levels */
243 while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */
249 lua_pushliteral(L, "\n\t");
250 lua_getinfo(L, "Snl", &ar);
251 lua_pushfstring(L, "%s:", ar.short_src);
252 if (ar.currentline > 0)
253 lua_pushfstring(L, "%d:", ar.currentline);
254 switch (*ar.namewhat) {
255 case 'g': /* global */
256 case 'l': /* local */
257 case 'f': /* field */
258 case 'm': /* method */
259 lua_pushfstring(L, " in function `%s'", ar.name);
262 if (*ar.what == 'm') /* main? */
263 lua_pushfstring(L, " in main chunk");
264 else if (*ar.what == 'C' || *ar.what == 't')
265 lua_pushliteral(L, " ?"); /* C function or tail call */
267 lua_pushfstring(L, " in function <%s:%d>",
268 ar.short_src, ar.linedefined);
271 lua_concat(L, lua_gettop(L));
273 lua_concat(L, lua_gettop(L));
278 static const luaL_reg dblib[] = {
279 {"getlocal", getlocal},
280 {"getinfo", getinfo},
281 {"gethook", gethook},
282 {"getupvalue", getupvalue},
283 {"sethook", sethook},
284 {"setlocal", setlocal},
285 {"setupvalue", setupvalue},
287 {"traceback", errorfb},
292 LUALIB_API int luaopen_debug (lua_State *L) {
293 luaL_openlib(L, LUA_DBLIBNAME, dblib, 0);
294 lua_pushliteral(L, "_TRACEBACK");
295 lua_pushcfunction(L, errorfb);
296 lua_settable(L, LUA_GLOBALSINDEX);