Jlm
file.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2018 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_UTIL_FILE_HPP
7 #define JLM_UTIL_FILE_HPP
8 
9 #include <jlm/util/common.hpp>
10 #include <jlm/util/strfmt.hpp>
11 
12 #include <filesystem>
13 #include <string>
14 
15 namespace jlm::util
16 {
17 
18 class FilePath final
19 {
20 public:
21  explicit FilePath(const std::string & path)
22  : path_(path)
23  {}
24 
25  FilePath(const FilePath & other)
26  : path_(other.path_)
27  {}
28 
29  FilePath(FilePath && other) noexcept
30  : path_(std::move(other.path_))
31  {}
32 
33  FilePath &
34  operator=(const FilePath & other)
35  {
36  if (this == &other)
37  return *this;
38 
39  path_ = other.path_;
40  return *this;
41  }
42 
43  FilePath &
44  operator=(FilePath && other) noexcept
45  {
46  if (this == &other)
47  return *this;
48 
49  path_ = std::move(other.path_);
50  return *this;
51  }
52 
60  [[nodiscard]] std::string
61  base() const noexcept
62  {
63  auto fn = name();
64  auto pos = fn.find_first_of(".");
65  if (pos == std::string::npos)
66  return fn;
67 
68  return fn.substr(0, pos);
69  }
70 
80  [[nodiscard]] std::string
81  name() const noexcept
82  {
83  auto pos = path_.find_last_of("/");
84  if (pos == std::string::npos)
85  return path_;
86 
87  return path_.substr(pos + 1, path_.size() - pos);
88  }
89 
97  [[nodiscard]] std::string
98  complete_suffix() const noexcept
99  {
100  auto fn = name();
101  auto pos = fn.find_first_of(".");
102  if (pos == std::string::npos)
103  return fn;
104 
105  return fn.substr(pos + 1, fn.size() - pos);
106  }
107 
115  [[nodiscard]] std::string
116  suffix() const noexcept
117  {
118  auto fn = name();
119  auto pos = fn.find_last_of(".");
120  if (pos == std::string::npos)
121  return fn;
122 
123  return fn.substr(pos + 1, fn.size() - pos);
124  }
125 
147  [[nodiscard]] FilePath
148  Dirname() const noexcept
149  {
150  if (path_.empty())
151  return FilePath(".");
152  if (path_ == "/")
153  return FilePath("/");
154 
155  // Find the last '/' char, ignoring a trailing '/'
156  size_t lastSlash = std::string::npos;
157  if (path_.size() >= 1)
158  lastSlash = path_.find_last_of('/', path_.size() - 2);
159 
160  // If no '/' was found, path_ is a file in the current working directory, or is "." itself
161  if (lastSlash == std::string::npos)
162  return FilePath(".");
163 
164  // The only '/' was at the very beginning of the path. We must keep it.
165  if (lastSlash == 0)
166  return FilePath("/");
167 
168  // Return the path of the parent directory, without a trailing '/'
169  return FilePath(path_.substr(0, lastSlash));
170  }
171 
192  [[nodiscard]] FilePath
193  Join(const std::string & other) const
194  {
195  std::filesystem::path t(path_ == "." ? "" : path_.c_str());
196  t.append(other);
197  return FilePath(t.string());
198  }
199 
200  [[nodiscard]] FilePath
201  Join(const FilePath & other) const
202  {
203  return Join(other.to_str());
204  }
205 
210  [[nodiscard]] FilePath
211  WithSuffix(const std::string & suffix) const
212  {
213  return FilePath(path_ + suffix);
214  }
215 
221  [[nodiscard]] bool
222  Exists() const noexcept
223  {
224  auto fileStatus = std::filesystem::status(path_);
225  return std::filesystem::exists(fileStatus);
226  }
227 
232  [[nodiscard]] bool
233  IsDirectory() const noexcept
234  {
235  auto fileStatus = std::filesystem::status(path_);
236  return std::filesystem::is_directory(fileStatus);
237  }
238 
243  [[nodiscard]] bool
244  isFile() const noexcept
245  {
246  auto fileStatus = std::filesystem::status(path_);
247  return std::filesystem::is_regular_file(fileStatus);
248  }
249 
257  void
259  {
260  if (isFile())
261  throw Error("file already exists: " + path_);
262 
263  FilePath baseDir(Dirname());
264  if (!baseDir.IsDirectory())
265  throw Error("parent directory is not a directory: " + baseDir.to_str());
266 
267  std::error_code ec;
268  std::filesystem::create_directory(path_, ec);
269 
270  if (ec.value() != 0)
271  throw Error("could not create directory '" + path_ + "': " + ec.message());
272  }
273 
274  [[nodiscard]] const std::string &
275  to_str() const noexcept
276  {
277  return path_;
278  }
279 
280  [[nodiscard]] bool
281  operator==(const FilePath & other) const noexcept
282  {
283  return path_ == other.path_;
284  }
285 
286  [[nodiscard]] bool
287  operator==(const std::string & f) const noexcept
288  {
289  return path_ == f;
290  }
291 
300  static FilePath
302  const FilePath & directory,
303  const std::string & fileNamePrefix,
304  const std::string & fileNameSuffix)
305  {
306  auto randomString = CreateRandomAlphanumericString(6);
307  FilePath filePath(directory.to_str() + "/" + fileNamePrefix + randomString + fileNameSuffix);
308 
309  JLM_ASSERT(!filePath.Exists());
310  return filePath;
311  }
312 
316  [[nodiscard]] static FilePath
318  {
319  return FilePath(std::filesystem::temp_directory_path().string());
320  }
321 
322 private:
323  std::string path_;
324 };
325 
326 class File final
327 {
328 public:
329  explicit File(const FilePath & path)
330  : fd_(NULL),
331  path_(path)
332  {}
333 
335  {
336  close();
337  }
338 
339  File(const File &) = delete;
340 
341  File(File && other) noexcept
342  : fd_(other.fd_),
343  path_(std::move(other.path_))
344  {
345  other.fd_ = NULL;
346  }
347 
348  File &
349  operator=(const File &) = delete;
350 
351  File &
352  operator=(File && other) noexcept
353  {
354  if (this == &other)
355  return *this;
356 
357  fd_ = other.fd_;
358  path_ = std::move(other.path_);
359  other.fd_ = NULL;
360 
361  return *this;
362  }
363 
364  void
365  close() noexcept
366  {
367  if (fd_)
368  fclose(fd_);
369 
370  fd_ = NULL;
371  }
372 
373  void
374  open(const char * mode)
375  {
376  fd_ = fopen(path_.to_str().c_str(), mode);
377  if (!fd_)
378  throw Error("Cannot open file " + path_.to_str());
379  }
380 
381  bool
382  is_open() const noexcept
383  {
384  return fd_ != NULL;
385  }
386 
387  FILE *
388  fd() const noexcept
389  {
390  return fd_;
391  }
392 
393  const FilePath &
394  path() const noexcept
395  {
396  return path_;
397  }
398 
399 private:
400  FILE * fd_;
402 };
403 
404 }
405 
406 #endif
static FilePath createUniqueFileName(const FilePath &directory, const std::string &fileNamePrefix, const std::string &fileNameSuffix)
Generates a unique file in a given directory with a prefix and suffix.
Definition: file.hpp:301
FilePath Join(const FilePath &other) const
Definition: file.hpp:201
std::string name() const noexcept
Returns the name of the file, excluding the path.
Definition: file.hpp:81
void CreateDirectory() const
Definition: file.hpp:258
bool IsDirectory() const noexcept
Determines whether file path is a directory.
Definition: file.hpp:233
static FilePath TempDirectoryPath()
Definition: file.hpp:317
std::string complete_suffix() const noexcept
Returns the complete suffix (extension) of the file.
Definition: file.hpp:98
const std::string & to_str() const noexcept
Definition: file.hpp:275
FilePath(const FilePath &other)
Definition: file.hpp:25
FilePath(const std::string &path)
Definition: file.hpp:21
FilePath Join(const std::string &other) const
Definition: file.hpp:193
bool operator==(const std::string &f) const noexcept
Definition: file.hpp:287
bool Exists() const noexcept
Determines whether the file path exists.
Definition: file.hpp:222
std::string base() const noexcept
Returns the base name of the file without the path.
Definition: file.hpp:61
std::string path_
Definition: file.hpp:323
FilePath & operator=(const FilePath &other)
Definition: file.hpp:34
FilePath(FilePath &&other) noexcept
Definition: file.hpp:29
bool isFile() const noexcept
Determines whether file path is a file.
Definition: file.hpp:244
FilePath Dirname() const noexcept
Returns the path to the file or directory's parent directory. Emulates the behavior of the GNU coreut...
Definition: file.hpp:148
std::string suffix() const noexcept
Returns the suffix (extension) of the file.
Definition: file.hpp:116
FilePath WithSuffix(const std::string &suffix) const
Definition: file.hpp:211
bool operator==(const FilePath &other) const noexcept
Definition: file.hpp:281
FilePath & operator=(FilePath &&other) noexcept
Definition: file.hpp:44
File(const FilePath &path)
Definition: file.hpp:329
void close() noexcept
Definition: file.hpp:365
FilePath path_
Definition: file.hpp:401
File(File &&other) noexcept
Definition: file.hpp:341
FILE * fd() const noexcept
Definition: file.hpp:388
bool is_open() const noexcept
Definition: file.hpp:382
void open(const char *mode)
Definition: file.hpp:374
File & operator=(const File &)=delete
const FilePath & path() const noexcept
Definition: file.hpp:394
FILE * fd_
Definition: file.hpp:400
File(const File &)=delete
File & operator=(File &&other) noexcept
Definition: file.hpp:352
#define JLM_ASSERT(x)
Definition: common.hpp:16
std::string CreateRandomAlphanumericString(std::size_t length)
Definition: strfmt.cpp:15