C++ Utilities  4.17.0
Useful C++ classes and routines such as argument parser, IO and conversion utilities
path.cpp
Go to the documentation of this file.
1 #include "./path.h"
2 
3 #include <cstdlib>
4 #include <fstream>
5 #include <sstream>
6 #include <string>
7 #if defined(PLATFORM_UNIX)
8 #include <dirent.h>
9 #include <pwd.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <unistd.h>
13 #elif defined(PLATFORM_WINDOWS)
14 #ifdef UNICODE
15 #undef UNICODE
16 #endif
17 #ifdef _UNICODE
18 #undef _UNICODE
19 #endif
20 #include <windows.h>
21 #else
22 #error Platform not supported.
23 #endif
24 
25 using namespace std;
26 
27 namespace IoUtilities {
28 
32 string fileName(const string &path)
33 {
34  size_t lastSlash = path.rfind('/');
35  size_t lastBackSlash = path.rfind('\\');
36  size_t lastSeparator;
37  if (lastSlash == string::npos && lastBackSlash == string::npos) {
38  return path;
39  } else if (lastSlash == string::npos) {
40  lastSeparator = lastBackSlash;
41  } else if (lastBackSlash == string::npos) {
42  lastSeparator = lastSlash;
43  } else {
44  lastSeparator = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;
45  }
46  return path.substr(lastSeparator + 1);
47 }
48 
52 string directory(const string &path)
53 {
54  size_t lastSlash = path.rfind('/');
55  size_t lastBackSlash = path.rfind('\\');
56  size_t lastSeparator;
57  if (lastSlash == string::npos && lastBackSlash == string::npos) {
58  return string();
59  } else if (lastSlash == string::npos) {
60  lastSeparator = lastBackSlash;
61  } else if (lastBackSlash == string::npos) {
62  lastSeparator = lastSlash;
63  } else {
64  lastSeparator = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;
65  }
66  return path.substr(0, lastSeparator + 1);
67 }
68 
74 void removeInvalidChars(std::string &fileName)
75 {
76  size_t startPos = 0;
77  static const char invalidPathChars[] = { '\"', '<', '>', '?', '!', '*', '|', '/', ':', '\\', '\n' };
78  for (const char *i = invalidPathChars, *end = invalidPathChars + sizeof(invalidPathChars); i != end; ++i) {
79  startPos = fileName.find(*i);
80  while (startPos != string::npos) {
81  fileName.replace(startPos, 1, string());
82  startPos = fileName.find(*i, startPos);
83  }
84  }
85 }
86 
95 bool settingsDirectory(std::string &result, std::string applicationDirectoryName, bool createApplicationDirectory)
96 {
97  result.clear();
98  // FIXME: this kind of configuration is not actually used so get rid of it, maybe just read env variable instead
99  fstream pathConfigFile("path.config", ios_base::in);
100  if (pathConfigFile.good()) {
101  for (string line; getline(pathConfigFile, line);) {
102  string::size_type p = line.find('=');
103  if ((p != string::npos) && (p + 1 < line.length())) {
104  string fieldName = line.substr(0, p);
105  if (fieldName == "settings") {
106  result.assign(line.substr(p + 1));
107  }
108  }
109  }
110  }
111  if (!result.empty()) {
112 #if defined(PLATFORM_UNIX)
113  struct stat sb;
114  return (stat(result.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode));
115 #elif defined(PLATFORM_WINDOWS)
116  // FIXME: use UTF-16 API to support unicode, or rewrite using fs abstraction lib
117  DWORD ftyp = GetFileAttributesA(result.c_str());
118  return (ftyp != INVALID_FILE_ATTRIBUTES) && (ftyp & FILE_ATTRIBUTE_DIRECTORY);
119 #endif
120  } else {
121  if (!applicationDirectoryName.empty()) {
122  removeInvalidChars(applicationDirectoryName);
123  }
124 #if defined(PLATFORM_UNIX) || defined(PLATFORM_MAC)
125  if (char *homeDir = getenv("HOME")) {
126  result = homeDir;
127  } else {
128  struct passwd *pw = getpwuid(getuid());
129  result = pw->pw_dir;
130  }
131  struct stat sb;
132  result += "/.config";
133  if (createApplicationDirectory && !(stat(result.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))) {
134  if (mkdir(result.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
135  return false;
136  }
137  }
138  if (!applicationDirectoryName.empty()) {
139  result += '/';
140  result += applicationDirectoryName;
141  if (createApplicationDirectory && !(stat(result.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))) {
142  if (mkdir(result.c_str(), S_IRUSR | S_IWUSR | S_IXUSR) != 0) {
143  return false;
144  }
145  }
146  }
147 #elif defined(PLATFORM_WINDOWS)
148  if (char *appData = getenv("appdata")) {
149  result = appData;
150  if (!applicationDirectoryName.empty()) {
151  result += '\\';
152  result += applicationDirectoryName;
153  if (createApplicationDirectory) {
154  // FIXME: use UTF-16 API to support unicode, or rewrite using fs abstraction lib
155  DWORD ftyp = GetFileAttributesA(result.c_str());
156  if (ftyp == INVALID_FILE_ATTRIBUTES) {
157  return false;
158  } else if (ftyp & FILE_ATTRIBUTE_DIRECTORY) {
159  return true;
160  } else {
161  if (CreateDirectory(result.c_str(), NULL) == 0) {
162  return false;
163  } else {
164  return true;
165  }
166  }
167  }
168  }
169  } else {
170  return false;
171  }
172 #endif
173  }
174  return true;
175 }
176 
181 std::list<std::string> directoryEntries(const char *path, DirectoryEntryType types)
182 {
183 #ifdef PLATFORM_UNIX
184  list<string> entries;
185  if (auto dir = opendir(path)) {
186  while (auto dirEntry = readdir(dir)) {
187  bool filter = false;
188  switch (dirEntry->d_type) {
189  case DT_REG:
190  filter = (types & DirectoryEntryType::File) != DirectoryEntryType::None;
191  break;
192  case DT_DIR:
193  filter = (types & DirectoryEntryType::Directory) != DirectoryEntryType::None;
194  break;
195  case DT_LNK:
196  filter = (types & DirectoryEntryType::Symlink) != DirectoryEntryType::None;
197  break;
198  default:
199  filter = (types & DirectoryEntryType::All) != DirectoryEntryType::None;
200  }
201  if (filter) {
202  entries.emplace_back(dirEntry->d_name);
203  }
204  }
205  closedir(dir);
206  }
207  return entries;
208 #else
209  return list<string>(); // TODO
210 #endif
211 }
212 } // namespace IoUtilities
CPP_UTILITIES_EXPORT std::list< std::string > directoryEntries(const char *path, DirectoryEntryType types=DirectoryEntryType::All)
Returns the names of the directory entries in the specified path with the specified types.
Definition: path.cpp:181
CPP_UTILITIES_EXPORT bool settingsDirectory(std::string &result, std::string applicationDirectoryName=std::string(), bool createApplicationDirectory=false)
Locates a directory meant to store application settings.
Definition: path.cpp:95
Contains utility classes helping to read and write streams.
Definition: binaryreader.h:10
constexpr int i
CPP_UTILITIES_EXPORT std::string directory(const std::string &path)
Returns the directory of the specified path string (including trailing slash).
Definition: path.cpp:52
CPP_UTILITIES_EXPORT std::string fileName(const std::string &path)
Returns the file name and extension of the specified path string.
Definition: path.cpp:32
CPP_UTILITIES_EXPORT void removeInvalidChars(std::string &fileName)
Removes invalid characters from the specified fileName.
Definition: path.cpp:74
DirectoryEntryType
The DirectoryEntryType enum specifies the type of a directory entry (file, directory or symlink).
Definition: path.h:26