openMSX
Reactor.cc
Go to the documentation of this file.
1 #include "Reactor.hh"
2 #include "CommandLineParser.hh"
3 #include "RTScheduler.hh"
4 #include "EventDistributor.hh"
6 #include "InputEventGenerator.hh"
7 #include "InputEvents.hh"
8 #include "DiskFactory.hh"
9 #include "DiskManipulator.hh"
10 #include "DiskChanger.hh"
11 #include "FilePool.hh"
12 #include "UserSettings.hh"
13 #include "RomDatabase.hh"
14 #include "RomInfo.hh"
15 #include "TclCallbackMessages.hh"
16 #include "MSXMotherBoard.hh"
18 #include "Command.hh"
19 #include "AfterCommand.hh"
20 #include "MessageCommand.hh"
21 #include "CommandException.hh"
22 #include "GlobalCliComm.hh"
23 #include "InfoTopic.hh"
24 #include "Display.hh"
25 #include "Mixer.hh"
26 #include "AviRecorder.hh"
27 #include "GlobalSettings.hh"
28 #include "BooleanSetting.hh"
29 #include "EnumSetting.hh"
30 #include "TclObject.hh"
31 #include "HardwareConfig.hh"
32 #include "XMLElement.hh"
33 #include "XMLException.hh"
34 #include "FileContext.hh"
35 #include "FileException.hh"
36 #include "FileOperations.hh"
37 #include "ReadDir.hh"
38 #include "Thread.hh"
39 #include "Timer.hh"
40 #include "serialize.hh"
41 #include "checked_cast.hh"
42 #include "ranges.hh"
43 #include "statp.hh"
44 #include "stl.hh"
45 #include "StringOp.hh"
46 #include "unreachable.hh"
47 #include "view.hh"
48 #include "build-info.hh"
49 #include <cassert>
50 #include <memory>
51 
52 using std::make_shared;
53 using std::make_unique;
54 using std::string;
55 using std::string_view;
56 using std::vector;
57 
58 namespace openmsx {
59 
60 // global variable to communicate the exit-code from the 'exit' command to main()
61 int exitCode = 0;
62 
63 class ExitCommand final : public Command
64 {
65 public:
66  ExitCommand(CommandController& commandController, EventDistributor& distributor);
67  void execute(span<const TclObject> tokens, TclObject& result) override;
68  string help(const vector<string>& tokens) const override;
69 private:
70  EventDistributor& distributor;
71 };
72 
73 class MachineCommand final : public Command
74 {
75 public:
76  MachineCommand(CommandController& commandController, Reactor& reactor);
77  void execute(span<const TclObject> tokens, TclObject& result) override;
78  string help(const vector<string>& tokens) const override;
79  void tabCompletion(vector<string>& tokens) const override;
80 private:
81  Reactor& reactor;
82 };
83 
84 class TestMachineCommand final : public Command
85 {
86 public:
87  TestMachineCommand(CommandController& commandController, Reactor& reactor);
88  void execute(span<const TclObject> tokens, TclObject& result) override;
89  string help(const vector<string>& tokens) const override;
90  void tabCompletion(vector<string>& tokens) const override;
91 private:
92  Reactor& reactor;
93 };
94 
95 class CreateMachineCommand final : public Command
96 {
97 public:
98  CreateMachineCommand(CommandController& commandController, Reactor& reactor);
99  void execute(span<const TclObject> tokens, TclObject& result) override;
100  string help(const vector<string>& tokens) const override;
101 private:
102  Reactor& reactor;
103 };
104 
105 class DeleteMachineCommand final : public Command
106 {
107 public:
108  DeleteMachineCommand(CommandController& commandController, Reactor& reactor);
109  void execute(span<const TclObject> tokens, TclObject& result) override;
110  string help(const vector<string>& tokens) const override;
111  void tabCompletion(vector<string>& tokens) const override;
112 private:
113  Reactor& reactor;
114 };
115 
116 class ListMachinesCommand final : public Command
117 {
118 public:
119  ListMachinesCommand(CommandController& commandController, Reactor& reactor);
120  void execute(span<const TclObject> tokens, TclObject& result) override;
121  string help(const vector<string>& tokens) const override;
122 private:
123  Reactor& reactor;
124 };
125 
126 class ActivateMachineCommand final : public Command
127 {
128 public:
129  ActivateMachineCommand(CommandController& commandController, Reactor& reactor);
130  void execute(span<const TclObject> tokens, TclObject& result) override;
131  string help(const vector<string>& tokens) const override;
132  void tabCompletion(vector<string>& tokens) const override;
133 private:
134  Reactor& reactor;
135 };
136 
137 class StoreMachineCommand final : public Command
138 {
139 public:
140  StoreMachineCommand(CommandController& commandController, Reactor& reactor);
141  void execute(span<const TclObject> tokens, TclObject& result) override;
142  string help(const vector<string>& tokens) const override;
143  void tabCompletion(vector<string>& tokens) const override;
144 private:
145  Reactor& reactor;
146 };
147 
148 class RestoreMachineCommand final : public Command
149 {
150 public:
151  RestoreMachineCommand(CommandController& commandController, Reactor& reactor);
152  void execute(span<const TclObject> tokens, TclObject& result) override;
153  string help(const vector<string>& tokens) const override;
154  void tabCompletion(vector<string>& tokens) const override;
155 private:
156  Reactor& reactor;
157 };
158 
159 class GetClipboardCommand final : public Command
160 {
161 public:
162  GetClipboardCommand(CommandController& commandController);
163  void execute(span<const TclObject> tokens, TclObject& result) override;
164  string help(const vector<string>& tokens) const override;
165 };
166 
167 class SetClipboardCommand final : public Command
168 {
169 public:
170  SetClipboardCommand(CommandController& commandController);
171  void execute(span<const TclObject> tokens, TclObject& result) override;
172  string help(const vector<string>& tokens) const override;
173 };
174 
175 class ConfigInfo final : public InfoTopic
176 {
177 public:
178  ConfigInfo(InfoCommand& openMSXInfoCommand, const string& configName);
179  void execute(span<const TclObject> tokens,
180  TclObject& result) const override;
181  string help(const vector<string>& tokens) const override;
182  void tabCompletion(vector<string>& tokens) const override;
183 private:
184  const string configName;
185 };
186 
187 class RealTimeInfo final : public InfoTopic
188 {
189 public:
190  explicit RealTimeInfo(InfoCommand& openMSXInfoCommand);
191  void execute(span<const TclObject> tokens,
192  TclObject& result) const override;
193  string help(const vector<string>& tokens) const override;
194 private:
195  const uint64_t reference;
196 };
197 
199 {
200 public:
201  SoftwareInfoTopic(InfoCommand& openMSXInfoCommand, Reactor& reactor);
202  void execute(span<const TclObject> tokens,
203  TclObject& result) const override;
204  std::string help(const std::vector<std::string>& tokens) const override;
205 private:
206  Reactor& reactor;
207 };
208 
209 
210 Reactor::Reactor() = default;
211 
213 {
214  rtScheduler = make_unique<RTScheduler>();
215  eventDistributor = make_unique<EventDistributor>(*this);
216  globalCliComm = make_unique<GlobalCliComm>();
217  globalCommandController = make_unique<GlobalCommandController>(
218  *eventDistributor, *globalCliComm, *this);
219  globalSettings = make_unique<GlobalSettings>(
220  *globalCommandController);
221  inputEventGenerator = make_unique<InputEventGenerator>(
222  *globalCommandController, *eventDistributor, *globalSettings);
223  mixer = make_unique<Mixer>(
224  *this, *globalCommandController);
225  diskFactory = make_unique<DiskFactory>(
226  *this);
227  diskManipulator = make_unique<DiskManipulator>(
228  *globalCommandController, *this);
229  virtualDrive = make_unique<DiskChanger>(
230  *this, "virtual_drive");
231  filePool = make_unique<FilePool>(*globalCommandController, *this);
232  userSettings = make_unique<UserSettings>(
233  *globalCommandController);
234  afterCommand = make_unique<AfterCommand>(
235  *this, *eventDistributor, *globalCommandController);
236  exitCommand = make_unique<ExitCommand>(
237  *globalCommandController, *eventDistributor);
238  messageCommand = make_unique<MessageCommand>(
239  *globalCommandController);
240  machineCommand = make_unique<MachineCommand>(
241  *globalCommandController, *this);
242  testMachineCommand = make_unique<TestMachineCommand>(
243  *globalCommandController, *this);
244  createMachineCommand = make_unique<CreateMachineCommand>(
245  *globalCommandController, *this);
246  deleteMachineCommand = make_unique<DeleteMachineCommand>(
247  *globalCommandController, *this);
248  listMachinesCommand = make_unique<ListMachinesCommand>(
249  *globalCommandController, *this);
250  activateMachineCommand = make_unique<ActivateMachineCommand>(
251  *globalCommandController, *this);
252  storeMachineCommand = make_unique<StoreMachineCommand>(
253  *globalCommandController, *this);
254  restoreMachineCommand = make_unique<RestoreMachineCommand>(
255  *globalCommandController, *this);
256  getClipboardCommand = make_unique<GetClipboardCommand>(
257  *globalCommandController);
258  setClipboardCommand = make_unique<SetClipboardCommand>(
259  *globalCommandController);
260  aviRecordCommand = make_unique<AviRecorder>(*this);
261  extensionInfo = make_unique<ConfigInfo>(
262  getOpenMSXInfoCommand(), "extensions");
263  machineInfo = make_unique<ConfigInfo>(
264  getOpenMSXInfoCommand(), "machines");
265  realTimeInfo = make_unique<RealTimeInfo>(
267  softwareInfoTopic = make_unique<SoftwareInfoTopic>(
268  getOpenMSXInfoCommand(), *this);
269  tclCallbackMessages = make_unique<TclCallbackMessages>(
270  *globalCliComm, *globalCommandController);
271 
272  createMachineSetting();
273 
275 
276  eventDistributor->registerEventListener(OPENMSX_QUIT_EVENT, *this);
277 #if PLATFORM_ANDROID
278  eventDistributor->registerEventListener(OPENMSX_FOCUS_EVENT, *this);
279 #endif
280  eventDistributor->registerEventListener(OPENMSX_DELETE_BOARDS, *this);
281  isInit = true;
282 }
283 
285 {
286  if (!isInit) return;
287  deleteBoard(activeBoard);
288 
289  eventDistributor->unregisterEventListener(OPENMSX_QUIT_EVENT, *this);
290 #if PLATFORM_ANDROID
291  eventDistributor->unregisterEventListener(OPENMSX_FOCUS_EVENT, *this);
292 #endif
293  eventDistributor->unregisterEventListener(OPENMSX_DELETE_BOARDS, *this);
294 
296 }
297 
299 {
300  if (!softwareDatabase) {
301  softwareDatabase = make_unique<RomDatabase>(*globalCliComm);
302  }
303  return *softwareDatabase;
304 }
305 
307 {
308  return *globalCliComm;
309 }
310 
312 {
314 }
315 
317 {
318  return *globalCommandController;
319 }
320 
322 {
323  return globalCommandController->getOpenMSXInfoCommand();
324 }
325 
326 vector<string> Reactor::getHwConfigs(string_view type)
327 {
328  vector<string> result;
329  for (auto& p : systemFileContext().getPaths()) {
330  const auto& path = FileOperations::join(p, type);
331  ReadDir configsDir(path);
332  while (auto* entry = configsDir.getEntry()) {
333  string_view name = entry->d_name;
334  const auto& fullname = FileOperations::join(path, name);
335  if (StringOp::endsWith(name, ".xml") &&
336  FileOperations::isRegularFile(fullname)) {
337  name.remove_suffix(4);
338  result.emplace_back(name);
339  } else if (FileOperations::isDirectory(fullname)) {
340  const auto& config = FileOperations::join(
341  fullname, "hardwareconfig.xml");
342  if (FileOperations::isRegularFile(config)) {
343  result.emplace_back(name);
344  }
345  }
346  }
347  }
348  // remove duplicates
349  ranges::sort(result);
350  result.erase(ranges::unique(result), end(result));
351  return result;
352 }
353 
354 void Reactor::createMachineSetting()
355 {
356  EnumSetting<int>::Map machines; // int's are unique dummy values
357  int count = 1;
358  append(machines, view::transform(getHwConfigs("machines"),
359  [&](auto& name) { return std::pair(name, count++); }));
360  machines.emplace_back("C-BIOS_MSX2+", 0); // default machine
361 
362  machineSetting = make_unique<EnumSetting<int>>(
363  *globalCommandController, "default_machine",
364  "default machine (takes effect next time openMSX is started)",
365  0, std::move(machines));
366 }
367 
369 {
370  assert(Thread::isMainThread());
371  return activeBoard;
372 }
373 
374 string_view Reactor::getMachineID() const
375 {
376  return activeBoard ? activeBoard->getMachineID() : string_view{};
377 }
378 
379 vector<string_view> Reactor::getMachineIDs() const
380 {
381  return to_vector(view::transform(
382  boards, [](auto& b) { return b->getMachineID(); }));
383 }
384 
385 MSXMotherBoard& Reactor::getMachine(string_view machineID) const
386 {
387  for (auto& b : boards) {
388  if (b->getMachineID() == machineID) {
389  return *b;
390  }
391  }
392  throw CommandException("No machine with ID: ", machineID);
393 }
394 
396 {
397  return make_unique<MSXMotherBoard>(*this);
398 }
399 
400 void Reactor::replaceBoard(MSXMotherBoard& oldBoard_, Board newBoard_)
401 {
402  assert(Thread::isMainThread());
403 
404  // Add new board.
405  auto* newBoard = newBoard_.get();
406  boards.push_back(move(newBoard_));
407 
408  // Lookup old board (it must be present).
409  auto it = find_if_unguarded(boards,
410  [&](auto& b) { return b.get() == &oldBoard_; });
411 
412  // If the old board was the active board, then activate the new board
413  if (it->get() == activeBoard) {
414  switchBoard(newBoard);
415  }
416 
417  // Remove (=delete) the old board.
418  // Note that we don't use the 'garbageBoards' mechanism as used in
419  // deleteBoard(). This means oldBoard cannot be used anymore right
420  // after this method returns.
421  move_pop_back(boards, it);
422 }
423 
424 void Reactor::switchMachine(const string& machine)
425 {
426  if (!display) {
427  display = make_unique<Display>(*this);
428  // TODO: Currently it is not possible to move this call into the
429  // constructor of Display because the call to createVideoSystem()
430  // indirectly calls Reactor.getDisplay().
431  display->createVideoSystem();
432  }
433 
434  // create+load new machine
435  // switch to new machine
436  // delete old active machine
437 
438  assert(Thread::isMainThread());
439  // Note: loadMachine can throw an exception and in that case the
440  // motherboard must be considered as not created at all.
441  auto newBoard_ = createEmptyMotherBoard();
442  auto* newBoard = newBoard_.get();
443  newBoard->loadMachine(machine);
444  boards.push_back(move(newBoard_));
445 
446  auto* oldBoard = activeBoard;
447  switchBoard(newBoard);
448  deleteBoard(oldBoard);
449 }
450 
451 void Reactor::switchBoard(MSXMotherBoard* newBoard)
452 {
453  assert(Thread::isMainThread());
454  assert(!newBoard ||
455  (ranges::any_of(boards, [&](auto& b) { return b.get() == newBoard; })));
456  assert(!activeBoard ||
457  (ranges::any_of(boards, [&](auto& b) { return b.get() == activeBoard; })));
458  if (activeBoard) {
459  activeBoard->activate(false);
460  }
461  {
462  // Don't hold the lock for longer than the actual switch.
463  // In the past we had a potential for deadlocks here, because
464  // (indirectly) the code below still acquires other locks.
465  std::lock_guard<std::mutex> lock(mbMutex);
466  activeBoard = newBoard;
467  }
468  eventDistributor->distributeEvent(
469  make_shared<SimpleEvent>(OPENMSX_MACHINE_LOADED_EVENT));
470  globalCliComm->update(CliComm::HARDWARE, getMachineID(), "select");
471  if (activeBoard) {
472  activeBoard->activate(true);
473  }
474 }
475 
476 void Reactor::deleteBoard(MSXMotherBoard* board)
477 {
478  // Note: pass 'board' by-value to keep the parameter from changing
479  // after the call to switchBoard(). switchBoard() changes the
480  // 'activeBoard' member variable, so the 'board' parameter would change
481  // if it were passed by reference to this method (AFAICS this only
482  // happens in ~Reactor()).
483  assert(Thread::isMainThread());
484  if (!board) return;
485 
486  if (board == activeBoard) {
487  // delete active board -> there is no active board anymore
488  switchBoard(nullptr);
489  }
490  auto it = rfind_if_unguarded(boards,
491  [&](auto& b) { return b.get() == board; });
492  auto board_ = move(*it);
493  move_pop_back(boards, it);
494  // Don't immediately delete old boards because it's possible this
495  // routine is called via a code path that goes through the old
496  // board. Instead remember this board and delete it at a safe moment
497  // in time.
498  garbageBoards.push_back(move(board_));
499  eventDistributor->distributeEvent(
500  make_shared<SimpleEvent>(OPENMSX_DELETE_BOARDS));
501 }
502 
504 {
505  // Note: this method can get called from different threads
506  if (Thread::isMainThread()) {
507  // Don't take lock in main thread to avoid recursive locking.
508  if (activeBoard) {
509  activeBoard->exitCPULoopSync();
510  }
511  } else {
512  std::lock_guard<std::mutex> lock(mbMutex);
513  if (activeBoard) {
514  activeBoard->exitCPULoopAsync();
515  }
516  }
517 }
518 
520 {
521  auto& commandController = *globalCommandController;
522 
523  // execute init.tcl
524  try {
525  commandController.source(
526  preferSystemFileContext().resolve("init.tcl"));
527  } catch (FileException&) {
528  // no init.tcl, ignore
529  }
530 
531  // execute startup scripts
532  for (auto& s : parser.getStartupScripts()) {
533  try {
534  commandController.source(userFileContext().resolve(s));
535  } catch (FileException& e) {
536  throw FatalError("Couldn't execute script: ",
537  e.getMessage());
538  }
539  }
540  for (auto& cmd : parser.getStartupCommands()) {
541  try {
542  commandController.executeCommand(cmd);
543  } catch (CommandException& e) {
544  throw FatalError("Couldn't execute command: ", cmd,
545  '\n', e.getMessage());
546  }
547  }
548 
549  // At this point openmsx is fully started, it's OK now to start
550  // accepting external commands
552 
553  // Run
554  if (parser.getParseStatus() == CommandLineParser::RUN) {
555  // don't use Tcl to power up the machine, we cannot pass
556  // exceptions through Tcl and ADVRAM might throw in its
557  // powerUp() method. Solution is to implement dependencies
558  // between devices so ADVRAM can check the error condition
559  // in its constructor
560  //commandController.executeCommand("set power on");
561  if (activeBoard) {
562  activeBoard->powerUp();
563  }
564  }
565 
566  while (doOneIteration()) {
567  // nothing
568  }
569 }
570 
571 bool Reactor::doOneIteration()
572 {
573  eventDistributor->deliverEvents();
574  assert(garbageBoards.empty());
575  bool blocked = (blockedCounter > 0) || !activeBoard;
576  if (!blocked) blocked = !activeBoard->execute();
577  if (blocked) {
578  // At first sight a better alternative is to use the
579  // SDL_WaitEvent() function. Though when inspecting
580  // the implementation of that function, it turns out
581  // to also use a sleep/poll loop, with even shorter
582  // sleep periods as we use here. Maybe in future
583  // SDL implementations this will be improved.
584  eventDistributor->sleep(20 * 1000);
585  }
586  return running;
587 }
588 
589 void Reactor::unpause()
590 {
591  if (paused) {
592  paused = false;
593  globalCliComm->update(CliComm::STATUS, "paused", "false");
594  unblock();
595  }
596 }
597 
598 void Reactor::pause()
599 {
600  if (!paused) {
601  paused = true;
602  globalCliComm->update(CliComm::STATUS, "paused", "true");
603  block();
604  }
605 }
606 
608 {
609  ++blockedCounter;
610  enterMainLoop();
611  mixer->mute();
612 }
613 
615 {
616  --blockedCounter;
617  assert(blockedCounter >= 0);
618  mixer->unmute();
619 }
620 
621 
622 // Observer<Setting>
623 void Reactor::update(const Setting& setting)
624 {
625  auto& pauseSetting = getGlobalSettings().getPauseSetting();
626  if (&setting == &pauseSetting) {
627  if (pauseSetting.getBoolean()) {
628  pause();
629  } else {
630  unpause();
631  }
632  }
633 }
634 
635 // EventListener
636 int Reactor::signalEvent(const std::shared_ptr<const Event>& event)
637 {
638  auto type = event->getType();
639  if (type == OPENMSX_QUIT_EVENT) {
640  enterMainLoop();
641  running = false;
642 #if PLATFORM_ANDROID
643  } else if (type == OPENMSX_FOCUS_EVENT) {
644  // Android SDL port sends a (un)focus event when an app is put in background
645  // by the OS for whatever reason (like an incoming phone call) and all screen
646  // resources are taken away from the app.
647  // In such case the app is supposed to behave as a good citizen
648  // and minize its resource usage and related battery drain.
649  // The SDL Android port already takes care of halting the Java
650  // part of the sound processing. The Display class makes sure that it wont try
651  // to render anything to the (temporary missing) graphics resources but the
652  // main emulation should also be temporary stopped, in order to minimize CPU usage
653  auto& focusEvent = checked_cast<const FocusEvent&>(*event);
654  if (focusEvent.getGain()) {
655  unblock();
656  } else {
657  block();
658  }
659 #endif
660  } else if (type == OPENMSX_DELETE_BOARDS) {
661  // Doesn't really matter which one we delete, just that we do
662  // one per event.
663  assert(!garbageBoards.empty());
664  garbageBoards.pop_back();
665  } else {
666  UNREACHABLE; // we didn't subscribe to this event...
667  }
668  return 0;
669 }
670 
671 
672 // class ExitCommand
673 
675  EventDistributor& distributor_)
676  : Command(commandController_, "exit")
677  , distributor(distributor_)
678 {
679 }
680 
682 {
683  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "?exitcode?");
684  switch (tokens.size()) {
685  case 1:
686  exitCode = 0;
687  break;
688  case 2:
689  exitCode = tokens[1].getInt(getInterpreter());
690  break;
691  }
692  distributor.distributeEvent(make_shared<QuitEvent>());
693 }
694 
695 string ExitCommand::help(const vector<string>& /*tokens*/) const
696 {
697  return "Use this command to stop the emulator.\n"
698  "Optionally you can pass an exit-code.\n";
699 }
700 
701 
702 // class MachineCommand
703 
705  Reactor& reactor_)
706  : Command(commandController_, "machine")
707  , reactor(reactor_)
708 {
709 }
710 
712 {
713  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "?machinetype?");
714  switch (tokens.size()) {
715  case 1: // get current machine
716  // nothing
717  break;
718  case 2:
719  try {
720  reactor.switchMachine(string(tokens[1].getString()));
721  } catch (MSXException& e) {
722  throw CommandException("Machine switching failed: ",
723  e.getMessage());
724  }
725  break;
726  }
727  // Always return machineID (of current or of new machine).
728  result = reactor.getMachineID();
729 }
730 
731 string MachineCommand::help(const vector<string>& /*tokens*/) const
732 {
733  return "Switch to a different MSX machine.";
734 }
735 
736 void MachineCommand::tabCompletion(vector<string>& tokens) const
737 {
738  completeString(tokens, Reactor::getHwConfigs("machines"));
739 }
740 
741 
742 // class TestMachineCommand
743 
745  Reactor& reactor_)
746  : Command(commandController_, "test_machine")
747  , reactor(reactor_)
748 {
749 }
750 
752  TclObject& result)
753 {
754  checkNumArgs(tokens, 2, "machinetype");
755  try {
756  MSXMotherBoard mb(reactor);
757  mb.loadMachine(string(tokens[1].getString()));
758  } catch (MSXException& e) {
759  result = e.getMessage(); // error
760  }
761 }
762 
763 string TestMachineCommand::help(const vector<string>& /*tokens*/) const
764 {
765  return "Test the configuration for the given machine. "
766  "Returns an error message explaining why the configuration is "
767  "invalid or an empty string in case of success.";
768 }
769 
770 void TestMachineCommand::tabCompletion(vector<string>& tokens) const
771 {
772  completeString(tokens, Reactor::getHwConfigs("machines"));
773 }
774 
775 
776 // class CreateMachineCommand
777 
779  CommandController& commandController_, Reactor& reactor_)
780  : Command(commandController_, "create_machine")
781  , reactor(reactor_)
782 {
783 }
784 
786 {
787  checkNumArgs(tokens, 1, Prefix{1}, nullptr);
788  auto newBoard = reactor.createEmptyMotherBoard();
789  result = newBoard->getMachineID();
790  reactor.boards.push_back(move(newBoard));
791 }
792 
793 string CreateMachineCommand::help(const vector<string>& /*tokens*/) const
794 {
795  return "Creates a new (empty) MSX machine. Returns the ID for the new "
796  "machine.\n"
797  "Use 'load_machine' to actually load a machine configuration "
798  "into this new machine.\n"
799  "The main reason create_machine and load_machine are two "
800  "separate commands is that sometimes you already want to know "
801  "the ID of the machine before load_machine starts emitting "
802  "events for this machine.";
803 }
804 
805 
806 // class DeleteMachineCommand
807 
809  CommandController& commandController_, Reactor& reactor_)
810  : Command(commandController_, "delete_machine")
811  , reactor(reactor_)
812 {
813 }
814 
816  TclObject& /*result*/)
817 {
818  checkNumArgs(tokens, 2, "id");
819  reactor.deleteBoard(&reactor.getMachine(tokens[1].getString()));
820 }
821 
822 string DeleteMachineCommand::help(const vector<string>& /*tokens*/) const
823 {
824  return "Deletes the given MSX machine.";
825 }
826 
827 void DeleteMachineCommand::tabCompletion(vector<string>& tokens) const
828 {
829  completeString(tokens, reactor.getMachineIDs());
830 }
831 
832 
833 // class ListMachinesCommand
834 
836  CommandController& commandController_, Reactor& reactor_)
837  : Command(commandController_, "list_machines")
838  , reactor(reactor_)
839 {
840 }
841 
843  TclObject& result)
844 {
845  result.addListElements(reactor.getMachineIDs());
846 }
847 
848 string ListMachinesCommand::help(const vector<string>& /*tokens*/) const
849 {
850  return "Returns a list of all machine IDs.";
851 }
852 
853 
854 // class ActivateMachineCommand
855 
857  CommandController& commandController_, Reactor& reactor_)
858  : Command(commandController_, "activate_machine")
859  , reactor(reactor_)
860 {
861 }
862 
864  TclObject& result)
865 {
866  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "id");
867  switch (tokens.size()) {
868  case 1:
869  break;
870  case 2:
871  reactor.switchBoard(&reactor.getMachine(tokens[1].getString()));
872  break;
873  }
874  result = reactor.getMachineID();
875 }
876 
877 string ActivateMachineCommand::help(const vector<string>& /*tokens*/) const
878 {
879  return "Make another machine the active msx machine.\n"
880  "Or when invoked without arguments, query the ID of the "
881  "active msx machine.";
882 }
883 
884 void ActivateMachineCommand::tabCompletion(vector<string>& tokens) const
885 {
886  completeString(tokens, reactor.getMachineIDs());
887 }
888 
889 
890 // class StoreMachineCommand
891 
893  CommandController& commandController_, Reactor& reactor_)
894  : Command(commandController_, "store_machine")
895  , reactor(reactor_)
896 {
897 }
898 
900 {
901  checkNumArgs(tokens, Between{1, 3}, Prefix{1}, "?id? ?filename?");
902  string filename;
903  string_view machineID;
904  switch (tokens.size()) {
905  case 1:
906  machineID = reactor.getMachineID();
907  filename = FileOperations::getNextNumberedFileName("savestates", "openmsxstate", ".xml.gz");
908  break;
909  case 2:
910  machineID = tokens[1].getString();
911  filename = FileOperations::getNextNumberedFileName("savestates", "openmsxstate", ".xml.gz");
912  break;
913  case 3:
914  machineID = tokens[1].getString();
915  filename = tokens[2].getString();
916  break;
917  }
918 
919  auto& board = reactor.getMachine(machineID);
920 
922  out.serialize("machine", board);
923  out.close();
924  result = filename;
925 }
926 
927 string StoreMachineCommand::help(const vector<string>& /*tokens*/) const
928 {
929  return
930  "store_machine Save state of current machine to file \"openmsxNNNN.xml.gz\"\n"
931  "store_machine machineID Save state of machine \"machineID\" to file \"openmsxNNNN.xml.gz\"\n"
932  "store_machine machineID <filename> Save state of machine \"machineID\" to indicated file\n"
933  "\n"
934  "This is a low-level command, the 'savestate' script is easier to use.";
935 }
936 
937 void StoreMachineCommand::tabCompletion(vector<string>& tokens) const
938 {
939  completeString(tokens, reactor.getMachineIDs());
940 }
941 
942 
943 // class RestoreMachineCommand
944 
946  CommandController& commandController_, Reactor& reactor_)
947  : Command(commandController_, "restore_machine")
948  , reactor(reactor_)
949 {
950 }
951 
953  TclObject& result)
954 {
955  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "?filename?");
956  auto newBoard = reactor.createEmptyMotherBoard();
957 
958  string filename;
959  switch (tokens.size()) {
960  case 1: {
961  // load last saved entry
962  struct stat st;
963  string dirName = FileOperations::getUserOpenMSXDir() + "/savestates/";
964  string lastEntry;
965  time_t lastTime = 0;
966  ReadDir dir(dirName);
967  while (dirent* d = dir.getEntry()) {
968  int res = stat(strCat(dirName, d->d_name).c_str(), &st);
969  if ((res == 0) && S_ISREG(st.st_mode)) {
970  time_t modTime = st.st_mtime;
971  if (modTime > lastTime) {
972  lastEntry = string(d->d_name);
973  lastTime = modTime;
974  }
975  }
976  }
977  if (lastEntry.empty()) {
978  throw CommandException("Can't find last saved state.");
979  }
980  filename = dirName + lastEntry;
981  break;
982  }
983  case 2:
984  filename = tokens[1].getString();
985  break;
986  }
987 
988  //std::cerr << "Loading " << filename << '\n';
989  try {
991  in.serialize("machine", *newBoard);
992  } catch (XMLException& e) {
993  throw CommandException("Cannot load state, bad file format: ",
994  e.getMessage());
995  } catch (MSXException& e) {
996  throw CommandException("Cannot load state: ", e.getMessage());
997  }
998 
999  // Savestate also contains stuff like the keyboard state at the moment
1000  // the snapshot was created (this is required for reverse/replay). But
1001  // now we want the MSX to see the actual host keyboard state.
1002  newBoard->getStateChangeDistributor().stopReplay(newBoard->getCurrentTime());
1003 
1004  result = newBoard->getMachineID();
1005  reactor.boards.push_back(move(newBoard));
1006 }
1007 
1008 string RestoreMachineCommand::help(const vector<string>& /*tokens*/) const
1009 {
1010  return "restore_machine Load state from last saved state in default directory\n"
1011  "restore_machine <filename> Load state from indicated file\n"
1012  "\n"
1013  "This is a low-level command, the 'loadstate' script is easier to use.";
1014 }
1015 
1016 void RestoreMachineCommand::tabCompletion(vector<string>& tokens) const
1017 {
1018  // TODO: add the default files (state files in user's savestates dir)
1019  completeFileName(tokens, userFileContext());
1020 }
1021 
1022 
1023 // class GetClipboardCommand
1024 
1026  : Command(commandController_, "get_clipboard_text")
1027 {
1028 }
1029 
1031 {
1032  checkNumArgs(tokens, 1, Prefix{1}, nullptr);
1033  if (char* text = SDL_GetClipboardText()) {
1034  result = text;
1035  SDL_free(text);
1036  }
1037 }
1038 
1039 string GetClipboardCommand::help(const vector<string>& /*tokens*/) const
1040 {
1041  return "Returns the (text) content of the clipboard as a string.";
1042 }
1043 
1044 
1045 // class SetClipboardCommand
1046 
1048  : Command(commandController_, "set_clipboard_text")
1049 {
1050 }
1051 
1053 {
1054  checkNumArgs(tokens, 2, "text");
1055  string text(tokens[1].getString());
1056  if (SDL_SetClipboardText(text.c_str()) != 0) {
1057  const char* err = SDL_GetError();
1058  SDL_ClearError();
1059  throw CommandException(err);
1060  }
1061 }
1062 
1063 string SetClipboardCommand::help(const vector<string>& /*tokens*/) const
1064 {
1065  return "Send the given string to the clipboard.";
1066 }
1067 
1068 
1069 // class ConfigInfo
1070 
1072  const string& configName_)
1073  : InfoTopic(openMSXInfoCommand, configName_)
1074  , configName(configName_)
1075 {
1076 }
1077 
1079 {
1080  // TODO make meta info available through this info topic
1081  switch (tokens.size()) {
1082  case 2: {
1083  result.addListElements(Reactor::getHwConfigs(configName));
1084  break;
1085  }
1086  case 3: {
1087  try {
1088  auto config = HardwareConfig::loadConfig(
1089  configName, tokens[2].getString());
1090  if (auto* info = config.findChild("info")) {
1091  for (auto& i : info->getChildren()) {
1092  result.addDictKeyValue(i.getName(), i.getData());
1093  }
1094  }
1095  } catch (MSXException& e) {
1096  throw CommandException(
1097  "Couldn't get config info: ", e.getMessage());
1098  }
1099  break;
1100  }
1101  default:
1102  throw CommandException("Too many parameters");
1103  }
1104 }
1105 
1106 string ConfigInfo::help(const vector<string>& /*tokens*/) const
1107 {
1108  return strCat("Shows a list of available ", configName, ", "
1109  "or get meta information about the selected item.\n");
1110 }
1111 
1112 void ConfigInfo::tabCompletion(vector<string>& tokens) const
1113 {
1114  completeString(tokens, Reactor::getHwConfigs(configName));
1115 }
1116 
1117 
1118 // class RealTimeInfo
1119 
1121  : InfoTopic(openMSXInfoCommand, "realtime")
1122  , reference(Timer::getTime())
1123 {
1124 }
1125 
1127  TclObject& result) const
1128 {
1129  auto delta = Timer::getTime() - reference;
1130  result = delta / 1000000.0;
1131 }
1132 
1133 string RealTimeInfo::help(const vector<string>& /*tokens*/) const
1134 {
1135  return "Returns the time in seconds since openMSX was started.";
1136 }
1137 
1138 
1139 // SoftwareInfoTopic
1140 
1142  : InfoTopic(openMSXInfoCommand, "software")
1143  , reactor(reactor_)
1144 {
1145 }
1146 
1148  span<const TclObject> tokens, TclObject& result) const
1149 {
1150  if (tokens.size() != 3) {
1151  throw CommandException("Wrong number of parameters");
1152  }
1153 
1154  Sha1Sum sha1sum = Sha1Sum(tokens[2].getString());
1155  auto& romDatabase = reactor.getSoftwareDatabase();
1156  const RomInfo* romInfo = romDatabase.fetchRomInfo(sha1sum);
1157  if (!romInfo) {
1158  // no match found
1159  throw CommandException(
1160  "Software with sha1sum ", sha1sum.toString(), " not found");
1161  }
1162 
1163  const char* bufStart = romDatabase.getBufferStart();
1164  result.addDictKeyValues("title", romInfo->getTitle(bufStart),
1165  "year", romInfo->getYear(bufStart),
1166  "company", romInfo->getCompany(bufStart),
1167  "country", romInfo->getCountry(bufStart),
1168  "orig_type", romInfo->getOrigType(bufStart),
1169  "remark", romInfo->getRemark(bufStart),
1170  "original", romInfo->getOriginal(),
1171  "mapper_type_name", RomInfo::romTypeToName(romInfo->getRomType()),
1172  "genmsxid", romInfo->getGenMSXid());
1173 }
1174 
1175 string SoftwareInfoTopic::help(const vector<string>& /*tokens*/) const
1176 {
1177  return "Returns information about the software "
1178  "given its sha1sum, in a paired list.";
1179 }
1180 
1181 } // namespace openmsx
openmsx::DeleteMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:827
openmsx::EnumSetting
Definition: Reactor.hh:54
openmsx::ListMachinesCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:848
openmsx::CommandException
Definition: CommandException.hh:8
openmsx::XMLException
Definition: XMLException.hh:8
DiskManipulator.hh
openmsx::Completer::checkNumArgs
void checkNumArgs(span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
Definition: Completer.cc:178
HardwareConfig.hh
openmsx::GetClipboardCommand::GetClipboardCommand
GetClipboardCommand(CommandController &commandController)
Definition: Reactor.cc:1025
openmsx::GetClipboardCommand
Definition: Reactor.cc:159
FileException.hh
openmsx::SoftwareInfoTopic
Definition: Reactor.cc:198
openmsx::RestoreMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:1016
openmsx::GlobalCommandController::getInterpreter
Interpreter & getInterpreter() override
Definition: GlobalCommandController.cc:123
openmsx::RomInfo::getYear
std::string_view getYear(const char *buf) const
Definition: RomInfo.hh:35
openmsx::SetClipboardCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:1052
openmsx::MSXMotherBoard::activate
void activate(bool active)
Definition: MSXMotherBoard.cc:626
openmsx::CreateMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:785
openmsx::Completer::Between
Definition: Completer.hh:55
openmsx::OPENMSX_QUIT_EVENT
Definition: Event.hh:31
openmsx::XmlOutputArchive::serialize
ALWAYS_INLINE void serialize(const char *tag, const T &t, Args &&...args)
Definition: serialize.hh:871
openmsx::Subject::detach
void detach(Observer< T > &observer)
Definition: Subject.hh:56
openmsx::CommandController
Definition: CommandController.hh:17
Timer.hh
Display.hh
serialize.hh
openmsx::StoreMachineCommand
Definition: Reactor.cc:137
openmsx::Completer::completeFileName
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
Definition: Completer.hh:139
openmsx::TestMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:770
openmsx::Sha1Sum::toString
std::string toString() const
Definition: utils/sha1.cc:232
openmsx::ListMachinesCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:842
ranges::sort
void sort(RandomAccessRange &&range)
Definition: ranges.hh:35
statp.hh
openmsx::Reactor::getOpenMSXInfoCommand
InfoCommand & getOpenMSXInfoCommand()
Definition: Reactor.cc:321
openmsx::SoftwareInfoTopic::SoftwareInfoTopic
SoftwareInfoTopic(InfoCommand &openMSXInfoCommand, Reactor &reactor)
Definition: Reactor.cc:1141
openmsx::StoreMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:937
DiskFactory.hh
openmsx::Reactor::unblock
void unblock()
Definition: Reactor.cc:614
TclObject.hh
openmsx::XmlInputArchive
Definition: serialize.hh:904
openmsx::FileOperations::getNextNumberedFileName
string getNextNumberedFileName(string_view directory, string_view prefix, string_view extension)
Definition: FileOperations.cc:705
openmsx::InfoTopic
Definition: InfoTopic.hh:15
openmsx::ConfigInfo::ConfigInfo
ConfigInfo(InfoCommand &openMSXInfoCommand, const string &configName)
Definition: Reactor.cc:1071
openmsx::ReadDir
Simple wrapper around openmdir() / readdir() / closedir() functions.
Definition: ReadDir.hh:15
XMLException.hh
openmsx::CreateMachineCommand
Definition: Reactor.cc:95
openmsx::RealTimeInfo
Definition: Reactor.cc:187
openmsx::RomInfo::getOrigType
std::string_view getOrigType(const char *buf) const
Definition: RomInfo.hh:44
DiskChanger.hh
ranges::any_of
bool any_of(InputRange &&range, UnaryPredicate pred)
Definition: ranges.hh:125
openmsx::MSXMotherBoard::loadMachine
std::string loadMachine(const std::string &machine)
Definition: MSXMotherBoard.cc:289
openmsx::RestoreMachineCommand::RestoreMachineCommand
RestoreMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:945
openmsx::StoreMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:899
openmsx::FileOperations::isRegularFile
bool isRegularFile(const Stat &st)
Definition: FileOperations.cc:654
CommandLineParser.hh
openmsx::ConfigInfo
Definition: Reactor.cc:175
LZ4::count
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
Definition: lz4.cc:207
openmsx::MachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:731
openmsx::DeleteMachineCommand::DeleteMachineCommand
DeleteMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:808
openmsx::MachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:736
openmsx::RestoreMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:1008
openmsx::RomInfo::getRomType
RomType getRomType() const
Definition: RomInfo.hh:50
openmsx::ConfigInfo::execute
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
Definition: Reactor.cc:1078
ranges.hh
openmsx::Reactor::block
void block()
Definition: Reactor.cc:607
openmsx::Timer::getTime
uint64_t getTime()
Get current (real) time in us.
Definition: Timer.cc:7
openmsx::MSXException
Definition: MSXException.hh:9
openmsx::SoftwareInfoTopic::help
std::string help(const std::vector< std::string > &tokens) const override
Print help for this topic.
Definition: Reactor.cc:1175
GlobalCliComm.hh
openmsx::userFileContext
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:161
XMLElement.hh
openmsx::Subject::attach
void attach(Observer< T > &observer)
Definition: Subject.hh:50
openmsx::Reactor::Board
std::unique_ptr< MSXMotherBoard > Board
Definition: Reactor.hh:110
openmsx::MSXMotherBoard::exitCPULoopAsync
void exitCPULoopAsync()
See CPU::exitCPULoopAsync().
Definition: MSXMotherBoard.cc:637
openmsx::Setting
Definition: Setting.hh:119
openmsx::RestoreMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:952
openmsx::SetClipboardCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:1063
openmsx::EventDistributor
Definition: EventDistributor.hh:16
openmsx::ReadDir::getEntry
struct dirent * getEntry()
Get directory entry for next file.
Definition: ReadDir.cc:17
openmsx::RomInfo::getCountry
std::string_view getCountry(const char *buf) const
Definition: RomInfo.hh:41
BooleanSetting.hh
StateChangeDistributor.hh
openmsx::Reactor::replaceBoard
void replaceBoard(MSXMotherBoard &oldBoard, Board newBoard)
Definition: Reactor.cc:400
AfterCommand.hh
openmsx::RomInfo::getOriginal
bool getOriginal() const
Definition: RomInfo.hh:51
openmsx::Reactor::createEmptyMotherBoard
Board createEmptyMotherBoard()
Definition: Reactor.cc:395
openmsx::StoreMachineCommand::StoreMachineCommand
StoreMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:892
span
Definition: span.hh:34
openmsx::Reactor
Contains the main loop of openMSX.
Definition: Reactor.hh:66
openmsx::XmlOutputArchive
Definition: serialize.hh:837
openmsx::TclObject::addListElements
void addListElements(ITER first, ITER last)
Definition: TclObject.hh:122
openmsx::Completer::completeString
static void completeString(std::vector< std::string > &tokens, ITER begin, ITER end, bool caseSensitive=true)
Definition: Completer.hh:125
openmsx::RealTimeInfo::help
string help(const vector< string > &tokens) const override
Print help for this topic.
Definition: Reactor.cc:1133
openmsx::RomInfo
Definition: RomInfo.hh:12
ReadDir.hh
StringOp::endsWith
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:81
Reactor.hh
openmsx::CliComm::STATUS
Definition: CliComm.hh:27
openmsx::SetClipboardCommand::SetClipboardCommand
SetClipboardCommand(CommandController &commandController)
Definition: Reactor.cc:1047
move_pop_back
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition: stl.hh:177
RomDatabase.hh
openmsx::MachineCommand
Definition: Reactor.cc:73
view::transform
auto transform(Range &&range, UnaryOp op)
Definition: view.hh:306
UNREACHABLE
#define UNREACHABLE
Definition: unreachable.hh:38
openmsx::RomInfo::getCompany
std::string_view getCompany(const char *buf) const
Definition: RomInfo.hh:38
openmsx::CreateMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:793
Mixer.hh
openmsx::MSXMotherBoard::powerUp
void powerUp()
Definition: MSXMotherBoard.cc:577
openmsx::Reactor::getMotherBoard
MSXMotherBoard * getMotherBoard() const
Definition: Reactor.cc:368
openmsx::MSXMotherBoard::getMachineID
std::string_view getMachineID() const
Definition: MSXMotherBoard.hh:68
openmsx::Reactor::getMachineID
std::string_view getMachineID() const
Definition: Reactor.cc:374
openmsx::TestMachineCommand
Definition: Reactor.cc:84
openmsx::SoftwareInfoTopic::execute
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
Definition: Reactor.cc:1147
openmsx::ListMachinesCommand::ListMachinesCommand
ListMachinesCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:835
openmsx::Reactor::Reactor
Reactor()
openmsx::Reactor::getInterpreter
Interpreter & getInterpreter()
Definition: Reactor.cc:311
openmsx::InfoCommand
Definition: InfoCommand.hh:11
openmsx::ActivateMachineCommand::ActivateMachineCommand
ActivateMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:856
openmsx::ExitCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:695
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:59
openmsx::CommandLineParser::RUN
Definition: CommandLineParser.hh:35
EventDistributor.hh
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
openmsx::MSXMotherBoard::execute
bool execute()
Run emulation.
Definition: MSXMotherBoard.cc:495
openmsx::TestMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:751
openmsx::Reactor::getCommandController
CommandController & getCommandController()
Definition: Reactor.cc:316
InputEvents.hh
openmsx::ExitCommand::ExitCommand
ExitCommand(CommandController &commandController, EventDistributor &distributor)
Definition: Reactor.cc:674
openmsx::RealTimeInfo::execute
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
Definition: Reactor.cc:1126
openmsx::FileOperations::getUserOpenMSXDir
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home directory.
Definition: FileOperations.cc:544
RTScheduler.hh
openmsx::FileException
Definition: FileException.hh:8
build-info.hh
openmsx::StoreMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:927
openmsx::Reactor::enterMainLoop
void enterMainLoop()
Definition: Reactor.cc:503
openmsx::XmlInputArchive::serialize
ALWAYS_INLINE void serialize(const char *tag, T &t, Args &&...args)
Definition: serialize.hh:942
view.hh
openmsx::TclObject::addDictKeyValue
void addDictKeyValue(const Key &key, const Value &value)
Definition: TclObject.hh:135
ranges::unique
auto unique(ForwardRange &&range)
Definition: ranges.hh:137
openmsx::ActivateMachineCommand
Definition: Reactor.cc:126
EnumSetting.hh
openmsx::Thread::isMainThread
bool isMainThread()
Returns true when called from the main thread.
Definition: Thread.cc:15
openmsx::Sha1Sum
This class represents the result of a sha1 calculation (a 160-bit value).
Definition: sha1.hh:19
FilePool.hh
openmsx::TestMachineCommand::TestMachineCommand
TestMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:744
openmsx::SetClipboardCommand
Definition: Reactor.cc:167
openmsx::TclObject::addDictKeyValues
void addDictKeyValues(Args &&... args)
Definition: TclObject.hh:138
GlobalSettings.hh
FileContext.hh
MessageCommand.hh
openmsx::FatalError
Definition: MSXException.hh:30
openmsx::RomInfo::getTitle
std::string_view getTitle(const char *buf) const
Definition: RomInfo.hh:32
openmsx::ActivateMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:877
AviRecorder.hh
openmsx::FileOperations::isDirectory
bool isDirectory(const Stat &st)
Definition: FileOperations.cc:664
FileOperations.hh
openmsx::ActivateMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:884
openmsx::CommandLineParser
Definition: CommandLineParser.hh:32
checked_cast.hh
openmsx::Reactor::run
void run(CommandLineParser &parser)
Main loop.
Definition: Reactor.cc:519
openmsx::OPENMSX_FOCUS_EVENT
Definition: Event.hh:29
openmsx::DeleteMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:815
openmsx::Reactor::getGlobalSettings
GlobalSettings & getGlobalSettings()
Definition: Reactor.hh:103
openmsx::GlobalCliComm::setAllowExternalCommands
void setAllowExternalCommands()
Definition: GlobalCliComm.cc:44
openmsx::DeleteMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:822
openmsx::Reactor::switchMachine
void switchMachine(const std::string &machine)
Definition: Reactor.cc:424
openmsx::Reactor::getGlobalCliComm
GlobalCliComm & getGlobalCliComm()
Definition: Reactor.hh:82
openmsx::CommandLineParser::getStartupCommands
const std::vector< std::string > & getStartupCommands() const
Definition: CommandLineParser.hh:58
RomInfo.hh
StringOp.hh
openmsx::Reactor::getCliComm
CliComm & getCliComm()
Definition: Reactor.cc:306
openmsx::Reactor::~Reactor
~Reactor()
Definition: Reactor.cc:284
openmsx::ActivateMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:863
openmsx::OPENMSX_MACHINE_LOADED_EVENT
Send when a (new) machine configuration is loaded.
Definition: Event.hh:58
openmsx::RomDatabase
Definition: RomDatabase.hh:14
Command.hh
GlobalCommandController.hh
openmsx::MachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:711
openmsx::ConfigInfo::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this topic.
Definition: Reactor.cc:1112
TclCallbackMessages.hh
UserSettings.hh
InfoTopic.hh
openmsx::Command
Definition: Command.hh:40
openmsx::CliComm
Definition: CliComm.hh:10
detail::append
void append(Result &)
Definition: stl.hh:340
openmsx::CreateMachineCommand::CreateMachineCommand
CreateMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:778
stl.hh
find_if_unguarded
ITER find_if_unguarded(ITER first, ITER last, PRED pred)
Faster alternative to 'find_if' when it's guaranteed that the predicate will be true for at least one...
Definition: stl.hh:131
openmsx::MachineCommand::MachineCommand
MachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:704
openmsx::TclObject
Definition: TclObject.hh:21
InputEventGenerator.hh
openmsx::GlobalSettings::getPauseSetting
BooleanSetting & getPauseSetting()
Definition: GlobalSettings.hh:32
openmsx::Reactor::getHwConfigs
static std::vector< std::string > getHwConfigs(std::string_view type)
Definition: Reactor.cc:326
openmsx::CommandLineParser::getStartupScripts
const std::vector< std::string > & getStartupScripts() const
Definition: CommandLineParser.hh:55
Thread.hh
openmsx::TestMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:763
openmsx::CommandLineParser::getParseStatus
ParseStatus getParseStatus() const
Definition: CommandLineParser.cc:282
unreachable.hh
openmsx::MSXException::getMessage
const std::string & getMessage() const &
Definition: MSXException.hh:23
openmsx::RestoreMachineCommand
Definition: Reactor.cc:148
openmsx::XmlOutputArchive::close
void close()
Definition: serialize.cc:282
openmsx::OPENMSX_DELETE_BOARDS
Delete old MSXMotherboards.
Definition: Event.hh:70
openmsx::RealTimeInfo::RealTimeInfo
RealTimeInfo(InfoCommand &openMSXInfoCommand)
Definition: Reactor.cc:1120
strCat
std::string strCat(Ts &&...ts)
Definition: strCat.hh:573
openmsx::Interpreter
Definition: Interpreter.hh:16
CommandException.hh
openmsx::Reactor::getGlobalCommandController
GlobalCommandController & getGlobalCommandController()
Definition: Reactor.hh:83
openmsx::FileOperations::join
string join(string_view part1, string_view part2)
Definition: FileOperations.cc:430
openmsx::ExitCommand
Definition: Reactor.cc:63
openmsx::DeleteMachineCommand
Definition: Reactor.cc:105
openmsx::Reactor::getSoftwareDatabase
RomDatabase & getSoftwareDatabase()
Definition: Reactor.cc:298
openmsx
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
to_vector
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))>>
Definition: stl.hh:311
MSXMotherBoard.hh
openmsx::RomInfo::getRemark
std::string_view getRemark(const char *buf) const
Definition: RomInfo.hh:47
openmsx::exitCode
int exitCode
Definition: Reactor.cc:61
openmsx::HardwareConfig::loadConfig
static XMLElement loadConfig(std::string_view type, std::string_view name)
Definition: HardwareConfig.cc:220
openmsx::CommandCompleter::getInterpreter
Interpreter & getInterpreter() const final
Definition: Command.cc:41
openmsx::Reactor::init
void init()
Definition: Reactor.cc:212
openmsx::CliComm::HARDWARE
Definition: CliComm.hh:24
openmsx::ConfigInfo::help
string help(const vector< string > &tokens) const override
Print help for this topic.
Definition: Reactor.cc:1106
openmsx::preferSystemFileContext
FileContext preferSystemFileContext()
Definition: FileContext.cc:155
rfind_if_unguarded
auto rfind_if_unguarded(RANGE &range, PRED pred)
Definition: stl.hh:160
openmsx::ListMachinesCommand
Definition: Reactor.cc:116
openmsx::GetClipboardCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:1039
openmsx::EventDistributor::distributeEvent
void distributeEvent(const EventPtr &event)
Schedule the given event for delivery.
Definition: EventDistributor.cc:44
openmsx::RomInfo::romTypeToName
static std::string_view romTypeToName(RomType type)
Definition: RomInfo.cc:195
openmsx::ExitCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:681
openmsx::systemFileContext
FileContext systemFileContext()
Definition: FileContext.cc:149
openmsx::MSXMotherBoard::exitCPULoopSync
void exitCPULoopSync()
Definition: MSXMotherBoard.cc:644
openmsx::Completer::Prefix
Definition: Completer.hh:56
openmsx::GetClipboardCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:1030
openmsx::RomInfo::getGenMSXid
int getGenMSXid() const
Definition: RomInfo.hh:52