diff options
author | Max Horn | 2006-09-16 16:58:27 +0000 |
---|---|---|
committer | Max Horn | 2006-09-16 16:58:27 +0000 |
commit | 919092e5fcd0389b4cbd862e9e8cceab202e6741 (patch) | |
tree | 7d9c8f643191812bb1eb24f2e7cc2e67586149d5 /common | |
parent | 1add07becae0179e026a90924b419b74ffb1078f (diff) | |
download | scummvm-rg350-919092e5fcd0389b4cbd862e9e8cceab202e6741.tar.gz scummvm-rg350-919092e5fcd0389b4cbd862e9e8cceab202e6741.tar.bz2 scummvm-rg350-919092e5fcd0389b4cbd862e9e8cceab202e6741.zip |
Overhaul of the debugger code
* Moved Common::Debuggger to GUI::Debugger (mainly to satisfy linker
restrictions)
* Change the base Debugger class to *not* be a template class anymore;
instead, a thin (template based) wrapper class is used to hook up
debugger commands
* Removed duplicate Cmd_Exit and Cmd_Help methods in favor of a single
version of each in GUI::Debugger
* New Cmd_Help doesn't word wrap after 39/78 chars, but rather queries
the console to determine when to wrap
* Debugger::preEnter and postEnter aren't pure virtual anymore
svn-id: r23890
Diffstat (limited to 'common')
-rw-r--r-- | common/debugger.cpp | 411 | ||||
-rw-r--r-- | common/debugger.h | 110 |
2 files changed, 0 insertions, 521 deletions
diff --git a/common/debugger.cpp b/common/debugger.cpp deleted file mode 100644 index e0ad40eea9..0000000000 --- a/common/debugger.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2001-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" - -#include "common/debugger.h" -#include "common/system.h" - -#if USE_CONSOLE - #include "gui/console.h" -#endif - -namespace Common { - -template <class T> -Debugger<T>::Debugger() { - _frame_countdown = 0; - _dvar_count = 0; - _dcmd_count = 0; - _detach_now = false; - _isAttached = false; - _errStr = NULL; - _firstTime = true; - _debuggerDialog = new GUI::ConsoleDialog(1.0, 0.67F); - _debuggerDialog->setInputCallback(debuggerInputCallback, this); - _debuggerDialog->setCompletionCallback(debuggerCompletionCallback, this); - - DCmd_Register("debugflag_list", &Debugger<T>::Cmd_DebugFlagsList); - DCmd_Register("debugflag_enable", &Debugger<T>::Cmd_DebugFlagEnable); - DCmd_Register("debugflag_disable", &Debugger<T>::Cmd_DebugFlagDisable); -} - -template <class T> -Debugger<T>::~Debugger() { - delete _debuggerDialog; -} - - -// Initialisation Functions -template <class T> -int Debugger<T>::DebugPrintf(const char *format, ...) { - va_list argptr; - - va_start(argptr, format); - int count; -#if USE_CONSOLE - count = _debuggerDialog->vprintf(format, argptr); -#else - count = ::vprintf(format, argptr); -#endif - va_end (argptr); - return count; -} - -#ifndef __SYMBIAN32__ // gcc/UIQ doesn't like the debugger code for some reason? Actually get a cc1plus core dump here :) -template <class T> -void Debugger<T>::attach(const char *entry) { - - g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); - - if (entry) { - _errStr = strdup(entry); - } - - _frame_countdown = 1; - _detach_now = false; - _isAttached = true; -} - -template <class T> -void Debugger<T>::detach() { - g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); - - _detach_now = false; - _isAttached = false; -} - -// Temporary execution handler -template <class T> -void Debugger<T>::onFrame() { - if (_frame_countdown == 0) - return; - --_frame_countdown; - - if (!_frame_countdown) { - - preEnter(); - enter(); - postEnter(); - - // Detach if we're finished with the debugger - if (_detach_now) - detach(); - } -} -#endif // of ifndef __SYMBIAN32__ // gcc/UIQ doesn't like the debugger code for some reason? Actually get a cc1plus core dump here :) - -// Main Debugger Loop -template <class T> -void Debugger<T>::enter() { -#if USE_CONSOLE - if (_firstTime) { - DebugPrintf("Debugger started, type 'exit' to return to the game.\n"); - DebugPrintf("Type 'help' to see a little list of commands and variables.\n"); - _firstTime = false; - } - - if (_errStr) { - DebugPrintf("ERROR: %s\n\n", _errStr); - free(_errStr); - _errStr = NULL; - } - - _debuggerDialog->runModal(); -#else - // TODO: compared to the console input, this here is very bare bone. - // For example, no support for tab completion and no history. At least - // we should re-add (optional) support for the readline library. - // Or maybe instead of choosing between a console dialog and stdio, - // we should move that choice into the ConsoleDialog class - that is, - // the console dialog code could be #ifdef'ed to not print to the dialog - // but rather to stdio. This way, we could also reuse the command history - // and tab completion of the console. It would still require a lot of - // work, but at least no dependency on a 3rd party library... - - printf("Debugger entered, please switch to this console for input.\n"); - - int i; - char buf[256]; - - do { - printf("debug> "); - if (!fgets(buf, sizeof(buf), stdin)) - return; - - i = strlen(buf); - while (i > 0 && buf[i - 1] == '\n') - buf[--i] = 0; - - if (i == 0) - continue; - } while (RunCommand(buf)); - -#endif -} - -// Command execution loop -template <class T> -bool Debugger<T>::RunCommand(const char *inputOrig) { - int i = 0, num_params = 0; - const char *param[256]; - char *input = strdup(inputOrig); // One of the rare occasions using strdup is OK (although avoiding strtok might be more elegant here). - - // Parse out any params - char *tok = strtok(input, " "); - if (tok) { - do { - param[num_params++] = tok; - } while ((tok = strtok(NULL, " ")) != NULL); - } else { - param[num_params++] = input; - } - - for (i=0; i < _dcmd_count; i++) { - if (!strcmp(_dcmds[i].name, param[0])) { - bool result = (((T *)this)->*_dcmds[i].function)(num_params, param); - free(input); - return result; - } - } - - // 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, param[0], strlen(_dvars[i].name))) { - if (num_params > 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_BYTE: - *(byte *)_dvars[i].variable = atoi(param[1]); - DebugPrintf("byte%s = %d\n", param[0], *(byte *)_dvars[i].variable); - break; - case DVAR_INT: - *(int32 *)_dvars[i].variable = atoi(param[1]); - DebugPrintf("(int)%s = %d\n", param[0], *(int32 *)_dvars[i].variable); - break; - // Integer Array - case DVAR_INTARRAY: { - char *chr = (char *)strchr(param[0], '['); - if (!chr) { - DebugPrintf("You must access this array as %s[element]\n", param[0]); - } else { - int element = atoi(chr+1); - int32 *var = *(int32 **)_dvars[i].variable; - if (element >= _dvars[i].optional) { - DebugPrintf("%s is out of range (array is %d elements big)\n", param[0], _dvars[i].optional); - } else { - var[element] = atoi(param[1]); - DebugPrintf("(int)%s = %d\n", param[0], var[element]); - } - } - } - break; - default: - DebugPrintf("Failed to set variable %s to %s - unknown type\n", _dvars[i].name, param[1]); - break; - } - } else { - // And again, type-dependent prints/defrefs. The array one is still ugly. - switch (_dvars[i].type) { - // Integer - case DVAR_BYTE: - DebugPrintf("(byte)%s = %d\n", param[0], *(const byte *)_dvars[i].variable); - break; - case DVAR_INT: - DebugPrintf("(int)%s = %d\n", param[0], *(const int32 *)_dvars[i].variable); - break; - // Integer array - case DVAR_INTARRAY: { - const char *chr = strchr(param[0], '['); - if (!chr) { - DebugPrintf("You must access this array as %s[element]\n", param[0]); - } else { - int element = atoi(chr+1); - const int32 *var = *(const int32 **)_dvars[i].variable; - if (element >= _dvars[i].optional) { - DebugPrintf("%s is out of range (array is %d elements big)\n", param[0], _dvars[i].optional); - } else { - DebugPrintf("(int)%s = %d\n", param[0], var[element]); - } - } - } - break; - // String - case DVAR_STRING: - DebugPrintf("(string)%s = %s\n", param[0], ((Common::String *)_dvars[i].variable)->c_str()); - break; - default: - DebugPrintf("%s = (unknown type)\n", param[0]); - break; - } - } - - free(input); - return true; - } - } - - DebugPrintf("Unknown command or variable\n"); - free(input); - return true; -} - -// returns true if something has been completed -// completion has to be delete[]-ed then -template <class T> -bool Debugger<T>::TabComplete(const char *input, char*& completion) { - // very basic tab completion - // for now it just supports command completions - - // adding completions of command parameters would be nice (but hard) :-) - // maybe also give a list of possible command completions? - // (but this will require changes to console) - - if (strchr(input, ' ')) - return false; // already finished the first word - - unsigned int inputlen = strlen(input); - - unsigned int matchlen = 0; - char match[30]; // the max. command name is 30 chars - - for (int i = 0; i < _dcmd_count; i++) { - if (!strncmp(_dcmds[i].name, input, inputlen)) { - unsigned int commandlen = strlen(_dcmds[i].name); - if (commandlen == inputlen) { // perfect match - return false; - } - if (commandlen > inputlen) { // possible match - // no previous match - if (matchlen == 0) { - strcpy(match, _dcmds[i].name + inputlen); - matchlen = commandlen - inputlen; - } else { - // take common prefix of previous match and this command - unsigned int j; - for (j = 0; j < matchlen; j++) { - if (match[j] != _dcmds[i].name[inputlen + j]) break; - } - matchlen = j; - } - if (matchlen == 0) - return false; - } - } - } - if (matchlen == 0) - return false; - - completion = new char[matchlen + 1]; - memcpy(completion, match, matchlen); - completion[matchlen] = 0; - return true; -} - -// Variable registration function -template <class T> -void Debugger<T>::DVar_Register(const char *varname, void *pointer, int type, int optional) { - assert(_dvar_count < ARRAYSIZE(_dvars)); - strcpy(_dvars[_dvar_count].name, varname); - _dvars[_dvar_count].type = type; - _dvars[_dvar_count].variable = pointer; - _dvars[_dvar_count].optional = optional; - - _dvar_count++; -} - -// Command registration function -template <class T> -void Debugger<T>::DCmd_Register(const char *cmdname, DebugProc pointer) { - assert(_dcmd_count < ARRAYSIZE(_dcmds)); - strcpy(_dcmds[_dcmd_count].name, cmdname); - _dcmds[_dcmd_count].function = pointer; - - _dcmd_count++; -} - -template <class T> -bool Debugger<T>::Cmd_DebugFlagsList(int argc, const char **argv) { - const Common::Array<Common::EngineDebugLevel> &debugLevels = Common::listSpecialDebugLevels(); - - DebugPrintf("Engine debug levels:\n"); - DebugPrintf("--------------------\n"); - if (!debugLevels.size()) { - DebugPrintf("No engine debug levels\n"); - return true; - } - for (uint i = 0; i < debugLevels.size(); ++i) { - DebugPrintf("'%s' - Description: %s\n", debugLevels[i].option.c_str(), debugLevels[i].description.c_str()); - } - DebugPrintf("\n"); - return true; -} - -template <class T> -bool Debugger<T>::Cmd_DebugFlagEnable(int argc, const char **argv) { - if (argc < 2) { - DebugPrintf("debugflag_enable <flag>\n"); - } else { - if (Common::enableSpecialDebugLevel(argv[1])) { - DebugPrintf("Enabled debug flag '%s'\n", argv[1]); - } else { - DebugPrintf("Failed to enable debug flag '%s'\n", argv[1]); - } - } - return true; -} - -template <class T> -bool Debugger<T>::Cmd_DebugFlagDisable(int argc, const char **argv) { - if (argc < 2) { - DebugPrintf("debugflag_disable <flag>\n"); - } else { - if (Common::disableSpecialDebugLevel(argv[1])) { - DebugPrintf("Disabled debug flag '%s'\n", argv[1]); - } else { - DebugPrintf("Failed to disable debug flag '%s'\n", argv[1]); - } - } - return true; -} - -// Console handler -#if USE_CONSOLE -template <class T> -bool Debugger<T>::debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon) { - Debugger *debugger = (Debugger *)refCon; - - return debugger->RunCommand(input); -} - - -template <class T> -bool Debugger<T>::debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, char*& completion, void *refCon) { - Debugger *debugger = (Debugger *)refCon; - - return debugger->TabComplete(input, completion); -} - -#endif - -} // End of namespace Common diff --git a/common/debugger.h b/common/debugger.h deleted file mode 100644 index 25ddff8ac2..0000000000 --- a/common/debugger.h +++ /dev/null @@ -1,110 +0,0 @@ -/* ScummVM - Scumm Interpreter - * Copyright (C) 2002-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - */ - -#ifndef COMMON_DEBUGGER_H -#define COMMON_DEBUGGER_H - -namespace GUI { - class ConsoleDialog; -} - -namespace Common { - -// Choose between text console or ScummConsole -#define USE_CONSOLE 1 - -template <class T> -class Debugger { -public: - Debugger(); - virtual ~Debugger(); - - int DebugPrintf(const char *format, ...); - -#ifndef __SYMBIAN32__ // gcc/UIQ doesn't like the debugger code for some reason? Actually get a cc1plus core dump here :) - virtual void onFrame(); - - virtual void attach(const char *entry = 0); -#else - void onFrame() {} - void attach(const char *entry = 0) {} -#endif - bool isAttached() const { return _isAttached; } - -protected: - typedef bool (T::*DebugProc)(int argc, const char **argv); - - enum { - DVAR_BYTE, - 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; - }; - - int _frame_countdown, _dvar_count, _dcmd_count; - DVar _dvars[256]; - DCmd _dcmds[256]; - bool _detach_now; - -private: - bool _isAttached; - char *_errStr; - bool _firstTime; - GUI::ConsoleDialog *_debuggerDialog; - -protected: - void detach(); - void enter(); - - virtual void preEnter() = 0; - virtual void postEnter() = 0; - - bool RunCommand(const char *input); - bool TabComplete(const char *input, char*& completion); - - void DVar_Register(const char *varname, void *pointer, int type, int optional); - void DCmd_Register(const char *cmdname, DebugProc pointer); - - bool Cmd_DebugFlagsList(int argc, const char **argv); - bool Cmd_DebugFlagEnable(int argc, const char **argv); - bool Cmd_DebugFlagDisable(int argc, const char **argv); - -#if USE_CONSOLE - static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon); - static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, char*& completion, void *refCon); -#endif -}; - -} // End of namespace Common - -#endif |