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
10using std::string;
11using std::string_view;
12using std::vector;
13
14namespace openmsx {
15
16const string USER_DIRS = "{{USER_DIRS}}";
17const string USER_OPENMSX = "{{USER_OPENMSX}}";
18const string USER_DATA = "{{USER_DATA}}";
19const 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
74FileContext::FileContext(vector<string>&& paths_, vector<string>&& savePaths_)
75 : paths(std::move(paths_)), savePaths(std::move(savePaths_))
76{
77}
78
79string FileContext::resolve(string_view filename) const
80{
81 string result = resolveHelper(getPaths(), filename);
83 return result;
84}
85
86string 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 }
105 return result;
106}
107
108std::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
121template<typename Archive>
122void FileContext::serialize(Archive& ar, unsigned /*version*/)
123{
124 ar.serialize("paths", paths,
125 "savePaths", savePaths);
126}
128
130
131static 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
149FileContext 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{
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
171FileContext 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
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)
std::string resolveCreate(std::string_view filename) const
std::span< const std::string > getPaths() const
bool isUserContext() const
std::string resolve(std::string_view filename) const
bool exists(zstring_view filename)
Does this file (directory) exists?
string expandTilde(string path)
Expand the '~' character to the users home directory.
const std::string & expandCurrentDirFromDrive(const std::string &path)
Get the current directory of the specified drive Linux: return the given string unchanged.
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.
string join(string_view part1, string_view part2)
Join two paths.
This file implemented 3 utility functions:
Definition Autofire.cc:9
const FileContext & systemFileContext()
const string USER_OPENMSX
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
const FileContext & currentDirFileContext()
const string USER_DIRS
const string SYSTEM_DATA
const FileContext & userFileContext()
const string USER_DATA
FileContext userDataFileContext(string_view subDir)
const FileContext & preferSystemFileContext()
STL namespace.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
Definition stl.hh:32
std::string strCat()
Definition strCat.hh:703