diff --git a/lib/Basics/FileUtils.cpp b/lib/Basics/FileUtils.cpp index d18bf80911..ca221a27e1 100644 --- a/lib/Basics/FileUtils.cpp +++ b/lib/Basics/FileUtils.cpp @@ -72,6 +72,29 @@ std::string removeTrailingSeparator(std::string const& name) { void normalizePath(std::string& name) { std::replace(name.begin(), name.end(), '/', TRI_DIR_SEPARATOR_CHAR); + +#ifdef _WIN32 + // for Windows the situation is a bit more complicated, + // as a mere replacement of all forward slashes to backslashes + // may leave us with a double backslash for sequences like "bla/\foo". + // in this case we collapse duplicate dir separators to a single one. + // we intentionally ignore the first 2 characters, because they may + // contain a network share filename such as "\\foo\bar" + + size_t const n = name.size(); + size_t out = 0; + + for (size_t i = 0; i < n; ++i) { + if (name[i] == TRI_DIR_SEPARATOR_CHAR && out > 1 && name[out - 1] == TRI_DIR_SEPARATOR_CHAR) { + continue; + } + name[out++] = name[i]; + } + + if (out != n) { + name.resize(out); + } +#endif } //////////////////////////////////////////////////////////////////////////////// diff --git a/tests/Basics/files-test.cpp b/tests/Basics/files-test.cpp index 0ac08b7dde..790b94a701 100644 --- a/tests/Basics/files-test.cpp +++ b/tests/Basics/files-test.cpp @@ -358,6 +358,59 @@ SECTION("tst_absolute_paths") { TRI_Free(path); #endif } + +SECTION("tst_normalize") { + std::string path; + + path = "/foo/bar/baz"; + FileUtils::normalizePath(path); +#ifdef _WIN32 + CHECK(std::string("\\foo\\bar\\baz") == path); +#else + CHECK(std::string("/foo/bar/baz") == path); +#endif + + path = "\\foo\\bar\\baz"; + FileUtils::normalizePath(path); +#ifdef _WIN32 + CHECK(std::string("\\foo\\bar\\baz") == path); +#else + CHECK(std::string("\\foo\\bar\\baz") == path); +#endif + + path = "/foo/bar\\baz"; + FileUtils::normalizePath(path); +#ifdef _WIN32 + CHECK(std::string("\\foo\\bar\\baz") == path); +#else + CHECK(std::string("/foo/bar\\baz") == path); +#endif + + path = "/foo/bar/\\baz"; + FileUtils::normalizePath(path); +#ifdef _WIN32 + CHECK(std::string("\\foo\\bar\\baz") == path); +#else + CHECK(std::string("/foo/bar/\\baz") == path); +#endif + + path = "//foo\\/bar/\\baz"; + FileUtils::normalizePath(path); +#ifdef _WIN32 + CHECK(std::string("\\\\foo\\bar\\baz") == path); +#else + CHECK(std::string("//foo\\/bar/\\baz") == path); +#endif + + path = "\\\\foo\\/bar/\\baz"; + FileUtils::normalizePath(path); +#ifdef _WIN32 + CHECK(std::string("\\\\foo\\bar\\baz") == path); +#else + CHECK(std::string("\\\\foo\\/bar/\\baz") == path); +#endif +} + } ////////////////////////////////////////////////////////////////////////////////