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 "foreach_file.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  auto fileAction = [&](const std::string& /*path*/, std::string_view name) {
331  if (StringOp::endsWith(name, ".xml")) {
332  name.remove_suffix(4);
333  result.emplace_back(name);
334  }
335  };
336  auto dirAction = [&](std::string& path, std::string_view name) {
337  auto size = path.size();
338  path += "/hardwareconfig.xml";
339  if (FileOperations::isRegularFile(path)) {
340  result.emplace_back(name);
341  }
342  path.resize(size);
343  };
344  foreach_file_and_directory(FileOperations::join(p, type), fileAction, dirAction);
345  }
346  // remove duplicates
347  ranges::sort(result);
348  result.erase(ranges::unique(result), end(result));
349  return result;
350 }
351 
352 void Reactor::createMachineSetting()
353 {
354  EnumSetting<int>::Map machines; // int's are unique dummy values
355  int count = 1;
356  append(machines, view::transform(getHwConfigs("machines"),
357  [&](auto& name) { return std::pair(name, count++); }));
358  machines.emplace_back("C-BIOS_MSX2+", 0); // default machine
359 
360  machineSetting = make_unique<EnumSetting<int>>(
361  *globalCommandController, "default_machine",
362  "default machine (takes effect next time openMSX is started)",
363  0, std::move(machines));
364 }
365 
367 {
368  assert(Thread::isMainThread());
369  return activeBoard;
370 }
371 
372 string_view Reactor::getMachineID() const
373 {
374  return activeBoard ? activeBoard->getMachineID() : string_view{};
375 }
376 
377 vector<string_view> Reactor::getMachineIDs() const
378 {
379  return to_vector(view::transform(
380  boards, [](auto& b) { return b->getMachineID(); }));
381 }
382 
383 MSXMotherBoard& Reactor::getMachine(string_view machineID) const
384 {
385  for (auto& b : boards) {
386  if (b->getMachineID() == machineID) {
387  return *b;
388  }
389  }
390  throw CommandException("No machine with ID: ", machineID);
391 }
392 
394 {
395  return make_unique<MSXMotherBoard>(*this);
396 }
397 
398 void Reactor::replaceBoard(MSXMotherBoard& oldBoard_, Board newBoard_)
399 {
400  assert(Thread::isMainThread());
401 
402  // Add new board.
403  auto* newBoard = newBoard_.get();
404  boards.push_back(move(newBoard_));
405 
406  // Lookup old board (it must be present).
407  auto it = find_if_unguarded(boards,
408  [&](auto& b) { return b.get() == &oldBoard_; });
409 
410  // If the old board was the active board, then activate the new board
411  if (it->get() == activeBoard) {
412  switchBoard(newBoard);
413  }
414 
415  // Remove (=delete) the old board.
416  // Note that we don't use the 'garbageBoards' mechanism as used in
417  // deleteBoard(). This means oldBoard cannot be used anymore right
418  // after this method returns.
419  move_pop_back(boards, it);
420 }
421 
422 void Reactor::switchMachine(const string& machine)
423 {
424  if (!display) {
425  display = make_unique<Display>(*this);
426  // TODO: Currently it is not possible to move this call into the
427  // constructor of Display because the call to createVideoSystem()
428  // indirectly calls Reactor.getDisplay().
429  display->createVideoSystem();
430  }
431 
432  // create+load new machine
433  // switch to new machine
434  // delete old active machine
435 
436  assert(Thread::isMainThread());
437  // Note: loadMachine can throw an exception and in that case the
438  // motherboard must be considered as not created at all.
439  auto newBoard_ = createEmptyMotherBoard();
440  auto* newBoard = newBoard_.get();
441  newBoard->loadMachine(machine);
442  boards.push_back(move(newBoard_));
443 
444  auto* oldBoard = activeBoard;
445  switchBoard(newBoard);
446  deleteBoard(oldBoard);
447 }
448 
449 void Reactor::switchBoard(MSXMotherBoard* newBoard)
450 {
451  assert(Thread::isMainThread());
452  assert(!newBoard ||
453  (ranges::any_of(boards, [&](auto& b) { return b.get() == newBoard; })));
454  assert(!activeBoard ||
455  (ranges::any_of(boards, [&](auto& b) { return b.get() == activeBoard; })));
456  if (activeBoard) {
457  activeBoard->activate(false);
458  }
459  {
460  // Don't hold the lock for longer than the actual switch.
461  // In the past we had a potential for deadlocks here, because
462  // (indirectly) the code below still acquires other locks.
463  std::lock_guard<std::mutex> lock(mbMutex);
464  activeBoard = newBoard;
465  }
466  eventDistributor->distributeEvent(
467  make_shared<SimpleEvent>(OPENMSX_MACHINE_LOADED_EVENT));
468  globalCliComm->update(CliComm::HARDWARE, getMachineID(), "select");
469  if (activeBoard) {
470  activeBoard->activate(true);
471  }
472 }
473 
474 void Reactor::deleteBoard(MSXMotherBoard* board)
475 {
476  // Note: pass 'board' by-value to keep the parameter from changing
477  // after the call to switchBoard(). switchBoard() changes the
478  // 'activeBoard' member variable, so the 'board' parameter would change
479  // if it were passed by reference to this method (AFAICS this only
480  // happens in ~Reactor()).
481  assert(Thread::isMainThread());
482  if (!board) return;
483 
484  if (board == activeBoard) {
485  // delete active board -> there is no active board anymore
486  switchBoard(nullptr);
487  }
488  auto it = rfind_if_unguarded(boards,
489  [&](auto& b) { return b.get() == board; });
490  auto board_ = move(*it);
491  move_pop_back(boards, it);
492  // Don't immediately delete old boards because it's possible this
493  // routine is called via a code path that goes through the old
494  // board. Instead remember this board and delete it at a safe moment
495  // in time.
496  garbageBoards.push_back(move(board_));
497  eventDistributor->distributeEvent(
498  make_shared<SimpleEvent>(OPENMSX_DELETE_BOARDS));
499 }
500 
502 {
503  // Note: this method can get called from different threads
504  if (Thread::isMainThread()) {
505  // Don't take lock in main thread to avoid recursive locking.
506  if (activeBoard) {
507  activeBoard->exitCPULoopSync();
508  }
509  } else {
510  std::lock_guard<std::mutex> lock(mbMutex);
511  if (activeBoard) {
512  activeBoard->exitCPULoopAsync();
513  }
514  }
515 }
516 
518 {
519  auto& commandController = *globalCommandController;
520 
521  // execute init.tcl
522  try {
523  commandController.source(
524  preferSystemFileContext().resolve("init.tcl"));
525  } catch (FileException&) {
526  // no init.tcl, ignore
527  }
528 
529  // execute startup scripts
530  for (auto& s : parser.getStartupScripts()) {
531  try {
532  commandController.source(userFileContext().resolve(s));
533  } catch (FileException& e) {
534  throw FatalError("Couldn't execute script: ",
535  e.getMessage());
536  }
537  }
538  for (auto& cmd : parser.getStartupCommands()) {
539  try {
540  commandController.executeCommand(cmd);
541  } catch (CommandException& e) {
542  throw FatalError("Couldn't execute command: ", cmd,
543  '\n', e.getMessage());
544  }
545  }
546 
547  // At this point openmsx is fully started, it's OK now to start
548  // accepting external commands
550 
551  // Run
552  if (parser.getParseStatus() == CommandLineParser::RUN) {
553  // don't use Tcl to power up the machine, we cannot pass
554  // exceptions through Tcl and ADVRAM might throw in its
555  // powerUp() method. Solution is to implement dependencies
556  // between devices so ADVRAM can check the error condition
557  // in its constructor
558  //commandController.executeCommand("set power on");
559  if (activeBoard) {
560  activeBoard->powerUp();
561  }
562  }
563 
564  while (doOneIteration()) {
565  // nothing
566  }
567 }
568 
569 bool Reactor::doOneIteration()
570 {
571  eventDistributor->deliverEvents();
572  assert(garbageBoards.empty());
573  bool blocked = (blockedCounter > 0) || !activeBoard;
574  if (!blocked) blocked = !activeBoard->execute();
575  if (blocked) {
576  // At first sight a better alternative is to use the
577  // SDL_WaitEvent() function. Though when inspecting
578  // the implementation of that function, it turns out
579  // to also use a sleep/poll loop, with even shorter
580  // sleep periods as we use here. Maybe in future
581  // SDL implementations this will be improved.
582  eventDistributor->sleep(20 * 1000);
583  }
584  return running;
585 }
586 
587 void Reactor::unpause()
588 {
589  if (paused) {
590  paused = false;
591  globalCliComm->update(CliComm::STATUS, "paused", "false");
592  unblock();
593  }
594 }
595 
596 void Reactor::pause()
597 {
598  if (!paused) {
599  paused = true;
600  globalCliComm->update(CliComm::STATUS, "paused", "true");
601  block();
602  }
603 }
604 
606 {
607  ++blockedCounter;
608  enterMainLoop();
609  mixer->mute();
610 }
611 
613 {
614  --blockedCounter;
615  assert(blockedCounter >= 0);
616  mixer->unmute();
617 }
618 
619 
620 // Observer<Setting>
621 void Reactor::update(const Setting& setting)
622 {
623  auto& pauseSetting = getGlobalSettings().getPauseSetting();
624  if (&setting == &pauseSetting) {
625  if (pauseSetting.getBoolean()) {
626  pause();
627  } else {
628  unpause();
629  }
630  }
631 }
632 
633 // EventListener
634 int Reactor::signalEvent(const std::shared_ptr<const Event>& event)
635 {
636  auto type = event->getType();
637  if (type == OPENMSX_QUIT_EVENT) {
638  enterMainLoop();
639  running = false;
640 #if PLATFORM_ANDROID
641  } else if (type == OPENMSX_FOCUS_EVENT) {
642  // Android SDL port sends a (un)focus event when an app is put in background
643  // by the OS for whatever reason (like an incoming phone call) and all screen
644  // resources are taken away from the app.
645  // In such case the app is supposed to behave as a good citizen
646  // and minize its resource usage and related battery drain.
647  // The SDL Android port already takes care of halting the Java
648  // part of the sound processing. The Display class makes sure that it wont try
649  // to render anything to the (temporary missing) graphics resources but the
650  // main emulation should also be temporary stopped, in order to minimize CPU usage
651  auto& focusEvent = checked_cast<const FocusEvent&>(*event);
652  if (focusEvent.getGain()) {
653  unblock();
654  } else {
655  block();
656  }
657 #endif
658  } else if (type == OPENMSX_DELETE_BOARDS) {
659  // Doesn't really matter which one we delete, just that we do
660  // one per event.
661  assert(!garbageBoards.empty());
662  garbageBoards.pop_back();
663  } else {
664  UNREACHABLE; // we didn't subscribe to this event...
665  }
666  return 0;
667 }
668 
669 
670 // class ExitCommand
671 
673  EventDistributor& distributor_)
674  : Command(commandController_, "exit")
675  , distributor(distributor_)
676 {
677 }
678 
680 {
681  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "?exitcode?");
682  switch (tokens.size()) {
683  case 1:
684  exitCode = 0;
685  break;
686  case 2:
687  exitCode = tokens[1].getInt(getInterpreter());
688  break;
689  }
690  distributor.distributeEvent(make_shared<QuitEvent>());
691 }
692 
693 string ExitCommand::help(const vector<string>& /*tokens*/) const
694 {
695  return "Use this command to stop the emulator.\n"
696  "Optionally you can pass an exit-code.\n";
697 }
698 
699 
700 // class MachineCommand
701 
703  Reactor& reactor_)
704  : Command(commandController_, "machine")
705  , reactor(reactor_)
706 {
707 }
708 
710 {
711  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "?machinetype?");
712  switch (tokens.size()) {
713  case 1: // get current machine
714  // nothing
715  break;
716  case 2:
717  try {
718  reactor.switchMachine(string(tokens[1].getString()));
719  } catch (MSXException& e) {
720  throw CommandException("Machine switching failed: ",
721  e.getMessage());
722  }
723  break;
724  }
725  // Always return machineID (of current or of new machine).
726  result = reactor.getMachineID();
727 }
728 
729 string MachineCommand::help(const vector<string>& /*tokens*/) const
730 {
731  return "Switch to a different MSX machine.";
732 }
733 
734 void MachineCommand::tabCompletion(vector<string>& tokens) const
735 {
736  completeString(tokens, Reactor::getHwConfigs("machines"));
737 }
738 
739 
740 // class TestMachineCommand
741 
743  Reactor& reactor_)
744  : Command(commandController_, "test_machine")
745  , reactor(reactor_)
746 {
747 }
748 
750  TclObject& result)
751 {
752  checkNumArgs(tokens, 2, "machinetype");
753  try {
754  MSXMotherBoard mb(reactor);
755  mb.loadMachine(string(tokens[1].getString()));
756  } catch (MSXException& e) {
757  result = e.getMessage(); // error
758  }
759 }
760 
761 string TestMachineCommand::help(const vector<string>& /*tokens*/) const
762 {
763  return "Test the configuration for the given machine. "
764  "Returns an error message explaining why the configuration is "
765  "invalid or an empty string in case of success.";
766 }
767 
768 void TestMachineCommand::tabCompletion(vector<string>& tokens) const
769 {
770  completeString(tokens, Reactor::getHwConfigs("machines"));
771 }
772 
773 
774 // class CreateMachineCommand
775 
777  CommandController& commandController_, Reactor& reactor_)
778  : Command(commandController_, "create_machine")
779  , reactor(reactor_)
780 {
781 }
782 
784 {
785  checkNumArgs(tokens, 1, Prefix{1}, nullptr);
786  auto newBoard = reactor.createEmptyMotherBoard();
787  result = newBoard->getMachineID();
788  reactor.boards.push_back(move(newBoard));
789 }
790 
791 string CreateMachineCommand::help(const vector<string>& /*tokens*/) const
792 {
793  return "Creates a new (empty) MSX machine. Returns the ID for the new "
794  "machine.\n"
795  "Use 'load_machine' to actually load a machine configuration "
796  "into this new machine.\n"
797  "The main reason create_machine and load_machine are two "
798  "separate commands is that sometimes you already want to know "
799  "the ID of the machine before load_machine starts emitting "
800  "events for this machine.";
801 }
802 
803 
804 // class DeleteMachineCommand
805 
807  CommandController& commandController_, Reactor& reactor_)
808  : Command(commandController_, "delete_machine")
809  , reactor(reactor_)
810 {
811 }
812 
814  TclObject& /*result*/)
815 {
816  checkNumArgs(tokens, 2, "id");
817  reactor.deleteBoard(&reactor.getMachine(tokens[1].getString()));
818 }
819 
820 string DeleteMachineCommand::help(const vector<string>& /*tokens*/) const
821 {
822  return "Deletes the given MSX machine.";
823 }
824 
825 void DeleteMachineCommand::tabCompletion(vector<string>& tokens) const
826 {
827  completeString(tokens, reactor.getMachineIDs());
828 }
829 
830 
831 // class ListMachinesCommand
832 
834  CommandController& commandController_, Reactor& reactor_)
835  : Command(commandController_, "list_machines")
836  , reactor(reactor_)
837 {
838 }
839 
841  TclObject& result)
842 {
843  result.addListElements(reactor.getMachineIDs());
844 }
845 
846 string ListMachinesCommand::help(const vector<string>& /*tokens*/) const
847 {
848  return "Returns a list of all machine IDs.";
849 }
850 
851 
852 // class ActivateMachineCommand
853 
855  CommandController& commandController_, Reactor& reactor_)
856  : Command(commandController_, "activate_machine")
857  , reactor(reactor_)
858 {
859 }
860 
862  TclObject& result)
863 {
864  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "id");
865  switch (tokens.size()) {
866  case 1:
867  break;
868  case 2:
869  reactor.switchBoard(&reactor.getMachine(tokens[1].getString()));
870  break;
871  }
872  result = reactor.getMachineID();
873 }
874 
875 string ActivateMachineCommand::help(const vector<string>& /*tokens*/) const
876 {
877  return "Make another machine the active msx machine.\n"
878  "Or when invoked without arguments, query the ID of the "
879  "active msx machine.";
880 }
881 
882 void ActivateMachineCommand::tabCompletion(vector<string>& tokens) const
883 {
884  completeString(tokens, reactor.getMachineIDs());
885 }
886 
887 
888 // class StoreMachineCommand
889 
891  CommandController& commandController_, Reactor& reactor_)
892  : Command(commandController_, "store_machine")
893  , reactor(reactor_)
894 {
895 }
896 
898 {
899  checkNumArgs(tokens, Between{1, 3}, Prefix{1}, "?id? ?filename?");
900  string filename;
901  string_view machineID;
902  switch (tokens.size()) {
903  case 1:
904  machineID = reactor.getMachineID();
905  filename = FileOperations::getNextNumberedFileName("savestates", "openmsxstate", ".xml.gz");
906  break;
907  case 2:
908  machineID = tokens[1].getString();
909  filename = FileOperations::getNextNumberedFileName("savestates", "openmsxstate", ".xml.gz");
910  break;
911  case 3:
912  machineID = tokens[1].getString();
913  filename = tokens[2].getString();
914  break;
915  }
916 
917  auto& board = reactor.getMachine(machineID);
918 
920  out.serialize("machine", board);
921  out.close();
922  result = filename;
923 }
924 
925 string StoreMachineCommand::help(const vector<string>& /*tokens*/) const
926 {
927  return
928  "store_machine Save state of current machine to file \"openmsxNNNN.xml.gz\"\n"
929  "store_machine machineID Save state of machine \"machineID\" to file \"openmsxNNNN.xml.gz\"\n"
930  "store_machine machineID <filename> Save state of machine \"machineID\" to indicated file\n"
931  "\n"
932  "This is a low-level command, the 'savestate' script is easier to use.";
933 }
934 
935 void StoreMachineCommand::tabCompletion(vector<string>& tokens) const
936 {
937  completeString(tokens, reactor.getMachineIDs());
938 }
939 
940 
941 // class RestoreMachineCommand
942 
944  CommandController& commandController_, Reactor& reactor_)
945  : Command(commandController_, "restore_machine")
946  , reactor(reactor_)
947 {
948 }
949 
951  TclObject& result)
952 {
953  checkNumArgs(tokens, Between{1, 2}, Prefix{1}, "?filename?");
954  auto newBoard = reactor.createEmptyMotherBoard();
955 
956  string filename;
957  switch (tokens.size()) {
958  case 1: {
959  // load last saved entry
960  string lastEntry;
961  time_t lastTime = 0;
962  foreach_file(
963  FileOperations::getUserOpenMSXDir() + "/savestates",
964  [&](const string& path, const FileOperations::Stat& st) {
965  time_t modTime = st.st_mtime;
966  if (modTime > lastTime) {
967  filename = path;
968  lastTime = modTime;
969  }
970  });
971  if (filename.empty()) {
972  throw CommandException("Can't find last saved state.");
973  }
974  break;
975  }
976  case 2:
977  filename = tokens[1].getString();
978  break;
979  }
980 
981  //std::cerr << "Loading " << filename << '\n';
982  try {
984  in.serialize("machine", *newBoard);
985  } catch (XMLException& e) {
986  throw CommandException("Cannot load state, bad file format: ",
987  e.getMessage());
988  } catch (MSXException& e) {
989  throw CommandException("Cannot load state: ", e.getMessage());
990  }
991 
992  // Savestate also contains stuff like the keyboard state at the moment
993  // the snapshot was created (this is required for reverse/replay). But
994  // now we want the MSX to see the actual host keyboard state.
995  newBoard->getStateChangeDistributor().stopReplay(newBoard->getCurrentTime());
996 
997  result = newBoard->getMachineID();
998  reactor.boards.push_back(move(newBoard));
999 }
1000 
1001 string RestoreMachineCommand::help(const vector<string>& /*tokens*/) const
1002 {
1003  return "restore_machine Load state from last saved state in default directory\n"
1004  "restore_machine <filename> Load state from indicated file\n"
1005  "\n"
1006  "This is a low-level command, the 'loadstate' script is easier to use.";
1007 }
1008 
1009 void RestoreMachineCommand::tabCompletion(vector<string>& tokens) const
1010 {
1011  // TODO: add the default files (state files in user's savestates dir)
1012  completeFileName(tokens, userFileContext());
1013 }
1014 
1015 
1016 // class GetClipboardCommand
1017 
1019  : Command(commandController_, "get_clipboard_text")
1020 {
1021 }
1022 
1024 {
1025  checkNumArgs(tokens, 1, Prefix{1}, nullptr);
1026  if (char* text = SDL_GetClipboardText()) {
1027  result = text;
1028  SDL_free(text);
1029  }
1030 }
1031 
1032 string GetClipboardCommand::help(const vector<string>& /*tokens*/) const
1033 {
1034  return "Returns the (text) content of the clipboard as a string.";
1035 }
1036 
1037 
1038 // class SetClipboardCommand
1039 
1041  : Command(commandController_, "set_clipboard_text")
1042 {
1043 }
1044 
1046 {
1047  checkNumArgs(tokens, 2, "text");
1048  string text(tokens[1].getString());
1049  if (SDL_SetClipboardText(text.c_str()) != 0) {
1050  const char* err = SDL_GetError();
1051  SDL_ClearError();
1052  throw CommandException(err);
1053  }
1054 }
1055 
1056 string SetClipboardCommand::help(const vector<string>& /*tokens*/) const
1057 {
1058  return "Send the given string to the clipboard.";
1059 }
1060 
1061 
1062 // class ConfigInfo
1063 
1065  const string& configName_)
1066  : InfoTopic(openMSXInfoCommand, configName_)
1067  , configName(configName_)
1068 {
1069 }
1070 
1072 {
1073  // TODO make meta info available through this info topic
1074  switch (tokens.size()) {
1075  case 2: {
1076  result.addListElements(Reactor::getHwConfigs(configName));
1077  break;
1078  }
1079  case 3: {
1080  try {
1081  auto config = HardwareConfig::loadConfig(
1082  configName, tokens[2].getString());
1083  if (auto* info = config.findChild("info")) {
1084  for (auto& i : info->getChildren()) {
1085  result.addDictKeyValue(i.getName(), i.getData());
1086  }
1087  }
1088  } catch (MSXException& e) {
1089  throw CommandException(
1090  "Couldn't get config info: ", e.getMessage());
1091  }
1092  break;
1093  }
1094  default:
1095  throw CommandException("Too many parameters");
1096  }
1097 }
1098 
1099 string ConfigInfo::help(const vector<string>& /*tokens*/) const
1100 {
1101  return strCat("Shows a list of available ", configName, ", "
1102  "or get meta information about the selected item.\n");
1103 }
1104 
1105 void ConfigInfo::tabCompletion(vector<string>& tokens) const
1106 {
1107  completeString(tokens, Reactor::getHwConfigs(configName));
1108 }
1109 
1110 
1111 // class RealTimeInfo
1112 
1114  : InfoTopic(openMSXInfoCommand, "realtime")
1115  , reference(Timer::getTime())
1116 {
1117 }
1118 
1120  TclObject& result) const
1121 {
1122  auto delta = Timer::getTime() - reference;
1123  result = delta / 1000000.0;
1124 }
1125 
1126 string RealTimeInfo::help(const vector<string>& /*tokens*/) const
1127 {
1128  return "Returns the time in seconds since openMSX was started.";
1129 }
1130 
1131 
1132 // SoftwareInfoTopic
1133 
1135  : InfoTopic(openMSXInfoCommand, "software")
1136  , reactor(reactor_)
1137 {
1138 }
1139 
1141  span<const TclObject> tokens, TclObject& result) const
1142 {
1143  if (tokens.size() != 3) {
1144  throw CommandException("Wrong number of parameters");
1145  }
1146 
1147  Sha1Sum sha1sum = Sha1Sum(tokens[2].getString());
1148  auto& romDatabase = reactor.getSoftwareDatabase();
1149  const RomInfo* romInfo = romDatabase.fetchRomInfo(sha1sum);
1150  if (!romInfo) {
1151  // no match found
1152  throw CommandException(
1153  "Software with sha1sum ", sha1sum.toString(), " not found");
1154  }
1155 
1156  const char* bufStart = romDatabase.getBufferStart();
1157  result.addDictKeyValues("title", romInfo->getTitle(bufStart),
1158  "year", romInfo->getYear(bufStart),
1159  "company", romInfo->getCompany(bufStart),
1160  "country", romInfo->getCountry(bufStart),
1161  "orig_type", romInfo->getOrigType(bufStart),
1162  "remark", romInfo->getRemark(bufStart),
1163  "original", romInfo->getOriginal(),
1164  "mapper_type_name", RomInfo::romTypeToName(romInfo->getRomType()),
1165  "genmsxid", romInfo->getGenMSXid());
1166 }
1167 
1168 string SoftwareInfoTopic::help(const vector<string>& /*tokens*/) const
1169 {
1170  return "Returns information about the software "
1171  "given its sha1sum, in a paired list.";
1172 }
1173 
1174 } // namespace openmsx
openmsx::DeleteMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:825
openmsx::EnumSetting
Definition: EnumSetting.hh:33
openmsx::ListMachinesCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:846
openmsx::CommandException
Definition: CommandException.hh:9
openmsx::XMLException
Definition: XMLException.hh:9
DiskManipulator.hh
openmsx::Completer::checkNumArgs
void checkNumArgs(span< const TclObject > tokens, unsigned exactly, const char *errMessage) const
Definition: Completer.cc:177
HardwareConfig.hh
openmsx::GetClipboardCommand::GetClipboardCommand
GetClipboardCommand(CommandController &commandController)
Definition: Reactor.cc:1018
openmsx::GetClipboardCommand
Definition: Reactor.cc:160
FileException.hh
openmsx::SoftwareInfoTopic
Definition: Reactor.cc:199
openmsx::RestoreMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:1009
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:1045
openmsx::MSXMotherBoard::activate
void activate(bool active)
Definition: MSXMotherBoard.cc:639
openmsx::CreateMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:783
openmsx::Completer::Between
Definition: Completer.hh:55
openmsx::OPENMSX_QUIT_EVENT
@ OPENMSX_QUIT_EVENT
Definition: Event.hh:33
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:18
Timer.hh
Display.hh
serialize.hh
openmsx::StoreMachineCommand
Definition: Reactor.cc:138
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:768
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:840
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:1134
openmsx::StoreMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:935
DiskFactory.hh
openmsx::Reactor::unblock
void unblock()
Definition: Reactor.cc:612
TclObject.hh
openmsx::XmlInputArchive
Definition: serialize.hh:905
openmsx::InfoTopic
Definition: InfoTopic.hh:16
openmsx::ConfigInfo::ConfigInfo
ConfigInfo(InfoCommand &openMSXInfoCommand, const string &configName)
Definition: Reactor.cc:1064
XMLException.hh
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
openmsx::CreateMachineCommand
Definition: Reactor.cc:96
openmsx::RealTimeInfo
Definition: Reactor.cc:188
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:303
openmsx::RestoreMachineCommand::RestoreMachineCommand
RestoreMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:943
openmsx::StoreMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:897
openmsx::FileOperations::Stat
struct stat Stat
Definition: FileOperations.hh:217
openmsx::FileOperations::isRegularFile
bool isRegularFile(const Stat &st)
Definition: FileOperations.cc:644
CommandLineParser.hh
openmsx::ConfigInfo
Definition: Reactor.cc:176
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:729
openmsx::DeleteMachineCommand::DeleteMachineCommand
DeleteMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:806
openmsx::MachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:734
openmsx::RestoreMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:1001
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:1071
ranges.hh
openmsx::Reactor::block
void block()
Definition: Reactor.cc:605
openmsx::Timer::getTime
uint64_t getTime()
Get current (real) time in us.
Definition: Timer.cc:7
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::SoftwareInfoTopic::help
std::string help(const std::vector< std::string > &tokens) const override
Print help for this topic.
Definition: Reactor.cc:1168
GlobalCliComm.hh
openmsx::userFileContext
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:164
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:650
openmsx::FileOperations::join
string join(string_view part1, string_view part2)
Join two paths.
Definition: FileOperations.cc:423
openmsx::Setting
Definition: Setting.hh:120
openmsx::RestoreMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:950
openmsx::SetClipboardCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:1056
openmsx::EventDistributor
Definition: EventDistributor.hh: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:398
AfterCommand.hh
openmsx::RomInfo::getOriginal
bool getOriginal() const
Definition: RomInfo.hh:51
openmsx::Reactor::createEmptyMotherBoard
Board createEmptyMotherBoard()
Definition: Reactor.cc:393
openmsx::StoreMachineCommand::StoreMachineCommand
StoreMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:890
span
Definition: span.hh:126
openmsx::Reactor
Contains the main loop of openMSX.
Definition: Reactor.hh:67
openmsx::XmlOutputArchive
Definition: serialize.hh:838
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:1126
openmsx::RomInfo
Definition: RomInfo.hh:13
StringOp::endsWith
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:81
Reactor.hh
openmsx::CliComm::STATUS
@ STATUS
Definition: CliComm.hh:27
openmsx::SetClipboardCommand::SetClipboardCommand
SetClipboardCommand(CommandController &commandController)
Definition: Reactor.cc:1040
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:74
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:791
Mixer.hh
openmsx::MSXMotherBoard::powerUp
void powerUp()
Definition: MSXMotherBoard.cc:590
openmsx::Reactor::getMotherBoard
MSXMotherBoard * getMotherBoard() const
Definition: Reactor.cc:366
openmsx::MSXMotherBoard::getMachineID
std::string_view getMachineID() const
Definition: MSXMotherBoard.hh:69
openmsx::Reactor::getMachineID
std::string_view getMachineID() const
Definition: Reactor.cc:372
openmsx::TestMachineCommand
Definition: Reactor.cc:85
openmsx::SoftwareInfoTopic::execute
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
Definition: Reactor.cc:1140
openmsx::ListMachinesCommand::ListMachinesCommand
ListMachinesCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:833
openmsx::Reactor::Reactor
Reactor()
openmsx::Reactor::getInterpreter
Interpreter & getInterpreter()
Definition: Reactor.cc:311
openmsx::InfoCommand
Definition: InfoCommand.hh:12
openmsx::ActivateMachineCommand::ActivateMachineCommand
ActivateMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:854
openmsx::ExitCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:693
openmsx::MSXMotherBoard
Definition: MSXMotherBoard.hh:61
openmsx::CommandLineParser::RUN
@ RUN
Definition: CommandLineParser.hh:37
EventDistributor.hh
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
openmsx::MSXMotherBoard::execute
bool execute()
Run emulation.
Definition: MSXMotherBoard.cc:508
openmsx::TestMachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:749
openmsx::Reactor::getCommandController
CommandController & getCommandController()
Definition: Reactor.cc:316
InputEvents.hh
openmsx::ExitCommand::ExitCommand
ExitCommand(CommandController &commandController, EventDistributor &distributor)
Definition: Reactor.cc:672
openmsx::RealTimeInfo::execute
void execute(span< const TclObject > tokens, TclObject &result) const override
Show info on this topic.
Definition: Reactor.cc:1119
openmsx::FileOperations::getUserOpenMSXDir
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home directory.
Definition: FileOperations.cc:535
RTScheduler.hh
openmsx::FileException
Definition: FileException.hh:9
build-info.hh
openmsx::StoreMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:925
openmsx::Reactor::enterMainLoop
void enterMainLoop()
Definition: Reactor.cc:501
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:127
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:20
FilePool.hh
openmsx::TestMachineCommand::TestMachineCommand
TestMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:742
openmsx::SetClipboardCommand
Definition: Reactor.cc:168
openmsx::TclObject::addDictKeyValues
void addDictKeyValues(Args &&... args)
Definition: TclObject.hh:138
GlobalSettings.hh
FileContext.hh
MessageCommand.hh
openmsx::FatalError
Definition: MSXException.hh:31
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:875
AviRecorder.hh
FileOperations.hh
openmsx::ActivateMachineCommand::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this command.
Definition: Reactor.cc:882
openmsx::CommandLineParser
Definition: CommandLineParser.hh:35
checked_cast.hh
openmsx::Reactor::run
void run(CommandLineParser &parser)
Main loop.
Definition: Reactor.cc:517
openmsx::OPENMSX_FOCUS_EVENT
@ 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:813
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:820
openmsx::Reactor::switchMachine
void switchMachine(const std::string &machine)
Definition: Reactor.cc:422
openmsx::Reactor::getGlobalCliComm
GlobalCliComm & getGlobalCliComm()
Definition: Reactor.hh:82
openmsx::CommandLineParser::getStartupCommands
const std::vector< std::string > & getStartupCommands() const
Definition: CommandLineParser.hh:60
span::size
constexpr index_type size() const noexcept
Definition: span.hh:296
RomInfo.hh
StringOp.hh
openmsx::Reactor::getCliComm
CliComm & getCliComm()
Definition: Reactor.cc:306
openmsx::foreach_file_and_directory
bool foreach_file_and_directory(std::string path, FileAction fileAction, DirAction dirAction)
Definition: foreach_file.hh:156
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:861
openmsx::OPENMSX_MACHINE_LOADED_EVENT
@ OPENMSX_MACHINE_LOADED_EVENT
Send when a (new) machine configuration is loaded.
Definition: Event.hh:60
foreach_file.hh
openmsx::RomDatabase
Definition: RomDatabase.hh:15
Command.hh
GlobalCommandController.hh
openmsx::MachineCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:709
openmsx::ConfigInfo::tabCompletion
void tabCompletion(vector< string > &tokens) const override
Attempt tab completion for this topic.
Definition: Reactor.cc:1105
TclCallbackMessages.hh
UserSettings.hh
InfoTopic.hh
openmsx::Command
Definition: Command.hh:41
openmsx::CliComm
Definition: CliComm.hh:11
detail::append
void append(Result &)
Definition: stl.hh:335
openmsx::CreateMachineCommand::CreateMachineCommand
CreateMachineCommand(CommandController &commandController, Reactor &reactor)
Definition: Reactor.cc:776
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:702
openmsx::TclObject
Definition: TclObject.hh:22
InputEventGenerator.hh
openmsx::GlobalSettings::getPauseSetting
BooleanSetting & getPauseSetting()
Definition: GlobalSettings.hh:30
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:57
Thread.hh
openmsx::TestMachineCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:761
openmsx::CommandLineParser::getParseStatus
ParseStatus getParseStatus() const
Definition: CommandLineParser.cc:290
unreachable.hh
openmsx::MSXException::getMessage
const std::string & getMessage() const &
Definition: MSXException.hh:23
openmsx::RestoreMachineCommand
Definition: Reactor.cc:149
openmsx::XmlOutputArchive::close
void close()
Definition: serialize.cc:283
openmsx::OPENMSX_DELETE_BOARDS
@ OPENMSX_DELETE_BOARDS
Delete old MSXMotherboards.
Definition: Event.hh:72
openmsx::RealTimeInfo::RealTimeInfo
RealTimeInfo(InfoCommand &openMSXInfoCommand)
Definition: Reactor.cc:1113
strCat
std::string strCat(Ts &&...ts)
Definition: strCat.hh:573
openmsx::Interpreter
Definition: Interpreter.hh:17
CommandException.hh
openmsx::Reactor::getGlobalCommandController
GlobalCommandController & getGlobalCommandController()
Definition: Reactor.hh:83
openmsx::foreach_file
bool foreach_file(std::string path, FileAction fileAction)
Definition: foreach_file.hh:149
openmsx::FileOperations::getNextNumberedFileName
string getNextNumberedFileName(string_view directory, string_view prefix, string_view extension)
Gets the next numbered file name with the specified prefix in the specified directory,...
Definition: FileOperations.cc:695
openmsx::ExitCommand
Definition: Reactor.cc:64
openmsx::DeleteMachineCommand
Definition: Reactor.cc:106
openmsx::Reactor::getSoftwareDatabase
RomDatabase & getSoftwareDatabase()
Definition: Reactor.cc:298
openmsx
This file implemented 3 utility functions:
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:223
openmsx::CommandCompleter::getInterpreter
Interpreter & getInterpreter() const final
Definition: Command.cc:41
openmsx::Reactor::init
void init()
Definition: Reactor.cc:212
openmsx::CliComm::HARDWARE
@ HARDWARE
Definition: CliComm.hh:24
openmsx::ConfigInfo::help
string help(const vector< string > &tokens) const override
Print help for this topic.
Definition: Reactor.cc:1099
openmsx::preferSystemFileContext
FileContext preferSystemFileContext()
Definition: FileContext.cc:158
rfind_if_unguarded
auto rfind_if_unguarded(RANGE &range, PRED pred)
Definition: stl.hh:160
openmsx::ListMachinesCommand
Definition: Reactor.cc:117
openmsx::GetClipboardCommand::help
string help(const vector< string > &tokens) const override
Print help for this command.
Definition: Reactor.cc:1032
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:197
openmsx::ExitCommand::execute
void execute(span< const TclObject > tokens, TclObject &result) override
Execute this command.
Definition: Reactor.cc:679
openmsx::systemFileContext
FileContext systemFileContext()
Definition: FileContext.cc:152
openmsx::MSXMotherBoard::exitCPULoopSync
void exitCPULoopSync()
Definition: MSXMotherBoard.cc:657
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:1023
openmsx::RomInfo::getGenMSXid
int getGenMSXid() const
Definition: RomInfo.hh:52