Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 <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. #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.  
  392.