aboutsummaryrefslogtreecommitdiff
path: root/cutl
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-10-22 11:19:52 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-10-22 11:19:52 +0200
commit547a401ac73d21b769939a3244f991112dd9d2f7 (patch)
tree6ffeaba2df9ed2877ea423e7a51619e38bea854b /cutl
parent13fe7d4568db4da0ec7dca7a69055f77933ce3f3 (diff)
Add additional path functions
These include: absolute(), relative(), current(), complete(), and normalize().
Diffstat (limited to 'cutl')
-rw-r--r--cutl/fs/path.cxx46
-rw-r--r--cutl/fs/path.hxx90
-rw-r--r--cutl/fs/path.ixx63
-rw-r--r--cutl/fs/path.txx102
4 files changed, 279 insertions, 22 deletions
diff --git a/cutl/fs/path.cxx b/cutl/fs/path.cxx
index 578cc5b..5aaf2a9 100644
--- a/cutl/fs/path.cxx
+++ b/cutl/fs/path.cxx
@@ -3,6 +3,14 @@
// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
// license : MIT; see accompanying LICENSE file
+#ifdef _WIN32
+# include <direct.h> // _getcwd, _wgetcwd, _MAX_PATH
+#else
+# include <stdlib.h> // mbstowcs
+# include <limits.h> // PATH_MAX
+# include <unistd.h> // getcwd
+#endif
+
#include <cutl/fs/path.hxx>
namespace cutl
@@ -14,5 +22,43 @@ namespace cutl
{
return "invalid filesystem path";
}
+
+ template <>
+ basic_path<char> basic_path<char>::
+ current ()
+ {
+#ifdef _WIN32
+ char cwd[_MAX_PATH];
+ if(_getcwd(cwd, _MAX_PATH) == 0)
+ throw invalid_basic_path<char> (".");
+#else
+ char cwd[PATH_MAX];
+ if (getcwd (cwd, PATH_MAX) == 0)
+ throw invalid_basic_path<char> (".");
+#endif
+
+ return basic_path<char> (cwd);
+ }
+
+ template <>
+ basic_path<wchar_t> basic_path<wchar_t>::
+ current ()
+ {
+#ifdef _WIN32
+ wchar_t wcwd[_MAX_PATH];
+ if(_wgetcwd(wcwd, _MAX_PATH) == 0)
+ throw invalid_basic_path<wchar_t> (".");
+#else
+ char cwd[PATH_MAX];
+ if (getcwd (cwd, PATH_MAX) == 0)
+ throw invalid_basic_path<wchar_t> (L".");
+
+ wchar_t wcwd[PATH_MAX];
+ if (mbstowcs (wcwd, cwd, PATH_MAX) == size_type (-1))
+ throw invalid_basic_path<wchar_t> (L".");
+#endif
+
+ return basic_path<wchar_t> (wcwd);
+ }
}
}
diff --git a/cutl/fs/path.hxx b/cutl/fs/path.hxx
index 9fed07a..9bef17f 100644
--- a/cutl/fs/path.hxx
+++ b/cutl/fs/path.hxx
@@ -29,11 +29,11 @@ namespace cutl
// Canonical directory and path seperators.
//
#ifdef _WIN32
- static char const directory_separator = '\\';
- static char const path_separator = ';';
+ static C const directory_separator = '\\';
+ static C const path_separator = ';';
#else
- static char const directory_separator = '/';
- static char const path_separator = ':';
+ static C const directory_separator = '/';
+ static C const path_separator = ':';
#endif
// Directory separator tests. On some platforms there
@@ -52,24 +52,29 @@ namespace cutl
}
static size_type
- find_separator (string_type const& s)
+ find_separator (string_type const& s, size_type pos = 0)
{
- for (size_type i (0), n (s.size ()); i < n; ++i)
+ for (size_type n (s.size ()); pos < n; ++pos)
{
- if (is_separator (s[i]))
- return i;
+ if (is_separator (s[pos]))
+ return pos;
}
return string_type::npos;
}
static size_type
- rfind_separator (string_type const& s)
+ rfind_separator (string_type const& s, size_type pos = string_type::npos)
{
- for (size_type i (s.size ()) ; i > 0; --i)
+ if (pos == string_type::npos)
+ pos = s.size ();
+ else
+ pos++;
+
+ for (; pos > 0; --pos)
{
- if (is_separator (s[i - 1]))
- return i - 1;
+ if (is_separator (s[pos - 1]))
+ return pos - 1;
}
return string_type::npos;
@@ -150,6 +155,34 @@ namespace cutl
init ();
}
+ void
+ swap (basic_path& p)
+ {
+ path_.swap (p.path_);
+ }
+
+ static basic_path
+ current ();
+
+ public:
+ bool
+ empty () const
+ {
+ return path_.empty ();
+ }
+
+ bool
+ absolute () const;
+
+ bool
+ relative () const
+ {
+ return !absolute ();
+ }
+
+ bool
+ root () const;
+
public:
// Return the path without the directory part.
//
@@ -168,6 +201,23 @@ namespace cutl
base () const;
public:
+ // Normalize the path. This includes collapsing the '.' and '..'
+ // directories if possible, collapsing multiple directory
+ // separators, converting all directory separators to the
+ // canonical form, and making the path lower-case if the
+ // filesystem is not case-sensitive (e.g., Windows). Returns
+ // *this.
+ //
+ basic_path&
+ normalize ();
+
+ // Make the path absolute using the current directory unless
+ // it is already absolute.
+ //
+ basic_path&
+ complete ();
+
+ public:
basic_path
operator/ (basic_path const& x)
{
@@ -204,13 +254,13 @@ namespace cutl
return !(*this == x);
}
- public:
bool
- empty () const
+ operator< (basic_path const& x) const
{
- return path_.empty ();
+ return path_ < x.path_;
}
+ public:
string_type
string () const
{
@@ -221,11 +271,10 @@ namespace cutl
void
init ();
- bool
- root () const
- {
- return path_.size () == 1 && traits::is_separator (path_[0]);
- }
+#ifdef _WIN32
+ static C
+ tolower (C);
+#endif
private:
string_type path_;
@@ -240,6 +289,7 @@ namespace cutl
}
}
+#include <cutl/fs/path.ixx>
#include <cutl/fs/path.txx>
#endif // CUTL_FS_PATH_HXX
diff --git a/cutl/fs/path.ixx b/cutl/fs/path.ixx
new file mode 100644
index 0000000..7a92110
--- /dev/null
+++ b/cutl/fs/path.ixx
@@ -0,0 +1,63 @@
+// file : cutl/fs/path.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#ifdef _WIN32
+# include <cctype> // std::tolower
+# include <cwctype> // std::towlower
+#endif
+
+namespace cutl
+{
+ namespace fs
+ {
+ template <typename C>
+ inline bool basic_path<C>::
+ absolute () const
+ {
+#ifdef _WIN32
+ return path_.size () > 1 && path_[1] == ':';
+#else
+ return !path_.empty () && traits::is_separator (path_[0]);
+#endif
+ }
+
+ template <typename C>
+ inline bool basic_path<C>::
+ root () const
+ {
+#ifdef _WIN32
+ return path_.size () == 2 && path_[1] == ':';
+#else
+ return path_.size () == 1 && traits::is_separator (path_[0]);
+#endif
+ }
+
+ template <typename C>
+ inline basic_path<C>& basic_path<C>::
+ complete ()
+ {
+ if (relative ())
+ *this = current () / *this;
+
+ return *this;
+ }
+
+#ifdef _WIN32
+ template <>
+ inline char basic_path<char>::
+ tolower (char c)
+ {
+ return std::tolower (c);
+ }
+
+ template <>
+ inline wchar_t basic_path<wchar_t>::
+ tolower (wchar_t c)
+ {
+ return std::towlower (c);
+ }
+#endif
+ }
+}
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 <vector>
+
namespace cutl
{
namespace fs
@@ -67,7 +69,7 @@ namespace cutl
basic_path<C>& basic_path<C>::
operator/= (basic_path<C> const& r)
{
- if (r.root ())
+ if (r.absolute ())
throw invalid_basic_path<C> (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 <typename C>
+ basic_path<C>& basic_path<C>::
+ normalize ()
+ {
+ if (empty ())
+ return *this;
+
+ bool abs (absolute ());
+
+ typedef std::vector<string_type> 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<C> (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 <typename C>
void basic_path<C>::
init ()
{