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