diff options
| -rw-r--r-- | ldblib.c | 134 |
1 files changed, 92 insertions, 42 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ldblib.c,v 1.79 2003/03/11 12:24:34 roberto Exp roberto $ | 2 | ** $Id: ldblib.c,v 1.80 2003/04/03 13:35:34 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 | */ |
| @@ -32,24 +32,39 @@ static void settabsi (lua_State *L, const char *i, int v) { | |||
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | 34 | ||
| 35 | static lua_State *getthread (lua_State *L, int *arg) { | ||
| 36 | if (lua_isthread(L, 1)) { | ||
| 37 | *arg = 1; | ||
| 38 | return lua_tothread(L, 1); | ||
| 39 | } | ||
| 40 | else { | ||
| 41 | *arg = 0; | ||
| 42 | return L; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | |||
| 35 | static int getinfo (lua_State *L) { | 47 | static int getinfo (lua_State *L) { |
| 36 | lua_Debug ar; | 48 | lua_Debug ar; |
| 37 | const char *options = luaL_optstring(L, 2, "flnSu"); | 49 | int arg; |
| 38 | if (lua_isnumber(L, 1)) { | 50 | lua_State *L1 = getthread(L, &arg); |
| 39 | if (!lua_getstack(L, (int)(lua_tonumber(L, 1)), &ar)) { | 51 | const char *options = luaL_optstring(L, arg+2, "flnSu"); |
| 52 | if (lua_isnumber(L, arg+1)) { | ||
| 53 | if (!lua_getstack(L1, (int)(lua_tonumber(L, arg+1)), &ar)) { | ||
| 40 | lua_pushnil(L); /* level out of range */ | 54 | lua_pushnil(L); /* level out of range */ |
| 41 | return 1; | 55 | return 1; |
| 42 | } | 56 | } |
| 43 | } | 57 | } |
| 44 | else if (lua_isfunction(L, 1)) { | 58 | else if (lua_isfunction(L, arg+1)) { |
| 45 | lua_pushfstring(L, ">%s", options); | 59 | lua_pushfstring(L, ">%s", options); |
| 46 | options = lua_tostring(L, -1); | 60 | options = lua_tostring(L, -1); |
| 47 | lua_pushvalue(L, 1); | 61 | lua_pushvalue(L, arg+1); |
| 62 | lua_xmove(L, L1, 1); | ||
| 48 | } | 63 | } |
| 49 | else | 64 | else |
| 50 | return luaL_argerror(L, 1, "function or level expected"); | 65 | return luaL_argerror(L, arg+1, "function or level expected"); |
| 51 | if (!lua_getinfo(L, options, &ar)) | 66 | if (!lua_getinfo(L1, options, &ar)) |
| 52 | return luaL_argerror(L, 2, "invalid option"); | 67 | return luaL_argerror(L, arg+2, "invalid option"); |
| 53 | lua_newtable(L); | 68 | lua_newtable(L); |
| 54 | for (; *options; options++) { | 69 | for (; *options; options++) { |
| 55 | switch (*options) { | 70 | switch (*options) { |
| @@ -71,7 +86,10 @@ static int getinfo (lua_State *L) { | |||
| 71 | break; | 86 | break; |
| 72 | case 'f': | 87 | case 'f': |
| 73 | lua_pushliteral(L, "func"); | 88 | lua_pushliteral(L, "func"); |
| 74 | lua_pushvalue(L, -3); | 89 | if (L == L1) |
| 90 | lua_pushvalue(L, -3); | ||
| 91 | else | ||
| 92 | lua_xmove(L1, L, 1); | ||
| 75 | lua_rawset(L, -3); | 93 | lua_rawset(L, -3); |
| 76 | break; | 94 | break; |
| 77 | } | 95 | } |
| @@ -81,12 +99,15 @@ static int getinfo (lua_State *L) { | |||
| 81 | 99 | ||
| 82 | 100 | ||
| 83 | static int getlocal (lua_State *L) { | 101 | static int getlocal (lua_State *L) { |
| 102 | int arg; | ||
| 103 | lua_State *L1 = getthread(L, &arg); | ||
| 84 | lua_Debug ar; | 104 | lua_Debug ar; |
| 85 | const char *name; | 105 | const char *name; |
| 86 | if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ | 106 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
| 87 | return luaL_argerror(L, 1, "level out of range"); | 107 | return luaL_argerror(L, arg+1, "level out of range"); |
| 88 | name = lua_getlocal(L, &ar, luaL_checkint(L, 2)); | 108 | name = lua_getlocal(L1, &ar, luaL_checkint(L, arg+2)); |
| 89 | if (name) { | 109 | if (name) { |
| 110 | lua_xmove(L1, L, 1); | ||
| 90 | lua_pushstring(L, name); | 111 | lua_pushstring(L, name); |
| 91 | lua_pushvalue(L, -2); | 112 | lua_pushvalue(L, -2); |
| 92 | return 2; | 113 | return 2; |
| @@ -99,11 +120,15 @@ static int getlocal (lua_State *L) { | |||
| 99 | 120 | ||
| 100 | 121 | ||
| 101 | static int setlocal (lua_State *L) { | 122 | static int setlocal (lua_State *L) { |
| 123 | int arg; | ||
| 124 | lua_State *L1 = getthread(L, &arg); | ||
| 102 | lua_Debug ar; | 125 | lua_Debug ar; |
| 103 | if (!lua_getstack(L, luaL_checkint(L, 1), &ar)) /* level out of range? */ | 126 | if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */ |
| 104 | return luaL_argerror(L, 1, "level out of range"); | 127 | return luaL_argerror(L, arg+1, "level out of range"); |
| 105 | luaL_checkany(L, 3); | 128 | luaL_checkany(L, arg+3); |
| 106 | lua_pushstring(L, lua_setlocal(L, &ar, luaL_checkint(L, 2))); | 129 | lua_settop(L, arg+3); |
| 130 | lua_xmove(L, L1, 1); | ||
| 131 | lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2))); | ||
| 107 | return 1; | 132 | return 1; |
| 108 | } | 133 | } |
| 109 | 134 | ||
| @@ -141,6 +166,8 @@ static void hookf (lua_State *L, lua_Debug *ar) { | |||
| 141 | {"call", "return", "line", "count", "tail return"}; | 166 | {"call", "return", "line", "count", "tail return"}; |
| 142 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | 167 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); |
| 143 | lua_rawget(L, LUA_REGISTRYINDEX); | 168 | lua_rawget(L, LUA_REGISTRYINDEX); |
| 169 | lua_pushlightuserdata(L, L); | ||
| 170 | lua_rawget(L, -2); | ||
| 144 | if (lua_isfunction(L, -1)) { | 171 | if (lua_isfunction(L, -1)) { |
| 145 | lua_pushstring(L, hooknames[(int)ar->event]); | 172 | lua_pushstring(L, hooknames[(int)ar->event]); |
| 146 | if (ar->currentline >= 0) | 173 | if (ar->currentline >= 0) |
| @@ -149,8 +176,6 @@ static void hookf (lua_State *L, lua_Debug *ar) { | |||
| 149 | lua_assert(lua_getinfo(L, "lS", ar)); | 176 | lua_assert(lua_getinfo(L, "lS", ar)); |
| 150 | lua_call(L, 2, 0); | 177 | lua_call(L, 2, 0); |
| 151 | } | 178 | } |
| 152 | else | ||
| 153 | lua_pop(L, 1); /* pop result from gettable */ | ||
| 154 | } | 179 | } |
| 155 | 180 | ||
| 156 | 181 | ||
| @@ -174,36 +199,59 @@ static char *unmakemask (int mask, char *smask) { | |||
| 174 | } | 199 | } |
| 175 | 200 | ||
| 176 | 201 | ||
| 202 | static void gethooktable (lua_State *L) { | ||
| 203 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||
| 204 | lua_rawget(L, LUA_REGISTRYINDEX); | ||
| 205 | if (!lua_istable(L, -1)) { | ||
| 206 | lua_pop(L, 1); | ||
| 207 | lua_newtable(L); | ||
| 208 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | ||
| 209 | lua_pushvalue(L, -2); | ||
| 210 | lua_rawset(L, LUA_REGISTRYINDEX); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | |||
| 177 | static int sethook (lua_State *L) { | 215 | static int sethook (lua_State *L) { |
| 178 | if (lua_isnoneornil(L, 1)) { | 216 | int arg; |
| 179 | lua_settop(L, 1); | 217 | lua_State *L1 = getthread(L, &arg); |
| 180 | lua_sethook(L, NULL, 0, 0); /* turn off hooks */ | 218 | if (lua_isnoneornil(L, arg+1)) { |
| 219 | lua_settop(L, arg+1); | ||
| 220 | lua_sethook(L1, NULL, 0, 0); /* turn off hooks */ | ||
| 181 | } | 221 | } |
| 182 | else { | 222 | else { |
| 183 | const char *smask = luaL_checkstring(L, 2); | 223 | const char *smask = luaL_checkstring(L, arg+2); |
| 184 | int count = luaL_optint(L, 3, 0); | 224 | int count = luaL_optint(L, arg+3, 0); |
| 185 | luaL_checktype(L, 1, LUA_TFUNCTION); | 225 | luaL_checktype(L, arg+1, LUA_TFUNCTION); |
| 186 | lua_sethook(L, hookf, makemask(smask, count), count); | 226 | lua_sethook(L1, hookf, makemask(smask, count), count); |
| 187 | } | 227 | } |
| 188 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | 228 | gethooktable(L1); |
| 189 | lua_pushvalue(L, 1); | 229 | lua_pushlightuserdata(L1, L1); |
| 190 | lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */ | 230 | lua_pushvalue(L, arg+1); |
| 231 | lua_xmove(L, L1, 1); | ||
| 232 | lua_rawset(L1, -3); /* set new hook */ | ||
| 233 | lua_pop(L1, 1); /* remove hook table */ | ||
| 191 | return 0; | 234 | return 0; |
| 192 | } | 235 | } |
| 193 | 236 | ||
| 194 | 237 | ||
| 195 | static int gethook (lua_State *L) { | 238 | static int gethook (lua_State *L) { |
| 239 | int arg; | ||
| 240 | lua_State *L1 = getthread(L, &arg); | ||
| 196 | char buff[5]; | 241 | char buff[5]; |
| 197 | int mask = lua_gethookmask(L); | 242 | int mask = lua_gethookmask(L1); |
| 198 | lua_Hook hook = lua_gethook(L); | 243 | lua_Hook hook = lua_gethook(L1); |
| 199 | if (hook != NULL && hook != hookf) /* external hook? */ | 244 | if (hook != NULL && hook != hookf) /* external hook? */ |
| 200 | lua_pushliteral(L, "external hook"); | 245 | lua_pushliteral(L, "external hook"); |
| 201 | else { | 246 | else { |
| 202 | lua_pushlightuserdata(L, (void *)&KEY_HOOK); | 247 | gethooktable(L1); |
| 203 | lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */ | 248 | lua_pushlightuserdata(L1, L1); |
| 249 | lua_rawget(L1, -2); /* get hook */ | ||
| 250 | lua_remove(L1, -2); /* remove hook table */ | ||
| 251 | lua_xmove(L1, L, 1); | ||
| 204 | } | 252 | } |
| 205 | lua_pushstring(L, unmakemask(mask, buff)); | 253 | lua_pushstring(L, unmakemask(mask, buff)); |
| 206 | lua_pushnumber(L, (lua_Number)lua_gethookcount(L)); | 254 | lua_pushnumber(L, (lua_Number)lua_gethookcount(L1)); |
| 207 | return 3; | 255 | return 3; |
| 208 | } | 256 | } |
| 209 | 257 | ||
| @@ -227,27 +275,29 @@ static int debug (lua_State *L) { | |||
| 227 | static int errorfb (lua_State *L) { | 275 | static int errorfb (lua_State *L) { |
| 228 | int level = 1; /* skip level 0 (it's this function) */ | 276 | int level = 1; /* skip level 0 (it's this function) */ |
| 229 | int firstpart = 1; /* still before eventual `...' */ | 277 | int firstpart = 1; /* still before eventual `...' */ |
| 278 | int arg; | ||
| 279 | lua_State *L1 = getthread(L, &arg); | ||
| 230 | lua_Debug ar; | 280 | lua_Debug ar; |
| 231 | if (lua_gettop(L) == 0) | 281 | if (lua_gettop(L) == arg) |
| 232 | lua_pushliteral(L, ""); | 282 | lua_pushliteral(L, ""); |
| 233 | else if (!lua_isstring(L, 1)) return 1; /* no string message */ | 283 | else if (!lua_isstring(L, arg+1)) return 1; /* no string message */ |
| 234 | else lua_pushliteral(L, "\n"); | 284 | else lua_pushliteral(L, "\n"); |
| 235 | lua_pushliteral(L, "stack traceback:"); | 285 | lua_pushliteral(L, "stack traceback:"); |
| 236 | while (lua_getstack(L, level++, &ar)) { | 286 | while (lua_getstack(L1, level++, &ar)) { |
| 237 | if (level > LEVELS1 && firstpart) { | 287 | if (level > LEVELS1 && firstpart) { |
| 238 | /* no more than `LEVELS2' more levels? */ | 288 | /* no more than `LEVELS2' more levels? */ |
| 239 | if (!lua_getstack(L, level+LEVELS2, &ar)) | 289 | if (!lua_getstack(L1, level+LEVELS2, &ar)) |
| 240 | level--; /* keep going */ | 290 | level--; /* keep going */ |
| 241 | else { | 291 | else { |
| 242 | lua_pushliteral(L, "\n\t..."); /* too many levels */ | 292 | lua_pushliteral(L, "\n\t..."); /* too many levels */ |
| 243 | while (lua_getstack(L, level+LEVELS2, &ar)) /* find last levels */ | 293 | while (lua_getstack(L1, level+LEVELS2, &ar)) /* find last levels */ |
| 244 | level++; | 294 | level++; |
| 245 | } | 295 | } |
| 246 | firstpart = 0; | 296 | firstpart = 0; |
| 247 | continue; | 297 | continue; |
| 248 | } | 298 | } |
| 249 | lua_pushliteral(L, "\n\t"); | 299 | lua_pushliteral(L, "\n\t"); |
| 250 | lua_getinfo(L, "Snl", &ar); | 300 | lua_getinfo(L1, "Snl", &ar); |
| 251 | lua_pushfstring(L, "%s:", ar.short_src); | 301 | lua_pushfstring(L, "%s:", ar.short_src); |
| 252 | if (ar.currentline > 0) | 302 | if (ar.currentline > 0) |
| 253 | lua_pushfstring(L, "%d:", ar.currentline); | 303 | lua_pushfstring(L, "%d:", ar.currentline); |
| @@ -268,9 +318,9 @@ static int errorfb (lua_State *L) { | |||
| 268 | ar.short_src, ar.linedefined); | 318 | ar.short_src, ar.linedefined); |
| 269 | } | 319 | } |
| 270 | } | 320 | } |
| 271 | lua_concat(L, lua_gettop(L)); | 321 | lua_concat(L, lua_gettop(L) - arg); |
| 272 | } | 322 | } |
| 273 | lua_concat(L, lua_gettop(L)); | 323 | lua_concat(L, lua_gettop(L) - arg); |
| 274 | return 1; | 324 | return 1; |
| 275 | } | 325 | } |
| 276 | 326 | ||
