changeset 2920:ad0e7def3338

Toolbox::SubstituteVariables and SystemToolbox::GetEnvironmentVariables
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 07 Nov 2018 11:13:30 +0100
parents 2ca9cd064b15
children 0a4428aad512
files Core/SystemToolbox.cpp Core/SystemToolbox.h Core/Toolbox.cpp Core/Toolbox.h UnitTestsSources/UnitTestsMain.cpp
diffstat 5 files changed, 138 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/Core/SystemToolbox.cpp	Tue Nov 06 15:41:21 2018 +0100
+++ b/Core/SystemToolbox.cpp	Wed Nov 07 11:13:30 2018 +0100
@@ -38,6 +38,7 @@
 #if defined(_WIN32)
 #  include <windows.h>
 #  include <process.h>   // For "_spawnvp()" and "_getpid()"
+#  include <stdlib.h>    // For "environ"
 #else
 #  include <unistd.h>    // For "execvp()"
 #  include <sys/wait.h>  // For "waitpid()"
@@ -72,6 +73,51 @@
 #include <boost/thread.hpp>
 
 
+/*=========================================================================
+  The section below comes from the Boost 1.68.0 project:
+  https://github.com/boostorg/program_options/blob/boost-1.68.0/src/parsers.cpp
+  
+  Copyright Vladimir Prus 2002-2004.
+  Distributed under the Boost Software License, Version 1.0.
+  (See accompanying file LICENSE_1_0.txt
+  or copy at http://www.boost.org/LICENSE_1_0.txt)
+  =========================================================================*/
+
+// The 'environ' should be declared in some cases. E.g. Linux man page says:
+// (This variable must be declared in the user program, but is declared in 
+// the header file unistd.h in case the header files came from libc4 or libc5, 
+// and in case they came from glibc and _GNU_SOURCE was defined.) 
+// To be safe, declare it here.
+
+// It appears that on Mac OS X the 'environ' variable is not
+// available to dynamically linked libraries.
+// See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
+// See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
+#if defined(__APPLE__) && defined(__DYNAMIC__)
+// The proper include for this is crt_externs.h, however it's not
+// available on iOS. The right replacement is not known. See
+// https://svn.boost.org/trac/boost/ticket/5053
+extern "C"
+{
+  extern char ***_NSGetEnviron(void);
+}
+#  define environ (*_NSGetEnviron()) 
+#else
+#  if defined(__MWERKS__)
+#    include <crtl.h>
+#  else
+#    if !defined(_WIN32) || defined(__COMO_VERSION__)
+extern char** environ;
+#    endif
+#  endif
+#endif
+
+
+/*=========================================================================
+  End of section from the Boost 1.68.0 project
+  =========================================================================*/
+
+
 namespace Orthanc
 {
   static bool finish_;
@@ -645,4 +691,23 @@
       return MimeType_Binary;
     }
   }
+
+
+  void SystemToolbox::GetEnvironmentVariables(std::map<std::string, std::string>& env)
+  {
+    env.clear();
+    
+    for (char **p = environ; *p != NULL; p++)
+    {
+      std::string v(*p);
+      size_t pos = v.find('=');
+
+      if (pos != std::string::npos)
+      {
+        std::string key = v.substr(0, pos);
+        std::string value = v.substr(pos + 1);
+        env[key] = value;
+      } 
+    }
+  }
 }
--- a/Core/SystemToolbox.h	Tue Nov 06 15:41:21 2018 +0100
+++ b/Core/SystemToolbox.h	Wed Nov 07 11:13:30 2018 +0100
@@ -43,6 +43,7 @@
 
 #include "Enumerations.h"
 
+#include <map>
 #include <vector>
 #include <string>
 #include <stdint.h>
@@ -102,5 +103,7 @@
     unsigned int GetHardwareConcurrency();
 
     MimeType AutodetectMimeType(const std::string& path);
+
+    void GetEnvironmentVariables(std::map<std::string, std::string>& env);
   }
 }
--- a/Core/Toolbox.cpp	Tue Nov 06 15:41:21 2018 +0100
+++ b/Core/Toolbox.cpp	Wed Nov 07 11:13:30 2018 +0100
@@ -1490,6 +1490,53 @@
 #endif
     return s;
   }
+
+
+  namespace
+  {
+    // Anonymous namespace to avoid clashes between compilation modules
+
+    class VariableFormatter
+    {
+    public:
+      typedef std::map<std::string, std::string>   Dictionary;
+
+    private:
+      const Dictionary& dictionary_;
+
+    public:
+      VariableFormatter(const Dictionary& dictionary) :
+        dictionary_(dictionary)
+      {
+      }
+  
+      template<typename Out>
+      Out operator()(const boost::smatch& what,
+                     Out out) const
+      {
+        Dictionary::const_iterator found = dictionary_.find(what[1]);
+    
+        if (found != dictionary_.end())
+        {
+          const std::string& value = found->second;
+          out = std::copy(value.begin(), value.end(), out);
+        }
+    
+        return out;
+      }
+    };
+  }
+
+  
+  std::string Toolbox::SubstituteVariables(const std::string& source,
+                                           const std::map<std::string, std::string>& dictionary)
+  {
+    const boost::regex pattern("\\${(.*?)}");
+
+    VariableFormatter formatter(dictionary);
+
+    return boost::regex_replace(source, pattern, formatter);
+  }
 }
 
 
--- a/Core/Toolbox.h	Tue Nov 06 15:41:21 2018 +0100
+++ b/Core/Toolbox.h	Wed Nov 07 11:13:30 2018 +0100
@@ -236,6 +236,9 @@
     void FinalizeOpenSsl();
 
     std::string GenerateUuid();
+
+    std::string SubstituteVariables(const std::string& source,
+                                    const std::map<std::string, std::string>& dictionary);
   }
 }
 
--- a/UnitTestsSources/UnitTestsMain.cpp	Tue Nov 06 15:41:21 2018 +0100
+++ b/UnitTestsSources/UnitTestsMain.cpp	Wed Nov 07 11:13:30 2018 +0100
@@ -1162,6 +1162,26 @@
 }
 
 
+TEST(Toolbox, SubstituteVariables)
+{
+  std::map<std::string, std::string> env;
+  env["NOPE"] = "nope";
+  env["WORLD"] = "world";
+
+  ASSERT_EQ("Hello world\r\nWorld \r\nDone world\r\n",
+            Toolbox::SubstituteVariables(
+              "Hello ${WORLD}\r\nWorld ${HELLO}\r\nDone ${WORLD}\r\n",
+              env));
+
+  SystemToolbox::GetEnvironmentVariables(env);
+  ASSERT_TRUE(env.find("NOPE") == env.end());
+
+  // The "PATH" environment variable should always be available on
+  // machines running the unit tests
+  ASSERT_TRUE(env.find("PATH") != env.end());
+}
+
+
 int main(int argc, char **argv)
 {
   Logging::Initialize();