28 # include <sys/stat.h> 41 namespace basis {
namespace os {
namespace path {
49 static const char cSeparator =
'\\';
50 static const char* cSeparators =
"\\/";
52 static const char cSeparator =
'/';
53 static const char* cSeparators =
"/";
60 return c ==
'/' || c ==
'\\';
67 static inline string replace(
string str,
char from,
char to)
69 string res(str.size(),
'\0');
70 string::const_iterator in = str.begin();
71 string::iterator out = res.begin();
72 while (in != str.end()) {
73 if (*in == from) *out = to;
83 if (path.empty())
return "";
84 char drive[3] = {
'\0',
':',
'\0'};
87 if (path.size() > 1 && path[1] ==
':') {
92 string norm_path = drive;
93 bool abs =
issep(path[i]);
96 while (i <= path.size() &&
issep(path[i])) {
97 norm_path += cSeparator;
101 norm_path += cSeparator;
105 vector<string> parts;
106 while (i <= path.size()) {
107 if (
issep(path[i]) || path[i] ==
'\0') {
108 if (current ==
"..") {
109 if (!abs && (parts.empty() || parts.back() ==
"..")) {
110 parts.push_back(current);
111 }
else if (!parts.empty()) {
114 }
else if (current !=
"" && current !=
".") {
115 parts.push_back(current);
123 for (i = 0; i < parts.size(); i++) {
124 norm_path =
join(norm_path, parts[i]);
126 return norm_path.empty() ?
"." : norm_path;
133 string norm_path = path;
135 string norm_path = replace(path,
'\\',
'/');
139 norm_path = replace(norm_path,
'\\',
'/');
148 string norm_path = path;
150 string norm_path = replace(path,
'\\',
'/');
154 norm_path = replace(norm_path,
'/',
'\\');
164 void split(
const string& path,
string& head,
string& tail)
166 size_t last = path.find_last_of(cSeparators);
167 if (last == string::npos) {
172 if (last > 0) pos = path.find_last_not_of(cSeparators, last - 1);
173 if (pos == string::npos) head = path.substr(0, last + 1);
174 else head = path.substr(0, pos + 1);
175 tail = path.substr(last + 1);
180 vector<string>
split(
const string& path)
182 vector<string> parts(2,
"");
183 split(path, parts[0], parts[1]);
188 void splitdrive(
const string& path,
string& drive,
string& tail)
191 if (path.size() > 1 && path[1] ==
':') {
192 tail = path.substr(2);
193 drive = path[0]; drive +=
':';
206 vector<string> parts(2,
"");
212 void splitext(
const string& path,
string& head,
string& ext,
const set<string>* exts,
bool icase)
214 size_t pos = string::npos;
217 for (set<string>::const_iterator i = exts->begin(); i != exts->end(); ++i) {
218 if (path.size() < i->size())
continue;
219 size_t start = path.size() - i->size();
222 string str = path.substr(start);
224 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
225 std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper);
226 if (str == ext) pos = start;
227 }
else if (path.compare(start, i->size(), *i) == 0) {
234 pos = path.find_last_of(
'.');
238 if (pos != string::npos && (pos == 0 ||
issep(path[pos - 1]))) {
244 if (pos == string::npos) {
250 string tmp = path.substr(0, pos);
251 ext = path.substr(pos);
257 vector<string>
splitext(
const string& path,
const set<string>* exts)
259 vector<string> parts(2,
"");
260 splitext(path, parts[0], parts[1], exts);
267 vector<string> parts(2,
"");
268 split(path, parts[0], parts[1]);
275 vector<string> parts(2,
"");
276 split(path, parts[0], parts[1]);
281 bool hasext(
const string& path,
const set<string>* exts)
283 string ext =
splitext(path, exts)[1];
284 return exts ? exts->find(ext) != exts->end() : !ext.empty();
296 if (path.size() > 1 && path[1] ==
':') i = 2;
298 return i < path.size() &&
issep(path[i]);
308 string relpath(
const string& path,
const string& base)
311 if (!
isabs(path))
return path;
319 if (drive != base_drive) {
321 "Path is on drive " << drive <<
", start is on drive " << base_drive);
325 string::const_iterator b = norm_base.begin();
326 string::const_iterator p = norm_path.begin();
329 while (b != norm_base.end() && p != norm_path.end()) {
331 if (!
issep(*b))
break;
333 }
else if (*b != *p) {
341 if ((b != norm_base.end() &&
issep(*b)) ||
342 (p != norm_path.end() &&
issep(*p))) pos = i;
344 if (b == norm_base.end() && p != norm_path.end() &&
issep(*p)) p++;
345 if (p == norm_path.end() && b != norm_base.end() &&
issep(*b)) b++;
355 if (b == norm_base.end() && p == norm_path.end())
return ".";
363 if (b != norm_base.end() && !
issep(norm_base[norm_base.size() - 1])) {
366 size_t pos = b - norm_base.begin();
367 norm_base += cSeparator;
368 b = norm_base.begin() + pos;
370 while (b != norm_base.end()) {
373 rel_path += cSeparator;
377 if (pos + 1 < norm_path.size()) rel_path += norm_path.substr(pos + 1);
379 if (
issep(rel_path[rel_path.size() - 1])) {
380 rel_path.erase(rel_path.size() - 1);
391 stringstream ss(curr_path);
398 while (getline(ss, fname,
'/')) {
405 for (
unsigned int i = 0; i < 100; i++) {
407 if (next_path.empty()) {
412 curr_path =
join(prev_path, next_path);
413 if (!
islink(next_path))
break;
424 prev_path = curr_path;
432 string join(
const string& base,
const string& path)
434 if (base.empty() ||
isabs(path))
return path;
435 if (
issep(base[base.size() - 1]))
return base + path;
437 return base +
'\\' + path;
439 return base +
'/' + path;
451 const DWORD info = ::GetFileAttributes(path.c_str());
452 return (FILE_ATTRIBUTE_DIRECTORY & info) == 0;
455 if (stat(path.c_str(), &info) != 0)
return false;
456 return S_ISREG(info.st_mode);
465 const DWORD info = ::GetFileAttributes(path.c_str());
466 return (FILE_ATTRIBUTE_DIRECTORY & info) != 0;
469 if (stat(path.c_str(), &info) != 0)
return false;
470 return S_ISDIR(info.st_mode);
479 const DWORD info = ::GetFileAttributes(path.c_str());
480 return info != INVALID_FILE_ATTRIBUTES;
483 if (stat(path.c_str(), &info) == 0)
return true;
495 if (lstat(path.c_str(), &info) != 0)
return false;
496 return S_ISLNK(info.st_mode);
Basic exceptions and related helper macros.
std::string ntpath(const std::string &path)
Convert path to Windows representation.
std::string getcwd()
Get absolute path of the (current) working directory.
function normpath(in path)
Clean path, i.e., remove occurences of "./", duplicate slashes,...
function realpath(in path)
Get canonical file path.
std::string join(const std::string &base, const std::string &path)
Join two paths, e.g., base path and relative path.
System related macro definitions.
bool hasext(const std::string &path, const std::set< std::string > *exts=NULL)
Test whether a given path has an extension.
bool isabs(const std::string &path)
Test whether a given path is absolute.
#define BASIS_THROW(type, msg)
Throw exception with given message.
void splitdrive(const std::string &path, std::string &drive, std::string &tail)
Get drive specification of Windows path.
bool issep(char c)
Determine if a given character is a path separator.
bool exists(const std::string path)
Test the existance of a file or directory.
bool isfile(const std::string path)
Test whether a given path is the path of an existent file.
std::string basename(const std::string &path)
Get file name.
void split(const std::string &path, std::string &head, std::string &tail)
Split path into two parts.
std::string relpath(const std::string &path, const std::string &base=std::string())
Make path relative.
Operating system dependent functions.
bool islink(const std::string &path)
Whether a given path is a symbolic link.
void splitext(const std::string &path, std::string &head, std::string &ext, const std::set< std::string > *exts=NULL, bool icase=false)
Get file name extension.
function abspath(in path)
Get absolute path given a relative path.
std::string dirname(const std::string &path)
Get file directory.
File/directory path related functions.
std::string readlink(const std::string &path)
Read value of symbolic link.
bool isdir(const std::string path)
Test whether a given path is the path of an existent directory.
std::string posixpath(const std::string &path)
Convert path to Posix (e.g., Unix, Mac OS) representation.