From c7d631cb6697a4c8c6d9cc0e32caba79f9f7b922 Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sun, 28 May 2017 22:39:41 +0200 Subject: 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. --- engines/sci/console.cpp | 17 ++++++------- engines/sci/engine/scriptdebug.cpp | 51 ++++++++++++++++++++++++++++++++++---- engines/sci/engine/scriptdebug.h | 2 ++ 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 []\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 -- cgit v1.2.3