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 "span.hh"
8 #include "stl.hh"
9 #include <cassert>
10 #include <utility>
11 
12 using std::string;
13 using std::string_view;
14 using std::vector;
15 
16 namespace openmsx {
17 
18 const string USER_DIRS = "{{USER_DIRS}}";
19 const string USER_OPENMSX = "{{USER_OPENMSX}}";
20 const string USER_DATA = "{{USER_DATA}}";
21 const string SYSTEM_DATA = "{{SYSTEM_DATA}}";
22 
23 
24 [[nodiscard]] static string subst(string_view path, string_view before, string_view after)
25 {
26  assert(StringOp::startsWith(path, before));
27  return strCat(after, path.substr(before.size()));
28 }
29 
30 [[nodiscard]] static vector<string> getPathsHelper(span<const string> input)
31 {
32  vector<string> result;
33  for (const auto& s : input) {
35  result.push_back(subst(s, USER_OPENMSX,
37  } else if (StringOp::startsWith(s, USER_DATA)) {
38  result.push_back(subst(s, USER_DATA,
40  } else if (StringOp::startsWith(s, SYSTEM_DATA)) {
41  result.push_back(subst(s, SYSTEM_DATA,
43  } else if (s == USER_DIRS) {
44  // Nothing. Keep USER_DIRS for isUserContext()
45  } else {
46  result.push_back(s);
47  }
48  }
49  for (const auto& s : result) {
50  assert(!FileOperations::needsTildeExpansion(s)); (void)s;
51  }
52  return result;
53 }
54 
55 [[nodiscard]] static string resolveHelper(span<const string> pathList,
56  string_view filename)
57 {
58  string filepath = FileOperations::expandTilde(
60  if (FileOperations::isAbsolutePath(filepath)) {
61  // absolute path, don't resolve
62  return filepath;
63  }
64 
65  for (const auto& p : pathList) {
66  string name = FileOperations::join(p, filename);
68  if (FileOperations::exists(name)) {
69  return name;
70  }
71  }
72  // not found in any path
73  throw FileException(filename, " not found in this context");
74 }
75 
76 FileContext::FileContext(vector<string>&& paths_, vector<string>&& savePaths_)
77  : paths(std::move(paths_)), savePaths(std::move(savePaths_))
78 {
79 }
80 
81 string FileContext::resolve(string_view filename) const
82 {
83  string result = resolveHelper(getPaths(), filename);
84  assert(!FileOperations::needsTildeExpansion(result));
85  return result;
86 }
87 
88 string FileContext::resolveCreate(string_view filename) const
89 {
90  if (savePaths2.empty()) {
91  savePaths2 = getPathsHelper(savePaths);
92  }
93 
94  string result;
95  try {
96  result = resolveHelper(savePaths2, filename);
97  } catch (FileException&) {
98  const string& path = savePaths2.front();
99  try {
101  } catch (FileException&) {
102  // ignore
103  }
104  result = FileOperations::join(path, filename);
105  }
106  assert(!FileOperations::needsTildeExpansion(result));
107  return result;
108 }
109 
111 {
112  if (paths2.empty()) {
113  paths2 = getPathsHelper(paths);
114  }
115  return paths2;
116 }
117 
119 {
120  return contains(paths, USER_DIRS);
121 }
122 
123 template<typename Archive>
124 void FileContext::serialize(Archive& ar, unsigned /*version*/)
125 {
126  ar.serialize("paths", paths,
127  "savePaths", savePaths);
128 }
130 
132 
133 static string backSubstSymbols(string_view path)
134 {
135  const string& systemData = FileOperations::getSystemDataDir();
136  if (StringOp::startsWith(path, systemData)) {
137  return subst(path, systemData, SYSTEM_DATA);
138  }
139  const string& userData = FileOperations::getUserDataDir();
140  if (StringOp::startsWith(path, userData)) {
141  return subst(path, userData, USER_DATA);
142  }
143  const string& userDir = FileOperations::getUserOpenMSXDir();
144  if (StringOp::startsWith(path, userDir)) {
145  return subst(path, userDir, USER_OPENMSX);
146  }
147  // TODO USER_DIRS (not needed ATM)
148  return string(path);
149 }
150 
151 FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
152 {
153  return { { backSubstSymbols(path) },
154  { strCat(USER_OPENMSX, "/persistent/", hwDescr, '/', userName) } };
155 }
156 
158 {
159  static const FileContext result{
160  { USER_DATA, SYSTEM_DATA },
161  { USER_DATA } };
162  return result;
163 }
164 
166 {
167  static const FileContext result{
168  { SYSTEM_DATA, USER_DATA }, // first system dir
169  {} };
170  return result;
171 }
172 
173 FileContext userFileContext(string_view savePath)
174 {
175  return { { string{}, USER_DIRS },
176  { strCat(USER_OPENMSX, "/persistent/", savePath) } };
177 }
178 
180 {
181  static const FileContext result{ { string{}, USER_DIRS }, {} };
182  return result;
183 }
184 
185 FileContext userDataFileContext(string_view subDir)
186 {
187  return { { string{}, strCat(USER_OPENMSX, '/', subDir) },
188  {} };
189 }
190 
192 {
193  static const FileContext result{{string{}}, {string{}}};
194  return result;
195 }
196 
197 } // namespace openmsx
void serialize(Archive &ar, unsigned version)
Definition: FileContext.cc:124
std::string resolveCreate(std::string_view filename) const
Definition: FileContext.cc:88
bool isUserContext() const
Definition: FileContext.cc:118
span< const std::string > getPaths() const
Definition: FileContext.cc:110
std::string resolve(std::string_view filename) const
Definition: FileContext.cc:81
Definition: span.hh:126
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:29
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:157
const string USER_OPENMSX
Definition: FileContext.cc:19
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
Definition: FileContext.cc:151
const FileContext & currentDirFileContext()
Definition: FileContext.cc:191
const string USER_DIRS
Definition: FileContext.cc:18
constexpr const char *const filename
const string SYSTEM_DATA
Definition: FileContext.cc:21
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:173
const string USER_DATA
Definition: FileContext.cc:20
FileContext userDataFileContext(string_view subDir)
Definition: FileContext.cc:185
const FileContext & preferSystemFileContext()
Definition: FileContext.cc:165
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:998
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition: stl.hh:31
std::string strCat(Ts &&...ts)
Definition: strCat.hh:591