From 75205dd307c57df24d282b94f1bca3b668579c1e Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 6 Sep 2014 14:26:41 +0200 Subject: Do not low-case paths in normalize() for Win32 Instead, do case-insensitive comparison. Also handle separators while at it. --- cutl/fs/path.hxx | 46 ++++++++++++++++++++++++++++++++++------------ cutl/fs/path.ixx | 32 ++++++++++++++++---------------- cutl/fs/path.txx | 8 +------- tests/fs/path/driver.cxx | 15 ++++++++++++--- 4 files changed, 63 insertions(+), 38 deletions(-) diff --git a/cutl/fs/path.hxx b/cutl/fs/path.hxx index cbe71a6..45a7891 100644 --- a/cutl/fs/path.hxx +++ b/cutl/fs/path.hxx @@ -39,7 +39,6 @@ namespace cutl // could be multiple seperators. For example, on Windows // we check for both '/' and '\'. // - static bool is_separator (C c) { @@ -78,6 +77,33 @@ namespace cutl return string_type::npos; } + + static int + compare (string_type const& l, string_type const& r) + { + size_type ln (l.size ()), rn (r.size ()), n (ln < rn ? ln : rn); + for (size_type i (0); i != n; ++i) + { +#ifdef _WIN32 + C lc (tolower (l[i])), rc (tolower (r[i])); +#else + C lc (l[i]), rc (r[i]); +#endif + if (is_separator (lc) && is_separator (rc)) + continue; + + if (lc < rc) return -1; + if (lc > rc) return 1; + } + + return ln < rn ? -1 : (ln > rn ? 1 : 0); + } + + private: +#ifdef _WIN32 + static C + tolower (C); +#endif }; template @@ -210,10 +236,8 @@ namespace cutl 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. + // separators, and converting all directory separators to the + // canonical form. Returns *this. // basic_path& normalize (); @@ -249,10 +273,13 @@ namespace cutl return *this; } + // Note that comparison is case-insensitive if the filesystem is + // not case-sensitive (e.g., Windows). + // bool operator== (basic_path const& x) const { - return path_ == x.path_; + return traits::compare (path_, x.path_) == 0; } bool @@ -264,7 +291,7 @@ namespace cutl bool operator< (basic_path const& x) const { - return path_ < x.path_; + return traits::compare (path_, x.path_) < 0; } public: @@ -287,11 +314,6 @@ namespace cutl void init (); -#ifdef _WIN32 - static C - tolower (C); -#endif - private: string_type path_; }; diff --git a/cutl/fs/path.ixx b/cutl/fs/path.ixx index 80d3bb3..64d05a6 100644 --- a/cutl/fs/path.ixx +++ b/cutl/fs/path.ixx @@ -11,6 +11,22 @@ namespace cutl { namespace fs { +#ifdef _WIN32 + template <> + inline char path_traits:: + tolower (char c) + { + return std::tolower (c); + } + + template <> + inline wchar_t path_traits:: + tolower (wchar_t c) + { + return std::towlower (c); + } +#endif + template inline bool basic_path:: absolute () const @@ -51,21 +67,5 @@ namespace cutl return string (); } #endif - -#ifdef _WIN32 - template <> - inline char basic_path:: - tolower (char c) - { - return std::tolower (c); - } - - template <> - inline wchar_t basic_path:: - tolower (wchar_t c) - { - return std::towlower (c); - } -#endif } } diff --git a/cutl/fs/path.txx b/cutl/fs/path.txx index e95c890..8939665 100644 --- a/cutl/fs/path.txx +++ b/cutl/fs/path.txx @@ -182,15 +182,9 @@ namespace cutl 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) + if (++i != e) p += traits::directory_separator; } diff --git a/tests/fs/path/driver.cxx b/tests/fs/path/driver.cxx index 6c77e67..c6bf46a 100644 --- a/tests/fs/path/driver.cxx +++ b/tests/fs/path/driver.cxx @@ -112,11 +112,20 @@ main () assert (path ("./..").normalize ().string () == ".."); assert (path ("../.").normalize ().string () == ".."); assert (path ("foo/./..").normalize ().string () == ""); - assert (path ("C:/foo/./..").normalize ().string () == "c:"); + assert (path ("C:/foo/./..").normalize ().string () == "C:"); assert (path ("./foo").normalize ().string () == "foo"); - assert (path ("C:").normalize ().string () == "c:"); - assert (path ("C:\\Foo12//Bar").normalize ().string () == "c:\\foo12\\bar"); + assert (path ("C:").normalize ().string () == "C:"); + assert (path ("C:\\Foo12//Bar").normalize ().string () == "C:\\Foo12\\Bar"); +#endif + + // comparison + // + assert (path ("./foo") == path("./foo")); + assert (path ("./boo") < path("./foo")); +#ifdef _WIN32 + assert (path (".\\foo") == path("./FoO")); + assert (path (".\\boo") < path(".\\Foo")); #endif // posix_string -- cgit v1.1