]> git.tdb.fi Git - libs/core.git/blobdiff - source/path.cpp
Add relative() to utils
[libs/core.git] / source / path.cpp
index 1a9460ac9c15f4496fd320adacf89d9aed36401a..6127f7a84c06955dc4963589a8406515d3bd4207 100644 (file)
@@ -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)