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:
parent
932bfdeed7
commit
e989809665
5 changed files with 316 additions and 8 deletions
|
@ -37,7 +37,7 @@ This code is not finished, so please don't complain :-)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#define PROMPT "$ "
|
#define PROMPT ") "
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
* - it is very inefficient to redraw the full thingy when just one char is added/removed.
|
* - it is very inefficient to redraw the full thingy when just one char is added/removed.
|
||||||
|
|
240
scumm/debugger.cpp
Normal file
240
scumm/debugger.cpp
Normal 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
72
scumm/debugger.h
Normal 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
|
|
@ -6,8 +6,7 @@ SCUMM_OBJS = \
|
||||||
scumm/boxes.o \
|
scumm/boxes.o \
|
||||||
scumm/bundle.o \
|
scumm/bundle.o \
|
||||||
scumm/costume.o \
|
scumm/costume.o \
|
||||||
scumm/debug.o \
|
scumm/debugger.o \
|
||||||
scumm/debugrl.o \
|
|
||||||
scumm/dialogs.o \
|
scumm/dialogs.o \
|
||||||
scumm/gfx.o \
|
scumm/gfx.o \
|
||||||
scumm/imuse.o \
|
scumm/imuse.o \
|
||||||
|
|
|
@ -46,6 +46,7 @@ extern void drawError(char*);
|
||||||
|
|
||||||
// Use g_scumm from error() ONLY
|
// Use g_scumm from error() ONLY
|
||||||
Scumm *g_scumm = 0;
|
Scumm *g_scumm = 0;
|
||||||
|
ScummDebugger g_debugger;
|
||||||
|
|
||||||
extern NewGui *g_gui;
|
extern NewGui *g_gui;
|
||||||
|
|
||||||
|
@ -1003,9 +1004,7 @@ void Scumm::saveloadDialog()
|
||||||
|
|
||||||
void Scumm::debuggerDialog()
|
void Scumm::debuggerDialog()
|
||||||
{
|
{
|
||||||
if (!_debuggerDialog)
|
g_debugger.attach(this);
|
||||||
_debuggerDialog = new ConsoleDialog(_newgui);
|
|
||||||
runDialog(_debuggerDialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scumm::optionsDialog()
|
void Scumm::optionsDialog()
|
||||||
|
@ -1374,8 +1373,6 @@ void NORETURN CDECL error(const char *s, ...)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScummDebugger g_debugger;
|
|
||||||
|
|
||||||
void Scumm::waitForTimer(int msec_delay) {
|
void Scumm::waitForTimer(int msec_delay) {
|
||||||
OSystem::Event event;
|
OSystem::Event event;
|
||||||
uint32 start_time;
|
uint32 start_time;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue