openMSX
FilePool.cc
Go to the documentation of this file.
1 #include "FilePool.hh"
2 #include "File.hh"
3 #include "FileContext.hh"
4 #include "FileOperations.hh"
5 #include "TclObject.hh"
6 #include "CommandException.hh"
7 #include "Display.hh"
8 #include "EventDistributor.hh"
9 #include "CliComm.hh"
10 #include "Reactor.hh"
11 #include "outer.hh"
12 #include "xrange.hh"
13 #include <memory>
14 
15 namespace openmsx {
16 
17 [[nodiscard]] static TclObject initialFilePoolSettingValue()
18 {
19  TclObject result;
20 
21  for (auto& p : systemFileContext().getPaths()) {
22  result.addListElement(
23  makeTclDict("-path", tmpStrCat(p, "/systemroms"),
24  "-types", "system_rom"),
25  makeTclDict("-path", tmpStrCat(p, "/software"),
26  "-types", "rom disk tape"));
27  }
28  return result;
29 }
30 
32  : core(FileOperations::getUserDataDir() + "/.filecache",
33  [&] { return getDirectories(); },
34  [&](std::string_view message) { reportProgress(message); })
35  , filePoolSetting(
36  controller, "__filepool",
37  "This is an internal setting. Don't change this directly, "
38  "instead use the 'filepool' command.",
39  initialFilePoolSettingValue().getString())
40  , reactor(reactor_)
41  , sha1SumCommand(controller)
42 {
43  filePoolSetting.attach(*this);
44  reactor.getEventDistributor().registerEventListener(EventType::QUIT, *this);
45 }
46 
48 {
50  filePoolSetting.detach(*this);
51 }
52 
53 File FilePool::getFile(FileType fileType, const Sha1Sum& sha1sum)
54 {
55  return core.getFile(fileType, sha1sum);
56 }
57 
59 {
60  return core.getSha1Sum(file);
61 }
62 
63 [[nodiscard]] static FileType parseTypes(Interpreter& interp, const TclObject& list)
64 {
65  auto result = FileType::NONE;
66  for (auto i : xrange(list.getListLength(interp))) {
67  std::string_view elem = list.getListIndex(interp, i).getString();
68  if (elem == "system_rom") {
69  result |= FileType::SYSTEM_ROM;
70  } else if (elem == "rom") {
71  result |= FileType::ROM;
72  } else if (elem == "disk") {
73  result |= FileType::DISK;
74  } else if (elem == "tape") {
75  result |= FileType::TAPE;
76  } else {
77  throw CommandException("Unknown type: ", elem);
78  }
79  }
80  return result;
81 }
82 
83 FilePoolCore::Directories FilePool::getDirectories() const
84 {
86  try {
87  auto& interp = filePoolSetting.getInterpreter();
88  const TclObject& all = filePoolSetting.getValue();
89  for (auto i : xrange(all.getListLength(interp))) {
90  FilePoolCore::Dir dir;
91  bool hasPath = false;
92  dir.types = FileType::NONE;
93  TclObject line = all.getListIndex(interp, i);
94  unsigned numItems = line.getListLength(interp);
95  if (numItems & 1) {
96  throw CommandException(
97  "Expected a list with an even number "
98  "of elements, but got ", line.getString());
99  }
100  for (unsigned j = 0; j < numItems; j += 2) {
101  std::string_view name = line.getListIndex(interp, j + 0).getString();
102  TclObject value = line.getListIndex(interp, j + 1);
103  if (name == "-path") {
104  dir.path = value.getString();
105  hasPath = true;
106  } else if (name == "-types") {
107  dir.types = parseTypes(interp, value);
108  } else {
109  throw CommandException("Unknown item: ", name);
110  }
111  }
112  if (!hasPath) {
113  throw CommandException(
114  "Missing -path item: ", line.getString());
115  }
116  if (dir.types == FileType::NONE) {
117  throw CommandException(
118  "Missing -types item: ", line.getString());
119  }
120  result.push_back(std::move(dir));
121  }
122  } catch (CommandException& e) {
123  reactor.getCliComm().printWarning(
124  "Error while parsing '__filepool' setting", e.getMessage());
125  }
126  return result;
127 }
128 
129 void FilePool::update(const Setting& setting) noexcept
130 {
131  assert(&setting == &filePoolSetting); (void)setting;
132  (void)getDirectories(); // check for syntax errors
133 }
134 
135 void FilePool::reportProgress(std::string_view message)
136 {
137  if (quit) core.abort();
138  reactor.getCliComm().printProgress(message);
139  reactor.getDisplay().repaint();
140 }
141 
142 int FilePool::signalEvent(const Event& event) noexcept
143 {
144  (void)event; // avoid warning for non-assert compiles
145  assert(getType(event) == EventType::QUIT);
146  quit = true;
147  return 0;
148 }
149 
150 
151 // class Sha1SumCommand
152 
153 FilePool::Sha1SumCommand::Sha1SumCommand(
154  CommandController& commandController_)
155  : Command(commandController_, "sha1sum")
156 {
157 }
158 
159 void FilePool::Sha1SumCommand::execute(span<const TclObject> tokens, TclObject& result)
160 {
161  checkNumArgs(tokens, 2, "filename");
162  File file(FileOperations::expandTilde(std::string(tokens[1].getString())));
163  auto& filePool = OUTER(FilePool, sha1SumCommand);
164  result = filePool.getSha1Sum(file).toString();
165 }
166 
167 std::string FilePool::Sha1SumCommand::help(span<const TclObject> /*tokens*/) const
168 {
169  return "Calculate sha1 value for the given file. If the file is "
170  "(g)zipped the sha1 is calculated on the unzipped version.";
171 }
172 
173 void FilePool::Sha1SumCommand::tabCompletion(std::vector<std::string>& tokens) const
174 {
175  completeFileName(tokens, userFileContext());
176 }
177 
178 } // namespace openmsx
BaseSetting * setting
Definition: Interpreter.cc:27
void printProgress(std::string_view message)
Definition: CliComm.cc:20
void printWarning(std::string_view message)
Definition: CliComm.cc:10
void repaint()
Redraw the display.
Definition: Display.cc:369
void unregisterEventListener(EventType type, EventListener &listener)
Unregisters a previously registered event listener.
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
void abort()
This is only meaningful to call from within the 'reportProgress' callback (constructor parameter).
Definition: FilePoolCore.hh:68
std::vector< Dir > Directories
Definition: FilePoolCore.hh:44
FilePool(CommandController &controller, Reactor &reactor)
Definition: FilePool.cc:31
Sha1Sum getSha1Sum(File &file)
Calculate sha1sum for the given File object.
Definition: FilePool.cc:58
File getFile(FileType fileType, const Sha1Sum &sha1sum)
Search file with the given sha1sum.
Definition: FilePool.cc:53
Contains the main loop of openMSX.
Definition: Reactor.hh:68
EventDistributor & getEventDistributor()
Definition: Reactor.hh:82
Display & getDisplay()
Definition: Reactor.hh:86
CliComm & getCliComm()
Definition: Reactor.cc:312
const TclObject & getValue() const final
Gets the current value of this setting as a TclObject.
Definition: Setting.hh:142
Interpreter & getInterpreter() const
Definition: Setting.cc:148
This class represents the result of a sha1 calculation (a 160-bit value).
Definition: sha1.hh:22
void detach(Observer< T > &observer)
Definition: Subject.hh:56
unsigned getListLength(Interpreter &interp) const
Definition: TclObject.cc:125
TclObject getListIndex(Interpreter &interp, unsigned index) const
Definition: TclObject.cc:143
void addListElement(const T &t)
Definition: TclObject.hh:129
zstring_view getString() const
Definition: TclObject.cc:111
Definition: span.hh:126
string expandTilde(string path)
Expand the '~' character to the users home directory.
const string & getUserDataDir()
Get the openMSX data dir in the user's home directory.
This file implemented 3 utility functions:
Definition: Autofire.cc:9
const FileContext & systemFileContext()
Definition: FileContext.cc:157
EventType getType(const Event &event)
Definition: Event.hh:645
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:173
TclObject makeTclDict(Args &&... args)
Definition: TclObject.hh:296
#define OUTER(type, member)
Definition: outer.hh:41
TemporaryString tmpStrCat(Ts &&... ts)
Definition: strCat.hh:659
constexpr auto xrange(T e)
Definition: xrange.hh:155