From: <m97...@us...> - 2006-09-22 19:01:19
|
Revision: 5677 http://svn.sourceforge.net/openmsx/?rev=5677&view=rev Author: m9710797 Date: 2006-09-22 12:00:57 -0700 (Fri, 22 Sep 2006) Log Message: ----------- also made Commands recordable (was SimpleCommands) / record 'debug write' command Modified Paths: -------------- openmsx/trunk/ChangeLog openmsx/trunk/src/debugger/Debugger.cc openmsx/trunk/src/events/InputEvents.cc openmsx/trunk/src/events/InputEvents.hh openmsx/trunk/src/fdc/DiskChanger.cc openmsx/trunk/src/fdc/DiskChanger.hh openmsx/trunk/src/input/RecordedCommand.cc openmsx/trunk/src/input/RecordedCommand.hh Modified: openmsx/trunk/ChangeLog =================================================================== --- openmsx/trunk/ChangeLog 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/ChangeLog 2006-09-22 19:00:57 UTC (rev 5677) @@ -1,6 +1,11 @@ $Id$ -2006-09-20 Wouter Vermaelen <wou...@sc...> +2006-09-22 Wouter Vermaelen <wou...@sc...> + * Made Command's also Recordable (was only SimpleCommand's) + * record 'debug write' commands: + - record/replay now also works when trainers are used + +2006-09-21 Wouter Vermaelen <wou...@sc...> * Made 'hda', 'cda', 'type', 'keymatrixup' and 'keymatrixdown' commands recorded * Changed format of event recorder to also allow ':' characters in Modified: openmsx/trunk/src/debugger/Debugger.cc =================================================================== --- openmsx/trunk/src/debugger/Debugger.cc 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/debugger/Debugger.cc 2006-09-22 19:00:57 UTC (rev 5677) @@ -9,7 +9,7 @@ #include "MSXWatchIODevice.hh" #include "TclObject.hh" #include "CommandController.hh" -#include "Command.hh" +#include "RecordedCommand.hh" #include "CommandException.hh" #include "StringOp.hh" #include <cassert> @@ -26,13 +26,15 @@ namespace openmsx { -class DebugCmd : public Command +class DebugCmd : public RecordedCommand { public: DebugCmd(CommandController& commandController, - Debugger& debugger); + MSXEventDistributor& msxEventDistributor, + Scheduler& scheduler, Debugger& debugger); + virtual bool needRecord(const vector<TclObject*>& tokens) const; virtual void execute(const vector<TclObject*>& tokens, - TclObject& result); + TclObject& result, const EmuTime& time); virtual string help(const vector<string>& tokens) const; virtual void tabCompletion(vector<string>& tokens) const; @@ -71,7 +73,9 @@ Debugger::Debugger(MSXMotherBoard& motherBoard_) : motherBoard(motherBoard_) - , debugCmd(new DebugCmd(motherBoard.getCommandController(), *this)) + , debugCmd(new DebugCmd(motherBoard.getCommandController(), + motherBoard.getMSXEventDistributor(), + motherBoard.getScheduler(), *this)) , cpu(0) { } @@ -139,15 +143,24 @@ return addr; } -DebugCmd::DebugCmd(CommandController& commandController_, - Debugger& debugger_) - : Command(commandController_, "debug") +DebugCmd::DebugCmd(CommandController& commandController, + MSXEventDistributor& msxEventDistributor, + Scheduler& scheduler, Debugger& debugger_) + : RecordedCommand(commandController, msxEventDistributor, + scheduler, "debug") , debugger(debugger_) { } +bool DebugCmd::needRecord(const vector<TclObject*>& tokens) const +{ + if (tokens.size() < 2) return false; + string subCmd = tokens[1]->getString(); + return (subCmd == "write") || (subCmd == "write_block"); +} + void DebugCmd::execute(const vector<TclObject*>& tokens, - TclObject& result) + TclObject& result, const EmuTime& /*time*/) { if (tokens.size() < 2) { throw CommandException("Missing argument"); Modified: openmsx/trunk/src/events/InputEvents.cc =================================================================== --- openmsx/trunk/src/events/InputEvents.cc 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/events/InputEvents.cc 2006-09-22 19:00:57 UTC (rev 5677) @@ -374,19 +374,43 @@ MSXCommandEvent::MSXCommandEvent(const vector<string>& tokens_) : InputEvent(OPENMSX_MSX_COMMAND_EVENT) + , owned(true) +{ + for (vector<string>::const_iterator it = tokens_.begin(); + it != tokens_.end(); ++it) { + tokens.push_back(new TclObject(0, *it)); + } +} + +MSXCommandEvent::MSXCommandEvent(const vector<TclObject*>& tokens_) + : InputEvent(OPENMSX_MSX_COMMAND_EVENT) , tokens(tokens_) + , owned(false) { } -const vector<string>& MSXCommandEvent::getTokens() const +MSXCommandEvent::~MSXCommandEvent() { + if (owned) { + for (vector<TclObject*>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + delete *it; + } + } +} + +const vector<TclObject*>& MSXCommandEvent::getTokens() const +{ return tokens; } void MSXCommandEvent::toStringImpl(TclObject& result) const { result.addListElement("command"); - result.addListElements(tokens.begin(), tokens.end()); + for (vector<TclObject*>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + result.addListElement(**it); + } } bool MSXCommandEvent::lessImpl(const InputEvent& other) const Modified: openmsx/trunk/src/events/InputEvents.hh =================================================================== --- openmsx/trunk/src/events/InputEvents.hh 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/events/InputEvents.hh 2006-09-22 19:00:57 UTC (rev 5677) @@ -213,11 +213,14 @@ { public: MSXCommandEvent(const std::vector<std::string>& tokens); - const std::vector<std::string>& getTokens() const; + MSXCommandEvent(const std::vector<TclObject*>& tokens); + virtual ~MSXCommandEvent(); + const std::vector<TclObject*>& getTokens() const; private: virtual void toStringImpl(TclObject& result) const; virtual bool lessImpl(const InputEvent& other) const; - const std::vector<std::string> tokens; + std::vector<TclObject*> tokens; + bool owned; }; Modified: openmsx/trunk/src/fdc/DiskChanger.cc =================================================================== --- openmsx/trunk/src/fdc/DiskChanger.cc 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/fdc/DiskChanger.cc 2006-09-22 19:00:57 UTC (rev 5677) @@ -119,9 +119,10 @@ const MSXCommandEvent* commandEvent = checked_cast<const MSXCommandEvent*>(event.get()); - const vector<string>& tokens = commandEvent->getTokens(); - if ((tokens[0] == getDriveName()) && (tokens.size() >= 2)) { - if (tokens[1] == "-eject") { + const vector<TclObject*>& tokens = commandEvent->getTokens(); + if ((tokens.size() >= 2) && + (tokens[0]->getString() == getDriveName())) { + if (tokens[1]->getString() == "-eject") { ejectDisk(); } else { insertDisk(tokens); @@ -129,10 +130,10 @@ } } -void DiskChanger::insertDisk(const vector<string>& args) +void DiskChanger::insertDisk(const vector<TclObject*>& args) { std::auto_ptr<Disk> newDisk; - const string& diskImage = args[1]; + const string& diskImage = args[1]->getString(); if (diskImage == "-ramdsk") { newDisk.reset(new RamDSKDiskImage()); } else { @@ -155,7 +156,7 @@ } } for (unsigned i = 2; i < args.size(); ++i) { - disk->applyPatch(args[i]); + disk->applyPatch(args[i]->getString()); } // no errors, only now replace original disk Modified: openmsx/trunk/src/fdc/DiskChanger.hh =================================================================== --- openmsx/trunk/src/fdc/DiskChanger.hh 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/fdc/DiskChanger.hh 2006-09-22 19:00:57 UTC (rev 5677) @@ -19,6 +19,7 @@ class DiskCommand; class CliComm; class GlobalSettings; +class TclObject; class DiskChanger : public DiskContainer, private MSXEventListener { @@ -40,7 +41,7 @@ virtual SectorAccessibleDisk* getSectorAccessibleDisk(); private: - void insertDisk(const std::vector<std::string>& args); + void insertDisk(const std::vector<TclObject*>& args); void ejectDisk(); void changeDisk(std::auto_ptr<Disk> newDisk); void sendChangeDiskEvent(const std::vector<std::string>& args); Modified: openmsx/trunk/src/input/RecordedCommand.cc =================================================================== --- openmsx/trunk/src/input/RecordedCommand.cc 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/input/RecordedCommand.cc 2006-09-22 19:00:57 UTC (rev 5677) @@ -1,9 +1,12 @@ // $Id: $ #include "RecordedCommand.hh" +#include "CommandController.hh" #include "MSXEventDistributor.hh" +#include "TclObject.hh" #include "Scheduler.hh" #include "InputEvents.hh" +#include "ScopedAssign.hh" #include "checked_cast.hh" using std::vector; @@ -15,9 +18,11 @@ MSXEventDistributor& msxEventDistributor_, Scheduler& scheduler_, const string& name) - : SimpleCommand(commandController, name) + : Command(commandController, name) , msxEventDistributor(msxEventDistributor_) , scheduler(scheduler_) + , dummyResultObject(new TclObject(commandController.getInterpreter())) + , currentResultObject(dummyResultObject.get()) { msxEventDistributor.registerEventListener(*this); } @@ -27,19 +32,32 @@ msxEventDistributor.unregisterEventListener(*this); } -string RecordedCommand::execute(const vector<string>& tokens) +void RecordedCommand::execute(const vector<TclObject*>& tokens, + TclObject& result) { + const EmuTime& time = scheduler.getCurrentTime(); if (needRecord(tokens)) { + ScopedAssign<TclObject*> sa(currentResultObject, &result); msxEventDistributor.distributeEvent( MSXEventDistributor::EventPtr( new MSXCommandEvent(tokens)), - scheduler.getCurrentTime()); - return resultString; + time); } else { - return execute(tokens, scheduler.getCurrentTime()); + execute(tokens, result, time); } } +bool RecordedCommand::needRecord(const vector<TclObject*>& tokens) const +{ + vector<string> strings; + strings.reserve(tokens.size()); + for (vector<TclObject*>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + strings.push_back((*it)->getString()); + } + return needRecord(strings); +} + bool RecordedCommand::needRecord(const vector<string>& /*tokens*/) const { return true; @@ -51,10 +69,30 @@ if (event->getType() != OPENMSX_MSX_COMMAND_EVENT) return; const MSXCommandEvent* commandEvent = checked_cast<const MSXCommandEvent*>(event.get()); - const vector<string>& tokens = commandEvent->getTokens(); - if (tokens[0] != getName()) return; + const vector<TclObject*>& tokens = commandEvent->getTokens(); + if (tokens[0]->getString() != getName()) return; - resultString = execute(tokens, time); + execute(tokens, *currentResultObject, time); } +void RecordedCommand::execute(const vector<TclObject*>& tokens, + TclObject& result, const EmuTime& time) +{ + vector<string> strings; + strings.reserve(tokens.size()); + for (vector<TclObject*>::const_iterator it = tokens.begin(); + it != tokens.end(); ++it) { + strings.push_back((*it)->getString()); + } + result.setString(execute(strings, time)); +} + +string RecordedCommand::execute(const vector<string>& /*tokens*/, + const EmuTime& /*time*/) +{ + // either this method or the method above should be reimplemented + // by the subclasses + assert(false); +} + } // namespace openmsx Modified: openmsx/trunk/src/input/RecordedCommand.hh =================================================================== --- openmsx/trunk/src/input/RecordedCommand.hh 2006-09-21 19:01:22 UTC (rev 5676) +++ openmsx/trunk/src/input/RecordedCommand.hh 2006-09-22 19:00:57 UTC (rev 5677) @@ -16,22 +16,35 @@ * so that they can be recorded by the event recorder. This class helps to * implement that. */ -class RecordedCommand : public SimpleCommand, private MSXEventListener +class RecordedCommand : public Command, private MSXEventListener { public: - /** This is like the execute() method of SimpleCommand - * @param tokens The command tokens (see SimpleCommand) - * @param time The current time - * @result Result string of the command + /** This is like the execute() method of the Command class, it only + * has an extra time parameter. + * There are two variants of this method. The one with tclObjects is + * the fastest, the one with strings is often more convenient to use. + * Subclasses must reimplement exactly one of these two. */ + virtual void execute( + const std::vector<TclObject*>& tokens, TclObject& result, + const EmuTime& time); virtual std::string execute( - const std::vector<std::string>& tokens, const EmuTime& time) = 0; + const std::vector<std::string>& tokens, const EmuTime& time); /** It's possible that in some cases the command doesn't need to be * recorded after all (e.g. a query subcommand). In that case you can * override this method. Return false iff the command doesn't need - * to be recorded. The default implementation always returns true. + * to be recorded. + * Similar to the execute() method above there are two variants of + * this method. However in this case it's allowed to override none + * or just one of the two variants (but not both). + * The default implementation always returns true (will always + * record). If this default implementation is fine but speed is very + * important (e.g. the debug command) it is still recommenced to + * override the TclObject variant of this method (and just return + * true). */ + virtual bool needRecord(const std::vector<TclObject*>& tokens) const; virtual bool needRecord(const std::vector<std::string>& tokens) const; protected: @@ -42,8 +55,9 @@ virtual ~RecordedCommand(); private: - // SimpleCommand - virtual std::string execute(const std::vector<std::string>& tokens); + // Command + virtual void execute(const std::vector<TclObject*>& tokens, + TclObject& result); // MSXEventListener virtual void signalEvent(shared_ptr<const Event> event, @@ -51,7 +65,8 @@ MSXEventDistributor& msxEventDistributor; Scheduler& scheduler; - std::string resultString; + std::auto_ptr<TclObject> dummyResultObject; + TclObject* currentResultObject; }; } // namespace openmsx This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |