📄 ldblib.c
字号:
/*
** $Id: ldblib.c,v 1.104 2005/12/29 15:32:11 roberto Exp $
** Interface from PVE to its debug API
** See Copyright Notice in PVE.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ldblib_c
#define PVE_LIB
#include "PVE.h"
#include "lauxlib.h"
#include "PVElib.h"
static int db_getregistry (PVE_State *L) {
PVE_pushvalue(L, PVE_REGISTRYINDEX);
return 1;
}
static int db_getmetatable (PVE_State *L) {
PVEL_checkany(L, 1);
if (!PVE_getmetatable(L, 1)) {
PVE_pushnil(L); /* no metatable */
}
return 1;
}
static int db_setmetatable (PVE_State *L) {
int t = PVE_type(L, 2);
PVEL_argcheck(L, t == PVE_TNIL || t == PVE_TTABLE, 2,
"nil or table expected");
PVE_settop(L, 2);
PVE_pushboolean(L, PVE_setmetatable(L, 1));
return 1;
}
static int db_getfenv (PVE_State *L) {
PVE_getfenv(L, 1);
return 1;
}
static int db_setfenv (PVE_State *L) {
PVEL_checktype(L, 2, PVE_TTABLE);
PVE_settop(L, 2);
if (PVE_setfenv(L, 1) == 0)
PVEL_error(L, PVE_QL("setfenv")
" cannot change environment of given object");
return 1;
}
static void settabss (PVE_State *L, const char *i, const char *v) {
PVE_pushstring(L, v);
PVE_setfield(L, -2, i);
}
static void settabsi (PVE_State *L, const char *i, int v) {
PVE_pushinteger(L, v);
PVE_setfield(L, -2, i);
}
static PVE_State *getthread (PVE_State *L, int *arg) {
if (PVE_isthread(L, 1)) {
*arg = 1;
return PVE_tothread(L, 1);
}
else {
*arg = 0;
return L;
}
}
static void treatstackoption (PVE_State *L, PVE_State *L1, const char *fname) {
if (L == L1) {
PVE_pushvalue(L, -2);
PVE_remove(L, -3);
}
else
PVE_xmove(L1, L, 1);
PVE_setfield(L, -2, fname);
}
static int db_getinfo (PVE_State *L) {
PVE_Debug ar;
int arg;
PVE_State *L1 = getthread(L, &arg);
const char *options = PVEL_optstring(L, arg+2, "flnSu");
if (PVE_isnumber(L, arg+1)) {
if (!PVE_getstack(L1, (int)PVE_tointeger(L, arg+1), &ar)) {
PVE_pushnil(L); /* level out of range */
return 1;
}
}
else if (PVE_isfunction(L, arg+1)) {
PVE_pushfstring(L, ">%s", options);
options = PVE_tostring(L, -1);
PVE_pushvalue(L, arg+1);
PVE_xmove(L, L1, 1);
}
else
return PVEL_argerror(L, arg+1, "function or level expected");
if (!PVE_getinfo(L1, options, &ar))
return PVEL_argerror(L, arg+2, "invalid option");
PVE_createtable(L, 0, 2);
if (strchr(options, 'S')) {
settabss(L, "source", ar.source);
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
settabss(L, "what", ar.what);
}
if (strchr(options, 'l'))
settabsi(L, "currentline", ar.currentline);
if (strchr(options, 'u'))
settabsi(L, "nups", ar.nups);
if (strchr(options, 'n')) {
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
}
if (strchr(options, 'L'))
treatstackoption(L, L1, "activelines");
if (strchr(options, 'f'))
treatstackoption(L, L1, "func");
return 1; /* return table */
}
static int db_getlocal (PVE_State *L) {
int arg;
PVE_State *L1 = getthread(L, &arg);
PVE_Debug ar;
const char *name;
if (!PVE_getstack(L1, PVEL_checkint(L, arg+1), &ar)) /* out of range? */
return PVEL_argerror(L, arg+1, "level out of range");
name = PVE_getlocal(L1, &ar, PVEL_checkint(L, arg+2));
if (name) {
PVE_xmove(L1, L, 1);
PVE_pushstring(L, name);
PVE_pushvalue(L, -2);
return 2;
}
else {
PVE_pushnil(L);
return 1;
}
}
static int db_setlocal (PVE_State *L) {
int arg;
PVE_State *L1 = getthread(L, &arg);
PVE_Debug ar;
if (!PVE_getstack(L1, PVEL_checkint(L, arg+1), &ar)) /* out of range? */
return PVEL_argerror(L, arg+1, "level out of range");
PVEL_checkany(L, arg+3);
PVE_settop(L, arg+3);
PVE_xmove(L, L1, 1);
PVE_pushstring(L, PVE_setlocal(L1, &ar, PVEL_checkint(L, arg+2)));
return 1;
}
static int auxupvalue (PVE_State *L, int get) {
const char *name;
int n = PVEL_checkint(L, 2);
PVEL_checktype(L, 1, PVE_TFUNCTION);
if (PVE_iscfunction(L, 1)) return 0; /* cannot touch C upvalues from PVE */
name = get ? PVE_getupvalue(L, 1, n) : PVE_setupvalue(L, 1, n);
if (name == NULL) return 0;
PVE_pushstring(L, name);
PVE_insert(L, -(get+1));
return get + 1;
}
static int db_getupvalue (PVE_State *L) {
return auxupvalue(L, 1);
}
static int db_setupvalue (PVE_State *L) {
PVEL_checkany(L, 3);
return auxupvalue(L, 0);
}
static const char KEY_HOOK = 'h';
static void hookf (PVE_State *L, PVE_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail return"};
PVE_pushlightuserdata(L, (void *)&KEY_HOOK);
PVE_rawget(L, PVE_REGISTRYINDEX);
PVE_pushlightuserdata(L, L);
PVE_rawget(L, -2);
if (PVE_isfunction(L, -1)) {
PVE_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
PVE_pushinteger(L, ar->currentline);
else PVE_pushnil(L);
PVE_assert(PVE_getinfo(L, "lS", ar));
PVE_call(L, 2, 0);
}
}
static int makemask (const char *smask, int count) {
int mask = 0;
if (strchr(smask, 'c')) mask |= PVE_MASKCALL;
if (strchr(smask, 'r')) mask |= PVE_MASKRET;
if (strchr(smask, 'l')) mask |= PVE_MASKLINE;
if (count > 0) mask |= PVE_MASKCOUNT;
return mask;
}
static char *unmakemask (int mask, char *smask) {
int i = 0;
if (mask & PVE_MASKCALL) smask[i++] = 'c';
if (mask & PVE_MASKRET) smask[i++] = 'r';
if (mask & PVE_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
static void gethooktable (PVE_State *L) {
PVE_pushlightuserdata(L, (void *)&KEY_HOOK);
PVE_rawget(L, PVE_REGISTRYINDEX);
if (!PVE_istable(L, -1)) {
PVE_pop(L, 1);
PVE_createtable(L, 0, 1);
PVE_pushlightuserdata(L, (void *)&KEY_HOOK);
PVE_pushvalue(L, -2);
PVE_rawset(L, PVE_REGISTRYINDEX);
}
}
static int db_sethook (PVE_State *L) {
int arg;
PVE_State *L1 = getthread(L, &arg);
if (PVE_isnoneornil(L, arg+1)) {
PVE_settop(L, arg+1);
PVE_sethook(L1, NULL, 0, 0); /* turn off hooks */
}
else {
const char *smask = PVEL_checkstring(L, arg+2);
int count = PVEL_optint(L, arg+3, 0);
PVEL_checktype(L, arg+1, PVE_TFUNCTION);
PVE_sethook(L1, hookf, makemask(smask, count), count);
}
gethooktable(L1);
PVE_pushlightuserdata(L1, L1);
PVE_pushvalue(L, arg+1);
PVE_xmove(L, L1, 1);
PVE_rawset(L1, -3); /* set new hook */
PVE_pop(L1, 1); /* remove hook table */
return 0;
}
static int db_gethook (PVE_State *L) {
int arg;
PVE_State *L1 = getthread(L, &arg);
char buff[5];
int mask = PVE_gethookmask(L1);
PVE_Hook hook = PVE_gethook(L1);
if (hook != NULL && hook != hookf) /* external hook? */
PVE_pushliteral(L, "external hook");
else {
gethooktable(L1);
PVE_pushlightuserdata(L1, L1);
PVE_rawget(L1, -2); /* get hook */
PVE_remove(L1, -2); /* remove hook table */
PVE_xmove(L1, L, 1);
}
PVE_pushstring(L, unmakemask(mask, buff));
PVE_pushinteger(L, PVE_gethookcount(L1));
return 3;
}
static int db_debug (PVE_State *L) {
for (;;) {
char buffer[250];
fputs("PVE_debug> ", stderr);
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (PVEL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
PVE_pcall(L, 0, 0, 0)) {
fputs(PVE_tostring(L, -1), stderr);
fputs("\n", stderr);
}
PVE_settop(L, 0); /* remove eventual returns */
}
}
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
static int db_errorfb (PVE_State *L) {
int level;
int firstpart = 1; /* still before eventual `...' */
int arg;
PVE_State *L1 = getthread(L, &arg);
PVE_Debug ar;
if (PVE_isnumber(L, arg+2)) {
level = (int)PVE_tointeger(L, arg+2);
PVE_pop(L, 1);
}
else
level = (L == L1) ? 1 : 0; /* level 0 may be this own function */
if (PVE_gettop(L) == arg)
PVE_pushliteral(L, "");
else if (!PVE_isstring(L, arg+1)) return 1; /* message is not a string */
else PVE_pushliteral(L, "\n");
PVE_pushliteral(L, "stack traceback:");
while (PVE_getstack(L1, level++, &ar)) {
if (level > LEVELS1 && firstpart) {
/* no more than `LEVELS2' more levels? */
if (!PVE_getstack(L1, level+LEVELS2, &ar))
level--; /* keep going */
else {
PVE_pushliteral(L, "\n\t..."); /* too many levels */
while (PVE_getstack(L1, level+LEVELS2, &ar)) /* find last levels */
level++;
}
firstpart = 0;
continue;
}
PVE_pushliteral(L, "\n\t");
PVE_getinfo(L1, "Snl", &ar);
PVE_pushfstring(L, "%s:", ar.short_src);
if (ar.currentline > 0)
PVE_pushfstring(L, "%d:", ar.currentline);
if (*ar.namewhat != '\0') /* is there a name? */
PVE_pushfstring(L, " in function " PVE_QS, ar.name);
else {
if (*ar.what == 'm') /* main? */
PVE_pushfstring(L, " in main chunk");
else if (*ar.what == 'C' || *ar.what == 't')
PVE_pushliteral(L, " ?"); /* C function or tail call */
else
PVE_pushfstring(L, " in function <%s:%d>",
ar.short_src, ar.linedefined);
}
PVE_concat(L, PVE_gettop(L) - arg);
}
PVE_concat(L, PVE_gettop(L) - arg);
return 1;
}
static const PVEL_Reg dblib[] = {
{"debug", db_debug},
{"getfenv", db_getfenv},
{"gethook", db_gethook},
{"getinfo", db_getinfo},
{"getlocal", db_getlocal},
{"getregistry", db_getregistry},
{"getmetatable", db_getmetatable},
{"getupvalue", db_getupvalue},
{"setfenv", db_setfenv},
{"sethook", db_sethook},
{"setlocal", db_setlocal},
{"setmetatable", db_setmetatable},
{"setupvalue", db_setupvalue},
{"traceback", db_errorfb},
{NULL, NULL}
};
PVELIB_API int PVEopen_debug (PVE_State *L) {
PVEL_register(L, PVE_DBLIBNAME, dblib);
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -