openMSX
FileContext.cc
Go to the documentation of this file.
1 #include "FileContext.hh"
2 #include "FileOperations.hh"
3 #include "FileException.hh"
4 #include "serialize.hh"
5 #include "serialize_stl.hh"
6 #include "stl.hh"
7 #include <cassert>
8 #include <utility>
9 
10 using std::string;
11 using std::string_view;
12 using std::vector;
13 
14 namespace openmsx {
15 
16 const string USER_DIRS = "{{USER_DIRS}}";
17 const string USER_OPENMSX = "{{USER_OPENMSX}}";
18 const string USER_DATA = "{{USER_DATA}}";
19 const string SYSTEM_DATA = "{{SYSTEM_DATA}}";
20 
21 
22 [[nodiscard]] static string subst(string_view path, string_view before, string_view after)
23 {
24  assert(path.starts_with(before));
25  return strCat(after, path.substr(before.size()));
26 }
27 
28 [[nodiscard]] static vector<string> getPathsHelper(std::span<const string> input)
29 {
30  vector<string> result;
31  for (const auto& s : input) {
32  if (s.starts_with(USER_OPENMSX)) {
33  result.push_back(subst(s, USER_OPENMSX,
35  } else if (s.starts_with(USER_DATA)) {
36  result.push_back(subst(s, USER_DATA,
38  } else if (s.starts_with(SYSTEM_DATA)) {
39  result.push_back(subst(s, SYSTEM_DATA,
41  } else if (s == USER_DIRS) {
42  // Nothing. Keep USER_DIRS for isUserContext()
43  } else {
44  result.push_back(s);
45  }
46  }
47  for (const auto& s : result) {
48  assert(!FileOperations::needsTildeExpansion(s)); (void)s;
49  }
50  return result;
51 }
52 
53 [[nodiscard]] static string resolveHelper(std::span<const string> pathList,
54  string_view filename)
55 {
56  string filepath = FileOperations::expandTilde(
58  if (FileOperations::isAbsolutePath(filepath)) {
59  // absolute path, don't resolve
60  return filepath;
61  }
62 
63  for (const auto& p : pathList) {
64  string name = FileOperations::join(p, filename);
66  if (FileOperations::exists(name)) {
67  return name;
68  }
69  }
70  // not found in any path
71  throw FileException(filename, " not found in this context");
72 }
73 
74 FileContext::FileContext(vector<string>&& paths_, vector<string>&& savePaths_)
75  : paths(std::move(paths_)), savePaths(std::move(savePaths_))
76 {
77 }
78 
79 string FileContext::resolve(string_view filename) const
80 {
81  string result = resolveHelper(getPaths(), filename);
82  assert(!FileOperations::needsTildeExpansion(result));
83  return result;
84 }
85 
86 string FileContext::resolveCreate(string_view filename) const
87 {
88  if (savePaths2.empty()) {
89  savePaths2 = getPathsHelper(savePaths);
90  }
91 
92  string result;
93  try {
94  result = resolveHelper(savePaths2, filename);
95  } catch (FileException&) {
96  const string& path = savePaths2.front();
97  try {
99  } catch (FileException&) {
100  // ignore
101  }
102  result = FileOperations::join(path, filename);
103  }
104  assert(!FileOperations::needsTildeExpansion(result));
105  return result;
106 }
107 
108 std::span<const string> FileContext::getPaths() const
109 {
110  if (paths2.empty()) {
111  paths2 = getPathsHelper(paths);
112  }
113  return paths2;
114 }
115 
117 {
118  return contains(paths, USER_DIRS);
119 }
120 
121 template<typename Archive>
122 void FileContext::serialize(Archive& ar, unsigned /*version*/)
123 {
124  ar.serialize("paths", paths,
125  "savePaths", savePaths);
126 }
128 
130 
131 static string backSubstSymbols(string_view path)
132 {
133  if (const string& systemData = FileOperations::getSystemDataDir();
134  path.starts_with(systemData)) {
135  return subst(path, systemData, SYSTEM_DATA);
136  }
137  if (const string& userData = FileOperations::getUserDataDir();
138  path.starts_with(userData)) {
139  return subst(path, userData, USER_DATA);
140  }
141  if (const string& userDir = FileOperations::getUserOpenMSXDir();
142  path.starts_with(userDir)) {
143  return subst(path, userDir, USER_OPENMSX);
144  }
145  // TODO USER_DIRS (not needed ATM)
146  return string(path);
147 }
148 
149 FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
150 {
151  return { { backSubstSymbols(path) },
152  { strCat(USER_OPENMSX, "/persistent/", hwDescr, '/', userName) } };
153 }
154 
156 {
157  static const FileContext result{
158  { USER_DATA, SYSTEM_DATA },
159  { USER_DATA } };
160  return result;
161 }
162 
164 {
165  static const FileContext result{
166  { SYSTEM_DATA, USER_DATA }, // first system dir
167  {} };
168  return result;
169 }
170 
171 FileContext userFileContext(string_view savePath)
172 {
173  return { { string{}, USER_DIRS },
174  { strCat(USER_OPENMSX, "/persistent/", savePath) } };
175 }
176 
178 {
179  static const FileContext result{ { string{}, USER_DIRS }, {} };
180  return result;
181 }
182 
183 FileContext userDataFileContext(string_view subDir)
184 {
185  return { { string{}, strCat(USER_OPENMSX, '/', subDir) },
186  {} };
187 }
188 
190 {
191  static const FileContext result{{string{}}, {string{}}};
192  return result;
193 }
194 
195 } // namespace openmsx
void serialize(Archive &ar, unsigned version)
Definition: FileContext.cc:122
std::string resolveCreate(std::string_view filename) const
Definition: FileContext.cc:86
std::span< const std::string > getPaths() const
Definition: FileContext.cc:108
bool isUserContext() const
Definition: FileContext.cc:116
std::string resolve(std::string_view filename) const
Definition: FileContext.cc:79
bool exists(zstring_view filename)
Does this file (directory) exists?
string expandTilde(string path)
Expand the '~' character to the users home directory.
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home directory.
bool isAbsolutePath(string_view path)
Checks whether it's a absolute path or not.
const string & getSystemDataDir()
Get system directory.
bool needsTildeExpansion(std::string_view path)
Returns true iff expandTilde(s) would have an effect.
void mkdirp(string path)
Acts like the unix command "mkdir -p".
const string & getUserDataDir()
Get the openMSX data dir in the user's home directory.
const std::string & expandCurrentDirFromDrive(const std::string &path)
Get the current directory of the specified drive Linux: return the given string unchanged.
string join(string_view part1, string_view part2)
Join two paths.
This file implemented 3 utility functions:
Definition: Autofire.cc:9
const FileContext & systemFileContext()
Definition: FileContext.cc:155
const string USER_OPENMSX
Definition: FileContext.cc:17
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
Definition: FileContext.cc:149
const FileContext & currentDirFileContext()
Definition: FileContext.cc:189
const string USER_DIRS
Definition: FileContext.cc:16
constexpr const char *const filename
const string SYSTEM_DATA
Definition: FileContext.cc:19
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:171
const string USER_DATA
Definition: FileContext.cc:18
FileContext userDataFileContext(string_view subDir)
Definition: FileContext.cc:183
const FileContext & preferSystemFileContext()
Definition: FileContext.cc:163
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1009
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:23
std::string strCat(Ts &&...ts)
Definition: strCat.hh:549