/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "glk/tads/tads2/debug.h"
#include "glk/tads/tads2/list.h"
#include "glk/tads/tads2/run.h"
#include "glk/tads/tads2/vocabulary.h"
#include "glk/tads/os_glk.h"
namespace Glk {
namespace TADS {
namespace TADS2 {
/* add a string to the history buffer */
void dbgaddhist(dbgcxdef *ctx, char *buf, int l)
{
char *p;
int dell;
if (ctx->dbgcxhstf + l + 1 >= ctx->dbgcxhstl)
{
/* delete first lines until we have enough space */
for (dell = 0, p = ctx->dbgcxhstp ; *p || dell < l ; ++p, ++dell) ;
if (*p) ++p;
memmove(ctx->dbgcxhstp, ctx->dbgcxhstp + dell,
(size_t)(ctx->dbgcxhstf - dell));
ctx->dbgcxhstf -= dell;
}
memcpy(ctx->dbgcxhstp + ctx->dbgcxhstf, buf, (size_t)l);
ctx->dbgcxhstf += l;
}
/* callback for dbgent - saves history line to a char buffer */
static void dbgent1(void *ctx0, const char *str, int strl)
{
char **ctx = (char **)ctx0;
memcpy(*ctx, str, (size_t)strl);
*ctx += strl;
}
void dbgent(dbgcxdef *ctx, runsdef *bp, objnum self, objnum target,
prpnum prop, int binum, int argc)
{
dbgfdef *p;
++(ctx->dbgcxdep); /* increment actual depth */
if (ctx->dbgcxfcn == DBGMAXFRAME)
{
--(ctx->dbgcxfcn); /* back to top frame */
memmove(ctx->dbgcxfrm, ctx->dbgcxfrm + 1,
(size_t)((DBGMAXFRAME - 1) * sizeof(dbgfdef)));
}
p = &ctx->dbgcxfrm[ctx->dbgcxfcn];
++(ctx->dbgcxfcn); /* increment frame pointer */
p->dbgfbp = bp;
p->dbgfself = self;
p->dbgftarg = target;
p->dbgfprop = prop;
p->dbgfbif = binum;
p->dbgfargc = argc;
p->dbgffr = 0; /* no frame has yet been recorded */
p->dbgflin = 0;
/* save call history */
if (ctx->dbgcxflg & DBGCXFTRC)
{
char buf[128];
char *tmp;
int l;
tmp = buf;
dbgstktr(ctx, dbgent1, &tmp, -1, TRUE, FALSE);
if ((l = (tmp - buf)) > 0 && buf[l-1] == '\n') --l;
buf[l++] = '\0';
dbgaddhist(ctx, buf, l);
}
}
void dbglv(dbgcxdef *ctx, int exittype)
{
--(ctx->dbgcxdep); /* decrement actual depth */
if (ctx->dbgcxfcn) --(ctx->dbgcxfcn); /* decrement frame pointer */
/*
* if we're in STEP OUT/OVER mode, and the target context is level
* 0, and we're now at level 0, it means that we are stepping out of
* a routine called directly by the system and the debugger is
* supposed to break when that happens -- return to single-stepping
* mode so that we break into the debugger the next time the system
* calls a method
*/
if ((ctx->dbgcxflg & DBGCXFSS) != 0
&& (ctx->dbgcxflg & DBGCXFSO) != 0
&& ctx->dbgcxsof == 0 && ctx->dbgcxdep == 0)
{
/*
* stepping out/over at level 0 - go to normal single-step mode
* (clear the out/over flag)
*/
ctx->dbgcxflg &= ~DBGCXFSO;
}
/* record exit in call history if appropriate */
if (ctx->dbgcxflg & DBGCXFTRC)
{
char buf[128];
char *p;
switch(exittype)
{
case DBGEXVAL:
if (ctx->dbgcxfcn > 1)
{
memset(buf, ' ', (size_t)(ctx->dbgcxfcn - 1));
dbgaddhist(ctx, buf, (int)ctx->dbgcxfcn - 1);
}
memcpy(buf, " => ", (size_t)4);
p = buf + 4;
dbgpval(ctx, ctx->dbgcxrun->runcxsp - 1,
dbgent1, &p, TRUE);
*p++ = '\0';
dbgaddhist(ctx, buf, (int)(p - buf));
break;
case DBGEXPASS:
memcpy(buf, " [pass]", (size_t)8);
dbgaddhist(ctx, buf, 8);
break;
}
}
}
/* get a symbol name; returns length of name */
int dbgnam(dbgcxdef *ctx, char *outbuf, int typ, int val)
{
toksdef sym;
if (!ctx->dbgcxtab)
{
memcpy(outbuf, "", (size_t)17);
return(17);
}
if (tokthfind((toktdef *)ctx->dbgcxtab, typ, val, &sym))
{
memcpy(outbuf, sym.toksnam, (size_t)sym.tokslen);
return(sym.tokslen);
}
else if (typ == TOKSTOBJ)
{
if ((mcmon)val == MCMONINV)
{
memcpy(outbuf, "", 16);
return 16;
}
else
{
Common::sprintf_s(outbuf, TOKNAMMAX + 1, "