From 816663495874e123c2d4a187edb6eab07593f10d Mon Sep 17 00:00:00 2001
From: KWSys Upstream <kwrobot@kitware.com>
Date: Thu, 28 Mar 2019 11:02:39 -0400
Subject: KWSys 2019-03-28 (e92bdbe8)

Code extracted from:

    https://gitlab.kitware.com/utils/kwsys.git

at commit e92bdbe8e6eca2a8b6dcf14920e5e25308504206 (master).

Upstream Shortlog
-----------------

Ben Boeckel (7):
      30198dbc DynamicLoader: fix error reporting on Windows
      cf6b5f69 DynamicLoader: use Encoding::ToWindowsExtendedPath for the libname
      d17291ad DynamicLoader: support loading libraries using flags
      40d9e482 DynamicLoader: support loading sibling libraries on Windows
      971809c5 DynamicLoader: test the SearchBesideLibrary flag
      efb006b9 DynamicLoader: include stdio.h for _snprintf
      9e8e9ba0 DynamicLoader: avoid the min/max macros from windows.h

Brad King (1):
      92334e76 SystemTools: CopyFileAlways: avoid copying file over self
---
 CMakeLists.txt        |  17 ++++++++
 DynamicLoader.cxx     | 110 +++++++++++++++++++++++++++++++++++++-------------
 DynamicLoader.hxx.in  |  15 ++++++-
 SystemTools.cxx       |   8 ++--
 testDynamicLoader.cxx |  28 ++++++++++---
 testDynloadImpl.c     |  10 +++++
 testDynloadImpl.h     |  15 +++++++
 testDynloadUse.c      |  15 +++++++
 8 files changed, 179 insertions(+), 39 deletions(-)
 create mode 100644 testDynloadImpl.c
 create mode 100644 testDynloadImpl.h
 create mode 100644 testDynloadUse.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8577506..db4ef90 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -172,6 +172,9 @@ ENDIF()
 IF(KWSYS_USE_Directory)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
+IF(KWSYS_USE_DynamicLoader)
+  SET(KWSYS_USE_Encoding 1)
+ENDIF()
 IF(KWSYS_USE_FStream)
   SET(KWSYS_USE_Encoding 1)
 ENDIF()
@@ -1096,6 +1099,20 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
       ADD_LIBRARY(${KWSYS_NAMESPACE}TestDynload MODULE testDynload.c)
       SET_PROPERTY(TARGET ${KWSYS_NAMESPACE}TestDynload PROPERTY LABELS ${KWSYS_LABELS_LIB})
       ADD_DEPENDENCIES(${KWSYS_NAMESPACE}TestDynload ${KWSYS_TARGET_INTERFACE})
+
+      if (WIN32)
+        # Windows tests supported flags.
+        add_library(${KWSYS_NAMESPACE}TestDynloadImpl SHARED testDynloadImpl.c)
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY LABELS ${KWSYS_LABELS_LIB})
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY DEFINE_SYMBOL BUILDING_TestDynloadImpl)
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadImpl PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+        add_dependencies(${KWSYS_NAMESPACE}TestDynloadImpl ${KWSYS_TARGET_INTERFACE})
+        add_library(${KWSYS_NAMESPACE}TestDynloadUse MODULE testDynloadUse.c)
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LABELS ${KWSYS_LABELS_LIB})
+        set_property(TARGET ${KWSYS_NAMESPACE}TestDynloadUse PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/dynloaddir")
+        add_dependencies(${KWSYS_NAMESPACE}TestDynloadUse ${KWSYS_TARGET_INTERFACE})
+        target_link_libraries(${KWSYS_NAMESPACE}TestDynloadUse PRIVATE ${KWSYS_NAMESPACE}TestDynloadImpl)
+      endif ()
     ENDIF()
     CREATE_TEST_SOURCELIST(
       KWSYS_CXX_TEST_SRCS ${KWSYS_NAMESPACE}TestsCxx.cxx
diff --git a/DynamicLoader.cxx b/DynamicLoader.cxx
index a85690f..b93a215 100644
--- a/DynamicLoader.cxx
+++ b/DynamicLoader.cxx
@@ -1,9 +1,14 @@
 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
    file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#if defined(_WIN32)
+#  define NOMINMAX // hide min,max to not conflict with <limits>
+#endif
+
 #include "kwsysPrivate.h"
 #include KWSYS_HEADER(DynamicLoader.hxx)
 
 #include KWSYS_HEADER(Configure.hxx)
+#include KWSYS_HEADER(Encoding.hxx)
 
 // Work-around CMake dependency scanning limitation.  This must
 // duplicate the above list of headers.
@@ -25,6 +30,28 @@
 // Each part of the ifdef contains a complete implementation for
 // the static methods of DynamicLoader.
 
+#define CHECK_OPEN_FLAGS(var, supported, ret)                                 \
+  do {                                                                        \
+    /* Check for unknown flags. */                                            \
+    if ((var & AllOpenFlags) != var) {                                        \
+      return ret;                                                             \
+    }                                                                         \
+                                                                              \
+    /* Check for unsupported flags. */                                        \
+    if ((var & (supported)) != var) {                                         \
+      return ret;                                                             \
+    }                                                                         \
+  } while (0)
+
+namespace KWSYS_NAMESPACE {
+
+DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
+  const std::string& libname)
+{
+  return DynamicLoader::OpenLibrary(libname, 0);
+}
+}
+
 #if !KWSYS_SUPPORTS_SHARED_LIBS
 // Implementation for environments without dynamic libs
 #  include <string.h> // for strerror()
@@ -32,7 +59,7 @@
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
   return 0;
 }
@@ -67,8 +94,10 @@ const char* DynamicLoader::LastError()
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, 0);
+
   return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
 }
 
@@ -130,8 +159,10 @@ const char* DynamicLoader::LastError()
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, 0);
+
   NSObjectFileImageReturnCode rc;
   NSObjectFileImage image = 0;
 
@@ -185,19 +216,22 @@ const char* DynamicLoader::LastError()
 // Implementation for Windows win32 code but not cygwin
 #  include <windows.h>
 
+#  include <stdio.h>
+
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
-  DynamicLoader::LibraryHandle lh;
-  int length = MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, NULL, 0);
-  wchar_t* wchars = new wchar_t[length + 1];
-  wchars[0] = '\0';
-  MultiByteToWideChar(CP_UTF8, 0, libname.c_str(), -1, wchars, length);
-  lh = LoadLibraryW(wchars);
-  delete[] wchars;
-  return lh;
+  CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, NULL);
+
+  DWORD llFlags = 0;
+  if (flags & SearchBesideLibrary) {
+    llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH;
+  }
+
+  return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), NULL,
+                        llFlags);
 }
 
 int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
@@ -247,24 +281,38 @@ DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
 #  endif
 }
 
+#  define DYNLOAD_ERROR_BUFFER_SIZE 1024
+
 const char* DynamicLoader::LastError()
 {
-  LPVOID lpMsgBuf = NULL;
-
-  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
-                NULL, GetLastError(),
-                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
-                (LPTSTR)&lpMsgBuf, 0, NULL);
+  wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+  DWORD error = GetLastError();
+  DWORD length = FormatMessageW(
+    FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+    lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, NULL);
+
+  static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1];
+
+  if (length < 1) {
+    /* FormatMessage failed.  Use a default message.  */
+    _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+              "DynamicLoader encountered error 0x%X.  "
+              "FormatMessage failed with error 0x%X",
+              error, GetLastError());
+    return str;
+  }
 
-  if (!lpMsgBuf) {
-    return NULL;
+  if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str,
+                           DYNLOAD_ERROR_BUFFER_SIZE, NULL, NULL)) {
+    /* WideCharToMultiByte failed.  Use a default message.  */
+    _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
+              "DynamicLoader encountered error 0x%X.  "
+              "WideCharToMultiByte failed with error 0x%X",
+              error, GetLastError());
   }
 
-  static char* str = 0;
-  delete[] str;
-  str = strcpy(new char[strlen((char*)lpMsgBuf) + 1], (char*)lpMsgBuf);
-  // Free the buffer.
-  LocalFree(lpMsgBuf);
   return str;
 }
 
@@ -282,8 +330,10 @@ namespace KWSYS_NAMESPACE {
 static image_id last_dynamic_err = B_OK;
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, 0);
+
   // image_id's are integers, errors are negative. Add one just in case we
   //  get a valid image_id of zero (is that even possible?).
   image_id rc = load_add_on(libname.c_str());
@@ -360,8 +410,10 @@ const char* DynamicLoader::LastError()
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, NULL);
+
   char* name = (char*)calloc(1, libname.size() + 1);
   dld_init(program_invocation_name);
   strncpy(name, libname.c_str(), libname.size());
@@ -404,8 +456,10 @@ const char* DynamicLoader::LastError()
 namespace KWSYS_NAMESPACE {
 
 DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
-  const std::string& libname)
+  const std::string& libname, int flags)
 {
+  CHECK_OPEN_FLAGS(flags, 0, NULL);
+
   return dlopen(libname.c_str(), RTLD_LAZY);
 }
 
diff --git a/DynamicLoader.hxx.in b/DynamicLoader.hxx.in
index 08f2790..539c742 100644
--- a/DynamicLoader.hxx.in
+++ b/DynamicLoader.hxx.in
@@ -66,10 +66,23 @@ public:
   // Return type from DynamicLoader::GetSymbolAddress.
   typedef void (*SymbolPointer)();
 
+  enum OpenFlags
+  {
+    // Search for dependent libraries beside the library being loaded.
+    //
+    // This is currently only supported on Windows.
+    SearchBesideLibrary = 0x00000001,
+
+    AllOpenFlags = SearchBesideLibrary
+  };
+
   /** Load a dynamic library into the current process.
    * The returned LibraryHandle can be used to access the symbols in the
-   * library. */
+   * library. The optional second argument is a set of flags to use when
+   * opening the library. If unrecognized or unsupported flags are specified,
+   * the library is not opened. */
   static LibraryHandle OpenLibrary(const std::string&);
+  static LibraryHandle OpenLibrary(const std::string&, int);
 
   /** Attempt to detach a dynamic library from the
    * process.  A value of true is returned if it is successful. */
diff --git a/SystemTools.cxx b/SystemTools.cxx
index b736ed4..87da80e 100644
--- a/SystemTools.cxx
+++ b/SystemTools.cxx
@@ -2436,10 +2436,6 @@ static bool CloneFileContent(const std::string& source,
 bool SystemTools::CopyFileAlways(const std::string& source,
                                  const std::string& destination)
 {
-  // If files are the same do not copy
-  if (SystemTools::SameFile(source, destination)) {
-    return true;
-  }
   mode_t perm = 0;
   bool perms = SystemTools::GetPermissions(source, perm);
   std::string real_destination = destination;
@@ -2460,6 +2456,10 @@ bool SystemTools::CopyFileAlways(const std::string& source,
     } else {
       destination_dir = SystemTools::GetFilenamePath(destination);
     }
+    // If files are the same do not copy
+    if (SystemTools::SameFile(source, real_destination)) {
+      return true;
+    }
 
     // Create destination directory
 
diff --git a/testDynamicLoader.cxx b/testDynamicLoader.cxx
index ce87117..eff2ed7 100644
--- a/testDynamicLoader.cxx
+++ b/testDynamicLoader.cxx
@@ -21,11 +21,15 @@
 // left on disk.
 #include <testSystemTools.h>
 
-static std::string GetLibName(const char* lname)
+static std::string GetLibName(const char* lname, const char* subdir = NULL)
 {
   // Construct proper name of lib
   std::string slname;
   slname = EXECUTABLE_OUTPUT_PATH;
+  if (subdir) {
+    slname += "/";
+    slname += subdir;
+  }
 #ifdef CMAKE_INTDIR
   slname += "/";
   slname += CMAKE_INTDIR;
@@ -45,26 +49,29 @@ static std::string GetLibName(const char* lname)
  * r3: should CloseLibrary succeed ?
  */
 static int TestDynamicLoader(const char* libname, const char* symbol, int r1,
-                             int r2, int r3)
+                             int r2, int r3, int flags = 0)
 {
   std::cerr << "Testing: " << libname << std::endl;
   kwsys::DynamicLoader::LibraryHandle l =
-    kwsys::DynamicLoader::OpenLibrary(libname);
+    kwsys::DynamicLoader::OpenLibrary(libname, flags);
   // If result is incompatible with expectation just fails (xor):
   if ((r1 && !l) || (!r1 && l)) {
-    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    std::cerr << "OpenLibrary: " << kwsys::DynamicLoader::LastError()
+              << std::endl;
     return 1;
   }
   kwsys::DynamicLoader::SymbolPointer f =
     kwsys::DynamicLoader::GetSymbolAddress(l, symbol);
   if ((r2 && !f) || (!r2 && f)) {
-    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    std::cerr << "GetSymbolAddress: " << kwsys::DynamicLoader::LastError()
+              << std::endl;
     return 1;
   }
 #ifndef __APPLE__
   int s = kwsys::DynamicLoader::CloseLibrary(l);
   if ((r3 && !s) || (!r3 && s)) {
-    std::cerr << kwsys::DynamicLoader::LastError() << std::endl;
+    std::cerr << "CloseLibrary: " << kwsys::DynamicLoader::LastError()
+              << std::endl;
     return 1;
   }
 #else
@@ -113,5 +120,14 @@ int testDynamicLoader(int argc, char* argv[])
   res += TestDynamicLoader(libname.c_str(), "TestDynamicLoaderData", 1, 1, 1);
   res += TestDynamicLoader(libname.c_str(), "_TestDynamicLoaderData", 1, 0, 1);
 
+#ifdef _WIN32
+  libname = GetLibName(KWSYS_NAMESPACE_STRING "TestDynloadUse", "dynloaddir");
+  res += TestDynamicLoader(libname.c_str(), "dummy", 0, 0, 0);
+  res += TestDynamicLoader(libname.c_str(), "TestLoad", 1, 1, 1,
+                           kwsys::DynamicLoader::SearchBesideLibrary);
+  res += TestDynamicLoader(libname.c_str(), "_TestLoad", 1, 0, 1,
+                           kwsys::DynamicLoader::SearchBesideLibrary);
+#endif
+
   return res;
 }
diff --git a/testDynloadImpl.c b/testDynloadImpl.c
new file mode 100644
index 0000000..2b9069b
--- /dev/null
+++ b/testDynloadImpl.c
@@ -0,0 +1,10 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+
+#include "testDynloadImpl.h"
+
+int TestDynamicLoaderImplData = 0;
+
+void TestDynamicLoaderImplSymbolPointer()
+{
+}
diff --git a/testDynloadImpl.h b/testDynloadImpl.h
new file mode 100644
index 0000000..d0c9dfb
--- /dev/null
+++ b/testDynloadImpl.h
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#ifdef _WIN32
+#  ifdef BUILDING_TestDynloadImpl
+#    define DLIMPL_EXPORT __declspec(dllexport)
+#  else
+#    define DLIMPL_EXPORT __declspec(dllimport)
+#  endif
+#else
+#  define DLIMPL_EXPORT
+#endif
+
+DLIMPL_EXPORT int TestDynamicLoaderImplData;
+
+DLIMPL_EXPORT void TestDynamicLoaderImplSymbolPointer();
diff --git a/testDynloadUse.c b/testDynloadUse.c
new file mode 100644
index 0000000..5402add
--- /dev/null
+++ b/testDynloadUse.c
@@ -0,0 +1,15 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
+#include "testDynloadImpl.h"
+
+#ifdef _WIN32
+#  define DL_EXPORT __declspec(dllexport)
+#else
+#  define DL_EXPORT
+#endif
+
+DL_EXPORT int TestLoad()
+{
+  TestDynamicLoaderImplSymbolPointer();
+  return TestDynamicLoaderImplData;
+}
-- 
cgit v0.12