aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWillem Jan Palenstijn2017-05-28 22:39:41 +0200
committerWillem Jan Palenstijn2017-06-10 21:32:35 +0200
commitc7d631cb6697a4c8c6d9cc0e32caba79f9f7b922 (patch)
tree707d44999386ee59930dd7ad2e8dcb608db620bd
parente7b6a257b95fd19055d0df22afcbceb614ab1899 (diff)
downloadscummvm-rg350-c7d631cb6697a4c8c6d9cc0e32caba79f9f7b922.tar.gz
scummvm-rg350-c7d631cb6697a4c8c6d9cc0e32caba79f9f7b922.tar.bz2
scummvm-rg350-c7d631cb6697a4c8c6d9cc0e32caba79f9f7b922.zip
SCI: Expand kernel breakpoint pattern matching for negative matches
See matchKernelBreakpointPattern() for samples. The main envisioned use is DoSound*,!DoSoundUpdateCues to match all DoSound sub-functions except DoSoundUpdateCues.
-rw-r--r--engines/sci/console.cpp17
-rw-r--r--engines/sci/engine/scriptdebug.cpp51
-rw-r--r--engines/sci/engine/scriptdebug.h2
3 files changed, 56 insertions, 14 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 701f08b97e..4508854d10 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -3993,6 +3993,9 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
debugPrintf("Sets a breakpoint on execution of a kernel function.\n");
debugPrintf("Usage: %s <name> [<action>]\n", argv[0]);
debugPrintf("Example: %s DrawPic\n", argv[0]);
+ debugPrintf(" %s DoSoundPlay,DoSoundStop\n", argv[0]);
+ debugPrintf(" %s DoSound*\n", argv[0]);
+ debugPrintf(" %s DoSound*,!DoSoundUpdateCues\n", argv[0]);
debugPrintf(" %s DrawPic log\n", argv[0]);
debugPrintf("See bp_action usage for possible actions.\n");
return true;
@@ -4008,11 +4011,7 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
}
// Check if any kernel functions match, to catch typos
- Common::String name = argv[1];
- bool wildcard = name.lastChar() == '*';
- Common::String prefix = name;
- if (wildcard)
- prefix.deleteLastChar();
+ Common::String pattern = argv[1];
bool found = false;
const Kernel::KernelFunctionArray &kernelFuncs = _engine->getKernel()->_kernelFuncs;
for (uint id = 0; id < kernelFuncs.size() && !found; id++) {
@@ -4020,14 +4019,14 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
const KernelSubFunction *kernelSubCall = kernelFuncs[id].subFunctions;
if (!kernelSubCall) {
Common::String kname = kernelFuncs[id].name;
- if (name == kname || (wildcard && kname.hasPrefix(prefix)))
+ if (matchKernelBreakpointPattern(pattern, kname))
found = true;
} else {
uint kernelSubCallCount = kernelFuncs[id].subFunctionCount;
for (uint subId = 0; subId < kernelSubCallCount; subId++) {
if (kernelSubCall->name) {
Common::String kname = kernelSubCall->name;
- if (name == kname || (wildcard && kname.hasPrefix(prefix)))
+ if (matchKernelBreakpointPattern(pattern, kname))
found = true;
}
kernelSubCall++;
@@ -4036,13 +4035,13 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
}
}
if (!found) {
- debugPrintf("No kernel functions match %s.\n", name.c_str());
+ debugPrintf("No kernel functions match %s.\n", pattern.c_str());
return true;
}
Breakpoint bp;
bp._type = BREAK_KERNEL;
- bp._name = name;
+ bp._name = pattern;
bp._action = action;
_debugState._breakpoints.push_back(bp);
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index faf3411885..a15725e894 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -30,6 +30,8 @@
#include "sci/engine/script.h"
#include "sci/engine/scriptdebug.h"
+#include "common/algorithm.h"
+
namespace Sci {
//#define VM_DEBUG_SEND
@@ -782,6 +784,49 @@ bool SciEngine::checkAddressBreakpoint(const reg32_t &address) {
return found;
}
+bool matchKernelBreakpointPattern(const Common::String &pattern, const Common::String &name) {
+ // Pattern:
+ // A comma-separated list of atoms.
+ // An atom is a (possibly empty) word, optionally with a ! prefix (for
+ // a negative-match), and/or a * suffix (for a prefix-match).
+
+ // The last matching atom in the pattern takes effect.
+
+ // Examples:
+ // FrameOut : matches only FrameOut
+ // * : matches everything
+ // *,!FrameOut : matches everything except FrameOut
+ // InitBresen,DoBresen : matches InitBresen and DoBresen
+ // DoSound*,!DoSoundUpdateCues : matches all DoSound sub-functions except
+ // DoSoundUpdateCues
+
+ bool result = false;
+
+ Common::String::const_iterator i = pattern.begin();
+ while (i != pattern.end()) {
+ Common::String::const_iterator next = Common::find(i, pattern.end(), ',');
+ bool negative = *i == '!';
+
+ if (negative)
+ i++;
+
+ Common::String atom(i, next - i);
+
+ bool wildcard = atom.lastChar() == '*';
+ if (wildcard)
+ atom.deleteLastChar();
+
+ if ((!wildcard && atom == name) || (wildcard && name.hasPrefix(atom)))
+ result = !negative;
+
+ i = next;
+ if (i != pattern.end())
+ ++i; // skip comma
+ }
+
+ return result;
+}
+
bool SciEngine::checkKernelBreakpoint(const Common::String &name) {
if (!(_debugState._activeBreakpointTypes & BREAK_KERNEL))
return false;
@@ -793,11 +838,7 @@ bool SciEngine::checkKernelBreakpoint(const Common::String &name) {
if (bp->_action == BREAK_NONE || bp->_type != BREAK_KERNEL)
continue;
- bool wildcard = bp->_name.lastChar() == '*';
- Common::String prefix = bp->_name;
- if (wildcard)
- prefix.deleteLastChar();
- if (bp->_name == name || (wildcard && name.hasPrefix(prefix))) {
+ if (matchKernelBreakpointPattern(bp->_name, name)) {
if (bp->_action == BREAK_BREAK) {
if (!found)
_console->debugPrintf("Break on k%s\n", name.c_str());
diff --git a/engines/sci/engine/scriptdebug.h b/engines/sci/engine/scriptdebug.h
index f8930998e2..5e927efaf1 100644
--- a/engines/sci/engine/scriptdebug.h
+++ b/engines/sci/engine/scriptdebug.h
@@ -39,6 +39,8 @@ void logBacktrace();
bool printObject(reg_t obj);
+bool matchKernelBreakpointPattern(const Common::String &pattern, const Common::String &name);
+
}
#endif