OGS
FileTools.cpp
Go to the documentation of this file.
1
15#include "FileTools.h"
16
17#include <spdlog/fmt/bundled/core.h>
18
19#include <boost/algorithm/string/predicate.hpp>
20#include <filesystem>
21#include <fstream>
22#include <typeindex>
23#include <unordered_map>
24
25#include "BaseLib/Logging.h"
26#include "Error.h"
27
28namespace
29{
32
35} // anonymous namespace
36
37namespace BaseLib
38{
40{
41 return project_directory_is_set;
42}
43
47bool IsFileExisting(const std::string& strFilename)
48{
49 return std::filesystem::exists(std::filesystem::path(strFilename));
50}
51
52std::tuple<std::string, std::string::size_type, std::string::size_type>
53getParenthesizedString(std::string const& in,
54 char const open_char,
55 char const close_char,
56 std::string::size_type pos)
57{
58 auto const pos_curly_brace_open = in.find_first_of(open_char, pos);
59 if (pos_curly_brace_open == std::string::npos)
60 {
61 return std::make_tuple("", std::string::npos, std::string::npos);
62 }
63 auto const pos_curly_brace_close =
64 in.find_first_of(close_char, pos_curly_brace_open);
65 if (pos_curly_brace_close == std::string::npos)
66 {
67 return std::make_tuple("", std::string::npos, std::string::npos);
68 }
69 return std::make_tuple(
70 in.substr(pos_curly_brace_open + 1,
71 pos_curly_brace_close - (pos_curly_brace_open + 1)),
72 pos_curly_brace_open, pos_curly_brace_close);
73}
74
75std::string containsKeyword(std::string const& str, std::string const& keyword)
76{
77 auto const position = str.find(keyword);
78 if (position != std::string::npos)
79 {
80 return str.substr(0, position);
81 }
82 return "";
83}
84
85template <typename T>
86bool substituteKeyword(std::string& result,
87 std::string const& parenthesized_string,
88 std::string::size_type const begin,
89 std::string::size_type const end,
90 std::string const& keyword, T& data)
91{
92 std::string precision_specification =
93 containsKeyword(parenthesized_string, keyword);
94
95 if (precision_specification.empty())
96 {
97 return false;
98 }
99
100 std::unordered_map<std::type_index, char> type_specification;
101 type_specification[std::type_index(typeid(int))] = 'd';
102 type_specification[std::type_index(typeid(double))] = 'f'; // default
103 type_specification[std::type_index(typeid(std::string))] = 's';
104
105 auto const& b = precision_specification.back();
106 // see https://fmt.dev/latest/syntax.html#formatspec
107 if (b == 'e' || b == 'E' || b == 'f' || b == 'F' || b == 'g' || b == 'G')
108 {
109 type_specification[std::type_index(typeid(double))] = b;
110 precision_specification.pop_back();
111 }
112
113 std::string const generated_fmt_string =
114 "{" + precision_specification +
115 type_specification[std::type_index(typeid(data))] + "}";
116 result.replace(
117 begin, end - begin + 1,
118 fmt::vformat(generated_fmt_string, fmt::make_format_args(data)));
119
120 return true;
121}
122
123std::string constructFormattedFileName(std::string const& format_specification,
124 std::string const& mesh_name,
125 int const timestep,
126 double const t,
127 int const iteration)
128{
129 char const open_char = '{';
130 char const close_char = '}';
131 std::string::size_type begin = 0;
132 std::string::size_type end = std::string::npos;
133 std::string result = format_specification;
134
135 while (begin != std::string::npos)
136 {
137 auto length_before_substitution = result.length();
138 // find next parenthesized string
139 std::string str = "";
140 std::tie(str, begin, end) =
141 getParenthesizedString(result, open_char, close_char, begin);
142 if (!substituteKeyword(result, str, begin, end, "timestep", timestep) &&
143 !substituteKeyword(result, str, begin, end, "time", t) &&
144 !substituteKeyword(result, str, begin, end, "iteration", iteration))
145 {
146 substituteKeyword(result, str, begin, end, "meshname", mesh_name);
147 }
148 begin = end - (length_before_substitution - result.length());
149 }
150
151 return result;
152}
153
154double swapEndianness(double const& v)
155{
156 union
157 {
158 double v;
159 char c[sizeof(double)];
160 } a{}, b{};
161
162 a.v = v;
163 for (unsigned short i = 0; i < sizeof(double) / 2; i++)
164 {
165 b.c[i] = a.c[sizeof(double) / 2 - i - 1];
166 }
167
168 for (unsigned short i = sizeof(double) / 2; i < sizeof(double); i++)
169 {
170 b.c[i] = a.c[sizeof(double) + sizeof(double) / 2 - i - 1];
171 }
172
173 return b.v;
174}
175
176std::string dropFileExtension(std::string const& filename)
177{
178 auto const filename_path = std::filesystem::path(filename);
179 return (filename_path.parent_path() / filename_path.stem()).string();
180}
181
182std::string extractBaseName(std::string const& pathname)
183{
184 return std::filesystem::path(pathname).filename().string();
185}
186
187std::string extractBaseNameWithoutExtension(std::string const& pathname)
188{
189 std::string basename = extractBaseName(pathname);
190 return dropFileExtension(basename);
191}
192
193std::string getFileExtension(const std::string& path)
194{
195 return std::filesystem::path(path).extension().string();
196}
197
198bool hasFileExtension(std::string const& extension, std::string const& filename)
199{
200 return boost::iequals(extension, getFileExtension(filename));
201}
202
203std::string copyPathToFileName(const std::string& file_name,
204 const std::string& source)
205{
206 auto filePath = std::filesystem::path(file_name);
207 if (filePath.has_parent_path())
208 {
209 return filePath.string();
210 }
211 return (std::filesystem::path(source) /= filePath).string();
212}
213
214std::string extractPath(std::string const& pathname)
215{
216 return std::filesystem::path(pathname).parent_path().string();
217}
218
219std::string joinPaths(std::string const& pathA, std::string const& pathB)
220{
221 return (std::filesystem::path(pathA) /= std::filesystem::path(pathB))
222 .string();
223}
224
225std::string const& getProjectDirectory()
226{
227 if (!project_directory_is_set)
228 {
229 OGS_FATAL("The project directory has not yet been set.");
230 }
231 return project_directory;
232}
233
234void setProjectDirectory(std::string const& dir)
235{
236 if (project_directory_is_set)
237 {
238 OGS_FATAL("The project directory has already been set.");
239 }
240 // TODO Remove these global vars. They are a possible source of errors when
241 // invoking OGS from Python multiple times within a single session.
242 project_directory = dir;
243 project_directory_is_set = true;
244}
245
247{
248 project_directory.clear();
249 project_directory_is_set = false;
250}
251
252void removeFile(std::string const& filename)
253{
254 bool const success =
255 std::filesystem::remove(std::filesystem::path(filename));
256 if (success)
257 {
258 DBUG("Removed '{:s}'", filename);
259 }
260}
261
262void removeFiles(std::vector<std::string> const& files)
263{
264 for (auto const& file : files)
265 {
266 removeFile(file);
267 }
268}
269
270template <typename T>
271T readBinaryValue(std::istream& in)
272{
273 T v;
274 in.read(reinterpret_cast<char*>(&v), sizeof(T));
275 return v;
276}
277
278// explicit template instantiation
279template float readBinaryValue<float>(std::istream&);
280template double readBinaryValue<double>(std::istream&);
281
282template <typename T>
283std::vector<T> readBinaryArray(std::string const& filename, std::size_t const n)
284{
285 std::ifstream in(filename.c_str());
286 if (!in)
287 {
288 ERR("readBinaryArray(): Error while reading from file '{:s}'.",
289 filename);
290 ERR("Could not open file '{:s}' for input.", filename);
291 in.close();
292 return std::vector<T>();
293 }
294
295 std::vector<T> result;
296 result.reserve(n);
297
298 for (std::size_t p = 0; in && !in.eof() && p < n; ++p)
299 {
300 result.push_back(BaseLib::readBinaryValue<T>(in));
301 }
302
303 if (result.size() == n)
304 {
305 return result;
306 }
307
308 ERR("readBinaryArray(): Error while reading from file '{:s}'.", filename);
309 ERR("Read different number of values. Expected {:d}, got {:d}.",
310 n,
311 result.size());
312
313 if (!in.eof())
314 {
315 ERR("EOF reached.\n");
316 }
317
318 return std::vector<T>();
319}
320
321// explicit template instantiation
322template std::vector<float> readBinaryArray<float>(std::string const&,
323 std::size_t const);
324
325template <typename T>
326void writeValueBinary(std::ostream& out, T const& val)
327{
328 out.write(reinterpret_cast<const char*>(&val), sizeof(T));
329}
330
331// explicit template instantiation
332template void writeValueBinary<std::size_t>(std::ostream&, std::size_t const&);
333
334} // end namespace BaseLib
#define OGS_FATAL(...)
Definition Error.h:26
Filename manipulation routines.
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
std::vector< T > readBinaryArray(std::string const &filename, std::size_t const n)
std::string containsKeyword(std::string const &str, std::string const &keyword)
Definition FileTools.cpp:75
std::string constructFormattedFileName(std::string const &format_specification, std::string const &mesh_name, int const timestep, double const t, int const iteration)
void removeFile(std::string const &filename)
std::string const & getProjectDirectory()
Returns the directory where the prj file resides.
std::string getFileExtension(const std::string &path)
void writeValueBinary(std::ostream &out, T const &val)
write value as binary into the given output stream
std::string extractPath(std::string const &pathname)
std::tuple< std::string, std::string::size_type, std::string::size_type > getParenthesizedString(std::string const &in, char const open_char, char const close_char, std::string::size_type pos)
Definition FileTools.cpp:53
T readBinaryValue(std::istream &in)
bool IsFileExisting(const std::string &strFilename)
Returns true if given file exists.
Definition FileTools.cpp:47
std::string copyPathToFileName(const std::string &file_name, const std::string &source)
template void writeValueBinary< std::size_t >(std::ostream &, std::size_t const &)
template float readBinaryValue< float >(std::istream &)
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::string dropFileExtension(std::string const &filename)
bool isProjectDirectorySet()
Returns true if the project directory is set.
Definition FileTools.cpp:39
std::string joinPaths(std::string const &pathA, std::string const &pathB)
void unsetProjectDirectory()
Unsets the project directory.
template double readBinaryValue< double >(std::istream &)
std::string extractBaseName(std::string const &pathname)
double swapEndianness(double const &v)
bool substituteKeyword(std::string &result, std::string const &parenthesized_string, std::string::size_type const begin, std::string::size_type const end, std::string const &keyword, T &data)
Definition FileTools.cpp:86
void setProjectDirectory(std::string const &dir)
Sets the project directory.
template std::vector< float > readBinaryArray< float >(std::string const &, std::size_t const)
bool hasFileExtension(std::string const &extension, std::string const &filename)
void removeFiles(std::vector< std::string > const &files)
std::string project_directory
The directory where the prj file resides.
Definition FileTools.cpp:31
bool project_directory_is_set
Whether the project directory has already been set.
Definition FileTools.cpp:34