From: Mikko Rasa Date: Sun, 27 Aug 2006 17:23:03 +0000 (+0000) Subject: Add relative() to utils X-Git-Tag: fs-1.0~21 X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=commitdiff_plain;h=bfbb7edfb2ae76d23f26e0b22787617ff621747d Add relative() to utils Unify init and operator/= with add_component Allow a Path to start with .. --- diff --git a/source/path.cpp b/source/path.cpp index 1a9460a..6127f7a 100644 --- a/source/path.cpp +++ b/source/path.cpp @@ -34,6 +34,9 @@ bool Path::is_absolute() const return false; } +/** +Extracts the given component range from the path. +*/ Path Path::subpath(unsigned start, unsigned count) const { Path result; @@ -60,26 +63,7 @@ Path &Path::operator/=(const Path &p) else { for(iterator i=p.begin(); i!=p.end(); ++i) - { - if(*i=="..") - { - unsigned slash=path.rfind(DIRCHAR); -#ifdef WIN32 - if(is_windows_drive(path.substr(0,slash))) ++slash; -#endif - if(slash==0) ++slash; - if(slash==string::npos) - path=""; - else - path.erase(slash); - } - else if(*i!=".") - { - if(path.size()>1 || (path.size()==1 && path[0]!=DIRCHAR)) - path+=DIRCHAR; - path+=*i; - } - } + add_component(*i); } return *this; } @@ -116,20 +100,17 @@ bool Path::operator==(const Path &p) const #endif } -void Path::init(const std::string &p) +void Path::init(const string &p) { unsigned start=0; - bool absolute=false; - if(p[0]==DIRCHAR) - absolute=true; + if(p[0]=='/' || p[0]=='\\') + add_component(string(1, DIRCHAR)); while(1) { unsigned slash=p.find_first_of("/\\",start); if(slash>start) { - if(path.size() || absolute) - path+=DIRCHAR; - path+=p.substr(start,slash-start); + add_component(p.substr(start, slash-start)); } if(slash==string::npos) break; @@ -137,6 +118,62 @@ void Path::init(const std::string &p) } } +/** +Adds a single component to the path, emulating the cd command. +*/ +void Path::add_component(const string &comp) +{ + if(comp.empty()) + ; + else if(comp.size()==1 && comp[0]==DIRCHAR) + { + // Replace the path with the root directory +#ifdef WIN32 + unsigned slash=path.find(DIRCHAR); + if(is_windows_drive(path.substr(0, slash))) + path=path.substr(0,2); + else +#endif + path=comp; + } +#ifdef WIN32 + else if(is_windows_drive(comp)) + path=comp; +#endif + else if(comp=="..") + { + if(path.empty()) + path=comp; + // .. in root directory is a no-op + else if(path.size()==1 && path[0]==DIRCHAR) + ; +#ifdef WIN32 + else if(is_windows_drive(path)) + ; +#endif + else + { + unsigned slash=path.rfind(DIRCHAR); + unsigned start=(slash==string::npos)?0:slash+1; + if(path.compare(start, string::npos, "..")) + { + // If the last component already is a .., add another + path+=DIRCHAR; + path+=comp; + } + else + // Otherwise, erase the last component + path.erase(slash, string::npos); + } + } + else if(comp!=".") + { + if(path.size()>1 || (path.size()==1 && path[0]!=DIRCHAR)) + path+=DIRCHAR; + path+=comp; + } +} + Path::iterator::iterator(const Path &p): path(p), start(0) diff --git a/source/path.h b/source/path.h index 9e1e374..0f33301 100644 --- a/source/path.h +++ b/source/path.h @@ -59,6 +59,7 @@ private: std::string path; void init(const std::string &); + void add_component(const std::string &); }; inline std::ostream &operator<<(std::ostream &o, const Path &p) { o< list_files(const Path &); extern bool exists(const Path &); extern Filename splitext(const std::string &); extern int fnmatch(const std::string &, const Path &); +extern Path relative(const Path &, const Path &); inline int stat(const Path &fn, struct stat &st) { return ::stat(fn.str().c_str(), &st); }