mudgangster

Tiny, scriptable MUD client
Log | Files | Refs | README

ldblib.cc (12779B)


      1 /*
      2 ** $Id: ldblib.c,v 1.151.1.1 2017/04/19 17:20:42 roberto Exp $
      3 ** Interface from Lua to its debug API
      4 ** See Copyright Notice in lua.h
      5 */
      6 
      7 #define ldblib_c
      8 #define LUA_LIB
      9 
     10 #include "lprefix.h"
     11 
     12 
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 
     17 #include "lua.h"
     18 
     19 #include "lauxlib.h"
     20 #include "lualib.h"
     21 
     22 
     23 /*
     24 ** The hook table at registry[&HOOKKEY] maps threads to their current
     25 ** hook function. (We only need the unique address of 'HOOKKEY'.)
     26 */
     27 static const int HOOKKEY = 0;
     28 
     29 
     30 /*
     31 ** If L1 != L, L1 can be in any state, and therefore there are no
     32 ** guarantees about its stack space; any push in L1 must be
     33 ** checked.
     34 */
     35 static void checkstack (lua_State *L, lua_State *L1, int n) {
     36   if (L != L1 && !lua_checkstack(L1, n))
     37     luaL_error(L, "stack overflow");
     38 }
     39 
     40 
     41 static int db_getregistry (lua_State *L) {
     42   lua_pushvalue(L, LUA_REGISTRYINDEX);
     43   return 1;
     44 }
     45 
     46 
     47 static int db_getmetatable (lua_State *L) {
     48   luaL_checkany(L, 1);
     49   if (!lua_getmetatable(L, 1)) {
     50     lua_pushnil(L);  /* no metatable */
     51   }
     52   return 1;
     53 }
     54 
     55 
     56 static int db_setmetatable (lua_State *L) {
     57   int t = lua_type(L, 2);
     58   luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
     59                     "nil or table expected");
     60   lua_settop(L, 2);
     61   lua_setmetatable(L, 1);
     62   return 1;  /* return 1st argument */
     63 }
     64 
     65 
     66 static int db_getuservalue (lua_State *L) {
     67   if (lua_type(L, 1) != LUA_TUSERDATA)
     68     lua_pushnil(L);
     69   else
     70     lua_getuservalue(L, 1);
     71   return 1;
     72 }
     73 
     74 
     75 static int db_setuservalue (lua_State *L) {
     76   luaL_checktype(L, 1, LUA_TUSERDATA);
     77   luaL_checkany(L, 2);
     78   lua_settop(L, 2);
     79   lua_setuservalue(L, 1);
     80   return 1;
     81 }
     82 
     83 
     84 /*
     85 ** Auxiliary function used by several library functions: check for
     86 ** an optional thread as function's first argument and set 'arg' with
     87 ** 1 if this argument is present (so that functions can skip it to
     88 ** access their other arguments)
     89 */
     90 static lua_State *getthread (lua_State *L, int *arg) {
     91   if (lua_isthread(L, 1)) {
     92     *arg = 1;
     93     return lua_tothread(L, 1);
     94   }
     95   else {
     96     *arg = 0;
     97     return L;  /* function will operate over current thread */
     98   }
     99 }
    100 
    101 
    102 /*
    103 ** Variations of 'lua_settable', used by 'db_getinfo' to put results
    104 ** from 'lua_getinfo' into result table. Key is always a string;
    105 ** value can be a string, an int, or a boolean.
    106 */
    107 static void settabss (lua_State *L, const char *k, const char *v) {
    108   lua_pushstring(L, v);
    109   lua_setfield(L, -2, k);
    110 }
    111 
    112 static void settabsi (lua_State *L, const char *k, int v) {
    113   lua_pushinteger(L, v);
    114   lua_setfield(L, -2, k);
    115 }
    116 
    117 static void settabsb (lua_State *L, const char *k, int v) {
    118   lua_pushboolean(L, v);
    119   lua_setfield(L, -2, k);
    120 }
    121 
    122 
    123 /*
    124 ** In function 'db_getinfo', the call to 'lua_getinfo' may push
    125 ** results on the stack; later it creates the result table to put
    126 ** these objects. Function 'treatstackoption' puts the result from
    127 ** 'lua_getinfo' on top of the result table so that it can call
    128 ** 'lua_setfield'.
    129 */
    130 static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
    131   if (L == L1)
    132     lua_rotate(L, -2, 1);  /* exchange object and table */
    133   else
    134     lua_xmove(L1, L, 1);  /* move object to the "main" stack */
    135   lua_setfield(L, -2, fname);  /* put object into table */
    136 }
    137 
    138 
    139 /*
    140 ** Calls 'lua_getinfo' and collects all results in a new table.
    141 ** L1 needs stack space for an optional input (function) plus
    142 ** two optional outputs (function and line table) from function
    143 ** 'lua_getinfo'.
    144 */
    145 static int db_getinfo (lua_State *L) {
    146   lua_Debug ar;
    147   int arg;
    148   lua_State *L1 = getthread(L, &arg);
    149   const char *options = luaL_optstring(L, arg+2, "flnStu");
    150   checkstack(L, L1, 3);
    151   if (lua_isfunction(L, arg + 1)) {  /* info about a function? */
    152     options = lua_pushfstring(L, ">%s", options);  /* add '>' to 'options' */
    153     lua_pushvalue(L, arg + 1);  /* move function to 'L1' stack */
    154     lua_xmove(L, L1, 1);
    155   }
    156   else {  /* stack level */
    157     if (!lua_getstack(L1, (int)luaL_checkinteger(L, arg + 1), &ar)) {
    158       lua_pushnil(L);  /* level out of range */
    159       return 1;
    160     }
    161   }
    162   if (!lua_getinfo(L1, options, &ar))
    163     return luaL_argerror(L, arg+2, "invalid option");
    164   lua_newtable(L);  /* table to collect results */
    165   if (strchr(options, 'S')) {
    166     settabss(L, "source", ar.source);
    167     settabss(L, "short_src", ar.short_src);
    168     settabsi(L, "linedefined", ar.linedefined);
    169     settabsi(L, "lastlinedefined", ar.lastlinedefined);
    170     settabss(L, "what", ar.what);
    171   }
    172   if (strchr(options, 'l'))
    173     settabsi(L, "currentline", ar.currentline);
    174   if (strchr(options, 'u')) {
    175     settabsi(L, "nups", ar.nups);
    176     settabsi(L, "nparams", ar.nparams);
    177     settabsb(L, "isvararg", ar.isvararg);
    178   }
    179   if (strchr(options, 'n')) {
    180     settabss(L, "name", ar.name);
    181     settabss(L, "namewhat", ar.namewhat);
    182   }
    183   if (strchr(options, 't'))
    184     settabsb(L, "istailcall", ar.istailcall);
    185   if (strchr(options, 'L'))
    186     treatstackoption(L, L1, "activelines");
    187   if (strchr(options, 'f'))
    188     treatstackoption(L, L1, "func");
    189   return 1;  /* return table */
    190 }
    191 
    192 
    193 static int db_getlocal (lua_State *L) {
    194   int arg;
    195   lua_State *L1 = getthread(L, &arg);
    196   lua_Debug ar;
    197   const char *name;
    198   int nvar = (int)luaL_checkinteger(L, arg + 2);  /* local-variable index */
    199   if (lua_isfunction(L, arg + 1)) {  /* function argument? */
    200     lua_pushvalue(L, arg + 1);  /* push function */
    201     lua_pushstring(L, lua_getlocal(L, NULL, nvar));  /* push local name */
    202     return 1;  /* return only name (there is no value) */
    203   }
    204   else {  /* stack-level argument */
    205     int level = (int)luaL_checkinteger(L, arg + 1);
    206     if (!lua_getstack(L1, level, &ar))  /* out of range? */
    207       return luaL_argerror(L, arg+1, "level out of range");
    208     checkstack(L, L1, 1);
    209     name = lua_getlocal(L1, &ar, nvar);
    210     if (name) {
    211       lua_xmove(L1, L, 1);  /* move local value */
    212       lua_pushstring(L, name);  /* push name */
    213       lua_rotate(L, -2, 1);  /* re-order */
    214       return 2;
    215     }
    216     else {
    217       lua_pushnil(L);  /* no name (nor value) */
    218       return 1;
    219     }
    220   }
    221 }
    222 
    223 
    224 static int db_setlocal (lua_State *L) {
    225   int arg;
    226   const char *name;
    227   lua_State *L1 = getthread(L, &arg);
    228   lua_Debug ar;
    229   int level = (int)luaL_checkinteger(L, arg + 1);
    230   int nvar = (int)luaL_checkinteger(L, arg + 2);
    231   if (!lua_getstack(L1, level, &ar))  /* out of range? */
    232     return luaL_argerror(L, arg+1, "level out of range");
    233   luaL_checkany(L, arg+3);
    234   lua_settop(L, arg+3);
    235   checkstack(L, L1, 1);
    236   lua_xmove(L, L1, 1);
    237   name = lua_setlocal(L1, &ar, nvar);
    238   if (name == NULL)
    239     lua_pop(L1, 1);  /* pop value (if not popped by 'lua_setlocal') */
    240   lua_pushstring(L, name);
    241   return 1;
    242 }
    243 
    244 
    245 /*
    246 ** get (if 'get' is true) or set an upvalue from a closure
    247 */
    248 static int auxupvalue (lua_State *L, int get) {
    249   const char *name;
    250   int n = (int)luaL_checkinteger(L, 2);  /* upvalue index */
    251   luaL_checktype(L, 1, LUA_TFUNCTION);  /* closure */
    252   name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
    253   if (name == NULL) return 0;
    254   lua_pushstring(L, name);
    255   lua_insert(L, -(get+1));  /* no-op if get is false */
    256   return get + 1;
    257 }
    258 
    259 
    260 static int db_getupvalue (lua_State *L) {
    261   return auxupvalue(L, 1);
    262 }
    263 
    264 
    265 static int db_setupvalue (lua_State *L) {
    266   luaL_checkany(L, 3);
    267   return auxupvalue(L, 0);
    268 }
    269 
    270 
    271 /*
    272 ** Check whether a given upvalue from a given closure exists and
    273 ** returns its index
    274 */
    275 static int checkupval (lua_State *L, int argf, int argnup) {
    276   int nup = (int)luaL_checkinteger(L, argnup);  /* upvalue index */
    277   luaL_checktype(L, argf, LUA_TFUNCTION);  /* closure */
    278   luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup,
    279                    "invalid upvalue index");
    280   return nup;
    281 }
    282 
    283 
    284 static int db_upvalueid (lua_State *L) {
    285   int n = checkupval(L, 1, 2);
    286   lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
    287   return 1;
    288 }
    289 
    290 
    291 static int db_upvaluejoin (lua_State *L) {
    292   int n1 = checkupval(L, 1, 2);
    293   int n2 = checkupval(L, 3, 4);
    294   luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
    295   luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
    296   lua_upvaluejoin(L, 1, n1, 3, n2);
    297   return 0;
    298 }
    299 
    300 
    301 /*
    302 ** Call hook function registered at hook table for the current
    303 ** thread (if there is one)
    304 */
    305 static void hookf (lua_State *L, lua_Debug *ar) {
    306   static const char *const hooknames[] =
    307     {"call", "return", "line", "count", "tail call"};
    308   lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
    309   lua_pushthread(L);
    310   if (lua_rawget(L, -2) == LUA_TFUNCTION) {  /* is there a hook function? */
    311     lua_pushstring(L, hooknames[(int)ar->event]);  /* push event name */
    312     if (ar->currentline >= 0)
    313       lua_pushinteger(L, ar->currentline);  /* push current line */
    314     else lua_pushnil(L);
    315     lua_assert(lua_getinfo(L, "lS", ar));
    316     lua_call(L, 2, 0);  /* call hook function */
    317   }
    318 }
    319 
    320 
    321 /*
    322 ** Convert a string mask (for 'sethook') into a bit mask
    323 */
    324 static int makemask (const char *smask, int count) {
    325   int mask = 0;
    326   if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
    327   if (strchr(smask, 'r')) mask |= LUA_MASKRET;
    328   if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
    329   if (count > 0) mask |= LUA_MASKCOUNT;
    330   return mask;
    331 }
    332 
    333 
    334 /*
    335 ** Convert a bit mask (for 'gethook') into a string mask
    336 */
    337 static char *unmakemask (int mask, char *smask) {
    338   int i = 0;
    339   if (mask & LUA_MASKCALL) smask[i++] = 'c';
    340   if (mask & LUA_MASKRET) smask[i++] = 'r';
    341   if (mask & LUA_MASKLINE) smask[i++] = 'l';
    342   smask[i] = '\0';
    343   return smask;
    344 }
    345 
    346 
    347 static int db_sethook (lua_State *L) {
    348   int arg, mask, count;
    349   lua_Hook func;
    350   lua_State *L1 = getthread(L, &arg);
    351   if (lua_isnoneornil(L, arg+1)) {  /* no hook? */
    352     lua_settop(L, arg+1);
    353     func = NULL; mask = 0; count = 0;  /* turn off hooks */
    354   }
    355   else {
    356     const char *smask = luaL_checkstring(L, arg+2);
    357     luaL_checktype(L, arg+1, LUA_TFUNCTION);
    358     count = (int)luaL_optinteger(L, arg + 3, 0);
    359     func = hookf; mask = makemask(smask, count);
    360   }
    361   if (lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY) == LUA_TNIL) {
    362     lua_createtable(L, 0, 2);  /* create a hook table */
    363     lua_pushvalue(L, -1);
    364     lua_rawsetp(L, LUA_REGISTRYINDEX, &HOOKKEY);  /* set it in position */
    365     lua_pushstring(L, "k");
    366     lua_setfield(L, -2, "__mode");  /** hooktable.__mode = "k" */
    367     lua_pushvalue(L, -1);
    368     lua_setmetatable(L, -2);  /* setmetatable(hooktable) = hooktable */
    369   }
    370   checkstack(L, L1, 1);
    371   lua_pushthread(L1); lua_xmove(L1, L, 1);  /* key (thread) */
    372   lua_pushvalue(L, arg + 1);  /* value (hook function) */
    373   lua_rawset(L, -3);  /* hooktable[L1] = new Lua hook */
    374   lua_sethook(L1, func, mask, count);
    375   return 0;
    376 }
    377 
    378 
    379 static int db_gethook (lua_State *L) {
    380   int arg;
    381   lua_State *L1 = getthread(L, &arg);
    382   char buff[5];
    383   int mask = lua_gethookmask(L1);
    384   lua_Hook hook = lua_gethook(L1);
    385   if (hook == NULL)  /* no hook? */
    386     lua_pushnil(L);
    387   else if (hook != hookf)  /* external hook? */
    388     lua_pushliteral(L, "external hook");
    389   else {  /* hook table must exist */
    390     lua_rawgetp(L, LUA_REGISTRYINDEX, &HOOKKEY);
    391     checkstack(L, L1, 1);
    392     lua_pushthread(L1); lua_xmove(L1, L, 1);
    393     lua_rawget(L, -2);   /* 1st result = hooktable[L1] */
    394     lua_remove(L, -2);  /* remove hook table */
    395   }
    396   lua_pushstring(L, unmakemask(mask, buff));  /* 2nd result = mask */
    397   lua_pushinteger(L, lua_gethookcount(L1));  /* 3rd result = count */
    398   return 3;
    399 }
    400 
    401 
    402 static int db_debug (lua_State *L) {
    403   for (;;) {
    404     char buffer[250];
    405     lua_writestringerror("%s", "lua_debug> ");
    406     if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
    407         strcmp(buffer, "cont\n") == 0)
    408       return 0;
    409     if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
    410         lua_pcall(L, 0, 0, 0))
    411       lua_writestringerror("%s\n", lua_tostring(L, -1));
    412     lua_settop(L, 0);  /* remove eventual returns */
    413   }
    414 }
    415 
    416 
    417 static int db_traceback (lua_State *L) {
    418   int arg;
    419   lua_State *L1 = getthread(L, &arg);
    420   const char *msg = lua_tostring(L, arg + 1);
    421   if (msg == NULL && !lua_isnoneornil(L, arg + 1))  /* non-string 'msg'? */
    422     lua_pushvalue(L, arg + 1);  /* return it untouched */
    423   else {
    424     int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0);
    425     luaL_traceback(L, L1, msg, level);
    426   }
    427   return 1;
    428 }
    429 
    430 
    431 static const luaL_Reg dblib[] = {
    432   {"debug", db_debug},
    433   {"getuservalue", db_getuservalue},
    434   {"gethook", db_gethook},
    435   {"getinfo", db_getinfo},
    436   {"getlocal", db_getlocal},
    437   {"getregistry", db_getregistry},
    438   {"getmetatable", db_getmetatable},
    439   {"getupvalue", db_getupvalue},
    440   {"upvaluejoin", db_upvaluejoin},
    441   {"upvalueid", db_upvalueid},
    442   {"setuservalue", db_setuservalue},
    443   {"sethook", db_sethook},
    444   {"setlocal", db_setlocal},
    445   {"setmetatable", db_setmetatable},
    446   {"setupvalue", db_setupvalue},
    447   {"traceback", db_traceback},
    448   {NULL, NULL}
    449 };
    450 
    451 
    452 LUAMOD_API int luaopen_debug (lua_State *L) {
    453   luaL_newlib(L, dblib);
    454   return 1;
    455 }
    456