diff options
Diffstat (limited to 'butl')
-rw-r--r-- | butl/filesystem.cxx | 18 | ||||
-rw-r--r-- | butl/path | 50 | ||||
-rw-r--r-- | butl/path.cxx | 16 | ||||
-rw-r--r-- | butl/path.ixx | 16 | ||||
-rw-r--r-- | butl/path.txx | 38 | ||||
-rw-r--r-- | butl/process.cxx | 10 |
6 files changed, 97 insertions, 51 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. // @@ -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 { |