Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5205 | clevermous | 1 | /* |
2 | ** $Id: ldblib.c,v 1.131 2011/10/24 14:54:05 roberto Exp $ |
||
3 | ** Interface from Lua to its debug API |
||
4 | ** See Copyright Notice in lua.h |
||
5 | */ |
||
6 | |||
7 | |||
8 | #include |
||
9 | #include |
||
10 | #include |
||
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 | #define HOOKKEY "_HKEY" |
||
22 | |||
23 | |||
24 | |||
25 | static int db_getregistry (lua_State *L) { |
||
26 | lua_pushvalue(L, LUA_REGISTRYINDEX); |
||
27 | return 1; |
||
28 | } |
||
29 | |||
30 | |||
31 | static int db_getmetatable (lua_State *L) { |
||
32 | luaL_checkany(L, 1); |
||
33 | if (!lua_getmetatable(L, 1)) { |
||
34 | lua_pushnil(L); /* no metatable */ |
||
35 | } |
||
36 | return 1; |
||
37 | } |
||
38 | |||
39 | |||
40 | static int db_setmetatable (lua_State *L) { |
||
41 | int t = lua_type(L, 2); |
||
42 | luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, |
||
43 | "nil or table expected"); |
||
44 | lua_settop(L, 2); |
||
45 | lua_setmetatable(L, 1); |
||
46 | return 1; /* return 1st argument */ |
||
47 | } |
||
48 | |||
49 | |||
50 | static int db_getuservalue (lua_State *L) { |
||
51 | if (lua_type(L, 1) != LUA_TUSERDATA) |
||
52 | lua_pushnil(L); |
||
53 | else |
||
54 | lua_getuservalue(L, 1); |
||
55 | return 1; |
||
56 | } |
||
57 | |||
58 | |||
59 | static int db_setuservalue (lua_State *L) { |
||
60 | if (lua_type(L, 1) == LUA_TLIGHTUSERDATA) |
||
61 | luaL_argerror(L, 1, "full userdata expected, got light userdata"); |
||
62 | luaL_checktype(L, 1, LUA_TUSERDATA); |
||
63 | if (!lua_isnoneornil(L, 2)) |
||
64 | luaL_checktype(L, 2, LUA_TTABLE); |
||
65 | lua_settop(L, 2); |
||
66 | lua_setuservalue(L, 1); |
||
67 | return 1; |
||
68 | } |
||
69 | |||
70 | |||
71 | static void settabss (lua_State *L, const char *i, const char *v) { |
||
72 | lua_pushstring(L, v); |
||
73 | lua_setfield(L, -2, i); |
||
74 | } |
||
75 | |||
76 | |||
77 | static void settabsi (lua_State *L, const char *i, int v) { |
||
78 | lua_pushinteger(L, v); |
||
79 | lua_setfield(L, -2, i); |
||
80 | } |
||
81 | |||
82 | |||
83 | static void settabsb (lua_State *L, const char *i, int v) { |
||
84 | lua_pushboolean(L, v); |
||
85 | lua_setfield(L, -2, i); |
||
86 | } |
||
87 | |||
88 | |||
89 | static lua_State *getthread (lua_State *L, int *arg) { |
||
90 | if (lua_isthread(L, 1)) { |
||
91 | *arg = 1; |
||
92 | return lua_tothread(L, 1); |
||
93 | } |
||
94 | else { |
||
95 | *arg = 0; |
||
96 | return L; |
||
97 | } |
||
98 | } |
||
99 | |||
100 | |||
101 | static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { |
||
102 | if (L == L1) { |
||
103 | lua_pushvalue(L, -2); |
||
104 | lua_remove(L, -3); |
||
105 | } |
||
106 | else |
||
107 | lua_xmove(L1, L, 1); |
||
108 | lua_setfield(L, -2, fname); |
||
109 | } |
||
110 | |||
111 | |||
112 | static int db_getinfo (lua_State *L) { |
||
113 | lua_Debug ar; |
||
114 | int arg; |
||
115 | lua_State *L1 = getthread(L, &arg); |
||
116 | const char *options = luaL_optstring(L, arg+2, "flnStu"); |
||
117 | if (lua_isnumber(L, arg+1)) { |
||
118 | if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { |
||
119 | lua_pushnil(L); /* level out of range */ |
||
120 | return 1; |
||
121 | } |
||
122 | } |
||
123 | else if (lua_isfunction(L, arg+1)) { |
||
124 | lua_pushfstring(L, ">%s", options); |
||
125 | options = lua_tostring(L, -1); |
||
126 | lua_pushvalue(L, arg+1); |
||
127 | lua_xmove(L, L1, 1); |
||
128 | } |
||
129 | else |
||
130 | return luaL_argerror(L, arg+1, "function or level expected"); |
||
131 | if (!lua_getinfo(L1, options, &ar)) |
||
132 | return luaL_argerror(L, arg+2, "invalid option"); |
||
133 | lua_createtable(L, 0, 2); |
||
134 | if (strchr(options, 'S')) { |
||
135 | settabss(L, "source", ar.source); |
||
136 | settabss(L, "short_src", ar.short_src); |
||
137 | settabsi(L, "linedefined", ar.linedefined); |
||
138 | settabsi(L, "lastlinedefined", ar.lastlinedefined); |
||
139 | settabss(L, "what", ar.what); |
||
140 | } |
||
141 | if (strchr(options, 'l')) |
||
142 | settabsi(L, "currentline", ar.currentline); |
||
143 | if (strchr(options, 'u')) { |
||
144 | settabsi(L, "nups", ar.nups); |
||
145 | settabsi(L, "nparams", ar.nparams); |
||
146 | settabsb(L, "isvararg", ar.isvararg); |
||
147 | } |
||
148 | if (strchr(options, 'n')) { |
||
149 | settabss(L, "name", ar.name); |
||
150 | settabss(L, "namewhat", ar.namewhat); |
||
151 | } |
||
152 | if (strchr(options, 't')) |
||
153 | settabsb(L, "istailcall", ar.istailcall); |
||
154 | if (strchr(options, 'L')) |
||
155 | treatstackoption(L, L1, "activelines"); |
||
156 | if (strchr(options, 'f')) |
||
157 | treatstackoption(L, L1, "func"); |
||
158 | return 1; /* return table */ |
||
159 | } |
||
160 | |||
161 | |||
162 | static int db_getlocal (lua_State *L) { |
||
163 | int arg; |
||
164 | lua_State *L1 = getthread(L, &arg); |
||
165 | lua_Debug ar; |
||
166 | const char *name; |
||
167 | int nvar = luaL_checkint(L, arg+2); /* local-variable index */ |
||
168 | if (lua_isfunction(L, arg + 1)) { /* function argument? */ |
||
169 | lua_pushvalue(L, arg + 1); /* push function */ |
||
170 | lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ |
||
171 | return 1; |
||
172 | } |
||
173 | else { /* stack-level argument */ |
||
174 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
||
175 | return luaL_argerror(L, arg+1, "level out of range"); |
||
176 | name = lua_getlocal(L1, &ar, nvar); |
||
177 | if (name) { |
||
178 | lua_xmove(L1, L, 1); /* push local value */ |
||
179 | lua_pushstring(L, name); /* push name */ |
||
180 | lua_pushvalue(L, -2); /* re-order */ |
||
181 | return 2; |
||
182 | } |
||
183 | else { |
||
184 | lua_pushnil(L); /* no name (nor value) */ |
||
185 | return 1; |
||
186 | } |
||
187 | } |
||
188 | } |
||
189 | |||
190 | |||
191 | static int db_setlocal (lua_State *L) { |
||
192 | int arg; |
||
193 | lua_State *L1 = getthread(L, &arg); |
||
194 | lua_Debug ar; |
||
195 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
||
196 | return luaL_argerror(L, arg+1, "level out of range"); |
||
197 | luaL_checkany(L, arg+3); |
||
198 | lua_settop(L, arg+3); |
||
199 | lua_xmove(L, L1, 1); |
||
200 | lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); |
||
201 | return 1; |
||
202 | } |
||
203 | |||
204 | |||
205 | static int auxupvalue (lua_State *L, int get) { |
||
206 | const char *name; |
||
207 | int n = luaL_checkint(L, 2); |
||
208 | luaL_checktype(L, 1, LUA_TFUNCTION); |
||
209 | name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); |
||
210 | if (name == NULL) return 0; |
||
211 | lua_pushstring(L, name); |
||
212 | lua_insert(L, -(get+1)); |
||
213 | return get + 1; |
||
214 | } |
||
215 | |||
216 | |||
217 | static int db_getupvalue (lua_State *L) { |
||
218 | return auxupvalue(L, 1); |
||
219 | } |
||
220 | |||
221 | |||
222 | static int db_setupvalue (lua_State *L) { |
||
223 | luaL_checkany(L, 3); |
||
224 | return auxupvalue(L, 0); |
||
225 | } |
||
226 | |||
227 | |||
228 | static int checkupval (lua_State *L, int argf, int argnup) { |
||
229 | lua_Debug ar; |
||
230 | int nup = luaL_checkint(L, argnup); |
||
231 | luaL_checktype(L, argf, LUA_TFUNCTION); |
||
232 | lua_pushvalue(L, argf); |
||
233 | lua_getinfo(L, ">u", &ar); |
||
234 | luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); |
||
235 | return nup; |
||
236 | } |
||
237 | |||
238 | |||
239 | static int db_upvalueid (lua_State *L) { |
||
240 | int n = checkupval(L, 1, 2); |
||
241 | lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); |
||
242 | return 1; |
||
243 | } |
||
244 | |||
245 | |||
246 | static int db_upvaluejoin (lua_State *L) { |
||
247 | int n1 = checkupval(L, 1, 2); |
||
248 | int n2 = checkupval(L, 3, 4); |
||
249 | luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); |
||
250 | luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); |
||
251 | lua_upvaluejoin(L, 1, n1, 3, n2); |
||
252 | return 0; |
||
253 | } |
||
254 | |||
255 | |||
256 | #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY); |
||
257 | |||
258 | |||
259 | static void hookf (lua_State *L, lua_Debug *ar) { |
||
260 | static const char *const hooknames[] = |
||
261 | {"call", "return", "line", "count", "tail call"}; |
||
262 | gethooktable(L); |
||
263 | lua_rawgetp(L, -1, L); |
||
264 | if (lua_isfunction(L, -1)) { |
||
265 | lua_pushstring(L, hooknames[(int)ar->event]); |
||
266 | if (ar->currentline >= 0) |
||
267 | lua_pushinteger(L, ar->currentline); |
||
268 | else lua_pushnil(L); |
||
269 | lua_assert(lua_getinfo(L, "lS", ar)); |
||
270 | lua_call(L, 2, 0); |
||
271 | } |
||
272 | } |
||
273 | |||
274 | |||
275 | static int makemask (const char *smask, int count) { |
||
276 | int mask = 0; |
||
277 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; |
||
278 | if (strchr(smask, 'r')) mask |= LUA_MASKRET; |
||
279 | if (strchr(smask, 'l')) mask |= LUA_MASKLINE; |
||
280 | if (count > 0) mask |= LUA_MASKCOUNT; |
||
281 | return mask; |
||
282 | } |
||
283 | |||
284 | |||
285 | static char *unmakemask (int mask, char *smask) { |
||
286 | int i = 0; |
||
287 | if (mask & LUA_MASKCALL) smask[i++] = 'c'; |
||
288 | if (mask & LUA_MASKRET) smask[i++] = 'r'; |
||
289 | if (mask & LUA_MASKLINE) smask[i++] = 'l'; |
||
290 | smask[i] = '\0'; |
||
291 | return smask; |
||
292 | } |
||
293 | |||
294 | |||
295 | static int db_sethook (lua_State *L) { |
||
296 | int arg, mask, count; |
||
297 | lua_Hook func; |
||
298 | lua_State *L1 = getthread(L, &arg); |
||
299 | if (lua_isnoneornil(L, arg+1)) { |
||
300 | lua_settop(L, arg+1); |
||
301 | func = NULL; mask = 0; count = 0; /* turn off hooks */ |
||
302 | } |
||
303 | else { |
||
304 | const char *smask = luaL_checkstring(L, arg+2); |
||
305 | luaL_checktype(L, arg+1, LUA_TFUNCTION); |
||
306 | count = luaL_optint(L, arg+3, 0); |
||
307 | func = hookf; mask = makemask(smask, count); |
||
308 | } |
||
309 | gethooktable(L); |
||
310 | lua_pushvalue(L, arg+1); |
||
311 | lua_rawsetp(L, -2, L1); /* set new hook */ |
||
312 | lua_pop(L, 1); /* remove hook table */ |
||
313 | lua_sethook(L1, func, mask, count); /* set hooks */ |
||
314 | return 0; |
||
315 | } |
||
316 | |||
317 | |||
318 | static int db_gethook (lua_State *L) { |
||
319 | int arg; |
||
320 | lua_State *L1 = getthread(L, &arg); |
||
321 | char buff[5]; |
||
322 | int mask = lua_gethookmask(L1); |
||
323 | lua_Hook hook = lua_gethook(L1); |
||
324 | if (hook != NULL && hook != hookf) /* external hook? */ |
||
325 | lua_pushliteral(L, "external hook"); |
||
326 | else { |
||
327 | gethooktable(L); |
||
328 | lua_rawgetp(L, -1, L1); /* get hook */ |
||
329 | lua_remove(L, -2); /* remove hook table */ |
||
330 | } |
||
331 | lua_pushstring(L, unmakemask(mask, buff)); |
||
332 | lua_pushinteger(L, lua_gethookcount(L1)); |
||
333 | return 3; |
||
334 | } |
||
335 | |||
336 | |||
337 | static int db_debug (lua_State *L) { |
||
338 | for (;;) { |
||
339 | char buffer[250]; |
||
340 | luai_writestringerror("%s", "lua_debug> "); |
||
341 | if (fgets(buffer, sizeof(buffer), stdin) == 0 || |
||
342 | strcmp(buffer, "cont\n") == 0) |
||
343 | return 0; |
||
344 | if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || |
||
345 | lua_pcall(L, 0, 0, 0)) |
||
346 | luai_writestringerror("%s\n", lua_tostring(L, -1)); |
||
347 | lua_settop(L, 0); /* remove eventual returns */ |
||
348 | } |
||
349 | } |
||
350 | |||
351 | |||
352 | static int db_traceback (lua_State *L) { |
||
353 | int arg; |
||
354 | lua_State *L1 = getthread(L, &arg); |
||
355 | const char *msg = lua_tostring(L, arg + 1); |
||
356 | if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ |
||
357 | lua_pushvalue(L, arg + 1); /* return it untouched */ |
||
358 | else { |
||
359 | int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0); |
||
360 | luaL_traceback(L, L1, msg, level); |
||
361 | } |
||
362 | return 1; |
||
363 | } |
||
364 | |||
365 | |||
366 | static const luaL_Reg dblib[] = { |
||
367 | {"debug", db_debug}, |
||
368 | {"getuservalue", db_getuservalue}, |
||
369 | {"gethook", db_gethook}, |
||
370 | {"getinfo", db_getinfo}, |
||
371 | {"getlocal", db_getlocal}, |
||
372 | {"getregistry", db_getregistry}, |
||
373 | {"getmetatable", db_getmetatable}, |
||
374 | {"getupvalue", db_getupvalue}, |
||
375 | {"upvaluejoin", db_upvaluejoin}, |
||
376 | {"upvalueid", db_upvalueid}, |
||
377 | {"setuservalue", db_setuservalue}, |
||
378 | {"sethook", db_sethook}, |
||
379 | {"setlocal", db_setlocal}, |
||
380 | {"setmetatable", db_setmetatable}, |
||
381 | {"setupvalue", db_setupvalue}, |
||
382 | {"traceback", db_traceback}, |
||
383 | {NULL, NULL} |
||
384 | }; |
||
385 | |||
386 | |||
387 | LUAMOD_API int luaopen_debug (lua_State *L) { |
||
388 | luaL_newlib(L, dblib); |
||
389 | return 1; |
||
390 | }=>=> |
||
391 |