diff options
Diffstat (limited to 'ldblib.c')
-rw-r--r-- | ldblib.c | 155 |
1 files changed, 94 insertions, 61 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: ldblib.c,v 1.137 2014/03/12 20:57:40 roberto Exp roberto $ | 2 | ** $Id: ldblib.c,v 1.138 2014/04/30 18:59:15 roberto Exp roberto $ |
3 | ** Interface from Lua to its debug API | 3 | ** Interface from Lua to its debug API |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -28,7 +28,7 @@ static int db_Csize (lua_State *L) { | |||
28 | } sizes[] = { | 28 | } sizes[] = { |
29 | {'I', sizeof(lua_Integer)}, | 29 | {'I', sizeof(lua_Integer)}, |
30 | {'F', sizeof(lua_Number)}, | 30 | {'F', sizeof(lua_Number)}, |
31 | {'b', CHAR_BIT}, | 31 | {'b', CHAR_BIT}, /* here is number of bits (not bytes) */ |
32 | {'h', sizeof(short)}, | 32 | {'h', sizeof(short)}, |
33 | {'i', sizeof(int)}, | 33 | {'i', sizeof(int)}, |
34 | {'l', sizeof(long)}, | 34 | {'l', sizeof(long)}, |
@@ -91,24 +91,12 @@ static int db_setuservalue (lua_State *L) { | |||
91 | } | 91 | } |
92 | 92 | ||
93 | 93 | ||
94 | static void settabss (lua_State *L, const char *i, const char *v) { | 94 | /* |
95 | lua_pushstring(L, v); | 95 | ** Auxiliary function used by several library functions: check for |
96 | lua_setfield(L, -2, i); | 96 | ** an optional thread as function's first argument and set 'arg' with |
97 | } | 97 | ** 1 if this argument is present (so that functions can skip it to |
98 | 98 | ** access their other arguments) | |
99 | 99 | */ | |
100 | static void settabsi (lua_State *L, const char *i, int v) { | ||
101 | lua_pushinteger(L, v); | ||
102 | lua_setfield(L, -2, i); | ||
103 | } | ||
104 | |||
105 | |||
106 | static void settabsb (lua_State *L, const char *i, int v) { | ||
107 | lua_pushboolean(L, v); | ||
108 | lua_setfield(L, -2, i); | ||
109 | } | ||
110 | |||
111 | |||
112 | static lua_State *getthread (lua_State *L, int *arg) { | 100 | static lua_State *getthread (lua_State *L, int *arg) { |
113 | if (lua_isthread(L, 1)) { | 101 | if (lua_isthread(L, 1)) { |
114 | *arg = 1; | 102 | *arg = 1; |
@@ -116,44 +104,70 @@ static lua_State *getthread (lua_State *L, int *arg) { | |||
116 | } | 104 | } |
117 | else { | 105 | else { |
118 | *arg = 0; | 106 | *arg = 0; |
119 | return L; | 107 | return L; /* function will operate over current thread */ |
120 | } | 108 | } |
121 | } | 109 | } |
122 | 110 | ||
123 | 111 | ||
112 | /* | ||
113 | ** Variations of 'lua_settable', used by 'db_getinfo' to put results | ||
114 | ** from 'lua_getinfo' into result table. Key is always a string; | ||
115 | ** value can be a string, an int, or a boolean. | ||
116 | */ | ||
117 | static void settabss (lua_State *L, const char *k, const char *v) { | ||
118 | lua_pushstring(L, v); | ||
119 | lua_setfield(L, -2, k); | ||
120 | } | ||
121 | |||
122 | static void settabsi (lua_State *L, const char *k, int v) { | ||
123 | lua_pushinteger(L, v); | ||
124 | lua_setfield(L, -2, k); | ||
125 | } | ||
126 | |||
127 | static void settabsb (lua_State *L, const char *k, int v) { | ||
128 | lua_pushboolean(L, v); | ||
129 | lua_setfield(L, -2, k); | ||
130 | } | ||
131 | |||
132 | |||
133 | /* | ||
134 | ** In function 'db_getinfo', the call to 'lua_getinfo' may push | ||
135 | ** results on the stack; later it creates the result table to put | ||
136 | ** these objects. Function 'treatstackoption' puts the result from | ||
137 | ** 'lua_getinfo' on top of the result table so that it can call | ||
138 | ** 'lua_setfield'. | ||
139 | */ | ||
124 | static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { | 140 | static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { |
125 | if (L == L1) { | 141 | if (L == L1) |
126 | lua_pushvalue(L, -2); | 142 | lua_rotate(L, -2, 1); /* exchange object and table */ |
127 | lua_remove(L, -3); | ||
128 | } | ||
129 | else | 143 | else |
130 | lua_xmove(L1, L, 1); | 144 | lua_xmove(L1, L, 1); /* move object to the "main" stack */ |
131 | lua_setfield(L, -2, fname); | 145 | lua_setfield(L, -2, fname); /* put object into table */ |
132 | } | 146 | } |
133 | 147 | ||
134 | 148 | ||
149 | /* | ||
150 | ** Calls 'lua_getinfo' and collects all results in a new table. | ||
151 | */ | ||
135 | static int db_getinfo (lua_State *L) { | 152 | static int db_getinfo (lua_State *L) { |
136 | lua_Debug ar; | 153 | lua_Debug ar; |
137 | int arg; | 154 | int arg; |
138 | lua_State *L1 = getthread(L, &arg); | 155 | lua_State *L1 = getthread(L, &arg); |
139 | const char *options = luaL_optstring(L, arg+2, "flnStu"); | 156 | const char *options = luaL_optstring(L, arg+2, "flnStu"); |
140 | if (lua_isnumber(L, arg+1)) { | 157 | if (lua_isfunction(L, arg + 1)) { /* info about a function? */ |
141 | if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) { | 158 | options = lua_pushfstring(L, ">%s", options); /* add '>' to 'options' */ |
159 | lua_pushvalue(L, arg + 1); /* move function to 'L1' stack */ | ||
160 | lua_xmove(L, L1, 1); | ||
161 | } | ||
162 | else { /* stack level */ | ||
163 | if (!lua_getstack(L1, luaL_checkint(L, arg + 1), &ar)) { | ||
142 | lua_pushnil(L); /* level out of range */ | 164 | lua_pushnil(L); /* level out of range */ |
143 | return 1; | 165 | return 1; |
144 | } | 166 | } |
145 | } | 167 | } |
146 | else if (lua_isfunction(L, arg+1)) { | ||
147 | lua_pushfstring(L, ">%s", options); | ||
148 | options = lua_tostring(L, -1); | ||
149 | lua_pushvalue(L, arg+1); | ||
150 | lua_xmove(L, L1, 1); | ||
151 | } | ||
152 | else | ||
153 | return luaL_argerror(L, arg+1, "function or level expected"); | ||
154 | if (!lua_getinfo(L1, options, &ar)) | 168 | if (!lua_getinfo(L1, options, &ar)) |
155 | return luaL_argerror(L, arg+2, "invalid option"); | 169 | return luaL_argerror(L, arg+2, "invalid option"); |
156 | lua_createtable(L, 0, 2); | 170 | lua_newtable(L); /* table to collect results */ |
157 | if (strchr(options, 'S')) { | 171 | if (strchr(options, 'S')) { |
158 | settabss(L, "source", ar.source); | 172 | settabss(L, "source", ar.source); |
159 | settabss(L, "short_src", ar.short_src); | 173 | settabss(L, "short_src", ar.short_src); |
@@ -191,16 +205,16 @@ static int db_getlocal (lua_State *L) { | |||
191 | if (lua_isfunction(L, arg + 1)) { /* function argument? */ | 205 | if (lua_isfunction(L, arg + 1)) { /* function argument? */ |
192 | lua_pushvalue(L, arg + 1); /* push function */ | 206 | lua_pushvalue(L, arg + 1); /* push function */ |
193 | lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ | 207 | lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ |
194 | return 1; | 208 | return 1; /* return only name (there is no value) */ |
195 | } | 209 | } |
196 | else { /* stack-level argument */ | 210 | else { /* stack-level argument */ |
197 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ | 211 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
198 | return luaL_argerror(L, arg+1, "level out of range"); | 212 | return luaL_argerror(L, arg+1, "level out of range"); |
199 | name = lua_getlocal(L1, &ar, nvar); | 213 | name = lua_getlocal(L1, &ar, nvar); |
200 | if (name) { | 214 | if (name) { |
201 | lua_xmove(L1, L, 1); /* push local value */ | 215 | lua_xmove(L1, L, 1); /* move local value */ |
202 | lua_pushstring(L, name); /* push name */ | 216 | lua_pushstring(L, name); /* push name */ |
203 | lua_pushvalue(L, -2); /* re-order */ | 217 | lua_rotate(L, -2, 1); /* re-order */ |
204 | return 2; | 218 | return 2; |
205 | } | 219 | } |
206 | else { | 220 | else { |
@@ -225,14 +239,17 @@ static int db_setlocal (lua_State *L) { | |||
225 | } | 239 | } |
226 | 240 | ||
227 | 241 | ||
242 | /* | ||
243 | ** get (if 'get' is true) or set an upvalue from a closure | ||
244 | */ | ||
228 | static int auxupvalue (lua_State *L, int get) { | 245 | static int auxupvalue (lua_State *L, int get) { |
229 | const char *name; | 246 | const char *name; |
230 | int n = luaL_checkint(L, 2); | 247 | int n = luaL_checkint(L, 2); /* upvalue index */ |
231 | luaL_checktype(L, 1, LUA_TFUNCTION); | 248 | luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ |
232 | name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); | 249 | name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); |
233 | if (name == NULL) return 0; | 250 | if (name == NULL) return 0; |
234 | lua_pushstring(L, name); | 251 | lua_pushstring(L, name); |
235 | lua_insert(L, -(get+1)); | 252 | lua_insert(L, -(get+1)); /* no-op if get is false */ |
236 | return get + 1; | 253 | return get + 1; |
237 | } | 254 | } |
238 | 255 | ||
@@ -248,13 +265,15 @@ static int db_setupvalue (lua_State *L) { | |||
248 | } | 265 | } |
249 | 266 | ||
250 | 267 | ||
268 | /* | ||
269 | ** Check whether a given upvalue from a given closure exists and | ||
270 | ** returns its index | ||
271 | */ | ||
251 | static int checkupval (lua_State *L, int argf, int argnup) { | 272 | static int checkupval (lua_State *L, int argf, int argnup) { |
252 | lua_Debug ar; | 273 | int nup = luaL_checkint(L, argnup); /* upvalue index */ |
253 | int nup = luaL_checkint(L, argnup); | 274 | luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ |
254 | luaL_checktype(L, argf, LUA_TFUNCTION); | 275 | luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, |
255 | lua_pushvalue(L, argf); | 276 | "invalid upvalue index"); |
256 | lua_getinfo(L, ">u", &ar); | ||
257 | luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index"); | ||
258 | return nup; | 277 | return nup; |
259 | } | 278 | } |
260 | 279 | ||
@@ -276,25 +295,36 @@ static int db_upvaluejoin (lua_State *L) { | |||
276 | } | 295 | } |
277 | 296 | ||
278 | 297 | ||
298 | /* | ||
299 | ** The hook table (at registry[HOOKKEY]) maps threads to their current | ||
300 | ** hook function | ||
301 | */ | ||
279 | #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) | 302 | #define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY) |
280 | 303 | ||
281 | 304 | ||
305 | /* | ||
306 | ** Call hook function registered at hook table for the current | ||
307 | ** thread (if there is one) | ||
308 | */ | ||
282 | static void hookf (lua_State *L, lua_Debug *ar) { | 309 | static void hookf (lua_State *L, lua_Debug *ar) { |
283 | static const char *const hooknames[] = | 310 | static const char *const hooknames[] = |
284 | {"call", "return", "line", "count", "tail call"}; | 311 | {"call", "return", "line", "count", "tail call"}; |
285 | gethooktable(L); | 312 | gethooktable(L); |
286 | lua_pushthread(L); | 313 | lua_pushthread(L); |
287 | if (lua_rawget(L, -2) == LUA_TFUNCTION) { | 314 | if (lua_rawget(L, -2) == LUA_TFUNCTION) { /* is there a hook function? */ |
288 | lua_pushstring(L, hooknames[(int)ar->event]); | 315 | lua_pushstring(L, hooknames[(int)ar->event]); /* push event name */ |
289 | if (ar->currentline >= 0) | 316 | if (ar->currentline >= 0) |
290 | lua_pushinteger(L, ar->currentline); | 317 | lua_pushinteger(L, ar->currentline); /* push current line */ |
291 | else lua_pushnil(L); | 318 | else lua_pushnil(L); |
292 | lua_assert(lua_getinfo(L, "lS", ar)); | 319 | lua_assert(lua_getinfo(L, "lS", ar)); |
293 | lua_call(L, 2, 0); | 320 | lua_call(L, 2, 0); /* call hook function */ |
294 | } | 321 | } |
295 | } | 322 | } |
296 | 323 | ||
297 | 324 | ||
325 | /* | ||
326 | ** Convert a string mask (for 'sethook') into a bit mask | ||
327 | */ | ||
298 | static int makemask (const char *smask, int count) { | 328 | static int makemask (const char *smask, int count) { |
299 | int mask = 0; | 329 | int mask = 0; |
300 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; | 330 | if (strchr(smask, 'c')) mask |= LUA_MASKCALL; |
@@ -305,6 +335,9 @@ static int makemask (const char *smask, int count) { | |||
305 | } | 335 | } |
306 | 336 | ||
307 | 337 | ||
338 | /* | ||
339 | ** Convert a bit mask (for 'gethook') into a string mask | ||
340 | */ | ||
308 | static char *unmakemask (int mask, char *smask) { | 341 | static char *unmakemask (int mask, char *smask) { |
309 | int i = 0; | 342 | int i = 0; |
310 | if (mask & LUA_MASKCALL) smask[i++] = 'c'; | 343 | if (mask & LUA_MASKCALL) smask[i++] = 'c'; |
@@ -319,7 +352,7 @@ static int db_sethook (lua_State *L) { | |||
319 | int arg, mask, count; | 352 | int arg, mask, count; |
320 | lua_Hook func; | 353 | lua_Hook func; |
321 | lua_State *L1 = getthread(L, &arg); | 354 | lua_State *L1 = getthread(L, &arg); |
322 | if (lua_isnoneornil(L, arg+1)) { | 355 | if (lua_isnoneornil(L, arg+1)) { /* no hook? */ |
323 | lua_settop(L, arg+1); | 356 | lua_settop(L, arg+1); |
324 | func = NULL; mask = 0; count = 0; /* turn off hooks */ | 357 | func = NULL; mask = 0; count = 0; /* turn off hooks */ |
325 | } | 358 | } |
@@ -335,9 +368,9 @@ static int db_sethook (lua_State *L) { | |||
335 | lua_pushvalue(L, -1); | 368 | lua_pushvalue(L, -1); |
336 | lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ | 369 | lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */ |
337 | } | 370 | } |
338 | lua_pushthread(L1); lua_xmove(L1, L, 1); | 371 | lua_pushthread(L1); lua_xmove(L1, L, 1); /* key */ |
339 | lua_pushvalue(L, arg+1); | 372 | lua_pushvalue(L, arg+1); /* value */ |
340 | lua_rawset(L, -3); /* set new hook */ | 373 | lua_rawset(L, -3); /* hooktable[L1] = new Lua hook */ |
341 | lua_sethook(L1, func, mask, count); /* set hooks */ | 374 | lua_sethook(L1, func, mask, count); /* set hooks */ |
342 | return 0; | 375 | return 0; |
343 | } | 376 | } |
@@ -354,11 +387,11 @@ static int db_gethook (lua_State *L) { | |||
354 | else { | 387 | else { |
355 | gethooktable(L); | 388 | gethooktable(L); |
356 | lua_pushthread(L1); lua_xmove(L1, L, 1); | 389 | lua_pushthread(L1); lua_xmove(L1, L, 1); |
357 | lua_rawget(L, -2); /* get hook */ | 390 | lua_rawget(L, -2); /* 1st result = hooktable[L1] */ |
358 | lua_remove(L, -2); /* remove hook table */ | 391 | lua_remove(L, -2); /* remove hook table */ |
359 | } | 392 | } |
360 | lua_pushstring(L, unmakemask(mask, buff)); | 393 | lua_pushstring(L, unmakemask(mask, buff)); /* 2nd result = mask */ |
361 | lua_pushinteger(L, lua_gethookcount(L1)); | 394 | lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ |
362 | return 3; | 395 | return 3; |
363 | } | 396 | } |
364 | 397 | ||