Turned fixed-size lists of debugger/console commands and variables into more flexible data structures
svn-id: r40458
This commit is contained in:
parent
e3e3fbd7d1
commit
95a4b26efe
4 changed files with 80 additions and 83 deletions
|
@ -327,14 +327,13 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
|
||||||
str[i] = buffer(_promptStartPos + i);
|
str[i] = buffer(_promptStartPos + i);
|
||||||
str[len] = '\0';
|
str[len] = '\0';
|
||||||
|
|
||||||
char *completion = 0;
|
Common::String completion;
|
||||||
if ((*_completionCallbackProc)(this, str, completion, _callbackRefCon)) {
|
if ((*_completionCallbackProc)(this, str, completion, _callbackRefCon)) {
|
||||||
if (_caretVisible)
|
if (_caretVisible)
|
||||||
drawCaret(true);
|
drawCaret(true);
|
||||||
insertIntoPrompt(completion);
|
insertIntoPrompt(completion.c_str());
|
||||||
scrollToCurrent();
|
scrollToCurrent();
|
||||||
drawLine(pos2line(_currentPos));
|
drawLine(pos2line(_currentPos));
|
||||||
delete[] completion;
|
|
||||||
}
|
}
|
||||||
delete[] str;
|
delete[] str;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ class ScrollBarWidget;
|
||||||
implement this simple rewrapping -- we currently don't do that at all!).
|
implement this simple rewrapping -- we currently don't do that at all!).
|
||||||
|
|
||||||
Or, one can go and implement a more complete console, by replacing the
|
Or, one can go and implement a more complete console, by replacing the
|
||||||
_buffer by a real line buffer -- an arrach of char* pointers.
|
_buffer by a real line buffer -- an array of char* pointers.
|
||||||
This will allow one to implement resizing perfectly, but has the drawback
|
This will allow one to implement resizing perfectly, but has the drawback
|
||||||
of making things like scrolling, drawing etc. more complicated.
|
of making things like scrolling, drawing etc. more complicated.
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class ScrollBarWidget;
|
||||||
class ConsoleDialog : public Dialog {
|
class ConsoleDialog : public Dialog {
|
||||||
public:
|
public:
|
||||||
typedef bool (*InputCallbackProc)(ConsoleDialog *console, const char *input, void *refCon);
|
typedef bool (*InputCallbackProc)(ConsoleDialog *console, const char *input, void *refCon);
|
||||||
typedef bool (*CompletionCallbackProc)(ConsoleDialog* console, const char *input, char*& completion, void *refCon);
|
typedef bool (*CompletionCallbackProc)(ConsoleDialog* console, const char *input, Common::String &completion, void *refCon);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum {
|
enum {
|
||||||
|
|
123
gui/debugger.cpp
123
gui/debugger.cpp
|
@ -35,8 +35,6 @@ namespace GUI {
|
||||||
|
|
||||||
Debugger::Debugger() {
|
Debugger::Debugger() {
|
||||||
_frame_countdown = 0;
|
_frame_countdown = 0;
|
||||||
_dvar_count = 0;
|
|
||||||
_dcmd_count = 0;
|
|
||||||
_detach_now = false;
|
_detach_now = false;
|
||||||
_isAttached = false;
|
_isAttached = false;
|
||||||
_errStr = NULL;
|
_errStr = NULL;
|
||||||
|
@ -57,10 +55,6 @@ Debugger::Debugger() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Debugger::~Debugger() {
|
Debugger::~Debugger() {
|
||||||
for (int i = 0; i < _dcmd_count; i++) {
|
|
||||||
delete _dcmds[i].debuglet;
|
|
||||||
_dcmds[i].debuglet = 0;
|
|
||||||
}
|
|
||||||
delete _debuggerDialog;
|
delete _debuggerDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,13 +161,11 @@ void Debugger::enter() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Debugger::handleCommand(int argc, const char **argv, bool &result) {
|
bool Debugger::handleCommand(int argc, const char **argv, bool &result) {
|
||||||
for (int i = 0; i < _dcmd_count; ++i) {
|
if (_cmds.contains(argv[0])) {
|
||||||
if (!strcmp(_dcmds[i].name, argv[0])) {
|
Debuglet *debuglet = _cmds[argv[0]].get();
|
||||||
Debuglet *debuglet = _dcmds[i].debuglet;
|
assert(debuglet);
|
||||||
assert(debuglet);
|
result = (*debuglet)(argc, argv);
|
||||||
result = (*debuglet)(argc, argv);
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -181,7 +173,7 @@ bool Debugger::handleCommand(int argc, const char **argv, bool &result) {
|
||||||
|
|
||||||
// Command execution loop
|
// Command execution loop
|
||||||
bool Debugger::parseCommand(const char *inputOrig) {
|
bool Debugger::parseCommand(const char *inputOrig) {
|
||||||
int i = 0, num_params = 0;
|
int num_params = 0;
|
||||||
const char *param[256];
|
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).
|
char *input = strdup(inputOrig); // One of the rare occasions using strdup is OK (although avoiding strtok might be more elegant here).
|
||||||
|
|
||||||
|
@ -203,8 +195,8 @@ bool Debugger::parseCommand(const char *inputOrig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// It's not a command, so things get a little tricky for variables. Do fuzzy matching to ignore things like subscripts.
|
// 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++) {
|
for (uint i = 0; i < _dvars.size(); i++) {
|
||||||
if (!strncmp(_dvars[i].name, param[0], strlen(_dvars[i].name))) {
|
if (!strncmp(_dvars[i].name.c_str(), param[0], _dvars[i].name.size())) {
|
||||||
if (num_params > 1) {
|
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 :)
|
// 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) {
|
switch (_dvars[i].type) {
|
||||||
|
@ -235,7 +227,7 @@ bool Debugger::parseCommand(const char *inputOrig) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DebugPrintf("Failed to set variable %s to %s - unknown type\n", _dvars[i].name, param[1]);
|
DebugPrintf("Failed to set variable %s to %s - unknown type\n", _dvars[i].name.c_str(), param[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -286,7 +278,7 @@ bool Debugger::parseCommand(const char *inputOrig) {
|
||||||
|
|
||||||
// returns true if something has been completed
|
// returns true if something has been completed
|
||||||
// completion has to be delete[]-ed then
|
// completion has to be delete[]-ed then
|
||||||
bool Debugger::tabComplete(const char *input, char*& completion) {
|
bool Debugger::tabComplete(const char *input, Common::String &completion) const {
|
||||||
// very basic tab completion
|
// very basic tab completion
|
||||||
// for now it just supports command completions
|
// for now it just supports command completions
|
||||||
|
|
||||||
|
@ -297,63 +289,61 @@ bool Debugger::tabComplete(const char *input, char*& completion) {
|
||||||
if (strchr(input, ' '))
|
if (strchr(input, ' '))
|
||||||
return false; // already finished the first word
|
return false; // already finished the first word
|
||||||
|
|
||||||
unsigned int inputlen = strlen(input);
|
const uint inputlen = strlen(input);
|
||||||
|
|
||||||
unsigned int matchlen = 0;
|
completion.clear();
|
||||||
char match[30]; // the max. command name is 30 chars
|
|
||||||
|
|
||||||
for (int i = 0; i < _dcmd_count; i++) {
|
CommandsMap::const_iterator i, e = _cmds.end();
|
||||||
if (!strncmp(_dcmds[i].name, input, inputlen)) {
|
for (i = _cmds.begin(); i != e; ++i) {
|
||||||
unsigned int commandlen = strlen(_dcmds[i].name);
|
if (i->_key.hasPrefix(input)) {
|
||||||
if (commandlen == inputlen) { // perfect match
|
uint commandlen = i->_key.size();
|
||||||
|
if (commandlen == inputlen) { // perfect match, so no tab completion possible
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (commandlen > inputlen) { // possible match
|
if (commandlen > inputlen) { // possible match
|
||||||
// no previous match
|
// no previous match
|
||||||
if (matchlen == 0) {
|
if (completion.empty()) {
|
||||||
strcpy(match, _dcmds[i].name + inputlen);
|
completion = i->_key.c_str() + inputlen;
|
||||||
matchlen = commandlen - inputlen;
|
|
||||||
} else {
|
} else {
|
||||||
// take common prefix of previous match and this command
|
// take common prefix of previous match and this command
|
||||||
unsigned int j;
|
for (uint j = 0; j < completion.size(); j++) {
|
||||||
for (j = 0; j < matchlen; j++) {
|
if (completion[j] != i->_key[inputlen + j]) {
|
||||||
if (match[j] != _dcmds[i].name[inputlen + j]) break;
|
completion = Common::String(completion.begin(), completion.begin() + j);
|
||||||
|
// If there is no unambiguous completion, abort
|
||||||
|
if (completion.empty())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
matchlen = j;
|
|
||||||
}
|
}
|
||||||
if (matchlen == 0)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (matchlen == 0)
|
if (completion.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
completion = new char[matchlen + 1];
|
|
||||||
memcpy(completion, match, matchlen);
|
|
||||||
completion[matchlen] = 0;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variable registration function
|
// Variable registration function
|
||||||
void Debugger::DVar_Register(const char *varname, void *pointer, int type, int optional) {
|
void Debugger::DVar_Register(const Common::String &varname, void *pointer, int type, int optional) {
|
||||||
assert(_dvar_count < ARRAYSIZE(_dvars));
|
// TODO: Filter out duplicates
|
||||||
strcpy(_dvars[_dvar_count].name, varname);
|
// TODO: Sort this list? Then we can do binary search later on when doing lookups.
|
||||||
_dvars[_dvar_count].type = type;
|
assert(pointer);
|
||||||
_dvars[_dvar_count].variable = pointer;
|
|
||||||
_dvars[_dvar_count].optional = optional;
|
|
||||||
|
|
||||||
_dvar_count++;
|
DVar tmp;
|
||||||
|
tmp.name = varname;
|
||||||
|
tmp.type = type;
|
||||||
|
tmp.variable = pointer;
|
||||||
|
tmp.optional = optional;
|
||||||
|
|
||||||
|
_dvars.push_back(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Command registration function
|
// Command registration function
|
||||||
void Debugger::DCmd_Register(const char *cmdname, Debuglet *debuglet) {
|
void Debugger::DCmd_Register(const Common::String &cmdname, Debuglet *debuglet) {
|
||||||
assert(debuglet->isValid());
|
assert(debuglet && debuglet->isValid());
|
||||||
assert(_dcmd_count < ARRAYSIZE(_dcmds));
|
_cmds[cmdname] = Common::SharedPtr<Debuglet>(debuglet);
|
||||||
strcpy(_dcmds[_dcmd_count].name, cmdname);
|
|
||||||
_dcmds[_dcmd_count].debuglet = debuglet;
|
|
||||||
|
|
||||||
_dcmd_count++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -368,12 +358,23 @@ bool Debugger::Cmd_Exit(int argc, const char **argv) {
|
||||||
bool Debugger::Cmd_Help(int argc, const char **argv) {
|
bool Debugger::Cmd_Help(int argc, const char **argv) {
|
||||||
|
|
||||||
const int charsPerLine = _debuggerDialog->getCharsPerLine();
|
const int charsPerLine = _debuggerDialog->getCharsPerLine();
|
||||||
int width, size, i;
|
int width, size;
|
||||||
|
uint i;
|
||||||
|
|
||||||
DebugPrintf("Commands are:\n");
|
DebugPrintf("Commands are:\n");
|
||||||
|
|
||||||
|
// Obtain a list of sorted command names
|
||||||
|
Common::StringList cmds;
|
||||||
|
CommandsMap::const_iterator iter, e = _cmds.end();
|
||||||
|
for (iter = _cmds.begin(); iter != e; ++iter) {
|
||||||
|
cmds.push_back(iter->_key);
|
||||||
|
}
|
||||||
|
sort(cmds.begin(), cmds.end());
|
||||||
|
|
||||||
|
// Print them all
|
||||||
width = 0;
|
width = 0;
|
||||||
for (i = 0; i < _dcmd_count; i++) {
|
for (i = 0; i < cmds.size(); i++) {
|
||||||
size = strlen(_dcmds[i].name) + 1;
|
size = cmds[i].size() + 1;
|
||||||
|
|
||||||
if ((width + size) >= charsPerLine) {
|
if ((width + size) >= charsPerLine) {
|
||||||
DebugPrintf("\n");
|
DebugPrintf("\n");
|
||||||
|
@ -381,16 +382,16 @@ bool Debugger::Cmd_Help(int argc, const char **argv) {
|
||||||
} else
|
} else
|
||||||
width += size;
|
width += size;
|
||||||
|
|
||||||
DebugPrintf("%s ", _dcmds[i].name);
|
DebugPrintf("%s ", cmds[i].c_str());
|
||||||
}
|
}
|
||||||
DebugPrintf("\n");
|
DebugPrintf("\n");
|
||||||
|
|
||||||
if (_dvar_count > 0) {
|
if (!_dvars.empty()) {
|
||||||
DebugPrintf("\n");
|
DebugPrintf("\n");
|
||||||
DebugPrintf("Variables are:\n");
|
DebugPrintf("Variables are:\n");
|
||||||
width = 0;
|
width = 0;
|
||||||
for (i = 0; i < _dvar_count; i++) {
|
for (i = 0; i < _dvars.size(); i++) {
|
||||||
size = strlen(_dvars[i].name) + 1;
|
size = _dvars[i].name.size() + 1;
|
||||||
|
|
||||||
if ((width + size) >= charsPerLine) {
|
if ((width + size) >= charsPerLine) {
|
||||||
DebugPrintf("\n");
|
DebugPrintf("\n");
|
||||||
|
@ -398,7 +399,7 @@ bool Debugger::Cmd_Help(int argc, const char **argv) {
|
||||||
} else
|
} else
|
||||||
width += size;
|
width += size;
|
||||||
|
|
||||||
DebugPrintf("%s ", _dvars[i].name);
|
DebugPrintf("%s ", _dvars[i].name.c_str());
|
||||||
}
|
}
|
||||||
DebugPrintf("\n");
|
DebugPrintf("\n");
|
||||||
}
|
}
|
||||||
|
@ -459,7 +460,7 @@ bool Debugger::debuggerInputCallback(GUI::ConsoleDialog *console, const char *in
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Debugger::debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, char*& completion, void *refCon) {
|
bool Debugger::debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon) {
|
||||||
Debugger *debugger = (Debugger *)refCon;
|
Debugger *debugger = (Debugger *)refCon;
|
||||||
|
|
||||||
return debugger->tabComplete(input, completion);
|
return debugger->tabComplete(input, completion);
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
#define GUI_DEBUGGER_H
|
#define GUI_DEBUGGER_H
|
||||||
|
|
||||||
#include "common/func.h"
|
#include "common/func.h"
|
||||||
|
#include "common/ptr.h"
|
||||||
|
#include "common/hashmap.h"
|
||||||
|
#include "common/hash-str.h"
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
|
@ -51,7 +54,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
typedef Common::Functor2<int, const char **, bool> Debuglet;
|
typedef Common::Functor2<int, const char **, bool> Debuglet;
|
||||||
|
|
||||||
// Convenicence macro for registering a method of a debugger class
|
// Convenience macro for registering a method of a debugger class
|
||||||
// as the current command.
|
// as the current command.
|
||||||
#define WRAP_METHOD(cls, method) \
|
#define WRAP_METHOD(cls, method) \
|
||||||
new Common::Functor2Mem<int, const char **, bool, cls>(this, &cls::method)
|
new Common::Functor2Mem<int, const char **, bool, cls>(this, &cls::method)
|
||||||
|
@ -65,26 +68,20 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DVar {
|
struct DVar {
|
||||||
char name[30];
|
Common::String name;
|
||||||
void *variable;
|
void *variable;
|
||||||
int type, optional;
|
int type;
|
||||||
};
|
int optional;
|
||||||
|
|
||||||
struct DCmd {
|
|
||||||
char name[30];
|
|
||||||
Debuglet *debuglet;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int _frame_countdown;
|
int _frame_countdown;
|
||||||
bool _detach_now;
|
bool _detach_now;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO: Consider replacing the following two arrays by a Hashmap
|
Common::Array<DVar> _dvars;
|
||||||
int _dvar_count;
|
|
||||||
DVar _dvars[256];
|
|
||||||
|
|
||||||
int _dcmd_count;
|
typedef Common::HashMap<Common::String, Common::SharedPtr<Debuglet>, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> CommandsMap;
|
||||||
DCmd _dcmds[256];
|
CommandsMap _cmds;
|
||||||
|
|
||||||
bool _isAttached;
|
bool _isAttached;
|
||||||
char *_errStr;
|
char *_errStr;
|
||||||
|
@ -109,11 +106,11 @@ private:
|
||||||
void enter();
|
void enter();
|
||||||
|
|
||||||
bool parseCommand(const char *input);
|
bool parseCommand(const char *input);
|
||||||
bool tabComplete(const char *input, char*& completion);
|
bool tabComplete(const char *input, Common::String &completion) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void DVar_Register(const char *varname, void *pointer, int type, int optional);
|
void DVar_Register(const Common::String &varname, void *pointer, int type, int optional);
|
||||||
void DCmd_Register(const char *cmdname, Debuglet *debuglet);
|
void DCmd_Register(const Common::String &cmdname, Debuglet *debuglet);
|
||||||
|
|
||||||
bool Cmd_Exit(int argc, const char **argv);
|
bool Cmd_Exit(int argc, const char **argv);
|
||||||
bool Cmd_Help(int argc, const char **argv);
|
bool Cmd_Help(int argc, const char **argv);
|
||||||
|
@ -124,7 +121,7 @@ protected:
|
||||||
#if USE_CONSOLE
|
#if USE_CONSOLE
|
||||||
private:
|
private:
|
||||||
static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon);
|
static bool debuggerInputCallback(GUI::ConsoleDialog *console, const char *input, void *refCon);
|
||||||
static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, char*& completion, void *refCon);
|
static bool debuggerCompletionCallback(GUI::ConsoleDialog *console, const char *input, Common::String &completion, void *refCon);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue