Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/lua/ldblib.c @ 1809

Last change on this file since 1809 was 1806, checked in by rgrieder, 16 years ago

added single 5.1.3 directory for lua since CEGUILua 0.5 can also build against lua 5.1

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
1/*
2** $Id: ldblib.c,v 1.104.1.3 2008/01/21 13:11:21 roberto Exp $
3** Interface from Lua to its debug API
4** See Copyright Notice in lua.h
5*/
6
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#define ldblib_c
13#define LUA_LIB
14
15#include "lua.h"
16
17#include "lauxlib.h"
18#include "lualib.h"
19
20
21
22static int db_getregistry (lua_State *L) {
23  lua_pushvalue(L, LUA_REGISTRYINDEX);
24  return 1;
25}
26
27
28static int db_getmetatable (lua_State *L) {
29  luaL_checkany(L, 1);
30  if (!lua_getmetatable(L, 1)) {
31    lua_pushnil(L);  /* no metatable */
32  }
33  return 1;
34}
35
36
37static int db_setmetatable (lua_State *L) {
38  int t = lua_type(L, 2);
39  luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
40                    "nil or table expected");
41  lua_settop(L, 2);
42  lua_pushboolean(L, lua_setmetatable(L, 1));
43  return 1;
44}
45
46
47static int db_getfenv (lua_State *L) {
48  lua_getfenv(L, 1);
49  return 1;
50}
51
52
53static int db_setfenv (lua_State *L) {
54  luaL_checktype(L, 2, LUA_TTABLE);
55  lua_settop(L, 2);
56  if (lua_setfenv(L, 1) == 0)
57    luaL_error(L, LUA_QL("setfenv")
58                  " cannot change environment of given object");
59  return 1;
60}
61
62
63static void settabss (lua_State *L, const char *i, const char *v) {
64  lua_pushstring(L, v);
65  lua_setfield(L, -2, i);
66}
67
68
69static void settabsi (lua_State *L, const char *i, int v) {
70  lua_pushinteger(L, v);
71  lua_setfield(L, -2, i);
72}
73
74
75static lua_State *getthread (lua_State *L, int *arg) {
76  if (lua_isthread(L, 1)) {
77    *arg = 1;
78    return lua_tothread(L, 1);
79  }
80  else {
81    *arg = 0;
82    return L;
83  }
84}
85
86
87static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
88  if (L == L1) {
89    lua_pushvalue(L, -2);
90    lua_remove(L, -3);
91  }
92  else
93    lua_xmove(L1, L, 1);
94  lua_setfield(L, -2, fname);
95}
96
97
98static int db_getinfo (lua_State *L) {
99  lua_Debug ar;
100  int arg;
101  lua_State *L1 = getthread(L, &arg);
102  const char *options = luaL_optstring(L, arg+2, "flnSu");
103  if (lua_isnumber(L, arg+1)) {
104    if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
105      lua_pushnil(L);  /* level out of range */
106      return 1;
107    }
108  }
109  else if (lua_isfunction(L, arg+1)) {
110    lua_pushfstring(L, ">%s", options);
111    options = lua_tostring(L, -1);
112    lua_pushvalue(L, arg+1);
113    lua_xmove(L, L1, 1);
114  }
115  else
116    return luaL_argerror(L, arg+1, "function or level expected");
117  if (!lua_getinfo(L1, options, &ar))
118    return luaL_argerror(L, arg+2, "invalid option");
119  lua_createtable(L, 0, 2);
120  if (strchr(options, 'S')) {
121    settabss(L, "source", ar.source);
122    settabss(L, "short_src", ar.short_src);
123    settabsi(L, "linedefined", ar.linedefined);
124    settabsi(L, "lastlinedefined", ar.lastlinedefined);
125    settabss(L, "what", ar.what);
126  }
127  if (strchr(options, 'l'))
128    settabsi(L, "currentline", ar.currentline);
129  if (strchr(options, 'u'))
130    settabsi(L, "nups", ar.nups);
131  if (strchr(options, 'n')) {
132    settabss(L, "name", ar.name);
133    settabss(L, "namewhat", ar.namewhat);
134  }
135  if (strchr(options, 'L'))
136    treatstackoption(L, L1, "activelines");
137  if (strchr(options, 'f'))
138    treatstackoption(L, L1, "func");
139  return 1;  /* return table */
140}
141   
142
143static int db_getlocal (lua_State *L) {
144  int arg;
145  lua_State *L1 = getthread(L, &arg);
146  lua_Debug ar;
147  const char *name;
148  if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
149    return luaL_argerror(L, arg+1, "level out of range");
150  name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2));
151  if (name) {
152    lua_xmove(L1, L, 1);
153    lua_pushstring(L, name);
154    lua_pushvalue(L, -2);
155    return 2;
156  }
157  else {
158    lua_pushnil(L);
159    return 1;
160  }
161}
162
163
164static int db_setlocal (lua_State *L) {
165  int arg;
166  lua_State *L1 = getthread(L, &arg);
167  lua_Debug ar;
168  if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar))  /* out of range? */
169    return luaL_argerror(L, arg+1, "level out of range");
170  luaL_checkany(L, arg+3);
171  lua_settop(L, arg+3);
172  lua_xmove(L, L1, 1);
173  lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
174  return 1;
175}
176
177
178static int auxupvalue (lua_State *L, int get) {
179  const char *name;
180  int n = luaL_checkint(L, 2);
181  luaL_checktype(L, 1, LUA_TFUNCTION);
182  if (lua_iscfunction(L, 1)) return 0;  /* cannot touch C upvalues from Lua */
183  name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
184  if (name == NULL) return 0;
185  lua_pushstring(L, name);
186  lua_insert(L, -(get+1));
187  return get + 1;
188}
189
190
191static int db_getupvalue (lua_State *L) {
192  return auxupvalue(L, 1);
193}
194
195
196static int db_setupvalue (lua_State *L) {
197  luaL_checkany(L, 3);
198  return auxupvalue(L, 0);
199}
200
201
202
203static const char KEY_HOOK = 'h';
204
205
206static void hookf (lua_State *L, lua_Debug *ar) {
207  static const char *const hooknames[] =
208    {"call", "return", "line", "count", "tail return"};
209  lua_pushlightuserdata(L, (void *)&KEY_HOOK);
210  lua_rawget(L, LUA_REGISTRYINDEX);
211  lua_pushlightuserdata(L, L);
212  lua_rawget(L, -2);
213  if (lua_isfunction(L, -1)) {
214    lua_pushstring(L, hooknames[(int)ar->event]);
215    if (ar->currentline >= 0)
216      lua_pushinteger(L, ar->currentline);
217    else lua_pushnil(L);
218    lua_assert(lua_getinfo(L, "lS", ar));
219    lua_call(L, 2, 0);
220  }
221}
222
223
224static int makemask (const char *smask, int count) {
225  int mask = 0;
226  if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
227  if (strchr(smask, 'r')) mask |= LUA_MASKRET;
228  if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
229  if (count > 0) mask |= LUA_MASKCOUNT;
230  return mask;
231}
232
233
234static char *unmakemask (int mask, char *smask) {
235  int i = 0;
236  if (mask & LUA_MASKCALL) smask[i++] = 'c';
237  if (mask & LUA_MASKRET) smask[i++] = 'r';
238  if (mask & LUA_MASKLINE) smask[i++] = 'l';
239  smask[i] = '\0';
240  return smask;
241}
242
243
244static void gethooktable (lua_State *L) {
245  lua_pushlightuserdata(L, (void *)&KEY_HOOK);
246  lua_rawget(L, LUA_REGISTRYINDEX);
247  if (!lua_istable(L, -1)) {
248    lua_pop(L, 1);
249    lua_createtable(L, 0, 1);
250    lua_pushlightuserdata(L, (void *)&KEY_HOOK);
251    lua_pushvalue(L, -2);
252    lua_rawset(L, LUA_REGISTRYINDEX);
253  }
254}
255
256
257static int db_sethook (lua_State *L) {
258  int arg, mask, count;
259  lua_Hook func;
260  lua_State *L1 = getthread(L, &arg);
261  if (lua_isnoneornil(L, arg+1)) {
262    lua_settop(L, arg+1);
263    func = NULL; mask = 0; count = 0;  /* turn off hooks */
264  }
265  else {
266    const char *smask = luaL_checkstring(L, arg+2);
267    luaL_checktype(L, arg+1, LUA_TFUNCTION);
268    count = luaL_optint(L, arg+3, 0);
269    func = hookf; mask = makemask(smask, count);
270  }
271  gethooktable(L);
272  lua_pushlightuserdata(L, L1);
273  lua_pushvalue(L, arg+1);
274  lua_rawset(L, -3);  /* set new hook */
275  lua_pop(L, 1);  /* remove hook table */
276  lua_sethook(L1, func, mask, count);  /* set hooks */
277  return 0;
278}
279
280
281static int db_gethook (lua_State *L) {
282  int arg;
283  lua_State *L1 = getthread(L, &arg);
284  char buff[5];
285  int mask = lua_gethookmask(L1);
286  lua_Hook hook = lua_gethook(L1);
287  if (hook != NULL && hook != hookf)  /* external hook? */
288    lua_pushliteral(L, "external hook");
289  else {
290    gethooktable(L);
291    lua_pushlightuserdata(L, L1);
292    lua_rawget(L, -2);   /* get hook */
293    lua_remove(L, -2);  /* remove hook table */
294  }
295  lua_pushstring(L, unmakemask(mask, buff));
296  lua_pushinteger(L, lua_gethookcount(L1));
297  return 3;
298}
299
300
301static int db_debug (lua_State *L) {
302  for (;;) {
303    char buffer[250];
304    fputs("lua_debug> ", stderr);
305    if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
306        strcmp(buffer, "cont\n") == 0)
307      return 0;
308    if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
309        lua_pcall(L, 0, 0, 0)) {
310      fputs(lua_tostring(L, -1), stderr);
311      fputs("\n", stderr);
312    }
313    lua_settop(L, 0);  /* remove eventual returns */
314  }
315}
316
317
318#define LEVELS1 12      /* size of the first part of the stack */
319#define LEVELS2 10      /* size of the second part of the stack */
320
321static int db_errorfb (lua_State *L) {
322  int level;
323  int firstpart = 1;  /* still before eventual `...' */
324  int arg;
325  lua_State *L1 = getthread(L, &arg);
326  lua_Debug ar;
327  if (lua_isnumber(L, arg+2)) {
328    level = (int)lua_tointeger(L, arg+2);
329    lua_pop(L, 1);
330  }
331  else
332    level = (L == L1) ? 1 : 0;  /* level 0 may be this own function */
333  if (lua_gettop(L) == arg)
334    lua_pushliteral(L, "");
335  else if (!lua_isstring(L, arg+1)) return 1;  /* message is not a string */
336  else lua_pushliteral(L, "\n");
337  lua_pushliteral(L, "stack traceback:");
338  while (lua_getstack(L1, level++, &ar)) {
339    if (level > LEVELS1 && firstpart) {
340      /* no more than `LEVELS2' more levels? */
341      if (!lua_getstack(L1, level+LEVELS2, &ar))
342        level--;  /* keep going */
343      else {
344        lua_pushliteral(L, "\n\t...");  /* too many levels */
345        while (lua_getstack(L1, level+LEVELS2, &ar))  /* find last levels */
346          level++;
347      }
348      firstpart = 0;
349      continue;
350    }
351    lua_pushliteral(L, "\n\t");
352    lua_getinfo(L1, "Snl", &ar);
353    lua_pushfstring(L, "%s:", ar.short_src);
354    if (ar.currentline > 0)
355      lua_pushfstring(L, "%d:", ar.currentline);
356    if (*ar.namewhat != '\0')  /* is there a name? */
357        lua_pushfstring(L, " in function " LUA_QS, ar.name);
358    else {
359      if (*ar.what == 'm')  /* main? */
360        lua_pushfstring(L, " in main chunk");
361      else if (*ar.what == 'C' || *ar.what == 't')
362        lua_pushliteral(L, " ?");  /* C function or tail call */
363      else
364        lua_pushfstring(L, " in function <%s:%d>",
365                           ar.short_src, ar.linedefined);
366    }
367    lua_concat(L, lua_gettop(L) - arg);
368  }
369  lua_concat(L, lua_gettop(L) - arg);
370  return 1;
371}
372
373
374static const luaL_Reg dblib[] = {
375  {"debug", db_debug},
376  {"getfenv", db_getfenv},
377  {"gethook", db_gethook},
378  {"getinfo", db_getinfo},
379  {"getlocal", db_getlocal},
380  {"getregistry", db_getregistry},
381  {"getmetatable", db_getmetatable},
382  {"getupvalue", db_getupvalue},
383  {"setfenv", db_setfenv},
384  {"sethook", db_sethook},
385  {"setlocal", db_setlocal},
386  {"setmetatable", db_setmetatable},
387  {"setupvalue", db_setupvalue},
388  {"traceback", db_errorfb},
389  {NULL, NULL}
390};
391
392
393LUALIB_API int luaopen_debug (lua_State *L) {
394  luaL_register(L, LUA_DBLIBNAME, dblib);
395  return 1;
396}
397
Note: See TracBrowser for help on using the repository browser.