aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2016-12-07 01:22:53 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2016-12-07 11:27:32 +0300
commit3e6110dec6f4cb004b8594b9b798a9db5b08fe7a (patch)
treee27cd6b75386752c7bf5cbe0bb35b55e17ff6c0e
parente7b033d7b38bc55f934521b5f35060b43a8b0526 (diff)
Add path::current(), path::parent()
-rw-r--r--butl/filesystem.cxx18
-rw-r--r--butl/path50
-rw-r--r--butl/path.cxx16
-rw-r--r--butl/path.ixx16
-rw-r--r--butl/path.txx38
-rw-r--r--butl/process.cxx10
-rw-r--r--tests/path/driver.cxx17
-rw-r--r--tests/process/driver.cxx6
8 files changed, 113 insertions, 58 deletions
diff --git a/butl/filesystem.cxx b/butl/filesystem.cxx
index 424e361..0643938 100644
--- a/butl/filesystem.cxx
+++ b/butl/filesystem.cxx
@@ -531,14 +531,17 @@ namespace butl
errno = 0;
if (struct dirent* de = readdir (h_))
{
- const char* n (de->d_name);
+ // We can accept some overhead for '.' and '..' (relying on short
+ // string optimization) in favor of a more compact code.
+ //
+ path p (de->d_name);
// Skip '.' and '..'.
//
- if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
+ if (p.current () || p.parent ())
continue;
- e_.p_ = path (n);
+ e_.p_ = move (p);
e_.t_ = d_type<struct dirent> (de, nullptr);
e_.lt_ = entry_type::unknown;
}
@@ -665,14 +668,17 @@ namespace butl
if (r)
{
- const char* n (fi.name);
+ // We can accept some overhead for '.' and '..' (relying on short
+ // string optimization) in favor of a more compact code.
+ //
+ path p (fi.name);
// Skip '.' and '..'.
//
- if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
+ if (p.current () || p.parent ())
continue;
- e_.p_ = path (n);
+ e_.p_ = move (p);
// We do not support symlinks at the moment.
//
diff --git a/butl/path b/butl/path
index 2e243ff..726bbe6 100644
--- a/butl/path
+++ b/butl/path
@@ -121,6 +121,30 @@ namespace butl
#endif
}
+ static bool
+ current (const string_type& s)
+ {
+ return current (s.c_str (), s.size ());
+ }
+
+ static bool
+ current (const C* s, size_type n)
+ {
+ return n == 1 && s[0] == '.';
+ }
+
+ static bool
+ parent (const string_type& s)
+ {
+ return parent (s.c_str (), s.size ());
+ }
+
+ static bool
+ parent (const C* s, size_type n)
+ {
+ return n == 2 && s[0] == '.' && s[1] == '.';
+ }
+
static size_type
find_separator (string_type const& s,
size_type pos = 0,
@@ -276,16 +300,16 @@ namespace butl
// the underlying OS errors.
//
static string_type
- current ();
+ current_directory ();
static void
- current (string_type const&);
+ current_directory (string_type const&);
// Return the user home directory. Throw std::system_error to report the
// underlying OS errors.
//
static string_type
- home ();
+ home_directory ();
// Return the temporary directory. Throw std::system_error to report the
// underlying OS errors.
@@ -548,16 +572,16 @@ namespace butl
// the underlying OS errors.
//
static dir_type
- current () {return dir_type (traits::current ());}
+ current_directory () {return dir_type (traits::current_directory ());}
static void
- current (basic_path const&);
+ current_directory (basic_path const&);
// Return the user home directory. Throw std::system_error to report the
// underlying OS errors.
//
static dir_type
- home () {return dir_type (traits::home ());}
+ home_directory () {return dir_type (traits::home_directory ());}
// Return the temporary directory. Throw std::system_error to report the
// underlying OS errors.
@@ -603,6 +627,20 @@ namespace butl
bool
root () const;
+ // The following predicates return true for the "." and ".." paths,
+ // respectively. Note that the result doesn't depend on the presence or
+ // spelling of the trailing directory separator.
+ //
+ // Also note that the path must literally match the specified values rather
+ // than be semantically current or parent. For example for paths "foo/.."
+ // or "bar/../.." the predicates return false.
+ //
+ bool
+ current () const;
+
+ bool
+ parent () const;
+
// Test, based on the presence/absence of the trailing separator, if the
// path is to a directory.
//
diff --git a/butl/path.cxx b/butl/path.cxx
index 03d4b1f..d77f9a4 100644
--- a/butl/path.cxx
+++ b/butl/path.cxx
@@ -60,7 +60,7 @@ namespace butl
template <>
LIBBUTL_EXPORT path_traits<char>::string_type path_traits<char>::
- current ()
+ current_directory ()
{
#ifdef _WIN32
char cwd[_MAX_PATH];
@@ -78,7 +78,7 @@ namespace butl
template <>
LIBBUTL_EXPORT void path_traits<char>::
- current (string_type const& s)
+ current_directory (string_type const& s)
{
#ifdef _WIN32
if (_chdir (s.c_str ()) != 0)
@@ -173,10 +173,10 @@ namespace butl
template <>
LIBBUTL_EXPORT path_traits<char>::string_type path_traits<char>::
- home ()
+ home_directory ()
{
#ifndef _WIN32
- return butl::home ();
+ return home ();
#else
// Could be set by, e.g., MSYS and Cygwin shells.
//
@@ -223,7 +223,7 @@ namespace butl
template <>
LIBBUTL_EXPORT path_traits<wchar_t>::string_type path_traits<wchar_t>::
- current ()
+ current_directory ()
{
#ifdef _WIN32
wchar_t wcwd[_MAX_PATH];
@@ -245,7 +245,7 @@ namespace butl
template <>
LIBBUTL_EXPORT void path_traits<wchar_t>::
- current (string_type const& s)
+ current_directory (string_type const& s)
{
#ifdef _WIN32
if (_wchdir (s.c_str ()) != 0)
@@ -305,11 +305,11 @@ namespace butl
template <>
LIBBUTL_EXPORT path_traits<wchar_t>::string_type path_traits<wchar_t>::
- home ()
+ home_directory ()
{
#ifndef _WIN32
wchar_t d[PATH_MAX];
- size_t r (mbstowcs (d, butl::home ().c_str (), PATH_MAX));
+ size_t r (mbstowcs (d, home ().c_str (), PATH_MAX));
if (r == size_t (-1))
throw system_error (EINVAL, system_category ());
diff --git a/butl/path.ixx b/butl/path.ixx
index c87a376..b1212f4 100644
--- a/butl/path.ixx
+++ b/butl/path.ixx
@@ -88,6 +88,20 @@ namespace butl
template <typename C, typename K>
inline bool basic_path<C, K>::
+ current () const
+ {
+ return traits::current (this->path_);
+ }
+
+ template <typename C, typename K>
+ inline bool basic_path<C, K>::
+ parent () const
+ {
+ return traits::parent (this->path_);
+ }
+
+ template <typename C, typename K>
+ inline bool basic_path<C, K>::
root () const
{
const string_type& s (this->path_);
@@ -232,7 +246,7 @@ namespace butl
complete ()
{
if (relative ())
- *this = current () / *this;
+ *this = current_directory () / *this;
return *this;
}
diff --git a/butl/path.txx b/butl/path.txx
index 0cdaf5b..7c46dbe 100644
--- a/butl/path.txx
+++ b/butl/path.txx
@@ -193,10 +193,7 @@ namespace butl
if (!tsep)
{
const string_type& l (ps.back ());
- size_type ln (l.size ());
-
- if ((ln == 1 && l[0] == '.') ||
- (ln == 2 && l[0] == '.' && l[1] == '.'))
+ if (traits::current (l) || traits::parent (l))
tsep = true;
}
}
@@ -208,30 +205,21 @@ namespace butl
for (typename paths::iterator i (ps.begin ()), e (ps.end ()); i != e; ++i)
{
string_type& s (*i);
- size_type n (s.size ());
- if (n == 1 && s[0] == '.')
+ if (traits::current (s))
continue;
- if (n == 2 && s[0] == '.' && s[1] == '.')
+ // If '..' then pop the last directory from r unless it is '..'.
+ //
+ if (traits::parent (s) && !r.empty () && !traits::parent (r.back ()))
{
- // Pop the last directory from r unless it is '..'.
+ // Cannot go past the root directory.
//
- if (!r.empty ())
- {
- string_type const& s1 (r.back ());
+ if (abs && r.size () == 1)
+ throw invalid_basic_path<C> (this->path_);
- if (!(s1.size () == 2 && s1[0] == '.' && s1[1] == '.'))
- {
- // Cannot go past the root directory.
- //
- if (abs && r.size () == 1)
- throw invalid_basic_path<C> (this->path_);
-
- r.pop_back ();
- continue;
- }
- }
+ r.pop_back ();
+ continue;
}
r.push_back (std::move (s));
@@ -286,7 +274,7 @@ namespace butl
}
else if (!cur_empty) // Collapse to canonical current directory.
{
- p = ".";
+ p.assign (1, '.');
ts = 1; // Canonical separator is always first.
}
else // Collapse to empty path.
@@ -304,14 +292,14 @@ namespace butl
template <typename C, typename K>
void basic_path<C, K>::
- current (basic_path const& p)
+ current_directory (basic_path const& p)
{
const string_type& s (p.string ());
if (s.empty ())
throw invalid_basic_path<char> (s);
- traits::current (s);
+ traits::current_directory (s);
}
template <typename C>
diff --git a/butl/process.cxx b/butl/process.cxx
index cf4b26d..df9fb1f 100644
--- a/butl/process.cxx
+++ b/butl/process.cxx
@@ -189,7 +189,7 @@ namespace butl
}
else
{
- const string& d (traits::current ());
+ const string& d (traits::current_directory ());
if (search (d.c_str (), d.size (), true))
return r;
@@ -507,7 +507,7 @@ namespace butl
}
else
{
- const string& d (traits::current ());
+ const string& d (traits::current_directory ());
if (search (d.c_str (), d.size (), true)) // Appends extension.
return r;
@@ -567,7 +567,7 @@ namespace butl
// idea to prepend .\ for clarity.
//
{
- const string& d (traits::current ());
+ const string& d (traits::current_directory ());
if (search (d.c_str (), d.size ()))
return r;
@@ -582,8 +582,8 @@ namespace butl
e = strchr (b, traits::path_separator);
// Empty path (i.e., a double colon or a colon at the beginning or end
- // of PATH) means search in the current dirrectory. Silently skip
- // invalid paths.
+ // of PATH) means search in the current directory. Silently skip invalid
+ // paths.
//
try
{
diff --git a/tests/path/driver.cxx b/tests/path/driver.cxx
index fe192ce..4806cea 100644
--- a/tests/path/driver.cxx
+++ b/tests/path/driver.cxx
@@ -141,6 +141,15 @@ main ()
assert (path ("C:\\foo.txt\\").base ().representation () == "C:\\foo\\");
#endif
+ // current/parent
+ //
+ assert (path (".").current ());
+ assert (path ("./").current ());
+ assert (!path (".abc").current ());
+ assert (path ("..").parent ());
+ assert (path ("../").parent ());
+ assert (!path ("..abc").parent ());
+
// iteration
//
{
@@ -483,8 +492,8 @@ main ()
assert (path::temp_directory ().absolute ());
//assert (wpath::temp_directory ().absolute ());
- assert (path::home ().absolute ());
- //assert (wpath::home ().absolute ());
+ assert (path::home_directory ().absolute ());
+ //assert (wpath::home_directory ().absolute ());
// normalize and actualize
//
@@ -503,7 +512,7 @@ main ()
assert (test ("c:\\pROGRAM fILES/NonSense\\sTUFF/") ==
"C:\\Program Files\\NonSense\\sTUFF\\");
- dir_path cwd (path::current ());
+ dir_path cwd (path::current_directory ());
assert (cwd.normalize (true).representation () == cwd.representation ());
}
#endif
@@ -512,7 +521,7 @@ main ()
path p ("../foo");
p.complete ();
- cerr << path::current () << endl;
+ cerr << path::current_directory () << endl;
cerr << p << endl;
p.normalize ();
cerr << p << endl;
diff --git a/tests/process/driver.cxx b/tests/process/driver.cxx
index bc75cc2..ac8f54d 100644
--- a/tests/process/driver.cxx
+++ b/tests/process/driver.cxx
@@ -225,7 +225,7 @@ main (int argc, const char* argv[])
// write it to cout and/or cerr.
//
- if (!wd.empty () && wd.realize () != dir_path::current ())
+ if (!wd.empty () && wd.realize () != dir_path::current_directory ())
return 1;
try
@@ -305,7 +305,7 @@ main (int argc, const char* argv[])
// Execute the child using the relative path.
//
- dir_path::current (fp.directory ());
+ dir_path::current_directory (fp.directory ());
assert (exec (dir_path (".") / fp.leaf ()));
@@ -326,7 +326,7 @@ main (int argc, const char* argv[])
assert (_putenv (("PATH=" + paths).c_str ()) == 0);
#endif
- dir_path::current (fp.directory () / dir_path (".."));
+ dir_path::current_directory (fp.directory () / dir_path (".."));
assert (exec (fp.leaf ()));