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 <algorithm>
9 #include <cassert>
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_ref path, string_ref before, string_ref after)
23 {
24  assert(path.starts_with(before));
25  return 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) {
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_ref filename)
52 {
53  PRT_DEBUG("Context: " << filename);
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  PRT_DEBUG("Context: try " << name);
65  if (FileOperations::exists(name)) {
66  return name;
67  }
68  }
69  // not found in any path
70  throw FileException(filename + " not found in this context");
71 }
72 
73 const string FileContext::resolve(string_ref filename) const
74 {
75  vector<string> pathList = getPathsHelper(paths);
76  string result = resolveHelper(pathList, filename);
77  assert(FileOperations::expandTilde(result) == result);
78  return result;
79 }
80 
81 const string FileContext::resolveCreate(string_ref filename) const
82 {
83  string result;
84  vector<string> pathList = getPathsHelper(savePaths);
85  try {
86  result = resolveHelper(pathList, filename);
87  } catch (FileException&) {
88  string path = pathList.front();
89  try {
91  } catch (FileException& e) {
92  PRT_DEBUG(e.getMessage());
93  (void)&e; // Prevent warning
94  }
95  result = FileOperations::join(path, filename);
96  }
97  assert(FileOperations::expandTilde(result) == result);
98  return result;
99 }
100 
101 vector<string> FileContext::getPaths() const
102 {
103  return getPathsHelper(paths);
104 }
105 
107 {
108  return find(paths.begin(), paths.end(), USER_DIRS) != paths.end();
109 }
110 
112 
113 static string backSubstSymbols(const string& path)
114 {
115  string systemData = FileOperations::getSystemDataDir();
116  if (StringOp::startsWith(path, systemData)) {
117  return subst(path, systemData, SYSTEM_DATA);
118  }
119  string userData = FileOperations::getSystemDataDir();
120  if (StringOp::startsWith(path, userData)) {
121  return subst(path, userData, SYSTEM_DATA);
122  }
123  string userDir = FileOperations::getUserOpenMSXDir();
124  if (StringOp::startsWith(path, userDir)) {
125  return subst(path, userDir, USER_OPENMSX);
126  }
127  // TODO USER_DIRS (not needed ATM)
128  return path;
129 }
130 
132  string_ref hwDescr,
133  string_ref userName)
134 {
135  paths.push_back(backSubstSymbols(FileOperations::expandTilde(path)));
137  USER_OPENMSX, "persistent", hwDescr, userName));
138 }
139 
141 {
142  paths.push_back(USER_DATA);
143  paths.push_back(SYSTEM_DATA);
144  savePaths.push_back(USER_DATA);
145 }
146 
148 {
149  paths.push_back(SYSTEM_DATA); // first system dir
150  paths.push_back(USER_DATA);
151 }
152 
154 {
155  paths.push_back("");
156  paths.push_back(USER_DIRS);
157 
158  if (!savePath.empty()) {
160  USER_OPENMSX, "persistent", savePath));
161  }
162 }
163 
165 {
166  paths.push_back("");
167  paths.push_back(USER_OPENMSX + '/' + subDir);
168 }
169 
171 {
172  paths.push_back("");
173 }
174 
175 
176 template<typename Archive>
177 void FileContext::serialize(Archive& ar, unsigned /*version*/)
178 {
179  ar.serialize("paths", paths);
180  ar.serialize("savePaths", savePaths);
181 }
183 
184 } // namespace openmsx