New debugger core. Doesn't really have anything implemented yet, but is far more expandable and userfriendly than our previous.

Enable experimental console debugger by default, as I havn't written the text console code yet :)

svn-id: r5990
This commit is contained in:
James Brown 2002-12-16 06:21:08 +00:00
parent 932bfdeed7
commit e989809665
5 changed files with 316 additions and 8 deletions

View File

@ -37,7 +37,7 @@ This code is not finished, so please don't complain :-)
*/
#define PROMPT "$ "
#define PROMPT ") "
/* TODO:
* - it is very inefficient to redraw the full thingy when just one char is added/removed.

240
scumm/debugger.cpp Normal file
View File

@ -0,0 +1,240 @@
#include "stdafx.h"
#include "scumm.h"
#include "sound.h"
#include "actor.h"
#include "debugger.h"
#include "common/util.h"
// The new debugger doesn't actually have the guts for text console coded yet ;)
#define USE_CONSOLE
// Choose between text console or ScummConsole
#ifdef USE_CONSOLE
#include "gui/console.h"
#define Debug_Printf _s->_debuggerDialog->printf
#else
#define Debug_Printf printf
#endif
// Initialisation Functions
void ScummDebugger::attach(Scumm *s)
{
if (_s)
detach();
_s = s;
s->_debugger = this;
_frame_countdown = 1;
_detach_now = false;
if (_dvar_count < 1) { // We need to register our variables
DVar_Register("debug_countdown", &_frame_countdown, DVAR_INT, 0);
DVar_Register("scumm_speed", &_s->_fastMode, DVAR_INT, 0);
DVar_Register("scumm_room", &_s->_currentRoom, DVAR_INT, 0);
DVar_Register("scumm_roomresource", &_s->_roomResource, DVAR_INT, 0);
DVar_Register("scumm_vars", &_s->_vars, DVAR_INTARRAY, _s->_numVariables);
DVar_Register("scumm_gamename", &_s->_game_name, DVAR_STRING, 0);
DVar_Register("scumm_exename", &_s->_exe_name, DVAR_STRING, 0);
DVar_Register("scumm_gameid", &_s->_gameId, DVAR_INT, 0);
}
if (_dcmd_count < 1) { // We need to register our commands
DCmd_Register("exit", &ScummDebugger::Cmd_Exit);
DCmd_Register("quit", &ScummDebugger::Cmd_Exit);
}
}
void ScummDebugger::detach()
{
#ifdef USE_CONSOLE
if (_s->_debuggerDialog)
_s->_debuggerDialog->setInputeCallback(0, 0);
#endif
_s->_debugger = NULL;
_s = NULL;
_detach_now = false;
}
// Temporary execution handler
void ScummDebugger::on_frame() {
if (_frame_countdown == 0)
return;
--_frame_countdown;
if (!_frame_countdown) {
// Pause sound output
bool old_soundsPaused = _s->_sound->_soundsPaused;
_s->_sound->pauseSounds(true);
// Enter debugger
enter();
_s->_sound->pauseSounds(old_soundsPaused); // Resume previous sound state
if (_detach_now) // Detach if we're finished with the debugger
detach();
}
}
// Console handler
#ifdef USE_CONSOLE
bool ScummDebugger::debuggerInputCallback(ConsoleDialog *console, const char *input, void *refCon)
{
ScummDebugger *debugger = (ScummDebugger *)refCon;
return debugger->RunCommand((char*)input);
}
#endif
///////////////////////////////////////////////////
// Now the fun stuff:
// Command/Variable registration functions
void ScummDebugger::DVar_Register(char *varname, void *pointer, int type, int optional) {
strcpy(_dvars[_dvar_count].name, varname);
_dvars[_dvar_count].type = type;
_dvars[_dvar_count].variable = pointer;
_dvars[_dvar_count].optional = optional;
_dvar_count++;
}
void ScummDebugger::DCmd_Register(char *cmdname, DebugProc pointer) {
strcpy(_dcmds[_dcmd_count].name, cmdname);
_dcmds[_dcmd_count].function = pointer;
_dcmd_count++;
}
// Main Debugger Loop
void ScummDebugger::enter()
{
#ifdef USE_CONSOLE
if (!_s->_debuggerDialog) {
_s->_debuggerDialog = new ConsoleDialog(_s->_newgui);
Debug_Printf("Debugger started, type 'exit' to return to the game\n");
}
_s->_debuggerDialog->setInputeCallback(debuggerInputCallback, this);
_s->_debuggerDialog->runModal();
#else
printf("Debugger entered, please switch to this console for input.\n");
// while(1) {
// ;
// }
#endif
}
// Command execution loop
bool ScummDebugger::RunCommand(char *input) {
int i = 0, num_parms = 0;
char parm[255][255];
// Parse out any params
char *tok = strtok(input, " ");
if (tok) {
do {
strcpy(parm[num_parms++], tok);
} while ((tok = strtok(NULL, " ")) != NULL);
} else
strcpy(parm[0], input);
for(i=0;i<_dcmd_count;i++) {
if (!strcmp(_dcmds[i].name, parm[0])) {
DebugProc cmd;
cmd = _dcmds[i].function;
return (this->*cmd)();
}
}
// It's not a command, so things get a little tricky for variables. Do fuzzy matching to ignore things like subscripts.
for(i=0;i<_dvar_count;i++) {
if (!strncmp(_dvars[i].name, parm[0], strlen(_dvars[i].name))) {
if (num_parms > 1) {
// Alright, we need to check the TYPE of the variable to deref and stuff... the array stuff is a bit ugly :)
switch(_dvars[i].type) {
// Integer
case DVAR_INT:
*(int *)_dvars[i].variable = atoi(parm[1]);
Debug_Printf("(int)%s = %d\n", parm[0], *(int *)_dvars[i].variable);
break;
// Integer Array
case DVAR_INTARRAY: {
char *chr = strchr(parm[0], '[');
if (!chr) {
Debug_Printf("You must access this array as %s[element]\n", parm[0]);
} else {
int element = atoi(chr+1);
int16 *var = *(int16 **)_dvars[i].variable;
if (element > _dvars[i].optional) {
Debug_Printf("%s is out of range (array is %d elements big)\n", parm[0], _dvars[i].optional);
} else {
var[element] = atoi(parm[1]);
Debug_Printf("(int)%s = %d\n", parm[0], var[element]);
}
}
}
break;
default:
Debug_Printf("Failed to set variable %s to %s - unknown type\n", _dvars[i].name, parm[1]);
break;
}
} else {
// And again, type-dependent prints/defrefs. The array one is still ugly.
switch(_dvars[i].type) {
// Integer
case DVAR_INT:
Debug_Printf("(int)%s = %d\n", parm[0], *(int *)_dvars[i].variable);
break;
// Integer array
case DVAR_INTARRAY: {
char *chr = strchr(parm[0], '[');
if (!chr) {
Debug_Printf("You must access this array as %s[element]\n", parm[0]);
} else {
int element = atoi(chr+1);
int16 *var = *(int16 **)_dvars[i].variable;
if (element > _dvars[i].optional) {
Debug_Printf("%s is out of range (array is %d elements big)\n", parm[0], _dvars[i].optional);
} else {
Debug_Printf("(int)%s = %d\n", parm[0], var[element]);
}
}
}
break;
// String
case DVAR_STRING:
Debug_Printf("(string)%s = %s\n", parm[0], *(char **)_dvars[i].variable);
break;
default:
Debug_Printf("%s = (unknown type)\n", parm[0]);
break;
}
}
return true;
}
}
Debug_Printf("Unknown command or variable\n");
return true;
}
// Commands
bool ScummDebugger::Cmd_Exit() {
_detach_now = true;
return false;
}

72
scumm/debugger.h Normal file
View File

@ -0,0 +1,72 @@
/* ScummVM - Scumm Interpreter
* Copyright (C) 2002 The ScummVM project
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* $Header$
*/
#ifndef DEBUG_H
#define DEBUG_H
class Scumm;
typedef bool (ScummDebugger::*DebugProc)();
enum {
DVAR_INT,
DVAR_BOOL,
DVAR_INTARRAY,
DVAR_STRING
};
struct DVar {
char name[30];
void *variable;
int type, optional;
};
struct DCmd {
char name[30];
DebugProc function;
};
class ScummDebugger {
public:
void on_frame();
void attach(Scumm *s);
protected:
Scumm *_s;
int _frame_countdown, _dvar_count, _dcmd_count;
DVar _dvars[255];
DCmd _dcmds[255];
bool _detach_now;
void enter();
void detach();
void DVar_Register(char *varname, void *pointer, int type, int optional);
void DCmd_Register(char *cmdname, DebugProc pointer);
bool RunCommand(char *input);
// Commands
bool Cmd_Exit();
#ifdef USE_CONSOLE
static bool ScummDebugger::debuggerInputCallback(ConsoleDialog *console, const char *input, void *refCon);
#endif
};
#endif

View File

@ -6,8 +6,7 @@ SCUMM_OBJS = \
scumm/boxes.o \
scumm/bundle.o \
scumm/costume.o \
scumm/debug.o \
scumm/debugrl.o \
scumm/debugger.o \
scumm/dialogs.o \
scumm/gfx.o \
scumm/imuse.o \

View File

@ -46,6 +46,7 @@ extern void drawError(char*);
// Use g_scumm from error() ONLY
Scumm *g_scumm = 0;
ScummDebugger g_debugger;
extern NewGui *g_gui;
@ -1003,9 +1004,7 @@ void Scumm::saveloadDialog()
void Scumm::debuggerDialog()
{
if (!_debuggerDialog)
_debuggerDialog = new ConsoleDialog(_newgui);
runDialog(_debuggerDialog);
g_debugger.attach(this);
}
void Scumm::optionsDialog()
@ -1374,8 +1373,6 @@ void NORETURN CDECL error(const char *s, ...)
exit(1);
}
ScummDebugger g_debugger;
void Scumm::waitForTimer(int msec_delay) {
OSystem::Event event;
uint32 start_time;