From 547a401ac73d21b769939a3244f991112dd9d2f7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 22 Oct 2010 11:19:52 +0200 Subject: Add additional path functions These include: absolute(), relative(), current(), complete(), and normalize(). --- cutl/fs/path.txx | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 100 insertions(+), 2 deletions(-) (limited to 'cutl/fs/path.txx') diff --git a/cutl/fs/path.txx b/cutl/fs/path.txx index e955928..f4bbb10 100644 --- a/cutl/fs/path.txx +++ b/cutl/fs/path.txx @@ -3,6 +3,8 @@ // copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC // license : MIT; see accompanying LICENSE file +#include + namespace cutl { namespace fs @@ -67,7 +69,7 @@ namespace cutl basic_path& basic_path:: operator/= (basic_path const& r) { - if (r.root ()) + if (r.absolute ()) throw invalid_basic_path (r.path_); if (path_.empty () || r.path_.empty ()) @@ -76,7 +78,7 @@ namespace cutl return *this; } - if (!root ()) + if (!traits::is_separator (path_[path_.size () - 1])) path_ += traits::directory_separator; path_ += r.path_; @@ -85,6 +87,102 @@ namespace cutl } template + basic_path& basic_path:: + normalize () + { + if (empty ()) + return *this; + + bool abs (absolute ()); + + typedef std::vector paths; + paths ps; + + for (size_type b (0), e (traits::find_separator (path_)), + n (path_.size ());; + e = traits::find_separator (path_, b)) + { + string_type s (path_, b, e == string_type::npos ? e : e - b); + ps.push_back (s); + + if (e == string_type::npos) + break; + + ++e; + + while (e < n && traits::is_separator (path_[e])) + ++e; + + if (e == n) + break; + + b = e; + } + + // First collapse '.' and '..'. + // + paths r; + + for (typename paths::const_iterator i (ps.begin ()), e (ps.end ()); + i != e; ++i) + { + string_type const& s (*i); + size_type n (s.size ()); + + if (n == 1 && s[0] == '.') + continue; + + if (n == 2 && s[0] == '.' && s[1] == '.') + { + // Pop the last directory from r unless it is '..'. + // + if (!r.empty ()) + { + string_type const& s1 (r.back ()); + + if (!(s1.size () == 2 && s1[0] == '.' && s1[1] == '.')) + { + // Cannot go past the root directory. + // + if (abs && r.size () == 1) + throw invalid_basic_path (path_); + + r.pop_back (); + continue; + } + } + } + + r.push_back (s); + } + + // Reassemble the path. + // + string_type p; + + for (typename paths::const_iterator i (r.begin ()), e (r.end ()); + i != e;) + { +#ifdef _WIN32 + for (size_type j (0), n (i->size ()); j < n; ++j) + p += tolower ((*i)[j]); +#else + p += *i; +#endif + ++i; + + if (i != e) + p += traits::directory_separator; + } + + if (p.empty () && !r.empty ()) + p += traits::directory_separator; // Root directory. + + path_.swap (p); + return *this; + } + + template void basic_path:: init () { -- cgit v1.1