38 std::string driveName_,
40 bool doubleSidedDrive_,
41 std::function<
void()> preChangeCallback_)
42 : reactor(board.getReactor())
43 , controller(board.getCommandController())
44 , stateChangeDistributor(&board.getStateChangeDistributor())
45 , scheduler(&board.getScheduler())
46 , preChangeCallback(
std::move(preChangeCallback_))
47 , driveName(
std::move(driveName_))
48 , doubleSidedDrive(doubleSidedDrive_)
55 , controller(reactor.getCommandController())
56 , stateChangeDistributor(nullptr)
58 , driveName(
std::move(driveName_))
59 , doubleSidedDrive(true)
64void DiskChanger::init(std::string_view prefix,
bool createCmd)
70 if (stateChangeDistributor) {
77 if (diskCommand)
return;
78 diskCommand.emplace(controller, *
this);
83 if (stateChangeDistributor) {
92 return disk->getName();
97 bool ret = diskChangedFlag || disk->hasChanged();
98 diskChangedFlag =
false;
104 if (
dynamic_cast<DummyDisk*
>(disk.get())) {
115void DiskChanger::sendChangeDiskEvent(std::span<const TclObject> args)
118 if (stateChangeDistributor) {
126void DiskChanger::signalStateChange(
const StateChange& event)
128 const auto* commandEvent =
dynamic_cast<const MSXCommandEvent*
>(&event);
129 if (!commandEvent)
return;
131 execute(commandEvent->getTokens());
134void DiskChanger::execute(std::span<const TclObject> tokens)
137 if (tokens[1] ==
"eject") {
145void DiskChanger::stopReplay(EmuTime::param )
noexcept
165 std::unique_ptr<Disk> newDisk(diskFactory.createDisk(diskImage, *
this));
166 for (
const auto& arg :
view::drop(args, 2)) {
175void DiskChanger::ejectDisk()
182 if (preChangeCallback) preChangeCallback();
183 disk = std::move(newDisk);
184 diskChangedFlag =
true;
194 :
Command(commandController_, diskChanger_.driveName)
195 , diskChanger(diskChanger_)
201 if (tokens.size() == 1) {
206 if (
dynamic_cast<DummyDisk*
>(diskChanger.disk.get())) {
208 }
else if (
dynamic_cast<DirAsDSK*
>(diskChanger.disk.get())) {
213 if (diskChanger.disk->isWriteProtected()) {
220 }
else if (tokens[1] ==
"ramdsk") {
222 diskChanger.sendChangeDiskEvent(args);
223 }
else if (tokens[1] ==
"-ramdsk") {
225 diskChanger.sendChangeDiskEvent(args);
226 result =
"Warning: use of '-ramdsk' is deprecated, instead use the 'ramdsk' subcommand";
227 }
else if (tokens[1] ==
"-eject") {
229 diskChanger.sendChangeDiskEvent(args);
230 result =
"Warning: use of '-eject' is deprecated, instead use the 'eject' subcommand";
231 }
else if (tokens[1] ==
"eject") {
233 diskChanger.sendChangeDiskEvent(args);
235 int firstFileToken = 1;
236 if (tokens[1] ==
"insert") {
237 if (tokens.size() > 2) {
245 for (
size_t i = firstFileToken; i < tokens.size(); ++i) {
246 std::string_view option = tokens[i].
getString();
247 if (option ==
"-ips") {
248 if (++i == tokens.size()) {
250 "Missing argument for option \"", option,
'\"');
252 args.emplace_back(tokens[i]);
255 args.emplace_back(option);
258 diskChanger.sendChangeDiskEvent(args);
267 const std::string& driveName = diskChanger.
getDriveName();
269 driveName,
" eject : remove disk from virtual drive\n",
270 driveName,
" ramdsk : create a virtual disk in RAM\n",
271 driveName,
" insert <filename> : change the disk file\n",
272 driveName,
" <filename> : change the disk file\n",
273 driveName,
" : show which disk image is in drive\n"
274 "The following options are supported when inserting a disk image:\n"
275 "-ips <filename> : apply the given IPS patch to the disk image");
280 if (tokens.size() >= 2) {
281 using namespace std::literals;
282 static constexpr std::array extra = {
283 "eject"sv,
"ramdsk"sv,
"insert"sv,
291 return tokens.size() > 1;
301template<
typename Archive>
304 DiskName diskName = disk->getName();
305 if (ar.versionBelow(version, 2)) {
318 std::vector<Filename> patches;
319 if constexpr (!Archive::IS_LOADER) {
322 ar.serialize(
"patches", patches);
325 std::string oldChecksum;
326 if constexpr (!Archive::IS_LOADER) {
329 ar.serialize(
"checksum", oldChecksum);
331 if constexpr (Archive::IS_LOADER) {
342 assert(!oldChecksum.empty());
345 if (file.is_open()) {
349 std::vector<TclObject> args =
351 for (
auto& p : patches) {
352 p.updateAfterLoadState();
353 args.emplace_back(p.getResolved());
360 "Couldn't reinsert disk in drive ",
368 if (oldChecksum != newChecksum) {
370 "The content of the disk image ",
372 " has changed since the time this savestate was "
373 "created. This might result in emulation problems "
374 "or even disk corruption. To prevent the latter, "
375 "the disk is now write-protected (eject and "
376 "reinsert the disk if you want to override this).");
382 ar.serialize(
"diskChanged", diskChangedFlag);
388 using type = std::tuple<std::string>;
390 template<
typename Archive>
396 template<
typename Archive>
type load(Archive& ar,
unsigned )
const
398 std::string driveName;
399 ar.serialize(
"driveName", driveName);
406 std::reference_wrapper<MSXMotherBoard>);
virtual void update(UpdateType type, std::string_view name, std::string_view value)=0
void printWarning(std::string_view message)
Interpreter & getInterpreter() const final
virtual CliComm & getCliComm()=0
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
const DiskName & getDiskName() const
int insertDisk(const std::string &filename) override
std::string_view getContainerName() const override
void serialize(Archive &ar, unsigned version)
const std::string & getDriveName() const
DiskChanger(MSXMotherBoard &board, std::string driveName, bool createCmd=true, bool doubleSidedDrive=true, std::function< void()> preChangeCallback={})
void changeDisk(std::unique_ptr< Disk > newDisk)
SectorAccessibleDisk * getSectorAccessibleDisk() override
bool diskChanged() override
bool needRecord(std::span< const TclObject > tokens) const
std::string help(std::span< const TclObject > tokens) const override
Print help for this command.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
void tabCompletion(std::vector< std::string > &tokens) const override
Attempt tab completion for this command.
DiskCommand(CommandController &commandController, DiskChanger &diskChanger)
void unregisterDrive(DiskContainer &drive)
void registerDrive(DiskContainer &drive, std::string_view prefix)
std::string getResolved() const
void serialize(Archive &ar, unsigned version)
void updateAfterLoadState()
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
const std::string & getURL() const
Returns the URL of this file object.
This class represents a filename.
const std::string & getOriginal() const
void serialize(Archive &ar, unsigned version)
This class is used to for Tcl commands that directly influence the MSX state (e.g.
std::string_view getMachineID() const
Contains the main loop of openMSX.
DiskManipulator & getDiskManipulator()
DiskFactory & getDiskFactory()
EmuTime::param getCurrentTime() const
Get the current scheduler time.
Sha1Sum getSha1Sum(FilePool &filePool)
Calculate SHA1 of the content of this disk.
std::vector< Filename > getPatches() const
This class represents the result of a sha1 calculation (a 160-bit value).
std::string toString() const
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
void distributeNew(EmuTime::param time, Args &&...args)
Deliver the event to all registered listeners MSX input devices should call the distributeNew() versi...
void unregisterListener(StateChangeListener &listener)
unsigned getListLength(Interpreter &interp) const
void addListElement(const T &t)
zstring_view getString() const
bool exists(zstring_view filename)
Does this file (directory) exists?
const std::string & getConventionalPath(const std::string &path)
Returns the path in conventional path-delimiter.
This file implemented 3 utility functions:
const FileContext & userFileContext()
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
TemporaryString tmpStrCat(Ts &&... ts)
void save(Archive &ar, const DiskChanger &changer) const
type load(Archive &ar, unsigned) const
std::tuple< std::string > type
Serialize (local) constructor arguments.