openMSX
FileContext.cc
Go to the documentation of this file.
1 #include "FileContext.hh"
2 #include "FileOperations.hh"
3 #include "FileException.hh"
4 #include "StringOp.hh"
5 #include "serialize.hh"
6 #include "serialize_stl.hh"
7 #include "stl.hh"
8 #include <cassert>
9 #include <utility>
10 
11 using std::string;
12 using std::string_view;
13 using std::vector;
14 
15 namespace openmsx {
16 
17 const string USER_DIRS = "{{USER_DIRS}}";
18 const string USER_OPENMSX = "{{USER_OPENMSX}}";
19 const string USER_DATA = "{{USER_DATA}}";
20 const string SYSTEM_DATA = "{{SYSTEM_DATA}}";
21 
22 
23 static string subst(string_view path, string_view before, string_view after)
24 {
25  assert(StringOp::startsWith(path, before));
26  return strCat(after, path.substr(before.size()));
27 }
28 
29 static vector<string> getPathsHelper(const vector<string>& input)
30 {
31  vector<string> result;
32  for (auto& s : input) {
33  if (StringOp::startsWith(s, USER_OPENMSX)) {
34  result.push_back(subst(s, USER_OPENMSX,
36  } else if (StringOp::startsWith(s, USER_DATA)) {
37  result.push_back(subst(s, USER_DATA,
39  } else if (StringOp::startsWith(s, SYSTEM_DATA)) {
40  result.push_back(subst(s, SYSTEM_DATA,
42  } else if (s == USER_DIRS) {
43  // Nothing. Keep USER_DIRS for isUserContext()
44  } else {
45  result.push_back(s);
46  }
47  }
48  return result;
49 }
50 
51 static string resolveHelper(const vector<string>& pathList,
52  string_view filename)
53 {
54  string filepath = FileOperations::expandCurrentDirFromDrive(filename);
55  filepath = FileOperations::expandTilde(filepath);
56  if (FileOperations::isAbsolutePath(filepath)) {
57  // absolute path, don't resolve
58  return filepath;
59  }
60 
61  for (auto& p : pathList) {
62  string name = FileOperations::join(p, filename);
63  name = FileOperations::expandTilde(name);
64  if (FileOperations::exists(name)) {
65  return name;
66  }
67  }
68  // not found in any path
69  throw FileException(filename, " not found in this context");
70 }
71 
72 FileContext::FileContext(vector<string>&& paths_, vector<string>&& savePaths_)
73  : paths(std::move(paths_)), savePaths(std::move(savePaths_))
74 {
75 }
76 
77 string FileContext::resolve(string_view filename) const
78 {
79  vector<string> pathList = getPathsHelper(paths);
80  string result = resolveHelper(pathList, filename);
81  assert(FileOperations::expandTilde(result) == result);
82  return result;
83 }
84 
85 string FileContext::resolveCreate(string_view filename) const
86 {
87  string result;
88  vector<string> pathList = getPathsHelper(savePaths);
89  try {
90  result = resolveHelper(pathList, filename);
91  } catch (FileException&) {
92  string path = pathList.front();
93  try {
95  } catch (FileException&) {
96  // ignore
97  }
98  result = FileOperations::join(path, filename);
99  }
100  assert(FileOperations::expandTilde(result) == result);
101  return result;
102 }
103 
104 vector<string> FileContext::getPaths() const
105 {
106  return getPathsHelper(paths);
107 }
108 
110 {
111  return contains(paths, USER_DIRS);
112 }
113 
114 template<typename Archive>
115 void FileContext::serialize(Archive& ar, unsigned /*version*/)
116 {
117  ar.serialize("paths", paths,
118  "savePaths", savePaths);
119 }
121 
123 
124 static string backSubstSymbols(const string& path)
125 {
126  const string& systemData = FileOperations::getSystemDataDir();
127  if (StringOp::startsWith(path, systemData)) {
128  return subst(path, systemData, SYSTEM_DATA);
129  }
130  const string& userData = FileOperations::getSystemDataDir();
131  if (StringOp::startsWith(path, userData)) {
132  return subst(path, userData, SYSTEM_DATA);
133  }
134  const string& userDir = FileOperations::getUserOpenMSXDir();
135  if (StringOp::startsWith(path, userDir)) {
136  return subst(path, userDir, USER_OPENMSX);
137  }
138  // TODO USER_DIRS (not needed ATM)
139  return path;
140 }
141 
142 FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
143 {
144  return { { backSubstSymbols(FileOperations::expandTilde(path)) },
146  USER_OPENMSX, "persistent", hwDescr, userName) } };
147 }
148 
150 {
151  return { { USER_DATA, SYSTEM_DATA },
152  { USER_DATA } };
153 }
154 
156 {
157  return { { SYSTEM_DATA, USER_DATA }, // first system dir
158  {} };
159 }
160 
161 FileContext userFileContext(string_view savePath)
162 {
163  vector<string> savePaths;
164  if (!savePath.empty()) {
165  savePaths = { FileOperations::join(
166  USER_OPENMSX, "persistent", savePath) };
167  }
168  return { { string{}, USER_DIRS }, std::move(savePaths) };
169 }
170 
171 FileContext userDataFileContext(string_view subDir)
172 {
173  return { { string{}, strCat(USER_OPENMSX, '/', subDir) },
174  {} };
175 }
176 
178 {
179  return {{string{}}, {string{}}};
180 }
181 
182 } // namespace openmsx
std::string resolveCreate(std::string_view filename) const
Definition: FileContext.cc:85
bool isAbsolutePath(string_view path)
FileContext userDataFileContext(string_view subDir)
Definition: FileContext.cc:171
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
Definition: FileContext.cc:142
const string USER_DIRS
Definition: FileContext.cc:17
const string USER_OPENMSX
Definition: FileContext.cc:18
FileContext preferSystemFileContext()
Definition: FileContext.cc:155
FileContext systemFileContext()
Definition: FileContext.cc:149
string getSystemDataDir()
Get system directory.
bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:92
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:71
STL namespace.
bool isUserContext() const
Definition: FileContext.cc:109
std::string resolve(std::string_view filename) const
Definition: FileContext.cc:77
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:161
constexpr const char *const filename
string getUserDataDir()
Get the openMSX data dir in the user&#39;s home directory.
const string SYSTEM_DATA
Definition: FileContext.cc:20
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
FileContext currentDirFileContext()
Definition: FileContext.cc:177
string expandCurrentDirFromDrive(string_view path)
bool exists(string_view filename)
const string & getUserOpenMSXDir()
Get the openMSX dir in the user&#39;s home directory.
std::vector< std::string > getPaths() const
Definition: FileContext.cc:104
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
void serialize(Archive &ar, unsigned version)
Definition: FileContext.cc:115
const string USER_DATA
Definition: FileContext.cc:19
string expandTilde(string_view path)
void mkdirp(string_view path_)
std::string strCat(Ts &&...ts)
Definition: strCat.hh:573
string join(string_view part1, string_view part2)