jubilant-funicular
Path.cpp
1 #include <fstream>
2 
3 #ifdef _UTILS_UNIX
4  #include <sys/stat.h>
5  #include <unistd.h>
6 #elif _UTILS_WINDOWS
7  #include <direct.h>
8 #endif
9 
10 #include "Path.h"
11 #include "common.h"
12 
13 using namespace std;
14 
15 namespace utils {
16  Path::Path(const string& path) {
17  m_path = replace_all(path, "\\", "/");
18  }
19  Path Path::cwd() {
20  char buf[FILENAME_MAX];
21  #ifdef _UTILS_UNIX
22  getcwd(buf, FILENAME_MAX);
23  #elif _UTILS_WINDOWS
24  _getcwd(buf, FILENAME_MAX);
25  #endif
26  return Path(buf);
27  }
28  Path Path::resolve() const {
29  if (is_empty()) return *this;
30 
31  Path ret;
32  if (is_relative()) {
33  ret = Path::cwd() + *this;
34  } else {
35  ret = *this;
36  }
37 
38  auto parts = split(ret.m_path, '/');
39  for (int i = parts.size()-1; i >= 0; i--) {
40  auto& part = parts[i];
41  if ((part.empty() || part == ".") && i != 0) {
42  parts.erase(parts.begin() + i);
43  } else if (part == ".." && i >= 1) {
44  parts.erase(parts.begin() + i);
45  parts.erase(parts.begin() + i - 1);
46  }
47  }
48  ret.m_path = "";
49  for (auto& part : parts) ret.m_path += part + "/";
50  ret.m_path.resize(ret.m_path.size()-1);
51 
52  return ret;
53  }
54  Path Path::parent() const {
55  Path ret = resolve();
56  do {
57  int pos = ret.m_path.rfind("/", ends_with(ret.m_path, "/") ? ret.m_path.size()-2 : string::npos);
58  ret.m_path.resize(pos);
59  } while (ret.m_path.back() == '/');
60  return ret;
61  }
62  string Path::file_name(bool extension) const {
63  int pos = m_path.rfind('/');
64  string end = m_path.substr(pos+1);
65  if (extension) return end;
66  pos = end.rfind('.');
67  return end.substr(0, pos);
68  }
69  bool Path::exists() const {
70  #ifdef _UTILS_UNIX
71  struct stat s;
72  return stat(m_path.c_str(), &s) == 0;
73  #elif _UTILS_WINDOWS
74  return GetFileAttributes(m_path.c_str()) != INVALID_FILE_ATTRIBUTES;
75  #endif
76  }
77  bool Path::is_file() const {
78  // Technically wrong because of symlinks and whatnot
79  return exists() && !is_directory();
80  }
81  bool Path::is_directory() const {
82  #ifdef _UTILS_UNIX
83  struct stat s;
84  if (stat(m_path.c_str(), &s) == 0) {
85  return s.st_mode & S_IFDIR;
86  } else {
87  return false;
88  }
89  #elif _UTILS_WINDOWS
90  return GetFileAttributes(m_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY;
91  #endif
92  }
93  bool Path::is_absolute() const {
94  if (m_path.empty()) return false;
95  int pos = m_path.find('/');
96  string root = m_path.substr(0, pos);
97  return root.empty() || (root.size() == 2 && root[1] == ':');
98  }
99  bool Path::operator==(const char* p) const {
100  return trim(m_path, "/\\") == trim(p, "/\\") ? true : resolve().m_path == Path(p).resolve().m_path;
101  }
102  Path Path::operator+(const char* p) const {
103  Path p2(p);
104  return ends_with(m_path, "/") ? Path(m_path + p2.m_path) :
105  Path(m_path + "/" + p2.m_path);
106  }
107  Path::iterator Path::begin() const {
108  iterator ret(this);
109  ret.set_begin(SetBeginEndKey());
110  return ret;
111  }
112  Path::iterator Path::end() const {
113  iterator ret(this);
114  ret.set_end(SetBeginEndKey());
115  return ret;
116  }
117 
118  ostream& operator<<(ostream& out, const Path& path) {
119  return out<<path.to_string();
120  }
121 }
utils::Path
A (case-sensitive) Path in a file system.
Definition: Path.h:16
nta::utils::trim
std::string trim(crstring str, crstring back_trash=" \t\n\v\f\r\0", crstring front_trash=" \t\n\v\f\r\0")
Removes leading and trailing whitespace.
Definition: utils.cpp:17
utils::Path::resolve
Path resolve() const
Returns an absolute path equivalent to this.
Definition: Path.cpp:28
nta::utils::replace_all
std::string replace_all(crstring str, crstring o, crstring n)
Replaces all occurences of o in str with n.
Definition: utils.cpp:11
nta::utils::ends_with
bool ends_with(crstring str, crstring suffix)
Checks if str ends with suffix.
Definition: utils.cpp:8