]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
enhance: Add util::getenv_path and util::getenv_path_list
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 17 Oct 2024 18:44:31 +0000 (20:44 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Tue, 22 Oct 2024 16:42:51 +0000 (18:42 +0200)
src/ccache/util/environment.cpp
src/ccache/util/environment.hpp
unittest/test_util_environment.cpp

index 5b1862aabd6ee778d90a2e6e2e154fdbf8638509..f3c0100910454a78eb7acd38f16739153daf791d 100644 (file)
 
 #include "environment.hpp"
 
+#include <ccache/util/filesystem.hpp>
 #include <ccache/util/format.hpp>
+#include <ccache/util/string.hpp>
 #include <ccache/util/wincompat.hpp>
 
+namespace fs = util::filesystem;
+
 namespace util {
 
 tl::expected<std::string, std::string>
@@ -79,6 +83,91 @@ expand_environment_variables(const std::string& str)
   return result;
 }
 
+#ifdef _WIN32
+
+static std::wstring
+wide_getenv(const char* name)
+{
+  std::vector<wchar_t> wname(strlen(name) + 1);
+  size_t n = mbstowcs(wname.data(), name, wname.size());
+  if (n == static_cast<size_t>(-1)) {
+    return {};
+  }
+
+  std::vector<wchar_t> value(1024);
+  auto len = GetEnvironmentVariableW(wname.data(), value.data(), value.size());
+  if (len == 0) {
+    // Variable not set.
+    return {};
+  }
+  if (len >= value.size()) {
+    // len is the number of needed characters including the terminating null.
+    value.resize(len);
+    len = GetEnvironmentVariableW(wname.data(), value.data(), value.size());
+  }
+  // len is the number of characters excluding the terminating null
+  return std::wstring(value.data(), len);
+}
+
+fs::path
+getenv_path(const char* name)
+{
+  return fs::path(wide_getenv(name));
+}
+
+std::vector<fs::path>
+getenv_path_list(const char* name)
+{
+  std::wstring value = wide_getenv(name);
+  if (value.empty()) {
+    return {};
+  }
+
+  std::vector<fs::path> result;
+  std::wstring_view view(value);
+  size_t left = 0;
+  while (left < view.size()) {
+    size_t right = view.find(';', left);
+    if (right == std::wstring_view::npos) {
+      right = view.length();
+    }
+    std::wstring_view path = view.substr(left, right - left);
+    if (!path.empty()) {
+      result.push_back(fs::path(path));
+    }
+    if (right == std::wstring_view::npos) {
+      break;
+    }
+    left = right + 1;
+  }
+  return result;
+}
+
+#else // _WIN32
+
+fs::path
+getenv_path(const char* name)
+{
+  const char* value = getenv(name);
+  return value ? value : "";
+}
+
+std::vector<fs::path>
+getenv_path_list(const char* name)
+{
+  const char* value = getenv(name);
+  if (!value) {
+    return {};
+  }
+
+  auto strings = split_into_views(value, ":");
+  std::vector<fs::path> paths;
+  std::copy(strings.cbegin(), strings.cend(), std::back_inserter(paths));
+  return paths;
+}
+
+#endif //_WIN32
+
 void
 setenv(const std::string& name, const std::string& value)
 {
index 771c213800a1d12c7ba2bdd0299264459177df86..252fea9eeacc19d8233cce12a4d01e29203e4a3b 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2023 Joel Rosdahl and other contributors
+// Copyright (C) 2023-2024 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -20,7 +20,9 @@
 
 #include <tl/expected.hpp>
 
+#include <filesystem>
 #include <string>
+#include <vector>
 
 namespace util {
 
@@ -29,6 +31,13 @@ namespace util {
 tl::expected<std::string, std::string>
 expand_environment_variables(const std::string& str);
 
+// Get value of environment variable `name` as a path.
+std::filesystem::path getenv_path(const char* name);
+
+// Get value of environment variable `name` as a vector of paths where the value
+// is delimited by ';' on Windows and ':' on other systems..
+std::vector<std::filesystem::path> getenv_path_list(const char* name);
+
 // Set environment variable `name` to `value`.
 void setenv(const std::string& name, const std::string& value);
 
index 2d60a7077230c384b1897d5b2c07449906268b29..4a4fa030732c2d1a734fb52b4b4359f509c3fd01 100644 (file)
 // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 #include <ccache/util/environment.hpp>
+#include <ccache/util/filesystem.hpp>
 
 #include <doctest/doctest.h>
 
+#include <vector>
+
+namespace fs = util::filesystem;
+
 TEST_SUITE_BEGIN("util");
 
+#ifdef _WIN32
+
+TEST_CASE("util::getenv_path_list")
+{
+  SUBCASE("unset")
+  {
+    util::unsetenv("test");
+    std::vector<fs::path> expected;
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("empty")
+  {
+    util::setenv("test", "");
+    std::vector<fs::path> expected = {};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("delimiters")
+  {
+    util::setenv("test", ";;");
+    std::vector<fs::path> expected = {};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("multiple")
+  {
+    util::setenv("test", "c:\\foo;/bar");
+    std::vector<fs::path> expected = {"c:\\foo", "/bar"};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("delimiters around")
+  {
+    util::setenv("test", ";c:\\foo;");
+    std::vector<fs::path> expected = {"c:\\foo"};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+}
+
+#else
+
+TEST_CASE("util::getenv_path_list")
+{
+  SUBCASE("unset")
+  {
+    util::unsetenv("test");
+    std::vector<fs::path> expected;
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("empty")
+  {
+    util::setenv("test", "");
+    std::vector<fs::path> expected = {};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("delimiters")
+  {
+    util::setenv("test", "::");
+    std::vector<fs::path> expected = {};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("multiple")
+  {
+    util::setenv("test", "/foo:/bar");
+    std::vector<fs::path> expected = {"/foo", "/bar"};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+
+  SUBCASE("delimiters around")
+  {
+    util::setenv("test", ":/foo:");
+    std::vector<fs::path> expected = {"/foo"};
+    CHECK(util::getenv_path_list("test") == expected);
+  }
+}
+
+#endif
+
 TEST_CASE("util::expand_environment_variables")
 {
   util::setenv("FOO", "bar");