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 "openmsx.hh"
8 #include "stl.hh"
9 #include <algorithm>
10 #include <cassert>
11 
12 using std::string;
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 static string subst(string_ref path, string_ref before, string_ref after)
24 {
25  assert(path.starts_with(before));
26  return after + path.substr(before.size());
27 }
28 
29 static vector<string> getPathsHelper(const vector<string>& input)
30 {
31  vector<string> result;
32  for (auto& s : input) {
33  if (StringOp::startsWith(s, USER_OPENMSX)) {
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  return result;
49 }
50 
51 static string resolveHelper(const vector<string>& pathList,
52  string_ref filename)
53 {
54  string filepath = FileOperations::expandCurrentDirFromDrive(filename);
55  filepath = FileOperations::expandTilde(filepath);
56  if (FileOperations::isAbsolutePath(filepath)) {
57  // absolute path, don't resolve
58  return filepath;
59  }
60 
61  for (auto& p : pathList) {
62  string name = FileOperations::join(p, filename);
63  name = FileOperations::expandTilde(name);
64  if (FileOperations::exists(name)) {
65  return name;
66  }
67  }
68  // not found in any path
69  throw FileException(filename + " not found in this context");
70 }
71 
72 const string FileContext::resolve(string_ref filename) const
73 {
74  vector<string> pathList = getPathsHelper(paths);
75  string result = resolveHelper(pathList, filename);
76  assert(FileOperations::expandTilde(result) == result);
77  return result;
78 }
79 
80 const string FileContext::resolveCreate(string_ref filename) const
81 {
82  string result;
83  vector<string> pathList = getPathsHelper(savePaths);
84  try {
85  result = resolveHelper(pathList, filename);
86  } catch (FileException&) {
87  string path = pathList.front();
88  try {
90  } catch (FileException&) {
91  // ignore
92  }
93  result = FileOperations::join(path, filename);
94  }
95  assert(FileOperations::expandTilde(result) == result);
96  return result;
97 }
98 
99 vector<string> FileContext::getPaths() const
100 {
101  return getPathsHelper(paths);
102 }
103 
105 {
106  return contains(paths, USER_DIRS);
107 }
108 
110 
111 static string backSubstSymbols(const string& path)
112 {
113  string systemData = FileOperations::getSystemDataDir();
114  if (StringOp::startsWith(path, systemData)) {
115  return subst(path, systemData, SYSTEM_DATA);
116  }
117  string userData = FileOperations::getSystemDataDir();
118  if (StringOp::startsWith(path, userData)) {
119  return subst(path, userData, SYSTEM_DATA);
120  }
121  string userDir = FileOperations::getUserOpenMSXDir();
122  if (StringOp::startsWith(path, userDir)) {
123  return subst(path, userDir, USER_OPENMSX);
124  }
125  // TODO USER_DIRS (not needed ATM)
126  return path;
127 }
128 
130  string_ref hwDescr,
131  string_ref userName)
132 {
133  paths = { backSubstSymbols(FileOperations::expandTilde(path)) };
135  USER_OPENMSX, "persistent", hwDescr, userName) };
136 }
137 
139 {
140  paths = { USER_DATA, SYSTEM_DATA };
141  savePaths = { USER_DATA };
142 }
143 
145 {
146  paths = { SYSTEM_DATA, USER_DATA }; // first system dir
147 }
148 
150 {
151  paths = { "", USER_DIRS };
152  if (!savePath.empty()) {
154  USER_OPENMSX, "persistent", savePath) };
155  }
156 }
157 
159 {
160  paths.emplace_back();
161  paths.emplace_back(USER_OPENMSX + '/' + subDir);
162 }
163 
165 {
166  paths = { "" };
167 }
168 
169 
170 template<typename Archive>
171 void FileContext::serialize(Archive& ar, unsigned /*version*/)
172 {
173  ar.serialize("paths", paths);
174  ar.serialize("savePaths", savePaths);
175 }
177 
178 } // namespace openmsx
bool isAbsolutePath(string_ref path)
Checks whether it's a absolute path or not.
const std::string resolveCreate(string_ref filename) const
Definition: FileContext.cc:80
const string USER_DIRS
Definition: FileContext.cc:17
const string USER_OPENMSX
Definition: FileContext.cc:18
void mkdirp(string_ref path_)
Acts like the unix command "mkdir -p".
UserDataFileContext(string_ref subdir)
Definition: FileContext.cc:158
UserFileContext(string_ref savePath="")
Definition: FileContext.cc:149
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:95
bool starts_with(string_ref x) const
Definition: string_ref.cc:138
std::vector< std::string > getPaths() const
Definition: FileContext.cc:99
string join(string_ref part1, string_ref part2)
Join two paths.
This class implements a subset of the proposal for std::string_ref (proposed for the next c++ standar...
Definition: string_ref.hh:18
string expandCurrentDirFromDrive(string_ref path)
Get the current directory of the specified drive Linux: just return an empty string.
size_type size() const
Definition: string_ref.hh:55
const std::string resolve(string_ref filename) const
Definition: FileContext.cc:72
bool startsWith(string_ref total, string_ref part)
Definition: StringOp.cc:242
bool isUserContext() const
Definition: FileContext.cc:104
std::vector< std::string > savePaths
Definition: FileContext.hh:23
string getUserDataDir()
Get the openMSX data dir in the user's home directory.
const string SYSTEM_DATA
Definition: FileContext.cc:20
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:7
ConfigFileContext(string_ref path, string_ref hwDescr, string_ref userName)
Definition: FileContext.cc:129
bool exists(string_ref filename)
Does this file (directory) exists?
const string & getUserOpenMSXDir()
Get the openMSX dir in the user's home directory.
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:802
void serialize(Archive &ar, unsigned version)
Definition: FileContext.cc:171
const string USER_DATA
Definition: FileContext.cc:19
string expandTilde(string_ref path)
Expand the '~' character to the users home directory.
std::vector< std::string > paths
Definition: FileContext.hh:22
string_ref substr(size_type pos, size_type n=npos) const
Definition: string_ref.cc:54
bool empty() const
Definition: string_ref.hh:56