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::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 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 static vector<string> getPathsHelper(const vector<string>& input)
29 {
30  vector<string> result;
31  for (auto& s : input) {
32  if (StringOp::startsWith(s, USER_OPENMSX)) {
33  result.push_back(subst(s, USER_OPENMSX,
35  } else if (StringOp::startsWith(s, USER_DATA)) {
36  result.push_back(subst(s, USER_DATA,
38  } else if (StringOp::startsWith(s, 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  return result;
48 }
49 
50 static string resolveHelper(const vector<string>& pathList,
51  string_view filename)
52 {
53  string filepath = FileOperations::expandCurrentDirFromDrive(filename);
54  filepath = FileOperations::expandTilde(filepath);
55  if (FileOperations::isAbsolutePath(filepath)) {
56  // absolute path, don't resolve
57  return filepath;
58  }
59 
60  for (auto& p : pathList) {
61  string name = FileOperations::join(p, filename);
62  name = FileOperations::expandTilde(name);
63  if (FileOperations::exists(name)) {
64  return name;
65  }
66  }
67  // not found in any path
68  throw FileException(filename, " not found in this context");
69 }
70 
71 FileContext::FileContext(vector<string>&& paths_, vector<string>&& savePaths_)
72  : paths(std::move(paths_)), savePaths(std::move(savePaths_))
73 {
74 }
75 
76 string FileContext::resolve(string_view filename) const
77 {
78  vector<string> pathList = getPathsHelper(paths);
79  string result = resolveHelper(pathList, filename);
80  assert(FileOperations::expandTilde(result) == result);
81  return result;
82 }
83 
85 {
86  string result;
87  vector<string> pathList = getPathsHelper(savePaths);
88  try {
89  result = resolveHelper(pathList, filename);
90  } catch (FileException&) {
91  string path = pathList.front();
92  try {
94  } catch (FileException&) {
95  // ignore
96  }
97  result = FileOperations::join(path, filename);
98  }
99  assert(FileOperations::expandTilde(result) == result);
100  return result;
101 }
102 
103 vector<string> FileContext::getPaths() const
104 {
105  return getPathsHelper(paths);
106 }
107 
109 {
110  return contains(paths, USER_DIRS);
111 }
112 
113 template<typename Archive>
114 void FileContext::serialize(Archive& ar, unsigned /*version*/)
115 {
116  ar.serialize("paths", paths,
117  "savePaths", savePaths);
118 }
120 
122 
123 static string backSubstSymbols(const string& path)
124 {
125  const string& systemData = FileOperations::getSystemDataDir();
126  if (StringOp::startsWith(path, systemData)) {
127  return subst(path, systemData, SYSTEM_DATA);
128  }
129  const string& userData = FileOperations::getSystemDataDir();
130  if (StringOp::startsWith(path, userData)) {
131  return subst(path, userData, SYSTEM_DATA);
132  }
133  const string& userDir = FileOperations::getUserOpenMSXDir();
134  if (StringOp::startsWith(path, userDir)) {
135  return subst(path, userDir, USER_OPENMSX);
136  }
137  // TODO USER_DIRS (not needed ATM)
138  return path;
139 }
140 
142 {
143  return { { backSubstSymbols(FileOperations::expandTilde(path)) },
145  USER_OPENMSX, "persistent", hwDescr, userName) } };
146 }
147 
149 {
150  return { { USER_DATA, SYSTEM_DATA },
151  { USER_DATA } };
152 }
153 
155 {
156  return { { SYSTEM_DATA, USER_DATA }, // first system dir
157  {} };
158 }
159 
161 {
162  vector<string> savePaths;
163  if (!savePath.empty()) {
164  savePaths = { FileOperations::join(
165  USER_OPENMSX, "persistent", savePath) };
166  }
167  return { { string{}, USER_DIRS }, std::move(savePaths) };
168 }
169 
171 {
172  return { { string{}, strCat(USER_OPENMSX, '/', subDir) },
173  {} };
174 }
175 
177 {
178  return {{string{}}, {string{}}};
179 }
180 
181 } // namespace openmsx
std::string resolveCreate(string_view filename) const
Definition: FileContext.cc:84
bool isAbsolutePath(string_view path)
Checks whether it&#39;s a absolute path or not.
FileContext userDataFileContext(string_view subDir)
Definition: FileContext.cc:170
string join(string_view part1, string_view part2)
Join two paths.
FileContext configFileContext(string_view path, string_view hwDescr, string_view userName)
Definition: FileContext.cc:141
bool starts_with(string_view x) const
Definition: string_view.cc:116
const string USER_DIRS
Definition: FileContext.cc:16
const string USER_OPENMSX
Definition: FileContext.cc:17
FileContext preferSystemFileContext()
Definition: FileContext.cc:154
FileContext systemFileContext()
Definition: FileContext.cc:148
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:106
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:69
STL namespace.
std::string resolve(string_view filename) const
Definition: FileContext.cc:76
bool isUserContext() const
Definition: FileContext.cc:108
FileContext userFileContext(string_view savePath)
Definition: FileContext.cc:160
string expandCurrentDirFromDrive(string_view path)
Get the current directory of the specified drive Linux: just return an empty string.
string getUserDataDir()
Get the openMSX data dir in the user&#39;s home directory.
const string SYSTEM_DATA
Definition: FileContext.cc:19
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
FileContext currentDirFileContext()
Definition: FileContext.cc:176
bool exists(string_view filename)
Does this file (directory) exists?
bool empty() const
Definition: string_view.hh:45
This class implements a (close approximation) of the std::string_view class.
Definition: string_view.hh:16
const string & getUserOpenMSXDir()
Get the openMSX dir in the user&#39;s home directory.
std::vector< std::string > getPaths() const
Definition: FileContext.cc:103
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:1006
void serialize(Archive &ar, unsigned version)
Definition: FileContext.cc:114
const string USER_DATA
Definition: FileContext.cc:18
string_view substr(size_type pos, size_type n=npos) const
Definition: string_view.cc:32
void mkdirp(string_view path_)
Acts like the unix command "mkdir -p".
std::string strCat(Ts &&...ts)
Definition: strCat.hh:577
size_type size() const
Definition: string_view.hh:44
string expandTilde(string_view path)
Expand the &#39;~&#39; character to the users home directory.