From 9c53b966c34d505e27681f2ed51998d3a737a663 Mon Sep 17 00:00:00 2001
From: Andrei Karas <akaras@inbox.ru>
Date: Fri, 10 Mar 2017 18:35:16 +0300
Subject: Add pathJoin functions for join parts of path.

---
 src/utils/stringutils.cpp         | 99 +++++++++++++++++++++++++++++++++++++++
 src/utils/stringutils.h           |  7 +++
 src/utils/stringutils_unittest.cc | 77 ++++++++++++++++++++++++++++++
 3 files changed, 183 insertions(+)

(limited to 'src')

diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp
index 28b2c8e1e..3663cc007 100644
--- a/src/utils/stringutils.cpp
+++ b/src/utils/stringutils.cpp
@@ -1044,6 +1044,105 @@ void sanitizePath(std::string &path)
     replaceRecursiveAll(path, sep2Str, sepStr);
 }
 
+std::string pathJoin(std::string str1,
+                     const std::string &str2)
+{
+#ifdef WIN32
+    const char sep = '\\';
+    std::string sepStr = "\\";
+#else
+    const char sep = '/';
+    std::string sepStr = "/";
+#endif
+
+    if (str1.empty())
+    {
+        if (str2[0] == sep)
+            return str2;
+        else
+            return sepStr.append(str2);
+    }
+    const size_t sz1 = str1.size();
+    if (str2.empty())
+    {
+        if (str1[sz1 - 1] == sep)
+            return str1;
+        else
+            return str1.append(sepStr);
+    }
+    if (str1[sz1 - 1] == sep)
+    {
+        if (str2[0] == sep)
+            return str1.append(str2.substr(1));
+        else
+            return str1.append(str2);
+    }
+    else
+    {
+        if (str2[0] == sep)
+            return str1.append(str2);
+        else
+            return str1.append(sepStr).append(str2);
+    }
+}
+
+std::string pathJoin(std::string str1,
+                     const std::string &str2,
+                     const std::string &str3)
+{
+#ifdef WIN32
+    const char sep = '\\';
+    std::string sepStr = "\\";
+#else
+    const char sep = '/';
+    std::string sepStr = "/";
+#endif
+
+    if (str1.empty())
+    {
+        return pathJoin(str2, str3);
+    }
+    size_t sz1 = str1.size();
+    if (str2.empty())
+    {
+        return pathJoin(str1, str3);
+    }
+    if (str3.empty())
+    {
+        return pathJoin(str1, str2);
+    }
+    if (str1[sz1 - 1] == sep)
+    {
+        if (str2[0] == sep)
+            str1.append(str2.substr(1));
+        else
+            str1.append(str2);
+    }
+    else
+    {
+        if (str2[0] == sep)
+            str1.append(str2);
+        else
+            str1.append(sepStr).append(str2);
+    }
+
+    sz1 = str1.size();
+    if (str1[sz1 - 1] == sep)
+    {
+        if (str3[0] == sep)
+            return str1.append(str3.substr(1));
+        else
+            return str1.append(str3);
+    }
+    else
+    {
+        if (str3[0] == sep)
+            return str1.append(str3);
+        else
+            return str1.append(sepStr).append(str3);
+    }
+}
+
 #ifndef DYECMD
 void replaceItemLinks(std::string &msg)
 {
diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h
index 4db1041ef..6c2b6f097 100644
--- a/src/utils/stringutils.h
+++ b/src/utils/stringutils.h
@@ -275,4 +275,11 @@ std::string escapeString(std::string str);
 
 void sanitizePath(std::string &path);
 
+std::string pathJoin(std::string str1,
+                     const std::string &str2);
+
+std::string pathJoin(std::string str1,
+                     const std::string &str2,
+                     const std::string &str3);
+
 #endif  // UTILS_STRINGUTILS_H
diff --git a/src/utils/stringutils_unittest.cc b/src/utils/stringutils_unittest.cc
index dd60af3cd..712935820 100644
--- a/src/utils/stringutils_unittest.cc
+++ b/src/utils/stringutils_unittest.cc
@@ -1339,6 +1339,83 @@ TEST_CASE("stringuntils sanitizePath")
         "dir" + sep + "with" + sep + "sepa" + sep + "ra" + sep + "tors");
 }
 
+TEST_CASE("stringuntils pathJoin1")
+{
+    const std::string sep = dirSeparator;
+
+    REQUIRE(pathJoin("", "") == sep);
+    REQUIRE(pathJoin(sep, "") == sep);
+    REQUIRE(pathJoin("", sep) == sep);
+    REQUIRE(pathJoin(sep, sep) == sep);
+    REQUIRE(pathJoin("dir1", "dir2") == "dir1" + sep + "dir2");
+    REQUIRE(pathJoin("dir1" + sep, "dir2") == "dir1" + sep + "dir2");
+    REQUIRE(pathJoin("dir1", sep + "dir2") == "dir1" + sep + "dir2");
+    REQUIRE(pathJoin("dir1" + sep, sep + "dir2") == "dir1" + sep + "dir2");
+    REQUIRE(pathJoin("dir1" + sep + "dir2" + sep + "dir3", "dir4") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4");
+    REQUIRE(pathJoin("dir1" + sep + "dir2" + sep, "dir3" + sep + "dir4") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4");
+    REQUIRE(pathJoin("dir1" + sep + "dir2", "dir3" + sep + "dir4") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4");
+    REQUIRE(pathJoin("dir1" + sep + "dir2", sep + "dir3" + sep + "dir4") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4");
+}
+
+TEST_CASE("stringuntils pathJoin2")
+{
+    const std::string sep = dirSeparator;
+
+    REQUIRE(pathJoin("", "", "") == sep);
+    REQUIRE(pathJoin(sep, "", "") == sep);
+    REQUIRE(pathJoin("", sep, "") == sep);
+    REQUIRE(pathJoin("", "", sep) == sep);
+    REQUIRE(pathJoin(sep, sep, "") == sep);
+    REQUIRE(pathJoin(sep, "", sep) == sep);
+    REQUIRE(pathJoin("", sep, sep) == sep);
+    REQUIRE(pathJoin(sep, sep, sep) == sep);
+
+    REQUIRE(pathJoin("dir1", "dir2", "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, "dir2", "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1", sep + "dir2", "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1", "dir2" + sep, "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1", "dir2", sep + "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1", "dir2", "dir3" + sep) ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep);
+    REQUIRE(pathJoin("dir1" + sep, sep + "dir2", "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, "dir2" + sep, "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, "dir2", sep + "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, sep + "dir2" + sep, "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, sep + "dir2", sep + "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, sep + "dir2" + sep, "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep, sep + "dir2" + sep, sep + "dir3") ==
+        "dir1" + sep + "dir2" + sep + "dir3");
+    REQUIRE(pathJoin("dir1" + sep + "dir2" + sep + "dir3", "dir4", "dir5") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5");
+    REQUIRE(pathJoin("dir1" + sep + "dir2" + sep,
+        "dir3" + sep + "dir4",
+        "dir5") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5");
+    REQUIRE(pathJoin("dir1" + sep + "dir2",
+        "dir3",
+        sep + "dir4" + sep + "dir5") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5");
+    REQUIRE(pathJoin("dir1" + sep + "dir2",
+        sep + "dir3" + sep + "dir4",
+        sep + "dir5") ==
+        "dir1" + sep + "dir2" + sep + "dir3" + sep + "dir4" + sep + "dir5");
+}
+
 TEST_CASE("stringuntils secureChatCommand")
 {
     std::string str;
-- 
cgit v1.2.3-70-g09d2