[Scummvm-git-logs] scummvm master -> 82605cc3ac34f589daf8e01d13cd3a9ec10ead34

sev- noreply at scummvm.org
Wed Sep 28 15:07:14 UTC 2022


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
2874f05eb3 DIRECTOR: Implement movie and nextmovie debugger commands
82605cc3ac DIRECTOR: Implement breakpoints


Commit: 2874f05eb3e0cea95e1d473aa0ed43faecc58e3e
    https://github.com/scummvm/scummvm/commit/2874f05eb3e0cea95e1d473aa0ed43faecc58e3e
Author: Scott Percival (code at moral.net.au)
Date: 2022-09-28T17:07:07+02:00

Commit Message:
DIRECTOR: Implement movie and nextmovie debugger commands

Changed paths:
    engines/director/debugger.cpp
    engines/director/debugger.h
    engines/director/window.cpp


diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 2aceab6a9df..72b21e72b6b 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -45,6 +45,8 @@ Debugger::Debugger(): GUI::Debugger() {
 	registerCmd("help", WRAP_METHOD(Debugger, cmdHelp));
 
 	registerCmd("version", WRAP_METHOD(Debugger, cmdVersion));
+	registerCmd("movie", WRAP_METHOD(Debugger, cmdMovie));
+	registerCmd("m", WRAP_METHOD(Debugger, cmdMovie));
 	registerCmd("frame", WRAP_METHOD(Debugger, cmdFrame));
 	registerCmd("f", WRAP_METHOD(Debugger, cmdFrame));
 	registerCmd("channels", WRAP_METHOD(Debugger, cmdChannels));
@@ -52,6 +54,8 @@ Debugger::Debugger(): GUI::Debugger() {
 	registerCmd("cast", WRAP_METHOD(Debugger, cmdCast));
 	registerCmd("nextframe", WRAP_METHOD(Debugger, cmdNextFrame));
 	registerCmd("nf", WRAP_METHOD(Debugger, cmdNextFrame));
+	registerCmd("nextmovie", WRAP_METHOD(Debugger, cmdNextMovie));
+	registerCmd("nm", WRAP_METHOD(Debugger, cmdNextMovie));
 
 	registerCmd("repl", WRAP_METHOD(Debugger, cmdRepl));
 	registerCmd("stack", WRAP_METHOD(Debugger, cmdStack));
@@ -70,7 +74,12 @@ Debugger::Debugger(): GUI::Debugger() {
 	registerCmd("n", WRAP_METHOD(Debugger, cmdNext));
 	registerCmd("finish", WRAP_METHOD(Debugger, cmdFinish));
 	registerCmd("fin", WRAP_METHOD(Debugger, cmdFinish));
+	registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
+	registerCmd("c", WRAP_METHOD(Debugger, cmdExit));
 
+	_nextFrame = false;
+	_nextFrameCounter = 0;
+	_nextMovie = false;
 	_step = false;
 	_stepCounter = 0;
 	_finish = false;
@@ -99,13 +108,13 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
 	debugPrintf("--------\n");
 	debugPrintf("Player:\n");
 	debugPrintf(" version - Shows the Director version\n");
-	//debugPrintf(" movie [moviePath] - Get or sets the current movie\n");
-	//debugPrintf(" movieinfo - Show information for the current movie\n");
+	debugPrintf(" movie / m [moviePath] - Get or sets the current movie\n");
+	//debugPrintf(" movieinfo / mi - Show information for the current movie\n");
 	debugPrintf(" frame / f [frameNum] - Gets or sets the current score frame\n");
 	debugPrintf(" channels / chan [frameNum] - Shows channel information for a score frame\n");
 	debugPrintf(" cast [castNum] - Shows the cast list or castNum for the current movie\n");
 	debugPrintf(" nextframe / nf [n] - Steps forward one or more score frames\n");
-	//debugPrintf(" nextmovie / nm - Steps forward until the next change of movie\n");
+	debugPrintf(" nextmovie / nm - Steps forward until the next change of movie\n");
 	debugPrintf("\n");
 	debugPrintf("Lingo execution:\n");
 	//debugPrintf(" eval [statement] - Evaluates a single Lingo statement\n");
@@ -119,6 +128,7 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
 	debugPrintf(" step / s [n] - Steps forward one or more operations\n");
 	debugPrintf(" next / n [n] - Steps forward one or more operations, skips over calls\n");
 	debugPrintf(" finish / fin - Steps until the current stack frame returns\n");
+	debugPrintf(" continue / c - Continues execution\n");
 	debugPrintf("\n");
 	debugPrintf("Breakpoints:\n");
 	debugPrintf("\n");
@@ -165,6 +175,18 @@ bool Debugger::cmdFrame(int argc, const char **argv) {
 	return true;
 }
 
+bool Debugger::cmdMovie(int argc, const char **argv) {
+	Lingo *lingo = g_director->getLingo();
+	Movie *movie = g_director->getCurrentMovie();
+	if (argc == 2) {
+		Datum frame, mov(argv[1]);
+		lingo->func_goto(frame, mov);
+	} else {
+		debugPrintf("%s\n", movie->getArchive()->getFileName().c_str());
+	}
+	return true;
+}
+
 bool Debugger::cmdChannels(int argc, const char **argv) {
 	Score *score = g_director->getCurrentMovie()->getScore();
 
@@ -223,6 +245,11 @@ bool Debugger::cmdNextFrame(int argc, const char **argv) {
 	return cmdExit(0, nullptr);
 }
 
+bool Debugger::cmdNextMovie(int argc, const char **argv) {
+	_nextMovie = true;
+	return cmdExit(0, nullptr);
+}
+
 bool Debugger::cmdRepl(int argc, const char **argv) {
 	debugPrintf("Switching to Lingo REPL mode, type 'lingo off' to return to the debug console.\n");
 	registerDefaultCmd(WRAP_DEFAULTCOMMAND(Debugger, lingoCommandProcessor));
@@ -413,6 +440,15 @@ void Debugger::frameHook() {
 	}
 }
 
+void Debugger::movieHook() {
+	if (_nextMovie) {
+		_nextMovie = false;
+		cmdMovie(0, nullptr);
+		attach();
+		g_system->updateScreen();
+	}
+}
+
 void Debugger::pushContextHook() {
 	if (_next)
 		_nextCounter++;
diff --git a/engines/director/debugger.h b/engines/director/debugger.h
index aa39940a2bb..8f2eec25152 100644
--- a/engines/director/debugger.h
+++ b/engines/director/debugger.h
@@ -34,6 +34,7 @@ public:
 	void debugLogFile(Common::String logs, bool prompt);
 	void stepHook();
 	void frameHook();
+	void movieHook();
 	void pushContextHook();
 	void popContextHook();
 
@@ -41,10 +42,12 @@ private:
 	bool cmdHelp(int argc, const char **argv);
 
 	bool cmdVersion(int argc, const char **argv);
+	bool cmdMovie(int argc, const char **argv);
 	bool cmdFrame(int argc, const char **argv);
 	bool cmdChannels(int argc, const char **argv);
 	bool cmdCast(int argc, const char **argv);
 	bool cmdNextFrame(int argc, const char **argv);
+	bool cmdNextMovie(int argc, const char **argv);
 	bool cmdRepl(int argc, const char **argv);
 	bool cmdBacktrace(int argc, const char **argv);
 	bool cmdDisasm(int argc, const char **argv);
@@ -64,6 +67,7 @@ private:
 
 	bool _nextFrame;
 	int _nextFrameCounter;
+	bool _nextMovie;
 	bool _step;
 	int _stepCounter;
 	bool _finish;
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 01616ba1819..80e9435d835 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -377,6 +377,7 @@ bool Window::step() {
 					_nextMovie.frameI = -1;
 				}
 
+
 				if (!debugChannelSet(-1, kDebugCompileOnly) && goodMovie) {
 					debugC(1, kDebugEvents, "Starting playback of movie '%s'", _currentMovie->getMacName().c_str());
 					_currentMovie->getScore()->startPlay();
@@ -384,6 +385,7 @@ bool Window::step() {
 						_currentMovie->getScore()->setCurrentFrame(_startFrame);
 						_startFrame = -1;
 					}
+					g_debugger->movieHook();
 				} else {
 					return false;
 				}


Commit: 82605cc3ac34f589daf8e01d13cd3a9ec10ead34
    https://github.com/scummvm/scummvm/commit/82605cc3ac34f589daf8e01d13cd3a9ec10ead34
Author: Scott Percival (code at moral.net.au)
Date: 2022-09-28T17:07:07+02:00

Commit Message:
DIRECTOR: Implement breakpoints

Changed paths:
    engines/director/debugger.cpp
    engines/director/debugger.h
    engines/director/lingo/lingo-code.cpp
    engines/director/lingo/lingo.cpp


diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 72b21e72b6b..a7281c163fd 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -77,6 +77,17 @@ Debugger::Debugger(): GUI::Debugger() {
 	registerCmd("continue", WRAP_METHOD(Debugger, cmdExit));
 	registerCmd("c", WRAP_METHOD(Debugger, cmdExit));
 
+	registerCmd("bpset", WRAP_METHOD(Debugger, cmdBpSet));
+	registerCmd("b", WRAP_METHOD(Debugger, cmdBpSet));
+	registerCmd("bpmovie", WRAP_METHOD(Debugger, cmdBpMovie));
+	registerCmd("bm", WRAP_METHOD(Debugger, cmdBpMovie));
+	registerCmd("bpframe", WRAP_METHOD(Debugger, cmdBpFrame));
+	registerCmd("bf", WRAP_METHOD(Debugger, cmdBpFrame));
+	registerCmd("bpdel", WRAP_METHOD(Debugger, cmdBpDel));
+	registerCmd("bpenable", WRAP_METHOD(Debugger, cmdBpEnable));
+	registerCmd("bpdisable", WRAP_METHOD(Debugger, cmdBpDisable));
+	registerCmd("bplist", WRAP_METHOD(Debugger, cmdBpList));
+
 	_nextFrame = false;
 	_nextFrameCounter = 0;
 	_nextMovie = false;
@@ -88,6 +99,10 @@ Debugger::Debugger(): GUI::Debugger() {
 	_nextCounter = 0;
 	_nextFrame = false;
 	_nextFrameCounter = 0;
+	_bpNextId = 1;
+	_bpCheckFuncName = false;
+	_bpCheckMoviePath = false;
+	_bpNextMovieMatch = false;
 }
 
 Debugger::~Debugger() {
@@ -120,7 +135,7 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
 	//debugPrintf(" eval [statement] - Evaluates a single Lingo statement\n");
 	debugPrintf(" repl - Switches to a REPL interface for evaluating Lingo code\n");
 	debugPrintf(" backtrace / bt - Prints a backtrace of all stack frames\n");
-	debugPrintf(" disasm / da [scriptid:funcname] - Lists the bytecode disassembly for a script function\n");
+	debugPrintf(" disasm / da [scriptId:funcName] - Lists the bytecode disassembly for a script function\n");
 	debugPrintf(" stack / st - Lists the elements on the stack\n");
 	debugPrintf(" scriptframe / sf - Prints the current script frame\n");
 	debugPrintf(" funcs - Lists all of the functions available in the current script frame\n");
@@ -131,16 +146,17 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
 	debugPrintf(" continue / c - Continues execution\n");
 	debugPrintf("\n");
 	debugPrintf("Breakpoints:\n");
-	debugPrintf("\n");
-	//debugPrintf(" bpset [funcname] - Creates a breakpoint on a Lingo function matching a name\n");
-	//debugPrintf(" bpset [funcname] [offset] - Creates a breakpoint on a Lingo function matching a name and offset\n");
-	//debugPrintf(" bpset [scriptid:funcname] - Creates a breakpoint on a Lingo function matching a script ID and name\n");
-	//debugPrintf(" bpset [scriptid:funcname] [offset] - Creates a breakpoint on a Lingo function matching a script ID, name and offset\n");
-	//debugPrintf(" bpframe [frameId] - Create a breakpoint on a frame in the score\n");
-	//debugPrintf(" bpdel [n] - Deletes a specific breakpoint\n");
-	//debugPrintf(" bpenable [n] - Enables a specific breakpoint\n");
-	//debugPrintf(" bpdisable [n] - Disables a specific breakpoint\n");
-	//debugPrintf(" bplist - Lists all breakpoints\n");
+	debugPrintf(" bpset / b [funcName] - Creates a breakpoint on a Lingo function matching a name\n");
+	debugPrintf(" bpset / b [funcName] [offset] - Creates a breakpoint on a Lingo function matching a name and offset\n");
+	debugPrintf(" bpset / b [scriptId:funcName] - Creates a breakpoint on a Lingo function matching a script ID and name\n");
+	debugPrintf(" bpset / b [scriptId:funcName] [offset] - Creates a breakpoint on a Lingo function matching a script ID, name and offset\n");
+	debugPrintf(" bpmovie / bf [moviePath] - Create a breakpoint on a switch to a movie\n");
+	debugPrintf(" bpframe / bf [frameId] - Create a breakpoint on a frame in the score\n");
+	debugPrintf(" bpframe / bf [moviePath] [frameId] - Create a breakpoint on a frame in the score of a specific movie\n");
+	debugPrintf(" bpdel [n] - Deletes a specific breakpoint\n");
+	debugPrintf(" bpenable [n] - Enables a specific breakpoint\n");
+	debugPrintf(" bpdisable [n] - Disables a specific breakpoint\n");
+	debugPrintf(" bplist - Lists all breakpoints\n");
 	return true;
 }
 
@@ -196,10 +212,10 @@ bool Debugger::cmdChannels(int argc, const char **argv) {
 		frameId = atoi(argv[1]);
 
 	if (frameId >= 1 && frameId <= maxSize) {
-		debugPrintf("Channel info for frame %d of %d", frameId, maxSize);
+		debugPrintf("Channel info for frame %d of %d\n", frameId, maxSize);
 		debugPrintf("%s\n", score->_frames[frameId-1]->formatChannelInfo().c_str());
 	} else {
-		debugPrintf("Must specify a frame number between 1 and %d\n", maxSize);
+		debugPrintf("Must specify a frame number between 1 and %d.\n", maxSize);
 	}
 	return true;
 }
@@ -393,6 +409,218 @@ bool Debugger::cmdFinish(int argc, const char **argv) {
 	return cmdExit(0, nullptr);
 }
 
+bool Debugger::cmdBpSet(int argc, const char **argv) {
+	if (argc == 2 || argc == 3) {
+		Breakpoint bp;
+		bp.id = _bpNextId;
+		_bpNextId++;
+		bp.type = kBreakpointFunction;
+		Common::String target(argv[1]);
+		uint splitPoint = target.findFirstOf(":");
+		if (splitPoint == Common::String::npos) {
+			bp.funcName = target;
+		} else {
+			bp.scriptId = atoi(target.substr(0, splitPoint).c_str());
+			bp.funcName = target.substr(splitPoint + 1, Common::String::npos);
+		}
+		if (argc == 3) {
+			bp.funcOffset = atoi(argv[2]);
+		}
+		_breakpoints.push_back(bp);
+		bpUpdateState();
+		debugPrintf("Added %s\n", bp.format().c_str());
+	} else {
+		debugPrintf("Must specify a function name.\n");
+	}
+	return true;
+}
+
+bool Debugger::cmdBpMovie(int argc, const char **argv) {
+	if (argc == 2) {
+		Breakpoint bp;
+		bp.id = _bpNextId;
+		_bpNextId++;
+		bp.type = kBreakpointMovie;
+		bp.moviePath = argv[1];
+		_breakpoints.push_back(bp);
+		bpUpdateState();
+		debugPrintf("Added %s\n", bp.format().c_str());
+	} else {
+		debugPrintf("Must specify a movie path.\n");
+	}
+	return true;
+}
+
+bool Debugger::cmdBpFrame(int argc, const char **argv) {
+	Movie *movie = g_director->getCurrentMovie();
+	if (argc == 2 || argc == 3) {
+		Breakpoint bp;
+		bp.id = _bpNextId;
+		_bpNextId++;
+		bp.type = kBreakpointMovieFrame;
+		Common::String target(argv[1]);
+		if (argc == 3) {
+			bp.moviePath = argv[1];
+			bp.frameOffset = atoi(argv[2]);
+		} else {
+			bp.moviePath = movie->getArchive()->getFileName();
+			bp.frameOffset = atoi(argv[1]);
+		}
+		if (bp.frameOffset == 0) {
+			debugPrintf("Must specify a valid frame ID.\n");
+			return true;
+		}
+		_breakpoints.push_back(bp);
+		bpUpdateState();
+		debugPrintf("Added %s\n", bp.format().c_str());
+	} else {
+		debugPrintf("Must specify a valid frame ID.\n");
+	}
+	return true;
+}
+
+bool Debugger::cmdBpDel(int argc, const char **argv) {
+	if (argc == 2 && atoi(argv[1]) > 0) {
+		bool found = false;
+		for (auto it = _breakpoints.begin(); it != _breakpoints.end(); ++it) {
+			if (it->id == atoi(argv[1])) {
+				it = _breakpoints.erase(it);
+				found = true;
+				bpUpdateState();
+				debugPrintf("Deleted breakpoint %s.\n", argv[1]);
+				break;
+			}
+		}
+		if (!found)
+			debugPrintf("No breakpoint with ID %s.\n", argv[1]);
+	} else {
+		debugPrintf("Must specify a breakpoint ID.\n");
+	}
+	return true;
+}
+
+bool Debugger::cmdBpEnable(int argc, const char **argv) {
+	if (argc == 2 && atoi(argv[1]) > 0) {
+		bool found = false;
+		for (auto it = _breakpoints.begin(); it != _breakpoints.end(); ++it) {
+			if (it->id == atoi(argv[1])) {
+				it->enabled = true;
+				found = true;
+				bpUpdateState();
+				debugPrintf("Enabled breakpoint %s.\n", argv[1]);
+				break;
+			}
+		}
+		if (!found)
+			debugPrintf("No breakpoint with ID %s.\n", argv[1]);
+	} else {
+		debugPrintf("Must specify a breakpoint ID.\n");
+	}
+	return true;
+}
+
+bool Debugger::cmdBpDisable(int argc, const char **argv) {
+	if (argc == 2 && atoi(argv[1]) > 0) {
+		bool found = false;
+		for (auto it = _breakpoints.begin(); it != _breakpoints.end(); ++it) {
+			if (it->id == atoi(argv[1])) {
+				it->enabled = false;
+				found = true;
+				bpUpdateState();
+				debugPrintf("Disabled breakpoint %s.\n", argv[1]);
+				break;
+			}
+		}
+		if (!found)
+			debugPrintf("No breakpoint with ID %s.\n", argv[1]);
+	} else {
+		debugPrintf("Must specify a breakpoint ID.\n");
+	}
+	return true;
+}
+
+bool Debugger::cmdBpList(int argc, const char **argv) {
+	if (_breakpoints.size()) {
+		for (auto &it : _breakpoints) {
+			debugPrintf("%s (%s)\n", it.format().c_str(), it.enabled ? "enabled" : "disabled");
+		}
+	} else {
+		debugPrintf("No breakpoints set.\n");
+	}
+	return true;
+}
+
+void Debugger::bpUpdateState() {
+	_bpCheckFuncName = false;
+	_bpCheckMoviePath = false;
+	_bpNextMovieMatch = false;
+	_bpMatchFuncOffsets.clear();
+	_bpMatchFuncName.clear();
+	_bpMatchMoviePath.clear();
+	_bpMatchFrameOffsets.clear();
+	Movie *movie = g_director->getCurrentMovie();
+	Common::Array<CFrame *> &callstack = g_director->getCurrentWindow()->_callstack;
+	for (auto &it : _breakpoints) {
+		if (!it.enabled)
+			continue;
+		if (it.type == kBreakpointFunction) {
+			_bpCheckFuncName = true;
+			if (!callstack.size())
+				continue;
+			CFrame *head = callstack[callstack.size() - 1];
+			if (!head->sp.name)
+				continue;
+			if (it.funcName.equalsIgnoreCase(*head->sp.name)) {
+				_bpMatchFuncName = it.funcName;
+				_bpMatchFuncOffsets.setVal(it.funcOffset, nullptr);
+			}
+		} else if (it.type == kBreakpointMovie || it.type == kBreakpointMovieFrame) {
+			_bpCheckMoviePath = true;
+			if (it.moviePath.equalsIgnoreCase(movie->getArchive()->getFileName())) {
+				_bpNextMovieMatch |= it.type == kBreakpointMovie;
+				_bpMatchMoviePath = it.moviePath;
+				_bpMatchFrameOffsets.setVal(it.frameOffset, nullptr);
+			}
+		}
+	}
+}
+
+void Debugger::bpTest(bool forceCheck) {
+	bool stop = forceCheck;
+	uint funcOffset = g_lingo->_pc;
+	Score *score = g_director->getCurrentMovie()->getScore();
+	uint frameOffset = score->getCurrentFrame();
+	if (_bpCheckFuncName) {
+		stop |= _bpMatchFuncOffsets.contains(funcOffset);
+	}
+	if (_bpCheckMoviePath) {
+		stop |= _bpMatchFrameOffsets.contains(frameOffset);
+	}
+	if (stop) {
+		debugPrintf("Hit a breakpoint:\n");
+		for (auto &it : _breakpoints) {
+			if (!it.enabled)
+				continue;
+			if (it.type == kBreakpointFunction) {
+				if (it.funcName.equalsIgnoreCase(_bpMatchFuncName) && it.funcOffset == funcOffset)
+					debugPrintf("%s\n", it.format().c_str());
+			} else if (it.type == kBreakpointMovie && _bpNextMovieMatch) {
+				if (it.moviePath.equalsIgnoreCase(_bpMatchMoviePath))
+					debugPrintf("%s\n", it.format().c_str());
+			} else if (it.type == kBreakpointMovieFrame) {
+				if (it.moviePath.equalsIgnoreCase(_bpMatchMoviePath) && it.frameOffset == frameOffset)
+					debugPrintf("%s\n", it.format().c_str());
+			}
+		}
+		// reset all step commands before returning to console
+		_nextMovie = false;
+		_nextFrame = false;
+		cmdScriptFrame(0, nullptr);
+		attach();
+		g_system->updateScreen();
+	}
+}
+
 bool Debugger::lingoCommandProcessor(const char *inputOrig) {
 	if (!strcmp(inputOrig, "lingo off")) {
 		registerDefaultCmd(nullptr);
@@ -410,6 +638,7 @@ bool Debugger::lingoCommandProcessor(const char *inputOrig) {
 }
 
 void Debugger::stepHook() {
+	bpTest();
 	if (_step && _nextCounter == 0) {
 		_stepCounter--;
 		if (_stepCounter == 0) {
@@ -429,6 +658,7 @@ void Debugger::stepHook() {
 }
 
 void Debugger::frameHook() {
+	bpTest();
 	if (_nextFrame) {
 		_nextFrameCounter--;
 		if (_nextFrameCounter == 0) {
@@ -441,6 +671,8 @@ void Debugger::frameHook() {
 }
 
 void Debugger::movieHook() {
+	bpUpdateState();
+	bpTest(_bpNextMovieMatch);
 	if (_nextMovie) {
 		_nextMovie = false;
 		cmdMovie(0, nullptr);
@@ -454,6 +686,7 @@ void Debugger::pushContextHook() {
 		_nextCounter++;
 	if (_finish)
 		_finishCounter++;
+	bpUpdateState();
 }
 
 void Debugger::popContextHook() {
@@ -461,6 +694,25 @@ void Debugger::popContextHook() {
 		_nextCounter--;
 	if (_finish)
 		_finishCounter--;
+	bpUpdateState();
+}
+
+void Debugger::builtinHook(const Symbol &funcSym) {
+	if (!funcSym.name)
+		return;
+	bpUpdateState();
+	bool builtinMatch = false;
+	if (_bpCheckFuncName) {
+		for (auto &it : _breakpoints) {
+			if (it.type != kBreakpointFunction)
+				continue;
+			if (it.funcName.equalsIgnoreCase(*funcSym.name)) {
+				builtinMatch = true;
+				break;
+			}
+		}
+	}
+	bpTest(builtinMatch);
 }
 
 void Debugger::debugLogFile(Common::String logs, bool prompt) {
diff --git a/engines/director/debugger.h b/engines/director/debugger.h
index 8f2eec25152..1f99d428bf0 100644
--- a/engines/director/debugger.h
+++ b/engines/director/debugger.h
@@ -22,11 +22,60 @@
 #ifndef DIRECTOR_DEBUGGER_H
 #define DIRECTOR_DEBUGGER_H
 
+#include "common/array.h"
+#include "common/str.h"
 #include "gui/debugger.h"
 #include "director/director.h"
+#include "director/lingo/lingo.h"
 
 namespace Director {
 
+enum BreakpointType {
+	kBreakpointTypeNull = 0,
+	kBreakpointFunction = 1,
+	kBreakpointMovie = 2,
+	kBreakpointMovieFrame = 3,
+};
+
+struct Breakpoint {
+	bool enabled = true;
+	BreakpointType type = kBreakpointTypeNull;
+	int id = 0;
+
+	uint16 scriptId = 0;
+	Common::String funcName;
+	uint funcOffset = 0;
+	Common::String moviePath;
+	uint frameOffset = 0;
+
+	Common::String format() {
+		Common::String result = Common::String::format("Breakpoint %d, ", id);
+		switch (type) {
+		case kBreakpointFunction:
+			result += "Function ";
+			if (scriptId)
+				result += Common::String::format("%d:", scriptId);
+			result += funcName;
+			if (funcOffset)
+				result += Common::String::format(" [%5d]", funcOffset);
+			break;
+		case kBreakpointMovie:
+			result += "Movie ";
+			result += moviePath;
+			break;
+		case kBreakpointMovieFrame:
+			result += "Movie ";
+			result += moviePath;
+			result += Common::String::format(":%d", frameOffset);
+			break;
+		default:
+			break;
+		}
+		return result;
+	}
+};
+
+
 class Debugger : public GUI::Debugger {
 public:
 	Debugger();
@@ -37,6 +86,7 @@ public:
 	void movieHook();
 	void pushContextHook();
 	void popContextHook();
+	void builtinHook(const Symbol &funcSym);
 
 private:
 	bool cmdHelp(int argc, const char **argv);
@@ -59,6 +109,17 @@ private:
 	bool cmdNext(int argc, const char **argv);
 	bool cmdFinish(int argc, const char **argv);
 
+	bool cmdBpSet(int argc, const char **argv);
+	bool cmdBpMovie(int argc, const char **argv);
+	bool cmdBpFrame(int argc, const char **argv);
+	bool cmdBpDel(int argc, const char **argv);
+	bool cmdBpEnable(int argc, const char **argv);
+	bool cmdBpDisable(int argc, const char **argv);
+	bool cmdBpList(int argc, const char **argv);
+
+	void bpUpdateState();
+	void bpTest(bool forceCheck = false);
+
 	bool lingoCommandProcessor(const char *inputOrig);
 
 
@@ -74,6 +135,16 @@ private:
 	int _finishCounter;
 	bool _next;
 	int _nextCounter;
+
+	Common::Array<Breakpoint> _breakpoints;
+	int _bpNextId;
+	bool _bpCheckFuncName;
+	bool _bpCheckMoviePath;
+	bool _bpNextMovieMatch;
+	Common::String _bpMatchFuncName;
+	Common::String _bpMatchMoviePath;
+	Common::HashMap<uint, void *> _bpMatchFuncOffsets;
+	Common::HashMap<uint, void *> _bpMatchFrameOffsets;
 };
 
 
diff --git a/engines/director/lingo/lingo-code.cpp b/engines/director/lingo/lingo-code.cpp
index c07dc25fba9..d70e7cf9fda 100644
--- a/engines/director/lingo/lingo-code.cpp
+++ b/engines/director/lingo/lingo-code.cpp
@@ -240,7 +240,6 @@ void Lingo::saveStateToWindow() {
 }
 
 void Lingo::pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRetVal) {
-	g_debugger->pushContextHook();
 	Common::Array<CFrame *> &callstack = _vm->getCurrentWindow()->_callstack;
 
 	debugC(5, kDebugLingoExec, "Pushing frame %d", callstack.size() + 1);
@@ -315,6 +314,8 @@ void Lingo::pushContext(const Symbol funcSym, bool allowRetVal, Datum defaultRet
 	if (debugChannelSet(2, kDebugLingoExec)) {
 		g_lingo->printCallStack(0);
 	}
+	g_lingo->_pc = 0;
+	g_debugger->pushContextHook();
 }
 
 void Lingo::popContext(bool aborting) {
@@ -1631,6 +1632,7 @@ void LC::call(const Symbol &funcSym, int nargs, bool allowRetVal) {
 	}
 
 	if (funcSym.type != HANDLER) {
+		g_debugger->builtinHook(funcSym);
 		uint stackSizeBefore = g_lingo->_stack.size() - nargs;
 
 		if (target.type != VOID) {
@@ -1670,8 +1672,6 @@ void LC::call(const Symbol &funcSym, int nargs, bool allowRetVal) {
 	}
 
 	g_lingo->pushContext(funcSym, allowRetVal, defaultRetVal);
-
-	g_lingo->_pc = 0;
 }
 
 void LC::c_procret() {
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index 2c615d041f9..57b23a5b699 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -356,7 +356,7 @@ void Lingo::printStack(const char *s, uint pc) {
 	Common::String stack(s);
 	stack += formatStack();
 
-	debugC(5, kDebugLingoExec, "[%3d]: %s", pc, stack.c_str());
+	debugC(5, kDebugLingoExec, "[%5d]: %s", pc, stack.c_str());
 }
 
 Common::String Lingo::formatCallStack(uint pc) {
@@ -404,7 +404,7 @@ Common::String Lingo::formatFrame() {
 		result += "[unknown]";
 	else
 		result += frame->sp.name->c_str();
-	result += Common::String::format(" at [%3d]", _pc);
+	result += Common::String::format(" at [%5d]", _pc);
 	return result;
 }
 
@@ -412,7 +412,7 @@ Common::String Lingo::formatCurrentInstruction() {
 	Common::String instr = decodeInstruction(_currentScript, _pc);
 	if (instr.empty())
 		return instr;
-	return Common::String::format("[%3d]: %s", _pc, instr.c_str());
+	return Common::String::format("[%5d]: %s", _pc, instr.c_str());
 }
 
 Common::String Lingo::decodeInstruction(ScriptData *sd, uint pc, uint *newPc) {
@@ -565,7 +565,7 @@ void Lingo::execute() {
 
 		if (debugChannelSet(3, kDebugLingoExec)) {
 			Common::String instr = decodeInstruction(_currentScript, _pc);
-			debugC(3, kDebugLingoExec, "[%3d]: %s", current, instr.c_str());
+			debugC(3, kDebugLingoExec, "[%5d]: %s", current, instr.c_str());
 		}
 
 		g_debugger->stepHook();




More information about the Scummvm-git-logs mailing list